diff --git a/rpc/handlers.go b/rpc/handlers.go index 520f84ca8b..f12123c02f 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -308,7 +308,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getTransactionByHash", Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, - Handler: h.rpcv7Handler.TransactionByHash, + Handler: h.rpcv6Handler.TransactionByHash, }, { Name: "starknet_getTransactionReceipt", diff --git a/rpc/v6/transaction.go b/rpc/v6/transaction.go index 753b1844a4..21b700979d 100644 --- a/rpc/v6/transaction.go +++ b/rpc/v6/transaction.go @@ -11,6 +11,7 @@ import ( "github.com/NethermindEth/juno/clients/gateway" "github.com/NethermindEth/juno/core" "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/db" "github.com/NethermindEth/juno/jsonrpc" rpccore "github.com/NethermindEth/juno/rpc/rpccore" "github.com/NethermindEth/juno/starknet" @@ -427,8 +428,28 @@ func adaptRPCTxToFeederTx(rpcTx *Transaction) *starknet.Transaction { func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Error) { txn, err := h.bcReader.TransactionByHash(&hash) if err != nil { - return nil, rpccore.ErrTxnHashNotFound + if !errors.Is(err, db.ErrKeyNotFound) { + return nil, rpccore.ErrInternal.CloneWithData(err) + } + + // check now if tx is in pending block + pendingB := h.syncReader.PendingBlock() + if pendingB == nil { + return nil, rpccore.ErrTxnHashNotFound + } + + for _, t := range pendingB.Transactions { + if hash.Equal(t.Hash()) { + txn = t + break + } + } + + if txn == nil { + return nil, rpccore.ErrTxnHashNotFound + } } + return AdaptTransaction(txn), nil } @@ -665,7 +686,7 @@ func AdaptTransaction(t core.Transaction) *Transaction { case *core.DeclareTransaction: txn = adaptDeclareTransaction(v) case *core.DeployAccountTransaction: - txn = adaptDeployAccountTrandaction(v) + txn = adaptDeployAccountTransaction(v) case *core.L1HandlerTransaction: nonce := v.Nonce if nonce == nil { @@ -809,7 +830,7 @@ func adaptDeclareTransaction(t *core.DeclareTransaction) *Transaction { return tx } -func adaptDeployAccountTrandaction(t *core.DeployAccountTransaction) *Transaction { +func adaptDeployAccountTransaction(t *core.DeployAccountTransaction) *Transaction { tx := &Transaction{ Hash: t.Hash(), MaxFee: t.MaxFee, diff --git a/rpc/v6/transaction_test.go b/rpc/v6/transaction_test.go index fb03def547..682826b4e3 100644 --- a/rpc/v6/transaction_test.go +++ b/rpc/v6/transaction_test.go @@ -27,14 +27,22 @@ func TestTransactionByHashNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) n := utils.Ptr(utils.Mainnet) - txHash := new(felt.Felt).SetBytes([]byte("random hash")) - mockReader.EXPECT().TransactionByHash(txHash).Return(nil, errors.New("tx not found")) + client := feeder.NewTestClient(t, n) + mainnetGw := adaptfeeder.New(client) - handler := rpc.New(mockReader, nil, nil, "", n, nil) + block, err := mainnetGw.BlockByNumber(context.Background(), 19199) + require.NoError(t, err) + + randomTxHash := new(felt.Felt).SetBytes([]byte("random hash")) + mockReader.EXPECT().TransactionByHash(randomTxHash).Return(nil, db.ErrKeyNotFound) + mockSyncReader.EXPECT().PendingBlock().Return(block) + + handler := rpc.New(mockReader, mockSyncReader, nil, "", n, nil) + tx, rpcErr := handler.TransactionByHash(*randomTxHash) - tx, rpcErr := handler.TransactionByHash(*txHash) assert.Nil(t, tx) assert.Equal(t, rpccore.ErrTxnHashNotFound, rpcErr) } diff --git a/rpc/v7/block_test.go b/rpc/v7/block_test.go index 919bd46147..165f0ef603 100644 --- a/rpc/v7/block_test.go +++ b/rpc/v7/block_test.go @@ -253,6 +253,11 @@ func TestBlockWithTxs(t *testing.T) { n := utils.Ptr(utils.Mainnet) handler := rpcv7.New(mockReader, mockSyncReader, nil, "", n, nil) + // Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler + mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl) + mockReaderV6 := mocks.NewMockReader(mockCtrl) + rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil) + client := feeder.NewTestClient(t, n) gw := adaptfeeder.New(client) @@ -267,10 +272,10 @@ func TestBlockWithTxs(t *testing.T) { assert.Equal(t, len(blockWithTxHashes.TxnHashes), len(blockWithTxs.Transactions)) for i, txnHash := range blockWithTxHashes.TxnHashes { - txn, err := handler.TransactionByHash(*txnHash) + txn, err := rpcv6Handler.TransactionByHash(*txnHash) require.Nil(t, err) - assert.Equal(t, txn, blockWithTxs.Transactions[i]) + assert.Equal(t, adaptV6TxToV7(t, txn), blockWithTxs.Transactions[i]) } } @@ -279,7 +284,7 @@ func TestBlockWithTxs(t *testing.T) { latestBlockTxMap[*tx.Hash()] = tx } - mockReader.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) { + mockReaderV6.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) { if tx, found := latestBlockTxMap[*hash]; found { return tx, nil } diff --git a/rpc/v7/transaction.go b/rpc/v7/transaction.go index 99651c32c4..b30956f5fb 100644 --- a/rpc/v7/transaction.go +++ b/rpc/v7/transaction.go @@ -422,36 +422,6 @@ func adaptRPCTxToFeederTx(rpcTx *Transaction) *starknet.Transaction { Transaction Handlers *****************************************************/ -// TransactionByHash returns the details of a transaction identified by the given hash. -// -// It follows the specification defined here: -// https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L158 -func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Error) { - txn, err := h.bcReader.TransactionByHash(&hash) - if err != nil { - if !errors.Is(err, db.ErrKeyNotFound) { - return nil, rpccore.ErrInternal.CloneWithData(err) - } - - pendingB := h.syncReader.PendingBlock() - if pendingB == nil { - return nil, rpccore.ErrTxnHashNotFound - } - - for _, t := range pendingB.Transactions { - if hash.Equal(t.Hash()) { - txn = t - break - } - } - - if txn == nil { - return nil, rpccore.ErrTxnHashNotFound - } - } - return AdaptTransaction(txn), nil -} - // TransactionByBlockIDAndIndex returns the details of a transaction identified by the given // BlockID and index. // diff --git a/rpc/v7/transaction_test.go b/rpc/v7/transaction_test.go index 73fa023e97..d7067d6212 100644 --- a/rpc/v7/transaction_test.go +++ b/rpc/v7/transaction_test.go @@ -13,6 +13,7 @@ import ( "github.com/NethermindEth/juno/db" "github.com/NethermindEth/juno/mocks" "github.com/NethermindEth/juno/rpc/rpccore" + rpcv6 "github.com/NethermindEth/juno/rpc/v6" rpc "github.com/NethermindEth/juno/rpc/v7" "github.com/NethermindEth/juno/starknet" adaptfeeder "github.com/NethermindEth/juno/starknetdata/feeder" @@ -23,329 +24,6 @@ import ( "go.uber.org/mock/gomock" ) -func TestTransactionByHashNotFound(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - mockReader := mocks.NewMockReader(mockCtrl) - mockSyncReader := mocks.NewMockSyncReader(mockCtrl) - - txHash := new(felt.Felt).SetBytes([]byte("random hash")) - mockReader.EXPECT().TransactionByHash(txHash).Return(nil, db.ErrKeyNotFound) - mockSyncReader.EXPECT().PendingBlock().Return(nil) - - handler := rpc.New(mockReader, mockSyncReader, nil, "", nil, nil) - - tx, rpcErr := handler.TransactionByHash(*txHash) - assert.Nil(t, tx) - assert.Equal(t, rpccore.ErrTxnHashNotFound, rpcErr) -} - -func TestTransactionByHash(t *testing.T) { - tests := map[string]struct { - hash string - network *utils.Network - expected string - }{ - "DECLARE v1": { - hash: "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "DECLARE", - "transaction_hash": "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", - "max_fee": "0xf6dbd653833", - "version": "0x1", - "signature": [ - "0x221b9576c4f7b46d900a331d89146dbb95a7b03d2eb86b4cdcf11331e4df7f2", - "0x667d8062f3574ba9b4965871eec1444f80dacfa7114e1d9c74662f5672c0620" - ], - "nonce": "0x5", - "class_hash": "0x7aed6898458c4ed1d720d43e342381b25668ec7c3e8837f761051bf4d655e54", - "sender_address": "0x39291faa79897de1fd6fb1a531d144daa1590d058358171b83eadb3ceafed8" - }`, - }, - - "DECLARE v0": { - hash: "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "transaction_hash": "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", - "type": "DECLARE", - "max_fee": "0x0", - "version": "0x0", - "signature": [], - "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", - "sender_address": "0x1" - }`, - }, - - "L1 Handler v0 with nonce": { - hash: "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "L1_HANDLER", - "transaction_hash": "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", - "version": "0x0", - "nonce": "0x2", - "contract_address": "0xda8054260ec00606197a4103eb2ef08d6c8af0b6a808b610152d1ce498f8c3", - "entry_point_selector": "0xc73f681176fc7b3f9693986fd7b14581e8d540519e27400e88b8713932be01", - "calldata": [ - "0x142273bcbfca76512b2a05aed21f134c4495208", - "0x160c35f9f962e1bc997f9133d9fb231afd5799f7d63dcbcd506af4866b3874", - "0x16345785d8a0000", - "0x0", - "0x3" - ] - }`, - }, - "L1 Handler v0 without nonce": { - hash: "0x5d50b7020f7cf8033fd7d913e489f47edf74fbf3c8ada85be512c7baa6a2eab", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "L1_HANDLER", - "transaction_hash": "0x5d50b7020f7cf8033fd7d913e489f47edf74fbf3c8ada85be512c7baa6a2eab", - "version": "0x0", - "nonce": "0x0", - "contract_address": "0x58b43819bb12aba8ab3fb2e997523e507399a3f48a1e2aa20a5fb7734a0449f", - "entry_point_selector": "0xe3f5e9e1456ffa52a3fbc7e8c296631d4cc2120c0be1e2829301c0d8fa026b", - "calldata": [ - "0x5474c49483aa09993090979ade8101ebb4cdce4a", - "0xabf8dd8438d1c21e83a8b5e9c1f9b58aaf3ed360", - "0x2", - "0x4c04fac82913f01a8f01f6e15ff7e834ff2d9a9a1d8e9adffc7bd45692f4f9a" - ] - }`, - }, - - "Invoke v1": { - hash: "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "INVOKE", - "transaction_hash": "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", - "max_fee": "0x17f0de82f4be6", - "version": "0x1", - "signature": [ - "0x383ba105b6d0f59fab96a412ad267213ddcd899e046278bdba64cd583d680b", - "0x1896619a17fde468978b8d885ffd6f5c8f4ac1b188233b81b91bcf7dbc56fbd" - ], - "nonce": "0x42", - "sender_address": "0x1fc039de7d864580b57a575e8e6b7114f4d2a954d7d29f876b2eb3dd09394a0", - "calldata": [ - "0x1", - "0x727a63f78ee3f1bd18f78009067411ab369c31dece1ae22e16f567906409905", - "0x22de356837ac200bca613c78bd1fcc962a97770c06625f0c8b3edeb6ae4aa59", - "0x0", - "0xb", - "0xb", - "0xa", - "0x6db793d93ce48bc75a5ab02e6a82aad67f01ce52b7b903090725dbc4000eaa2", - "0x6141eac4031dfb422080ed567fe008fb337b9be2561f479a377aa1de1d1b676", - "0x27eb1a21fa7593dd12e988c9dd32917a0dea7d77db7e89a809464c09cf951c0", - "0x400a29400a34d8f69425e1f4335e6a6c24ce1111db3954e4befe4f90ca18eb7", - "0x599e56821170a12cdcf88fb8714057ce364a8728f738853da61d5b3af08a390", - "0x46ad66f467df625f3b2dd9d3272e61713e8f74b68adac6718f7497d742cfb17", - "0x4f348b585e6c1919d524a4bfe6f97230ecb61736fe57534ec42b628f7020849", - "0x19ae40a095ffe79b0c9fc03df2de0d2ab20f59a2692ed98a8c1062dbf691572", - "0xe120336994adef6c6e47694f87278686511d4622997d4a6f216bd6e9fa9acc", - "0x56e6637a4958d062db8c8198e315772819f64d915e5c7a8d58a99fa90ff0742" - ] - }`, - }, - - "DEPLOY v0": { - hash: "0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "DEPLOY", - "transaction_hash": "0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0", - "version": "0x0", - "class_hash": "0x46f844ea1a3b3668f81d38b5c1bd55e816e0373802aefe732138628f0133486", - "contract_address_salt": "0x74dc2fe193daf1abd8241b63329c1123214842b96ad7fd003d25512598a956b", - "constructor_calldata": [ - "0x6d706cfbac9b8262d601c38251c5fbe0497c3a96cc91a92b08d91b61d9e70c4", - "0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463", - "0x2", - "0x6658165b4984816ab189568637bedec5aa0a18305909c7f5726e4a16e3afef6", - "0x6b648b36b074a91eee55730f5f5e075ec19c0a8f9ffb0903cefeee93b6ff328" - ] - }`, - }, - - "DEPLOY ACCOUNT v1": { - hash: "0xd61fc89f4d1dc4dc90a014957d655d38abffd47ecea8e3fa762e3160f155f2", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "DEPLOY_ACCOUNT", - "transaction_hash": "0xd61fc89f4d1dc4dc90a014957d655d38abffd47ecea8e3fa762e3160f155f2", - "max_fee": "0xb5e620f48000", - "version": "0x1", - "signature": [ - "0x41c3543008dd65ed98c767e5d218b0c0ce1bd0cd60877824951a6f87cc1637d", - "0x7f803845aa7e43d183fd05cd553c64711b1c49af69a155fe8144e8da9a5a50d" - ], - "nonce": "0x0", - "class_hash": "0x1fac3074c9d5282f0acc5c69a4781a1c711efea5e73c550c5d9fb253cf7fd3d", - "contract_address_salt": "0x14e2ae44cbb50dff0e18140e7c415c1f281207d06fd6a0106caf3ff21e130d8", - "constructor_calldata": [ - "0x6113c1775f3d0fda0b45efbb69f6e2306da3c174df523ef0acdd372bf0a61cb" - ] - }`, - }, - - "INVOKE v0": { - hash: "0xf1d99fb97509e0dfc425ddc2a8c5398b74231658ca58b6f8da92f39cb739e", - network: utils.Ptr(utils.Mainnet), - expected: `{ - "type": "INVOKE", - "transaction_hash": "0xf1d99fb97509e0dfc425ddc2a8c5398b74231658ca58b6f8da92f39cb739e", - "max_fee": "0x0", - "version": "0x0", - "signature": [], - "contract_address": "0x43324c97e376d7d164abded1af1e73e9ce8214249f711edb7059c1ca34560e8", - "entry_point_selector": "0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f", - "calldata": [ - "0x1b654cb59f978da2eee76635158e5ff1399bf607cb2d05e3e3b4e41d7660ca2", - "0x2", - "0x5f743efdb29609bfc2002041bdd5c72257c0c6b5c268fc929a3e516c171c731", - "0x635afb0ea6c4cdddf93f42287b45b67acee4f08c6f6c53589e004e118491546" - ] - }`, - }, - "DECLARE v3": { - hash: "0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3", - network: utils.Ptr(utils.Integration), - expected: `{ - "transaction_hash": "0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3", - "type": "DECLARE", - "version": "0x3", - "nonce": "0x1", - "sender_address": "0x2fab82e4aef1d8664874e1f194951856d48463c3e6bf9a8c68e234a629a6f50", - "class_hash": "0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7", - "compiled_class_hash": "0x1add56d64bebf8140f3b8a38bdf102b7874437f0c861ab4ca7526ec33b4d0f8", - "signature": [ - "0x29a49dff154fede73dd7b5ca5a0beadf40b4b069f3a850cd8428e54dc809ccc", - "0x429d142a17223b4f2acde0f5ecb9ad453e188b245003c86fab5c109bad58fc3" - ], - "resource_bounds": { - "l1_gas": { - "max_amount": "0x186a0", - "max_price_per_unit": "0x2540be400" - }, - "l2_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" } - }, - "tip": "0x0", - "paymaster_data": [], - "account_deployment_data": [], - "nonce_data_availability_mode": "L1", - "fee_data_availability_mode": "L1" - }`, - }, - "INVOKE v3": { - hash: "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", - network: utils.Ptr(utils.Integration), - expected: `{ - "type": "INVOKE", - "transaction_hash": "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", - "version": "0x3", - "signature": [ - "0x71a9b2cd8a8a6a4ca284dcddcdefc6c4fd20b92c1b201bd9836e4ce376fad16", - "0x6bef4745194c9447fdc8dd3aec4fc738ab0a560b0d2c7bf62fbf58aef3abfc5" - ], - "nonce": "0xe97", - "resource_bounds": { - "l1_gas": { - "max_amount": "0x186a0", - "max_price_per_unit": "0x5af3107a4000" - }, - "l2_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" } - }, - "tip": "0x0", - "paymaster_data": [], - "sender_address": "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41", - "calldata": [ - "0x2", - "0x450703c32370cf7ffff540b9352e7ee4ad583af143a361155f2b485c0c39684", - "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", - "0x0", - "0x4", - "0x4c312760dfd17a954cdd09e76aa9f149f806d88ec3e402ffaf5c4926f568a42", - "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", - "0x4", - "0x1", - "0x5", - "0x450703c32370cf7ffff540b9352e7ee4ad583af143a361155f2b485c0c39684", - "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", - "0x1", - "0x7fe4fd616c7fece1244b3616bb516562e230be8c9f29668b46ce0369d5ca829", - "0x287acddb27a2f9ba7f2612d72788dc96a5b30e401fc1e8072250940e024a587" - ], - "account_deployment_data": [], - "nonce_data_availability_mode": "L1", - "fee_data_availability_mode": "L1" - }`, - }, - "DEPLOY ACCOUNT v3": { - hash: "0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0", - network: utils.Ptr(utils.Integration), - expected: `{ - "transaction_hash": "0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0", - "version": "0x3", - "signature": [ - "0x6d756e754793d828c6c1a89c13f7ec70dbd8837dfeea5028a673b80e0d6b4ec", - "0x4daebba599f860daee8f6e100601d98873052e1c61530c630cc4375c6bd48e3" - ], - "nonce": "0x0", - "resource_bounds": { - "l1_gas": { - "max_amount": "0x186a0", - "max_price_per_unit": "0x5af3107a4000" - }, - "l2_gas": { "max_amount": "0x0", "max_price_per_unit": "0x0" } - }, - "tip": "0x0", - "paymaster_data": [], - "contract_address_salt": "0x0", - "class_hash": "0x2338634f11772ea342365abd5be9d9dc8a6f44f159ad782fdebd3db5d969738", - "constructor_calldata": [ - "0x5cd65f3d7daea6c63939d659b8473ea0c5cd81576035a4d34e52fb06840196c" - ], - "type": "DEPLOY_ACCOUNT", - "nonce_data_availability_mode": "L1", - "fee_data_availability_mode": "L1" - }`, - }, - } - - for name, test := range tests { - t.Run(name, func(t *testing.T) { - gw := adaptfeeder.New(feeder.NewTestClient(t, test.network)) - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - mockReader := mocks.NewMockReader(mockCtrl) - mockReader.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) { - return gw.Transaction(context.Background(), hash) - }).Times(1) - handler := rpc.New(mockReader, nil, nil, "", test.network, nil) - - hash, err := new(felt.Felt).SetString(test.hash) - require.NoError(t, err) - - expectedMap := make(map[string]any) - require.NoError(t, json.Unmarshal([]byte(test.expected), &expectedMap)) - - res, rpcErr := handler.TransactionByHash(*hash) - require.Nil(t, rpcErr) - - resJSON, err := json.Marshal(res) - require.NoError(t, err) - resMap := make(map[string]any) - require.NoError(t, json.Unmarshal(resJSON, &resMap)) - - assert.Equal(t, expectedMap, resMap, string(resJSON)) - }) - } -} - func TestTransactionByBlockIdAndIndex(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -410,18 +88,23 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { uint64(index)).DoAndReturn(func(number, index uint64) (core.Transaction, error) { return latestBlock.Transactions[index], nil }) - mockReader.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( + + // Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler + mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl) + mockReaderV6 := mocks.NewMockReader(mockCtrl) + mockReaderV6.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( func(hash *felt.Felt) (core.Transaction, error) { return latestBlock.Transactions[index], nil }) + rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil) txn1, rpcErr := handler.TransactionByBlockIDAndIndex(rpc.BlockID{Latest: true}, index) require.Nil(t, rpcErr) - txn2, rpcErr := handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) + txn2, rpcErr := rpcv6Handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) require.Nil(t, rpcErr) - assert.Equal(t, txn1, txn2) + assert.Equal(t, txn1, adaptV6TxToV7(t, txn2)) }) t.Run("blockID - hash", func(t *testing.T) { @@ -432,18 +115,23 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { uint64(index)).DoAndReturn(func(number, index uint64) (core.Transaction, error) { return latestBlock.Transactions[index], nil }) - mockReader.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( - func(hash *felt.Felt) (core.Transaction, error) { - return latestBlock.Transactions[index], nil - }) txn1, rpcErr := handler.TransactionByBlockIDAndIndex(rpc.BlockID{Hash: latestBlockHash}, index) require.Nil(t, rpcErr) - txn2, rpcErr := handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) + // Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler + mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl) + mockReaderV6 := mocks.NewMockReader(mockCtrl) + mockReaderV6.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( + func(hash *felt.Felt) (core.Transaction, error) { + return latestBlock.Transactions[index], nil + }) + rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil) + + txn2, rpcErr := rpcv6Handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) require.Nil(t, rpcErr) - assert.Equal(t, txn1, txn2) + assert.Equal(t, txn1, adaptV6TxToV7(t, txn2)) }) t.Run("blockID - number", func(t *testing.T) { @@ -454,18 +142,23 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { uint64(index)).DoAndReturn(func(number, index uint64) (core.Transaction, error) { return latestBlock.Transactions[index], nil }) - mockReader.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( - func(hash *felt.Felt) (core.Transaction, error) { - return latestBlock.Transactions[index], nil - }) txn1, rpcErr := handler.TransactionByBlockIDAndIndex(rpc.BlockID{Number: uint64(latestBlockNumber)}, index) require.Nil(t, rpcErr) - txn2, rpcErr := handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) + // Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler + mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl) + mockReaderV6 := mocks.NewMockReader(mockCtrl) + mockReaderV6.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( + func(hash *felt.Felt) (core.Transaction, error) { + return latestBlock.Transactions[index], nil + }) + rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil) + + txn2, rpcErr := rpcv6Handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) require.Nil(t, rpcErr) - assert.Equal(t, txn1, txn2) + assert.Equal(t, txn1, adaptV6TxToV7(t, txn2)) }) t.Run("blockID - pending", func(t *testing.T) { @@ -476,21 +169,76 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { mockSyncReader.EXPECT().Pending().Return(&sync.Pending{ Block: latestBlock, }, nil) - mockReader.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( - func(hash *felt.Felt) (core.Transaction, error) { - return latestBlock.Transactions[index], nil - }) txn1, rpcErr := handler.TransactionByBlockIDAndIndex(rpc.BlockID{Pending: true}, index) require.Nil(t, rpcErr) - txn2, rpcErr := handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) + // Use v6 handler as v7 `starknet_getTransactionByHash` uses v6 handler + mockSyncReaderV6 := mocks.NewMockSyncReader(mockCtrl) + mockReaderV6 := mocks.NewMockReader(mockCtrl) + mockReaderV6.EXPECT().TransactionByHash(latestBlock.Transactions[index].Hash()).DoAndReturn( + func(hash *felt.Felt) (core.Transaction, error) { + return latestBlock.Transactions[index], nil + }) + rpcv6Handler := rpcv6.New(mockReaderV6, mockSyncReaderV6, nil, "", n, nil) + + txn2, rpcErr := rpcv6Handler.TransactionByHash(*latestBlock.Transactions[index].Hash()) require.Nil(t, rpcErr) - assert.Equal(t, txn1, txn2) + assert.Equal(t, txn1, adaptV6TxToV7(t, txn2)) }) } +// Convert a v6 transaction object to a v7 transaction object +func adaptV6TxToV7(t *testing.T, tx *rpcv6.Transaction) *rpc.Transaction { + t.Helper() + + var v7ResourceBounds *map[rpc.Resource]rpc.ResourceBounds + if tx.ResourceBounds != nil { + v7ResourceBoundsMap := make(map[rpc.Resource]rpc.ResourceBounds) + for r, rb := range *tx.ResourceBounds { + v7ResourceBoundsMap[rpc.Resource(r)] = rpc.ResourceBounds{ + MaxAmount: rb.MaxAmount, + MaxPricePerUnit: rb.MaxPricePerUnit, + } + } + v7ResourceBounds = &v7ResourceBoundsMap + } + + var v7NonceDAMode *rpc.DataAvailabilityMode + if tx.NonceDAMode != nil { + v7NonceDAMode = utils.Ptr(rpc.DataAvailabilityMode(*tx.NonceDAMode)) + } + + var v7FeeDAMode *rpc.DataAvailabilityMode + if tx.FeeDAMode != nil { + v7FeeDAMode = utils.Ptr(rpc.DataAvailabilityMode(*tx.FeeDAMode)) + } + + return &rpc.Transaction{ + Hash: tx.Hash, + Type: rpc.TransactionType(tx.Type), + Version: tx.Version, + Nonce: tx.Nonce, + MaxFee: tx.MaxFee, + ContractAddress: tx.ContractAddress, + ContractAddressSalt: tx.ContractAddressSalt, + ClassHash: tx.ClassHash, + ConstructorCallData: tx.ConstructorCallData, + SenderAddress: tx.SenderAddress, + Signature: tx.Signature, + CallData: tx.CallData, + EntryPointSelector: tx.EntryPointSelector, + CompiledClassHash: tx.CompiledClassHash, + ResourceBounds: v7ResourceBounds, + Tip: tx.Tip, + PaymasterData: tx.PaymasterData, + AccountDeploymentData: tx.AccountDeploymentData, + NonceDAMode: v7NonceDAMode, + FeeDAMode: v7FeeDAMode, + } +} + // TODO[Pawel]: The following 2 tests `Test[Legacy]TransactionReceiptByHash` are skipped // but we still keep them here. I have a doubt whether they test anything useful. //