diff --git a/rpc/block.go b/rpc/block.go index 5496c10061..189c6ffff0 100644 --- a/rpc/block.go +++ b/rpc/block.go @@ -73,8 +73,8 @@ func (b *BlockID) UnmarshalJSON(data []byte) error { } type ResourcePrice struct { - InStark *felt.Felt `json:"price_in_strk,omitempty"` - InWei *felt.Felt `json:"price_in_wei,omitempty"` + InStark *felt.Felt `json:"price_in_strk"` + InWei *felt.Felt `json:"price_in_wei"` } // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1072 @@ -85,7 +85,7 @@ type BlockHeader struct { NewRoot *felt.Felt `json:"new_root,omitempty"` Timestamp uint64 `json:"timestamp"` SequencerAddress *felt.Felt `json:"sequencer_address,omitempty"` - L1GasPrice *ResourcePrice `json:"l1_gas_price,omitempty"` + L1GasPrice *ResourcePrice `json:"l1_gas_price"` StarknetVersion string `json:"starknet_version,omitempty"` } diff --git a/rpc/handlers.go b/rpc/handlers.go index 36b7115386..7c7153e5f7 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -219,15 +219,6 @@ func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Er }, nil } -func (h *Handler) LegacyBlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { - block, err := h.BlockWithTxHashes(id) - if block != nil { - block.BlockHeader.L1GasPrice = nil - block.BlockHeader.StarknetVersion = "" - } - return block, err -} - func (h *Handler) l1Head() (*core.L1Head, *jsonrpc.Error) { l1Head, err := h.bcReader.L1Head() if err != nil && !errors.Is(err, db.ErrKeyNotFound) { @@ -264,12 +255,20 @@ func adaptBlockHeader(header *core.Header) BlockHeader { Timestamp: header.Timestamp, SequencerAddress: sequencerAddress, L1GasPrice: &ResourcePrice{ - InWei: header.GasPrice, + InWei: header.GasPrice, + InStark: nilToZero(header.GasPriceSTRK), // Old block headers will be nil. }, StarknetVersion: header.ProtocolVersion, } } +func nilToZero(f *felt.Felt) *felt.Felt { + if f == nil { + return &felt.Zero + } + return f +} + // BlockWithTxs returns the block information with full transactions given a block ID. // // It follows the specification defined here: @@ -305,12 +304,16 @@ func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { } func (h *Handler) LegacyBlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { - block, err := h.BlockWithTxs(id) - if block != nil { - block.BlockHeader.L1GasPrice = nil - block.BlockHeader.StarknetVersion = "" + block, rpcErr := h.BlockWithTxs(id) + if rpcErr != nil { + return nil, rpcErr } - return block, err + for _, tx := range block.Transactions { + if err := tx.ToPreV3(); err != nil { + return nil, jsonrpc.Err(jsonrpc.InternalError, err) + } + } + return block, nil } func adaptTransaction(t core.Transaction) *Transaction { @@ -331,19 +334,7 @@ func adaptTransaction(t core.Transaction) *Transaction { case *core.DeclareTransaction: txn = adaptDeclareTransaction(v) case *core.DeployAccountTransaction: - sig := v.Signature() - // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1466 - txn = &Transaction{ - Hash: v.Hash(), - MaxFee: v.MaxFee, - Version: v.Version.AsFelt(), - Signature: &sig, - Nonce: v.Nonce, - Type: TxnDeployAccount, - ContractAddressSalt: v.ContractAddressSalt, - ConstructorCallData: &v.ConstructorCallData, - ClassHash: v.ClassHash, - } + txn = adaptDeployAccountTrandaction(v) case *core.L1HandlerTransaction: // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1669 txn = &Transaction{ @@ -367,13 +358,12 @@ func adaptTransaction(t core.Transaction) *Transaction { // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1605 func adaptInvokeTransaction(t *core.InvokeTransaction) *Transaction { - sig := t.Signature() - invTxn := &Transaction{ + tx := &Transaction{ Type: TxnInvoke, Hash: t.Hash(), MaxFee: t.MaxFee, Version: t.Version.AsFelt(), - Signature: &sig, + Signature: utils.Ptr(t.Signature()), Nonce: t.Nonce, CallData: &t.CallData, ContractAddress: t.ContractAddress, @@ -381,25 +371,65 @@ func adaptInvokeTransaction(t *core.InvokeTransaction) *Transaction { EntryPointSelector: t.EntryPointSelector, } - return invTxn + if tx.Version.Uint64() == 3 { + tx.ResourceBounds = utils.Ptr(adaptResourceBounds(t.ResourceBounds)) + tx.Tip = new(felt.Felt).SetUint64(t.Tip) + tx.PaymasterData = &t.PaymasterData + tx.AccountDeploymentData = &t.AccountDeploymentData + tx.NonceDAMode = utils.Ptr(DataAvailabilityMode(t.NonceDAMode)) + tx.FeeDAMode = utils.Ptr(DataAvailabilityMode(t.FeeDAMode)) + } + return tx } // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1340 func adaptDeclareTransaction(t *core.DeclareTransaction) *Transaction { - sig := t.Signature() - txn := &Transaction{ - Type: TxnDeclare, + tx := &Transaction{ Hash: t.Hash(), + Type: TxnDeclare, MaxFee: t.MaxFee, Version: t.Version.AsFelt(), - Signature: &sig, + Signature: utils.Ptr(t.Signature()), Nonce: t.Nonce, ClassHash: t.ClassHash, SenderAddress: t.SenderAddress, CompiledClassHash: t.CompiledClassHash, } - return txn + if tx.Version.Uint64() == 3 { + tx.ResourceBounds = utils.Ptr(adaptResourceBounds(t.ResourceBounds)) + tx.Tip = new(felt.Felt).SetUint64(t.Tip) + tx.PaymasterData = &t.PaymasterData + tx.AccountDeploymentData = &t.AccountDeploymentData + tx.NonceDAMode = utils.Ptr(DataAvailabilityMode(t.NonceDAMode)) + tx.FeeDAMode = utils.Ptr(DataAvailabilityMode(t.FeeDAMode)) + } + + return tx +} + +func adaptDeployAccountTrandaction(t *core.DeployAccountTransaction) *Transaction { + tx := &Transaction{ + Hash: t.Hash(), + MaxFee: t.MaxFee, + Version: t.Version.AsFelt(), + Signature: utils.Ptr(t.Signature()), + Nonce: t.Nonce, + Type: TxnDeployAccount, + ContractAddressSalt: t.ContractAddressSalt, + ConstructorCallData: &t.ConstructorCallData, + ClassHash: t.ClassHash, + } + + if tx.Version.Uint64() == 3 { + tx.ResourceBounds = utils.Ptr(adaptResourceBounds(t.ResourceBounds)) + tx.Tip = new(felt.Felt).SetUint64(t.Tip) + tx.PaymasterData = &t.PaymasterData + tx.NonceDAMode = utils.Ptr(DataAvailabilityMode(t.NonceDAMode)) + tx.FeeDAMode = utils.Ptr(DataAvailabilityMode(t.FeeDAMode)) + } + + return tx } func (h *Handler) blockByID(id *BlockID) (*core.Block, error) { @@ -450,6 +480,17 @@ func (h *Handler) TransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Erro return adaptTransaction(txn), nil } +func (h *Handler) LegacyTransactionByHash(hash felt.Felt) (*Transaction, *jsonrpc.Error) { + txn, rpcErr := h.TransactionByHash(hash) + if rpcErr != nil { + return nil, rpcErr + } + if err := txn.ToPreV3(); err != nil { + return nil, jsonrpc.Err(jsonrpc.InternalError, err) + } + return txn, nil +} + // BlockTransactionCount returns the number of transactions in a block // identified by the given BlockID. // @@ -499,6 +540,17 @@ func (h *Handler) TransactionByBlockIDAndIndex(id BlockID, txIndex int) (*Transa return adaptTransaction(txn), nil } +func (h *Handler) LegacyTransactionByBlockIDAndIndex(id BlockID, txIndex int) (*Transaction, *jsonrpc.Error) { + txn, rpcErr := h.TransactionByBlockIDAndIndex(id, txIndex) + if rpcErr != nil { + return nil, rpcErr + } + if err := txn.ToPreV3(); err != nil { + return nil, jsonrpc.Err(jsonrpc.InternalError, err) + } + return txn, nil +} + // TransactionReceiptByHash returns the receipt of a transaction identified by the given hash. // // It follows the specification defined here: @@ -565,12 +617,21 @@ func (h *Handler) TransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, es = TxnSuccess } + feeUnit := WEI + version := txn.TxVersion() + if !version.Is(0) && !version.Is(1) && !version.Is(2) { + feeUnit = STRK + } + return &TransactionReceipt{ - FinalityStatus: status, - ExecutionStatus: es, - Type: adaptTransaction(txn).Type, - Hash: txn.Hash(), - ActualFee: receipt.Fee, + FinalityStatus: status, + ExecutionStatus: es, + Type: adaptTransaction(txn).Type, + Hash: txn.Hash(), + ActualFee: &FeePayment{ + Amount: receipt.Fee, + Unit: feeUnit, + }, BlockHash: blockHash, BlockNumber: receiptBlockNumber, MessagesSent: messages, @@ -582,32 +643,34 @@ func (h *Handler) TransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, }, nil } +func (h *Handler) LegacyTransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, *jsonrpc.Error) { + receipt, rpcErr := h.TransactionReceiptByHash(hash) + if rpcErr != nil { + return nil, rpcErr + } + receipt.ActualFee.isLegacy = true + receipt.ExecutionResources.isLegacy = true + return receipt, nil +} + func adaptExecutionResources(resources *core.ExecutionResources) *ExecutionResources { if resources == nil { return &ExecutionResources{} } return &ExecutionResources{ - Steps: NumAsHex(resources.Steps), - MemoryHoles: NumAsHex(resources.MemoryHoles), - Pedersen: NumAsHex(resources.BuiltinInstanceCounter.Pedersen), - RangeCheck: NumAsHex(resources.BuiltinInstanceCounter.RangeCheck), - Bitwise: NumAsHex(resources.BuiltinInstanceCounter.Bitwise), - Ecsda: NumAsHex(resources.BuiltinInstanceCounter.Ecsda), - EcOp: NumAsHex(resources.BuiltinInstanceCounter.EcOp), - Keccak: NumAsHex(resources.BuiltinInstanceCounter.Keccak), - Poseidon: NumAsHex(resources.BuiltinInstanceCounter.Poseidon), + Steps: resources.Steps, + MemoryHoles: resources.MemoryHoles, + Pedersen: resources.BuiltinInstanceCounter.Pedersen, + RangeCheck: resources.BuiltinInstanceCounter.RangeCheck, + Bitwise: resources.BuiltinInstanceCounter.Bitwise, + Ecsda: resources.BuiltinInstanceCounter.Ecsda, + EcOp: resources.BuiltinInstanceCounter.EcOp, + Keccak: resources.BuiltinInstanceCounter.Keccak, + Poseidon: resources.BuiltinInstanceCounter.Poseidon, + SegmentArena: resources.BuiltinInstanceCounter.SegmentArena, } } -func (h *Handler) LegacyTransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, *jsonrpc.Error) { - receipt, err := h.TransactionReceiptByHash(hash) - if receipt != nil { - receipt.ExecutionResources = nil - receipt.MessageHash = "" - } - return receipt, err -} - // StateUpdate returns the state update identified by the given BlockID. // // It follows the specification defined here: @@ -1012,7 +1075,7 @@ func (h *Handler) AddTransaction(txnJSON json.RawMessage) (*AddTxResponse, *json return nil, jsonrpc.Err(jsonrpc.InternalError, errIn.Error()) } txnJSON = updatedReq - } else if version, ok := request["version"]; ok && version == "0x2" { + } else if version, ok := request["version"]; ok && (version == "0x2" || version == "0x3") { contractClass, ok := request["contract_class"].(map[string]interface{}) if !ok { return nil, jsonrpc.Err(jsonrpc.InvalidParams, "{'contract_class': ['Missing data for required field.']}") @@ -1102,23 +1165,6 @@ func makeJSONErrorFromGatewayError(err error) *jsonrpc.Error { } } -// PendingTransactions gets the transactions in the pending block -// -// It follows the specification defined here: -// https://github.com/starkware-libs/starknet-specs/blob/aaea417f193bbec87b59455128d4b09a06876c28/api/starknet_api_openrpc.json#L602-L616 -func (h *Handler) PendingTransactions() ([]*Transaction, *jsonrpc.Error) { - var pendingTxns []*Transaction - - pending, err := h.bcReader.Pending() - if err == nil { - pendingTxns = make([]*Transaction, 0, len(pending.Block.Transactions)) - for _, txn := range pending.Block.Transactions { - pendingTxns = append(pendingTxns, adaptTransaction(txn)) - } - } - return pendingTxns, nil -} - func (h *Handler) Version() (string, *jsonrpc.Error) { return h.version, nil } @@ -1540,6 +1586,10 @@ func (h *Handler) callAndLogErr(f func() error, msg string) { } func (h *Handler) SpecVersion() (string, *jsonrpc.Error) { + return "0.6.0-rc2", nil +} + +func (h *Handler) LegacySpecVersion() (string, *jsonrpc.Error) { return "0.5.1", nil } @@ -1615,6 +1665,7 @@ func (h *Handler) unsubscribe(sub *subscription, id uint64) { h.mu.Unlock() } +//nolint:dupl func (h *Handler) Methods() ([]jsonrpc.Method, string) { //nolint: funlen return []jsonrpc.Method{ { @@ -1765,9 +1816,10 @@ func (h *Handler) Methods() ([]jsonrpc.Method, string) { //nolint: funlen Params: []jsonrpc.Parameter{{Name: "id"}}, Handler: h.Unsubscribe, }, - }, "/v0_5" + }, "/v0_6" } +//nolint:dupl func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen return []jsonrpc.Method{ { @@ -1785,7 +1837,7 @@ func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getBlockWithTxHashes", Params: []jsonrpc.Parameter{{Name: "block_id"}}, - Handler: h.LegacyBlockWithTxHashes, + Handler: h.BlockWithTxHashes, }, { Name: "starknet_getBlockWithTxs", @@ -1795,7 +1847,7 @@ func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getTransactionByHash", Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, - Handler: h.TransactionByHash, + Handler: h.LegacyTransactionByHash, }, { Name: "starknet_getTransactionReceipt", @@ -1810,7 +1862,7 @@ func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getTransactionByBlockIdAndIndex", Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "index"}}, - Handler: h.TransactionByBlockIDAndIndex, + Handler: h.LegacyTransactionByBlockIDAndIndex, }, { Name: "starknet_getStateUpdate", @@ -1866,16 +1918,12 @@ func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen Params: []jsonrpc.Parameter{{Name: "filter"}}, Handler: h.Events, }, - { - Name: "starknet_pendingTransactions", - Handler: h.PendingTransactions, - }, { Name: "juno_version", Handler: h.Version, }, { - Name: "juno_getTransactionStatus", + Name: "starknet_getTransactionStatus", Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, Handler: h.TransactionStatus, }, @@ -1909,5 +1957,18 @@ func (h *Handler) LegacyMethods() ([]jsonrpc.Method, string) { //nolint: funlen Params: []jsonrpc.Parameter{{Name: "block_id"}}, Handler: h.LegacyTraceBlockTransactions, }, - }, "/v0_4" + { + Name: "starknet_specVersion", + Handler: h.LegacySpecVersion, + }, + { + Name: "juno_subscribeNewHeads", + Handler: h.SubscribeNewHeads, + }, + { + Name: "juno_unsubscribe", + Params: []jsonrpc.Parameter{{Name: "id"}}, + Handler: h.Unsubscribe, + }, + }, "/v0_5" } diff --git a/rpc/handlers_test.go b/rpc/handlers_test.go index 243689dd4a..19866239ab 100644 --- a/rpc/handlers_test.go +++ b/rpc/handlers_test.go @@ -352,9 +352,7 @@ func TestBlockWithTxs(t *testing.T) { assert.Equal(t, len(blockWithTxHashes.TxnHashes), len(blockWithTxs.Transactions)) for i, txnHash := range blockWithTxHashes.TxnHashes { - assert.Equal(t, txnHash, blockWithTxs.Transactions[i].Hash) - - txn, err := handler.TransactionByHash(*blockWithTxs.Transactions[i].Hash) + txn, err := handler.TransactionByHash(*txnHash) require.Nil(t, err) assert.Equal(t, txn, blockWithTxs.Transactions[i]) @@ -453,31 +451,98 @@ func TestBlockWithTxs(t *testing.T) { }) } -func TestTransactionByHash(t *testing.T) { +func TestBlockWithTxHashesV013(t *testing.T) { + network := utils.Integration mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) mockReader := mocks.NewMockReader(mockCtrl) + handler := rpc.New(mockReader, nil, network, nil, nil, nil, "", nil) - client := feeder.NewTestClient(t, utils.Mainnet) - mainnetGw := adaptfeeder.New(client) + blockNumber := uint64(319132) + gw := adaptfeeder.New(feeder.NewTestClient(t, network)) + coreBlock, err := gw.BlockByNumber(context.Background(), blockNumber) + require.NoError(t, err) + tx, ok := coreBlock.Transactions[0].(*core.InvokeTransaction) + require.True(t, ok) - handler := rpc.New(mockReader, nil, utils.Mainnet, nil, nil, nil, "", nil) + mockReader.EXPECT().BlockByNumber(gomock.Any()).Return(coreBlock, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{}, nil) + got, rpcErr := handler.BlockWithTxs(rpc.BlockID{Number: blockNumber}) + require.Nil(t, rpcErr) + got.Transactions = got.Transactions[:1] + + require.Equal(t, &rpc.BlockWithTxs{ + BlockHeader: rpc.BlockHeader{ + Hash: coreBlock.Hash, + StarknetVersion: coreBlock.ProtocolVersion, + NewRoot: coreBlock.GlobalStateRoot, + Number: &coreBlock.Number, + ParentHash: coreBlock.ParentHash, + L1GasPrice: &rpc.ResourcePrice{ + InStark: utils.HexToFelt(t, "0x2540be400"), + InWei: utils.HexToFelt(t, "0x3b9aca08"), + }, + SequencerAddress: coreBlock.SequencerAddress, + Timestamp: coreBlock.Timestamp, + }, + Status: rpc.BlockAcceptedL2, + Transactions: []*rpc.Transaction{ + { + Hash: tx.Hash(), + Type: rpc.TxnInvoke, + Version: tx.Version.AsFelt(), + Nonce: tx.Nonce, + MaxFee: tx.MaxFee, + ContractAddress: tx.ContractAddress, + SenderAddress: tx.SenderAddress, + Signature: &tx.TransactionSignature, + CallData: &tx.CallData, + EntryPointSelector: tx.EntryPointSelector, + ResourceBounds: &map[rpc.Resource]rpc.ResourceBounds{ + rpc.ResourceL1Gas: { + MaxAmount: new(felt.Felt).SetUint64(tx.ResourceBounds[core.ResourceL1Gas].MaxAmount), + MaxPricePerUnit: tx.ResourceBounds[core.ResourceL1Gas].MaxPricePerUnit, + }, + rpc.ResourceL2Gas: { + MaxAmount: new(felt.Felt).SetUint64(tx.ResourceBounds[core.ResourceL2Gas].MaxAmount), + MaxPricePerUnit: tx.ResourceBounds[core.ResourceL2Gas].MaxPricePerUnit, + }, + }, + Tip: new(felt.Felt).SetUint64(tx.Tip), + PaymasterData: &tx.PaymasterData, + AccountDeploymentData: &tx.AccountDeploymentData, + NonceDAMode: utils.Ptr(rpc.DataAvailabilityMode(tx.NonceDAMode)), + FeeDAMode: utils.Ptr(rpc.DataAvailabilityMode(tx.FeeDAMode)), + }, + }, + }, got) +} - t.Run("transaction not found", func(t *testing.T) { - txHash := new(felt.Felt).SetBytes([]byte("random hash")) - mockReader.EXPECT().TransactionByHash(txHash).Return(nil, errors.New("tx not found")) +func TestTransactionByHashNotFound(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + mockReader := mocks.NewMockReader(mockCtrl) - tx, rpcErr := handler.TransactionByHash(*txHash) - assert.Nil(t, tx) - assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) - }) + txHash := new(felt.Felt).SetBytes([]byte("random hash")) + mockReader.EXPECT().TransactionByHash(txHash).Return(nil, errors.New("tx not found")) + + handler := rpc.New(mockReader, nil, utils.Mainnet, nil, nil, nil, "", nil) + + tx, rpcErr := handler.TransactionByHash(*txHash) + assert.Nil(t, tx) + assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) +} +//nolint:dupl +func TestTransactionByHash(t *testing.T) { tests := map[string]struct { hash string + network utils.Network expected string }{ "DECLARE v1": { - hash: "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", + hash: "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", + network: utils.Mainnet, expected: `{ "type": "DECLARE", "transaction_hash": "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", @@ -494,10 +559,11 @@ func TestTransactionByHash(t *testing.T) { }, "DECLARE v0": { - hash: "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", + hash: "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", + network: utils.Mainnet, expected: `{ - "type": "DECLARE", "transaction_hash": "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", + "type": "DECLARE", "max_fee": "0x0", "version": "0x0", "signature": [], @@ -507,7 +573,8 @@ func TestTransactionByHash(t *testing.T) { }, "L1 Handler v0": { - hash: "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", + hash: "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", + network: utils.Mainnet, expected: `{ "type": "L1_HANDLER", "transaction_hash": "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", @@ -526,7 +593,8 @@ func TestTransactionByHash(t *testing.T) { }, "Invoke v1": { - hash: "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", + hash: "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", + network: utils.Mainnet, expected: `{ "type": "INVOKE", "transaction_hash": "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", @@ -561,7 +629,8 @@ func TestTransactionByHash(t *testing.T) { }, "DEPLOY v0": { - hash: "0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0", + hash: "0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0", + network: utils.Mainnet, expected: `{ "type": "DEPLOY", "transaction_hash": "0x6486c6303dba2f364c684a2e9609211c5b8e417e767f37b527cda51e776e6f0", @@ -579,7 +648,8 @@ func TestTransactionByHash(t *testing.T) { }, "DEPLOY ACCOUNT v1": { - hash: "0xd61fc89f4d1dc4dc90a014957d655d38abffd47ecea8e3fa762e3160f155f2", + hash: "0xd61fc89f4d1dc4dc90a014957d655d38abffd47ecea8e3fa762e3160f155f2", + network: utils.Mainnet, expected: `{ "type": "DEPLOY_ACCOUNT", "transaction_hash": "0xd61fc89f4d1dc4dc90a014957d655d38abffd47ecea8e3fa762e3160f155f2", @@ -599,7 +669,8 @@ func TestTransactionByHash(t *testing.T) { }, "INVOKE v0": { - hash: "0xf1d99fb97509e0dfc425ddc2a8c5398b74231658ca58b6f8da92f39cb739e", + hash: "0xf1d99fb97509e0dfc425ddc2a8c5398b74231658ca58b6f8da92f39cb739e", + network: utils.Mainnet, expected: `{ "type": "INVOKE", "transaction_hash": "0xf1d99fb97509e0dfc425ddc2a8c5398b74231658ca58b6f8da92f39cb739e", @@ -616,14 +687,122 @@ func TestTransactionByHash(t *testing.T) { ] }`, }, + "DECLARE v3": { + hash: "0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3", + network: 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.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.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" + }`, + }, } - mockReader.EXPECT().TransactionByHash(gomock.Any()).DoAndReturn(func(hash *felt.Felt) (core.Transaction, error) { - return mainnetGw.Transaction(context.Background(), hash) - }).Times(len(tests)) - 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, test.network, nil, nil, nil, "", nil) + hash, err := new(felt.Felt).SetString(test.hash) require.NoError(t, err) @@ -643,6 +822,263 @@ func TestTransactionByHash(t *testing.T) { } } +//nolint:dupl +func TestLegacyTransactionByHash(t *testing.T) { + tests := map[string]struct { + hash string + network utils.Network + expected string + }{ + "DECLARE v1": { + hash: "0x1b4d9f09276629d496af1af8ff00173c11ff146affacb1b5c858d7aa89001ae", + network: 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.Mainnet, + expected: `{ + "transaction_hash": "0x222f8902d1eeea76fa2642a90e2411bfd71cffb299b3a299029e1937fab3fe4", + "type": "DECLARE", + "max_fee": "0x0", + "version": "0x0", + "signature": [], + "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", + "sender_address": "0x1" + }`, + }, + + "L1 Handler v0": { + hash: "0x537eacfd3c49166eec905daff61ff7feef9c133a049ea2135cb94eec840a4a8", + network: 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" + ] + }`, + }, + + "Invoke v1": { + hash: "0x2897e3cec3e24e4d341df26b8cf1ab84ea1c01a051021836b36c6639145b497", + network: 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.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.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.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.Integration, + expected: `{ + "transaction_hash": "0x41d1f5206ef58a443e7d3d1ca073171ec25fa75313394318fc83a074a6631c3", + "type": "DECLARE", + "version": "0x2", + "nonce": "0x1", + "sender_address": "0x2fab82e4aef1d8664874e1f194951856d48463c3e6bf9a8c68e234a629a6f50", + "class_hash": "0x5ae9d09292a50ed48c5930904c880dab56e85b825022a7d689cfc9e65e01ee7", + "compiled_class_hash": "0x1add56d64bebf8140f3b8a38bdf102b7874437f0c861ab4ca7526ec33b4d0f8", + "signature": [ + "0x29a49dff154fede73dd7b5ca5a0beadf40b4b069f3a850cd8428e54dc809ccc", + "0x429d142a17223b4f2acde0f5ecb9ad453e188b245003c86fab5c109bad58fc3" + ], + "max_fee": "0x38d7ea4c68000" + }`, + }, + "INVOKE v3": { + hash: "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", + network: utils.Integration, + expected: `{ + "type": "INVOKE", + "transaction_hash": "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", + "version": "0x1", + "signature": [ + "0x71a9b2cd8a8a6a4ca284dcddcdefc6c4fd20b92c1b201bd9836e4ce376fad16", + "0x6bef4745194c9447fdc8dd3aec4fc738ab0a560b0d2c7bf62fbf58aef3abfc5" + ], + "nonce": "0xe97", + "max_fee": "0x8ac7230489e80000", + "sender_address": "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41", + "calldata": [ + "0x2", + "0x450703c32370cf7ffff540b9352e7ee4ad583af143a361155f2b485c0c39684", + "0x27c3334165536f239cfd400ed956eabff55fc60de4fb56728b6a4f6b87db01c", + "0x0", + "0x4", + "0x4c312760dfd17a954cdd09e76aa9f149f806d88ec3e402ffaf5c4926f568a42", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x4", + "0x1", + "0x5", + "0x450703c32370cf7ffff540b9352e7ee4ad583af143a361155f2b485c0c39684", + "0x5df99ae77df976b4f0e5cf28c7dcfe09bd6e81aab787b19ac0c08e03d928cf", + "0x1", + "0x7fe4fd616c7fece1244b3616bb516562e230be8c9f29668b46ce0369d5ca829", + "0x287acddb27a2f9ba7f2612d72788dc96a5b30e401fc1e8072250940e024a587" + ] + }`, + }, + "DEPLOY ACCOUNT v3": { + hash: "0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0", + network: utils.Integration, + expected: `{ + "transaction_hash": "0x29fd7881f14380842414cdfdd8d6c0b1f2174f8916edcfeb1ede1eb26ac3ef0", + "version": "0x1", + "signature": [ + "0x6d756e754793d828c6c1a89c13f7ec70dbd8837dfeea5028a673b80e0d6b4ec", + "0x4daebba599f860daee8f6e100601d98873052e1c61530c630cc4375c6bd48e3" + ], + "nonce": "0x0", + "max_fee": "0x8ac7230489e80000", + "contract_address_salt": "0x0", + "class_hash": "0x2338634f11772ea342365abd5be9d9dc8a6f44f159ad782fdebd3db5d969738", + "constructor_calldata": [ + "0x5cd65f3d7daea6c63939d659b8473ea0c5cd81576035a4d34e52fb06840196c" + ], + "type": "DEPLOY_ACCOUNT" + }`, + }, + } + + 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, test.network, nil, nil, nil, "", 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.LegacyTransactionByHash(*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) @@ -788,6 +1224,7 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { }) } +//nolint:dupl func TestTransactionReceiptByHash(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -827,6 +1264,263 @@ func TestTransactionReceiptByHash(t *testing.T) { assert.Equal(t, expectedMap, receiptMap) } + tests := map[string]struct { + index int + expected string + }{ + "with contract addr": { + index: 0, + expected: `{ + "type": "DEPLOY", + "transaction_hash": "0xe0a2e45a80bb827967e096bcf58874f6c01c191e0a0530624cba66a508ae75", + "actual_fee": {"amount": "0x0", "unit": "WEI"}, + "finality_status": "ACCEPTED_ON_L2", + "execution_status": "SUCCEEDED", + "block_hash": "0x47c3637b57c2b079b93c61539950c17e868a28f46cdef28f88521067f21e943", + "block_number": 0, + "messages_sent": [], + "events": [], + "contract_address": "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", + "execution_resources":{"steps":29} + }`, + }, + "without contract addr": { + index: 2, + expected: `{ + "type": "INVOKE", + "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", + "actual_fee": {"amount": "0x0", "unit": "WEI"}, + "finality_status": "ACCEPTED_ON_L2", + "execution_status": "SUCCEEDED", + "block_hash": "0x47c3637b57c2b079b93c61539950c17e868a28f46cdef28f88521067f21e943", + "block_number": 0, + "messages_sent": [ + { + "from_address": "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", + "to_address": "0xc84dd7fd43a7defb5b7a15c4fbbe11cbba6db1ba", + "payload": [ + "0xc", + "0x22" + ] + } + ], + "events": [], + "execution_resources":{"steps":31} + }`, + }, + } + for name, test := range tests { + t.Run(name, func(t *testing.T) { + txHash := block0.Transactions[test.index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block0.Transactions[test.index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block0.Receipts[test.index], block0.Hash, block0.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + + checkTxReceipt(t, txHash, test.expected) + }) + } + + t.Run("pending receipt", func(t *testing.T) { + i := 2 + expected := `{ + "type": "INVOKE", + "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", + "actual_fee": {"amount": "0x0", "unit": "WEI"}, + "finality_status": "ACCEPTED_ON_L2", + "execution_status": "SUCCEEDED", + "messages_sent": [ + { + "from_address": "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", + "to_address": "0xc84dd7fd43a7defb5b7a15c4fbbe11cbba6db1ba", + "payload": [ + "0xc", + "0x22" + ] + } + ], + "events": [], + "execution_resources":{"steps":31} + }` + + txHash := block0.Transactions[i].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block0.Transactions[i], nil) + mockReader.EXPECT().Receipt(txHash).Return(block0.Receipts[i], nil, uint64(0), nil) + + checkTxReceipt(t, txHash, expected) + }) + + t.Run("accepted on l1 receipt", func(t *testing.T) { + i := 2 + expected := `{ + "type": "INVOKE", + "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", + "actual_fee": {"amount": "0x0", "unit": "WEI"}, + "finality_status": "ACCEPTED_ON_L1", + "execution_status": "SUCCEEDED", + "block_hash": "0x47c3637b57c2b079b93c61539950c17e868a28f46cdef28f88521067f21e943", + "block_number": 0, + "messages_sent": [ + { + "from_address": "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", + "to_address": "0xc84dd7fd43a7defb5b7a15c4fbbe11cbba6db1ba", + "payload": [ + "0xc", + "0x22" + ] + } + ], + "events": [], + "execution_resources":{"steps":31} + }` + + txHash := block0.Transactions[i].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block0.Transactions[i], nil) + mockReader.EXPECT().Receipt(txHash).Return(block0.Receipts[i], block0.Hash, block0.Number, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{ + BlockNumber: block0.Number, + BlockHash: block0.Hash, + StateRoot: block0.GlobalStateRoot, + }, nil) + + checkTxReceipt(t, txHash, expected) + }) + t.Run("reverted", func(t *testing.T) { + expected := `{ + "type": "INVOKE", + "transaction_hash": "0x19abec18bbacec23c2eee160c70190a48e4b41dd5ff98ad8f247f9393559998", + "actual_fee": {"amount": "0x247aff6e224", "unit": "WEI"}, + "execution_status": "REVERTED", + "finality_status": "ACCEPTED_ON_L2", + "block_hash": "0x76e0229fd0c36dda2ee7905f7e4c9b3ebb78d98c4bfab550bcb3a03bf859a6", + "block_number": 304740, + "messages_sent": [], + "events": [], + "revert_reason": "Error in the called contract (0x00b1461de04c6a1aa3375bdf9b7723a8779c082ffe21311d683a0b15c078b5dc):\nError at pc=0:25:\nGot an exception while executing a hint.\nCairo traceback (most recent call last):\nUnknown location (pc=0:731)\nUnknown location (pc=0:677)\nUnknown location (pc=0:291)\nUnknown location (pc=0:314)\n\nError in the called contract (0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7):\nError at pc=0:104:\nGot an exception while executing a hint.\nCairo traceback (most recent call last):\nUnknown location (pc=0:1678)\nUnknown location (pc=0:1664)\n\nError in the called contract (0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7):\nError at pc=0:6:\nGot an exception while executing a hint: Assertion failed, 0 % 0x800000000000011000000000000000000000000000000000000000000000001 is equal to 0\nCairo traceback (most recent call last):\nUnknown location (pc=0:1238)\nUnknown location (pc=0:1215)\nUnknown location (pc=0:836)\n", + "execution_resources":{"steps":0} + }` + + integClient := feeder.NewTestClient(t, utils.Integration) + integGw := adaptfeeder.New(integClient) + + blockWithRevertedTxn, err := integGw.BlockByNumber(context.Background(), 304740) + require.NoError(t, err) + + revertedTxnIdx := 1 + revertedTxnHash := blockWithRevertedTxn.Transactions[revertedTxnIdx].Hash() + + mockReader.EXPECT().TransactionByHash(revertedTxnHash).Return(blockWithRevertedTxn.Transactions[revertedTxnIdx], nil) + mockReader.EXPECT().Receipt(revertedTxnHash).Return(blockWithRevertedTxn.Receipts[revertedTxnIdx], + blockWithRevertedTxn.Hash, blockWithRevertedTxn.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + + checkTxReceipt(t, revertedTxnHash, expected) + }) + + t.Run("v3 tx", func(t *testing.T) { + expected := `{ + "block_hash": "0x50e864db6b81ce69fbeb70e6a7284ee2febbb9a2e707415de7adab83525e9cd", + "block_number": 319132, + "execution_status": "SUCCEEDED", + "finality_status": "ACCEPTED_ON_L2", + "transaction_hash": "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", + "messages_sent": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x16d8b4ad4000", + "0x0" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0xa9fa878c35cd3d0191318f89033ca3e5501a3d90e21e3cc9256bdd5cd17fdd" + ], + "data": [ + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x18ad8494375bc00", + "0x0", + "0x18aef21f822fc00", + "0x0" + ] + } + ], + "execution_resources": { + "steps": 615, + "range_check_builtin_applications": 19, + "memory_holes": 4 + }, + "actual_fee": { + "amount": "0x16d8b4ad4000", + "unit": "STRK" + }, + "type": "INVOKE" + }` + + integClient := feeder.NewTestClient(t, utils.Integration) + integGw := adaptfeeder.New(integClient) + + block, err := integGw.BlockByNumber(context.Background(), 319132) + require.NoError(t, err) + + index := 0 + txnHash := block.Transactions[index].Hash() + + mockReader.EXPECT().TransactionByHash(txnHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txnHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + + checkTxReceipt(t, txnHash, expected) + }) +} + +//nolint:dupl +func TestLegacyTransactionReceiptByHash(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockReader := mocks.NewMockReader(mockCtrl) + handler := rpc.New(mockReader, nil, utils.Mainnet, nil, nil, nil, "", nil) + + t.Run("transaction not found", func(t *testing.T) { + txHash := new(felt.Felt).SetBytes([]byte("random hash")) + mockReader.EXPECT().TransactionByHash(txHash).Return(nil, errors.New("tx not found")) + + tx, rpcErr := handler.TransactionReceiptByHash(*txHash) + assert.Nil(t, tx) + assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) + }) + + client := feeder.NewTestClient(t, utils.Mainnet) + mainnetGw := adaptfeeder.New(client) + + block0, err := mainnetGw.BlockByNumber(context.Background(), 0) + require.NoError(t, err) + + checkTxReceipt := func(t *testing.T, h *felt.Felt, expected string) { + t.Helper() + + expectedMap := make(map[string]any) + require.NoError(t, json.Unmarshal([]byte(expected), &expectedMap)) + + receipt, err := handler.LegacyTransactionReceiptByHash(*h) + require.Nil(t, err) + + receiptJSON, jsonErr := json.Marshal(receipt) + require.NoError(t, jsonErr) + + receiptMap := make(map[string]any) + require.NoError(t, json.Unmarshal(receiptJSON, &receiptMap)) + assert.Equal(t, expectedMap, receiptMap) + } + tests := map[string]struct { index int expected string @@ -844,7 +1538,7 @@ func TestTransactionReceiptByHash(t *testing.T) { "messages_sent": [], "events": [], "contract_address": "0x20cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", - "execution_resources":{"steps":"0x1d","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"} + "execution_resources":{"steps":"0x1d"} }`, }, "without contract addr": { @@ -868,7 +1562,7 @@ func TestTransactionReceiptByHash(t *testing.T) { } ], "events": [], - "execution_resources":{"steps":"0x1f","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"} + "execution_resources":{"steps":"0x1f"} }`, }, } @@ -902,7 +1596,7 @@ func TestTransactionReceiptByHash(t *testing.T) { } ], "events": [], - "execution_resources":{"steps":"0x1f","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"} + "execution_resources":{"steps":"0x1f"} }` txHash := block0.Transactions[i].Hash() @@ -933,7 +1627,7 @@ func TestTransactionReceiptByHash(t *testing.T) { } ], "events": [], - "execution_resources":{"steps":"0x1f","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"} + "execution_resources":{"steps":"0x1f"} }` txHash := block0.Transactions[i].Hash() @@ -959,7 +1653,7 @@ func TestTransactionReceiptByHash(t *testing.T) { "messages_sent": [], "events": [], "revert_reason": "Error in the called contract (0x00b1461de04c6a1aa3375bdf9b7723a8779c082ffe21311d683a0b15c078b5dc):\nError at pc=0:25:\nGot an exception while executing a hint.\nCairo traceback (most recent call last):\nUnknown location (pc=0:731)\nUnknown location (pc=0:677)\nUnknown location (pc=0:291)\nUnknown location (pc=0:314)\n\nError in the called contract (0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7):\nError at pc=0:104:\nGot an exception while executing a hint.\nCairo traceback (most recent call last):\nUnknown location (pc=0:1678)\nUnknown location (pc=0:1664)\n\nError in the called contract (0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7):\nError at pc=0:6:\nGot an exception while executing a hint: Assertion failed, 0 % 0x800000000000011000000000000000000000000000000000000000000000001 is equal to 0\nCairo traceback (most recent call last):\nUnknown location (pc=0:1238)\nUnknown location (pc=0:1215)\nUnknown location (pc=0:836)\n", - "execution_resources":{"steps":"0x0","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"} + "execution_resources":{"steps":"0x0"} }` integClient := feeder.NewTestClient(t, utils.Integration) @@ -978,6 +1672,67 @@ func TestTransactionReceiptByHash(t *testing.T) { checkTxReceipt(t, revertedTxnHash, expected) }) + + t.Run("v3 tx", func(t *testing.T) { + expected := `{ + "block_hash": "0x50e864db6b81ce69fbeb70e6a7284ee2febbb9a2e707415de7adab83525e9cd", + "block_number": 319132, + "execution_status": "SUCCEEDED", + "finality_status": "ACCEPTED_ON_L2", + "transaction_hash": "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", + "messages_sent": [], + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x16d8b4ad4000", + "0x0" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0xa9fa878c35cd3d0191318f89033ca3e5501a3d90e21e3cc9256bdd5cd17fdd" + ], + "data": [ + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x18ad8494375bc00", + "0x0", + "0x18aef21f822fc00", + "0x0" + ] + } + ], + "execution_resources": { + "steps": "0x267", + "range_check_builtin_applications": "0x13", + "memory_holes": "0x4" + }, + "actual_fee": "0x16d8b4ad4000", + "type": "INVOKE" + }` + + integClient := feeder.NewTestClient(t, utils.Integration) + integGw := adaptfeeder.New(integClient) + + block, err := integGw.BlockByNumber(context.Background(), 319132) + require.NoError(t, err) + + index := 0 + txnHash := block.Transactions[index].Hash() + + mockReader.EXPECT().TransactionByHash(txnHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txnHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + + checkTxReceipt(t, txnHash, expected) + }) } func TestStateUpdate(t *testing.T) { @@ -1813,41 +2568,6 @@ func TestAddTransaction(t *testing.T) { }) } -func TestPendingTransactions(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - - mockReader := mocks.NewMockReader(mockCtrl) - log := utils.NewNopZapLogger() - handler := rpc.New(mockReader, nil, utils.Mainnet, nil, nil, nil, "", log) - - t.Run("no pending", func(t *testing.T) { - mockReader.EXPECT().Pending().Return(blockchain.Pending{}, errors.New("no pending")) - - txns, err := handler.PendingTransactions() - require.Nil(t, err) - require.Empty(t, txns) - }) - - t.Run("with pending", func(t *testing.T) { - mockReader.EXPECT().Pending().Return(blockchain.Pending{ - Block: &core.Block{ - Transactions: []core.Transaction{ - &core.InvokeTransaction{ - TransactionHash: utils.HexToFelt(t, "0xdeadbeef"), - Version: &core.TransactionVersion{}, - }, - }, - }, - }, nil) - - txns, err := handler.PendingTransactions() - require.Nil(t, err) - require.Len(t, txns, 1) - require.Equal(t, "deadbeef", txns[0].Hash.Text(16)) - }) -} - func TestVersion(t *testing.T) { const version = "1.2.3-rc1" @@ -2055,7 +2775,7 @@ func TestEstimateMessageFee(t *testing.T) { expectedGasConsumed := new(felt.Felt).SetUint64(37) mockVM.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), - gomock.Any(), utils.Mainnet, gomock.Any(), gomock.Any(), gomock.Any(), latestHeader.GasPrice, latestHeader.GasPriceSTRK, gomock.Any()).DoAndReturn( + gomock.Any(), utils.Mainnet, gomock.Any(), gomock.Any(), gomock.Any(), latestHeader.GasPrice, latestHeader.GasPriceSTRK, false).DoAndReturn( func(txns []core.Transaction, declaredClasses []core.Class, blockNumber, blockTimestamp uint64, sequencerAddress *felt.Felt, state core.StateReader, network utils.Network, paidFeesOnL1 []*felt.Felt, skipChargeFee, skipValidate bool, gasPriceWei, gasPriceSTRK *felt.Felt, legacyTraceJson bool, @@ -2400,7 +3120,7 @@ func TestSubscribeNewHeadsAndUnsubscribe(t *testing.T) { syncCancel() // Receive a block header. - want := `{"jsonrpc":"2.0","method":"juno_subscribeNewHeads","params":{"result":{"block_hash":"0x4e1f77f39545afe866ac151ac908bd1a347a2a8a7d58bef1276db4f06fdf2f6","parent_hash":"0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb","block_number":2,"new_root":"0x3ceee867d50b5926bb88c0ec7e0b9c20ae6b537e74aac44b8fcf6bb6da138d9","timestamp":1637084470,"sequencer_address":"0x0","l1_gas_price":{"price_in_wei":"0x0"}},"subscription":%d}}` + want := `{"jsonrpc":"2.0","method":"juno_subscribeNewHeads","params":{"result":{"block_hash":"0x4e1f77f39545afe866ac151ac908bd1a347a2a8a7d58bef1276db4f06fdf2f6","parent_hash":"0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb","block_number":2,"new_root":"0x3ceee867d50b5926bb88c0ec7e0b9c20ae6b537e74aac44b8fcf6bb6da138d9","timestamp":1637084470,"sequencer_address":"0x0","l1_gas_price":{"price_in_strk":"0x0","price_in_wei":"0x0"}},"subscription":%d}}` want = fmt.Sprintf(want, id) got := make([]byte, len(want)) _, err := clientConn.Read(got) @@ -2499,7 +3219,7 @@ func TestMultipleSubscribeNewHeadsAndUnsubscribe(t *testing.T) { syncCancel() // Receive a block header. - want = `{"jsonrpc":"2.0","method":"juno_subscribeNewHeads","params":{"result":{"block_hash":"0x4e1f77f39545afe866ac151ac908bd1a347a2a8a7d58bef1276db4f06fdf2f6","parent_hash":"0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb","block_number":2,"new_root":"0x3ceee867d50b5926bb88c0ec7e0b9c20ae6b537e74aac44b8fcf6bb6da138d9","timestamp":1637084470,"sequencer_address":"0x0","l1_gas_price":{"price_in_wei":"0x0"}},"subscription":%d}}` + want = `{"jsonrpc":"2.0","method":"juno_subscribeNewHeads","params":{"result":{"block_hash":"0x4e1f77f39545afe866ac151ac908bd1a347a2a8a7d58bef1276db4f06fdf2f6","parent_hash":"0x2a70fb03fe363a2d6be843343a1d81ce6abeda1e9bd5cc6ad8fa9f45e30fdeb","block_number":2,"new_root":"0x3ceee867d50b5926bb88c0ec7e0b9c20ae6b537e74aac44b8fcf6bb6da138d9","timestamp":1637084470,"sequencer_address":"0x0","l1_gas_price":{"price_in_strk":"0x0","price_in_wei":"0x0"}},"subscription":%d}}` firstWant = fmt.Sprintf(want, firstID) _, firstGot, err = conn1.Read(ctx) require.NoError(t, err) @@ -2537,12 +3257,12 @@ func TestTraceFallback(t *testing.T) { "old block": { hash: "0x3ae41b0f023e53151b0c8ab8b9caafb7005d5f41c9ab260276d5bdc49726279", blockNumber: 0, - want: `[{"trace_root":{"type":"DEPLOY","constructor_invocation":{"contract_address":"0x7b196a359045d4d0c10f73bdf244a9e1205a615dbb754b8df40173364288534","calldata":["0x187d50a5cf3ebd6d4d6fa8e29e4cad0a237759c6416304a25c4ea792ed4bba4","0x42f5af30d6693674296ad87301935d0c159036c3b24af4042ff0270913bf6c6"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x1d","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0x3fa1bff0c86f34b2eb32c26d12208b6bdb4a5f6a434ac1d4f0e2d1db71bd711"},{"trace_root":{"type":"DEPLOY","constructor_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x5cedec15acd969b0fba39fec9e7d9bd4d0b33f100969ad3a4543039a6f696d4","0xce9801d27b02543f4d88b60aa456860f94ee9f612fc56464abfbdeedc1ab72"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x1d","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x0","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0x154c02cc3165cceadaa32e7238a67061b3a1eac414138c4ebe1408f37fd93eb"},{"trace_root":{"type":"INVOKE","execute_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x17d9c35a8b9a0d4512fa05eafec01c2758a7a5b7ec7b47408a24a4b33124d9b","0x2","0x7f800b5bf79637f8f83f47a8fc4d368b43695c781b22a899f11b5f2faba874a","0x3a7a40d383612b0ad167aec8d90fb07e576e017d07948f63ac318b52511ae93"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0xa5","memory_holes":"0x16","pedersen_builtin_applications":"0x2","range_check_builtin_applications":"0x7","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0x7893675c16da857b7c4229cda449e08a4fe13b07ca817e79d1db02e8a046047"},{"trace_root":{"type":"INVOKE","execute_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x17d9c35a8b9a0d4512fa05eafec01c2758a7a5b7ec7b47408a24a4b33124d9b","0x2","0x7f800b5bf79637f8f83f47a8fc4d368b43695c781b22a899f11b5f2faba874a","0xf140b304e9266c72f1054116dd06d9c1c8e981db7bf34e3c6da99640e9a7c8"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0xa5","memory_holes":"0x16","pedersen_builtin_applications":"0x2","range_check_builtin_applications":"0x7","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0x4a277d67e3f42c4a343854081d1e2e9e425f1323255e4486d2badb37a1d8630"}]`, + want: `[{"trace_root":{"type":"DEPLOY","constructor_invocation":{"contract_address":"0x7b196a359045d4d0c10f73bdf244a9e1205a615dbb754b8df40173364288534","calldata":["0x187d50a5cf3ebd6d4d6fa8e29e4cad0a237759c6416304a25c4ea792ed4bba4","0x42f5af30d6693674296ad87301935d0c159036c3b24af4042ff0270913bf6c6"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":29}}},"transaction_hash":"0x3fa1bff0c86f34b2eb32c26d12208b6bdb4a5f6a434ac1d4f0e2d1db71bd711"},{"trace_root":{"type":"DEPLOY","constructor_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x5cedec15acd969b0fba39fec9e7d9bd4d0b33f100969ad3a4543039a6f696d4","0xce9801d27b02543f4d88b60aa456860f94ee9f612fc56464abfbdeedc1ab72"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":29}}},"transaction_hash":"0x154c02cc3165cceadaa32e7238a67061b3a1eac414138c4ebe1408f37fd93eb"},{"trace_root":{"type":"INVOKE","execute_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x17d9c35a8b9a0d4512fa05eafec01c2758a7a5b7ec7b47408a24a4b33124d9b","0x2","0x7f800b5bf79637f8f83f47a8fc4d368b43695c781b22a899f11b5f2faba874a","0x3a7a40d383612b0ad167aec8d90fb07e576e017d07948f63ac318b52511ae93"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":165,"memory_holes":22,"pedersen_builtin_applications":2,"range_check_builtin_applications":7}}},"transaction_hash":"0x7893675c16da857b7c4229cda449e08a4fe13b07ca817e79d1db02e8a046047"},{"trace_root":{"type":"INVOKE","execute_invocation":{"contract_address":"0x64ed79a8ebe97485d3357bbfdf5f6bea0d9db3b5f1feb6e80d564a179122dc6","calldata":["0x17d9c35a8b9a0d4512fa05eafec01c2758a7a5b7ec7b47408a24a4b33124d9b","0x2","0x7f800b5bf79637f8f83f47a8fc4d368b43695c781b22a899f11b5f2faba874a","0xf140b304e9266c72f1054116dd06d9c1c8e981db7bf34e3c6da99640e9a7c8"],"caller_address":"0x0","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":165,"memory_holes":22,"pedersen_builtin_applications":2,"range_check_builtin_applications":7}}},"transaction_hash":"0x4a277d67e3f42c4a343854081d1e2e9e425f1323255e4486d2badb37a1d8630"}]`, }, "newer block": { hash: "0xe3828bd9154ab385e2cbb95b3b650365fb3c6a4321660d98ce8b0a9194f9a3", blockNumber: 300000, - want: `[{"trace_root":{"type":"INVOKE","validate_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775","calldata":["0x1","0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","0x0","0x4","0x4","0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x59","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x2","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x1","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}},"execute_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad","calldata":["0x1","0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","0x0","0x4","0x4","0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[{"contract_address":"0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","entry_point_selector":"0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","calldata":["0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x165e7db96ab97a63c621229617a6d49633737238673477a54720e4c952f2c7e","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[{"order":0,"to_address":"0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","payload":["0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"]}],"execution_resources":{"steps":"0xe9","memory_holes":"0x1","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x5","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}],"events":[],"messages":[],"execution_resources":{"steps":"0x176","memory_holes":"0x4","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x7","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}},"fee_transfer_invocation":{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x127089df3a1984","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x127089df3a1984","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x28d7d394810ad8c52741ad8f7564717fd02c10ced68657a81d0b6710ce22079","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x1e8","memory_holes":"0x28","pedersen_builtin_applications":"0x4","range_check_builtin_applications":"0x15","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}],"events":[],"messages":[],"execution_resources":{"steps":"0x224","memory_holes":"0x28","pedersen_builtin_applications":"0x4","range_check_builtin_applications":"0x15","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0x2a648ab1aa6847eb38507fc842e050f256562bf87b26083c332f3f21318c2c3"},{"trace_root":{"type":"INVOKE","validate_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775","calldata":["0x1","0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","0x0","0x4","0x4","0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x59","memory_holes":"0x0","pedersen_builtin_applications":"0x0","range_check_builtin_applications":"0x2","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x1","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}},"execute_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad","calldata":["0x1","0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","0x0","0x4","0x4","0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[{"contract_address":"0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","entry_point_selector":"0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","calldata":["0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x13abfd2f333f9c69f690f1569140cdae25f6f66e3f371c9cbb998b65f664a85","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0xa6","memory_holes":"0x16","pedersen_builtin_applications":"0x2","range_check_builtin_applications":"0x7","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}],"events":[],"messages":[],"execution_resources":{"steps":"0x133","memory_holes":"0x19","pedersen_builtin_applications":"0x2","range_check_builtin_applications":"0x9","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}},"fee_transfer_invocation":{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x3b2d25cd7bccc","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x3b2d25cd7bccc","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x28d7d394810ad8c52741ad8f7564717fd02c10ced68657a81d0b6710ce22079","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":"0x1e8","memory_holes":"0x28","pedersen_builtin_applications":"0x4","range_check_builtin_applications":"0x15","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}],"events":[],"messages":[],"execution_resources":{"steps":"0x224","memory_holes":"0x28","pedersen_builtin_applications":"0x4","range_check_builtin_applications":"0x15","bitwise_builtin_applications":"0x0","ecdsa_builtin_applications":"0x0","ec_op_builtin_applications":"0x0","keccak_builtin_applications":"0x0","poseidon_builtin_applications":"0x0"}}},"transaction_hash":"0xbc984e8e1fe594dd518a3a51db4f338437a5d2fbdda772d4426b532a67ffff"}]`, + want: `[{"trace_root":{"type":"INVOKE","validate_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775","calldata":["0x1","0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","0x0","0x4","0x4","0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":89,"range_check_builtin_applications":2,"ecdsa_builtin_applications":1}},"execute_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad","calldata":["0x1","0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","0x0","0x4","0x4","0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[{"contract_address":"0x332299dc083f3778122e5b7762bc9d399da18fefe93769aee67bb49f51c8d2","entry_point_selector":"0x2d7cf5d5a324a320f9f37804b1615a533fde487400b41af80f13f7ac5581325","calldata":["0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","0x2","0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x165e7db96ab97a63c621229617a6d49633737238673477a54720e4c952f2c7e","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[{"order":0,"to_address":"0xaf35ee8ed700ff132c5d1d298a73becda25ccdf9","payload":["0x6cd852fe1b2bbd8587bb0aaeb09813436c57c8ce21e75651e317273a1f22228","0x58feb991988e53fffcba71f6df23c803fb062f1b3bab126d2c9ce574255b36e"]}],"execution_resources":{"steps":233,"memory_holes":1,"range_check_builtin_applications":5}}],"events":[],"messages":[],"execution_resources":{"steps":374,"memory_holes":4,"range_check_builtin_applications":7}},"fee_transfer_invocation":{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x127089df3a1984","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x127089df3a1984","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x28d7d394810ad8c52741ad8f7564717fd02c10ced68657a81d0b6710ce22079","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":488,"memory_holes":40,"pedersen_builtin_applications":4,"range_check_builtin_applications":21}}],"events":[],"messages":[],"execution_resources":{"steps":548,"memory_holes":40,"pedersen_builtin_applications":4,"range_check_builtin_applications":21}}},"transaction_hash":"0x2a648ab1aa6847eb38507fc842e050f256562bf87b26083c332f3f21318c2c3"},{"trace_root":{"type":"INVOKE","validate_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775","calldata":["0x1","0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","0x0","0x4","0x4","0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":89,"range_check_builtin_applications":2,"ecdsa_builtin_applications":1}},"execute_invocation":{"contract_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","entry_point_selector":"0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad","calldata":["0x1","0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","0x0","0x4","0x4","0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x0","class_hash":"0x646a72e2aab2fca75d713fbe4a58f2d12cbd64105621b89dc9ce7045b5bf02b","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[{"contract_address":"0x5f9211b05c9609d54a8bf5f9cfa4e2cd5a3cab3b5d79682c585575495a15dd1","entry_point_selector":"0x317eb442b72a9fae758d4fb26830ed0d9f31c8e7da4dbff4e8c59ea6a158e7f","calldata":["0x447379c077035ef4f442411d0407ce9aa66c558f0060137f6455f4f230eabeb","0x2","0x6811b7755a7dd0ec1fb6f51a883e3f255368e2dfd497b5f6480c00cf9cd5a2e","0x23b9e26720dd7aaf98c7cea56499f48f75dc1d4123f7e2d6c23bfc4d5f4a336"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x13abfd2f333f9c69f690f1569140cdae25f6f66e3f371c9cbb998b65f664a85","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":166,"memory_holes":22,"pedersen_builtin_applications":2,"range_check_builtin_applications":7}}],"events":[],"messages":[],"execution_resources":{"steps":307,"memory_holes":25,"pedersen_builtin_applications":2,"range_check_builtin_applications":9}},"fee_transfer_invocation":{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x3b2d25cd7bccc","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"contract_address":"0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7","entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8","0x3b2d25cd7bccc","0x0"],"caller_address":"0x58b7ee817bd2978c7657d05d3131e83e301ed1aa79d5ad16f01925fd52d1da7","class_hash":"0x28d7d394810ad8c52741ad8f7564717fd02c10ced68657a81d0b6710ce22079","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[],"messages":[],"execution_resources":{"steps":488,"memory_holes":40,"pedersen_builtin_applications":4,"range_check_builtin_applications":21}}],"events":[],"messages":[],"execution_resources":{"steps":548,"memory_holes":40,"pedersen_builtin_applications":4,"range_check_builtin_applications":21}}},"transaction_hash":"0xbc984e8e1fe594dd518a3a51db4f338437a5d2fbdda772d4426b532a67ffff"}]`, }, } @@ -2623,3 +3343,14 @@ func TestThrottledVMError(t *testing.T) { assert.Equal(t, utils.ErrResourceBusy.Error(), rpcErr.Data) }) } + +func TestSpecVersion(t *testing.T) { + handler := rpc.New(nil, nil, 0, nil, nil, nil, "", nil) + version, rpcErr := handler.SpecVersion() + require.Nil(t, rpcErr) + require.Equal(t, "0.6.0-rc2", version) + + legacyVersion, rpcErr := handler.LegacySpecVersion() + require.Nil(t, rpcErr) + require.Equal(t, "0.5.1", legacyVersion) +} diff --git a/rpc/trace.go b/rpc/trace.go index 83fbd71dd6..f85c20ec65 100644 --- a/rpc/trace.go +++ b/rpc/trace.go @@ -50,7 +50,7 @@ type OrderedL2toL1Message struct { MsgToL1 } -func adaptBlockTrace(block *BlockWithTxs, blockTrace *starknet.BlockTrace, _ bool) ([]TracedBlockTransaction, error) { +func adaptBlockTrace(block *BlockWithTxs, blockTrace *starknet.BlockTrace, legacyJSON bool) ([]TracedBlockTransaction, error) { if blockTrace == nil { return nil, nil } @@ -63,10 +63,10 @@ func adaptBlockTrace(block *BlockWithTxs, blockTrace *starknet.BlockTrace, _ boo trace := TransactionTrace{} trace.Type = block.Transactions[index].Type - trace.FeeTransferInvocation = adaptFunctionInvocation(feederTrace.FeeTransferInvocation) - trace.ValidateInvocation = adaptFunctionInvocation(feederTrace.ValidateInvocation) + trace.FeeTransferInvocation = adaptFunctionInvocation(feederTrace.FeeTransferInvocation, legacyJSON) + trace.ValidateInvocation = adaptFunctionInvocation(feederTrace.ValidateInvocation, legacyJSON) - fnInvocation := adaptFunctionInvocation(feederTrace.FunctionInvocation) + fnInvocation := adaptFunctionInvocation(feederTrace.FunctionInvocation, legacyJSON) switch block.Transactions[index].Type { case TxnDeploy: trace.ConstructorInvocation = fnInvocation @@ -96,7 +96,7 @@ func adaptBlockTrace(block *BlockWithTxs, blockTrace *starknet.BlockTrace, _ boo return traces, nil } -func adaptFunctionInvocation(snFnInvocation *starknet.FunctionInvocation) *FunctionInvocation { +func adaptFunctionInvocation(snFnInvocation *starknet.FunctionInvocation, legacyJSON bool) *FunctionInvocation { if snFnInvocation == nil { return nil } @@ -115,8 +115,13 @@ func adaptFunctionInvocation(snFnInvocation *starknet.FunctionInvocation) *Funct Messages: make([]OrderedL2toL1Message, 0, len(snFnInvocation.Messages)), ExecutionResources: adaptFeederExecutionResources(&snFnInvocation.ExecutionResources), } + + if legacyJSON { + fnInvocation.ExecutionResources = nil + } + for index := range snFnInvocation.InternalCalls { - fnInvocation.Calls = append(fnInvocation.Calls, *adaptFunctionInvocation(&snFnInvocation.InternalCalls[index])) + fnInvocation.Calls = append(fnInvocation.Calls, *adaptFunctionInvocation(&snFnInvocation.InternalCalls[index], legacyJSON)) } for index := range snFnInvocation.Events { snEvent := &snFnInvocation.Events[index] @@ -143,16 +148,17 @@ func adaptFunctionInvocation(snFnInvocation *starknet.FunctionInvocation) *Funct } func adaptFeederExecutionResources(resources *starknet.ExecutionResources) *ExecutionResources { - builtins := resources.BuiltinInstanceCounter + builtins := &resources.BuiltinInstanceCounter return &ExecutionResources{ - Steps: NumAsHex(resources.Steps), - MemoryHoles: NumAsHex(resources.MemoryHoles), - Pedersen: NumAsHex(builtins.Pedersen), - RangeCheck: NumAsHex(builtins.RangeCheck), - Bitwise: NumAsHex(builtins.Bitwise), - Ecsda: NumAsHex(builtins.Ecsda), - EcOp: NumAsHex(builtins.EcOp), - Keccak: NumAsHex(builtins.Keccak), - Poseidon: NumAsHex(builtins.Poseidon), + Steps: resources.Steps, + MemoryHoles: resources.MemoryHoles, + Pedersen: builtins.Pedersen, + RangeCheck: builtins.RangeCheck, + Bitwise: builtins.Bitwise, + Ecsda: builtins.Ecsda, + EcOp: builtins.EcOp, + Keccak: builtins.Keccak, + Poseidon: builtins.Poseidon, + SegmentArena: builtins.SegmentArena, } } diff --git a/rpc/transaction.go b/rpc/transaction.go index ae07ee8d6e..ee7248f3db 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -66,6 +66,24 @@ func (t *TransactionType) UnmarshalJSON(data []byte) error { return nil } +type FeeUnit byte + +const ( + WEI FeeUnit = iota + STRK +) + +func (u FeeUnit) MarshalJSON() ([]byte, error) { + switch u { + case WEI: + return []byte(`"WEI"`), nil + case STRK: + return []byte(`"STRK"`), nil + default: + return nil, errors.New("unknown FeeUnit") + } +} + type TxnStatus uint8 const ( @@ -126,24 +144,99 @@ func (fs TxnFinalityStatus) MarshalJSON() ([]byte, error) { } } +type DataAvailabilityMode uint32 + +const ( + DAModeL1 DataAvailabilityMode = iota + DAModeL2 +) + +func (m DataAvailabilityMode) MarshalJSON() ([]byte, error) { + switch m { + case DAModeL1: + return []byte(`"L1"`), nil + case DAModeL2: + return []byte(`"L2"`), nil + default: + return nil, errors.New("unknown DataAvailabilityMode") + } +} + +type Resource uint32 + +const ( + ResourceL1Gas Resource = iota + 1 + ResourceL2Gas +) + +func (r Resource) MarshalJSON() ([]byte, error) { + switch r { + case ResourceL1Gas: + return []byte("l1_gas"), nil + case ResourceL2Gas: + return []byte("l2_gas"), nil + default: + return nil, errors.New("unknown Resource") + } +} + +func (r Resource) MarshalText() ([]byte, error) { + return r.MarshalJSON() +} + +type ResourceBounds struct { + MaxAmount *felt.Felt `json:"max_amount"` + MaxPricePerUnit *felt.Felt `json:"max_price_per_unit"` +} + // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1252 // //nolint:lll type Transaction struct { - Hash *felt.Felt `json:"transaction_hash,omitempty"` - Type TransactionType `json:"type" validate:"required"` - Version *felt.Felt `json:"version,omitempty" validate:"required"` - Nonce *felt.Felt `json:"nonce,omitempty" validate:"required_unless=Version 0x0"` - MaxFee *felt.Felt `json:"max_fee,omitempty" validate:"required"` - ContractAddress *felt.Felt `json:"contract_address,omitempty"` - ContractAddressSalt *felt.Felt `json:"contract_address_salt,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` - ClassHash *felt.Felt `json:"class_hash,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` - ConstructorCallData *[]*felt.Felt `json:"constructor_calldata,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` - SenderAddress *felt.Felt `json:"sender_address,omitempty" validate:"required_if=Type DECLARE,required_if=Type INVOKE Version 0x1"` - Signature *[]*felt.Felt `json:"signature,omitempty" validate:"required"` - CallData *[]*felt.Felt `json:"calldata,omitempty" validate:"required_if=Type INVOKE"` - EntryPointSelector *felt.Felt `json:"entry_point_selector,omitempty" validate:"required_if=Type INVOKE Version 0x0"` - CompiledClassHash *felt.Felt `json:"compiled_class_hash,omitempty" validate:"required_if=Type DECLARE Version 0x2"` + Hash *felt.Felt `json:"transaction_hash,omitempty"` + Type TransactionType `json:"type" validate:"required"` + Version *felt.Felt `json:"version,omitempty" validate:"required"` + Nonce *felt.Felt `json:"nonce,omitempty" validate:"required_unless=Version 0x0"` + MaxFee *felt.Felt `json:"max_fee,omitempty" validate:"required_if=Version 0x0,required_if=Version 0x1,required_if=Version 0x2"` + ContractAddress *felt.Felt `json:"contract_address,omitempty"` + ContractAddressSalt *felt.Felt `json:"contract_address_salt,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` + ClassHash *felt.Felt `json:"class_hash,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` + ConstructorCallData *[]*felt.Felt `json:"constructor_calldata,omitempty" validate:"required_if=Type DEPLOY,required_if=Type DEPLOY_ACCOUNT"` + SenderAddress *felt.Felt `json:"sender_address,omitempty" validate:"required_if=Type DECLARE,required_if=Type INVOKE Version 0x1"` + Signature *[]*felt.Felt `json:"signature,omitempty" validate:"required"` + CallData *[]*felt.Felt `json:"calldata,omitempty" validate:"required_if=Type INVOKE"` + EntryPointSelector *felt.Felt `json:"entry_point_selector,omitempty" validate:"required_if=Type INVOKE Version 0x0"` + CompiledClassHash *felt.Felt `json:"compiled_class_hash,omitempty" validate:"required_if=Type DECLARE Version 0x2"` + ResourceBounds *map[Resource]ResourceBounds `json:"resource_bounds,omitempty" validate:"required_if=Version 0x3"` + Tip *felt.Felt `json:"tip,omitempty" validate:"required_if=Version 0x3"` + PaymasterData *[]*felt.Felt `json:"paymaster_data,omitempty" validate:"required_if=Version 0x3"` + AccountDeploymentData *[]*felt.Felt `json:"account_deployment_data,omitempty" validate:"required_if=Type INVOKE Version 0x3,required_if=Type DECLARE Version 0x3"` + NonceDAMode *DataAvailabilityMode `json:"nonce_data_availability_mode,omitempty" validate:"required_if=Version 0x3"` + FeeDAMode *DataAvailabilityMode `json:"fee_data_availability_mode,omitempty" validate:"required_if=Version 0x3"` +} + +func (tx *Transaction) ToPreV3() error { + if tx.Version.Uint64() != 3 { + return nil + } + switch tx.Type { + case TxnDeclare: + tx.Version.SetUint64(2) + case TxnInvoke, TxnDeployAccount: + tx.Version.SetUint64(1) + default: + return fmt.Errorf("unexpected transaction type %s", tx.Type) + } + l1Resources := (*tx.ResourceBounds)[ResourceL1Gas] + tx.MaxFee = new(felt.Felt).Mul(l1Resources.MaxAmount, l1Resources.MaxPricePerUnit) + + tx.ResourceBounds = nil + tx.Tip = nil + tx.PaymasterData = nil + tx.AccountDeploymentData = nil + tx.NonceDAMode = nil + tx.FeeDAMode = nil + return nil } type TransactionStatus struct { @@ -180,22 +273,38 @@ func (n NumAsHex) MarshalJSON() ([]byte, error) { } type ExecutionResources struct { - Steps NumAsHex `json:"steps"` - MemoryHoles NumAsHex `json:"memory_holes"` - Pedersen NumAsHex `json:"pedersen_builtin_applications"` - RangeCheck NumAsHex `json:"range_check_builtin_applications"` - Bitwise NumAsHex `json:"bitwise_builtin_applications"` - Ecsda NumAsHex `json:"ecdsa_builtin_applications"` - EcOp NumAsHex `json:"ec_op_builtin_applications"` - Keccak NumAsHex `json:"keccak_builtin_applications"` - Poseidon NumAsHex `json:"poseidon_builtin_applications"` + Steps uint64 `json:"steps"` + MemoryHoles uint64 `json:"memory_holes,omitempty"` + Pedersen uint64 `json:"pedersen_builtin_applications,omitempty"` + RangeCheck uint64 `json:"range_check_builtin_applications,omitempty"` + Bitwise uint64 `json:"bitwise_builtin_applications,omitempty"` + Ecsda uint64 `json:"ecdsa_builtin_applications,omitempty"` + EcOp uint64 `json:"ec_op_builtin_applications,omitempty"` + Keccak uint64 `json:"keccak_builtin_applications,omitempty"` + Poseidon uint64 `json:"poseidon_builtin_applications,omitempty"` + SegmentArena uint64 `json:"segment_arena_builtin,omitempty"` + isLegacy bool +} + +func (r *ExecutionResources) MarshalJSON() ([]byte, error) { + type resources ExecutionResources // Avoid infinite recursion with MarshalJSON. + rawJSON, err := json.Marshal(resources(*r)) + if !r.isLegacy { + return rawJSON, err + } + + hexMap := make(map[string]NumAsHex) + if err = json.Unmarshal(rawJSON, &hexMap); err != nil { + return nil, err + } + return json.Marshal(hexMap) } // https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L1871 type TransactionReceipt struct { Type TransactionType `json:"type"` Hash *felt.Felt `json:"transaction_hash"` - ActualFee *felt.Felt `json:"actual_fee"` + ActualFee *FeePayment `json:"actual_fee"` ExecutionStatus TxnExecutionStatus `json:"execution_status"` FinalityStatus TxnFinalityStatus `json:"finality_status"` BlockHash *felt.Felt `json:"block_hash,omitempty"` @@ -208,6 +317,20 @@ type TransactionReceipt struct { MessageHash string `json:"message_hash,omitempty"` } +type FeePayment struct { + Amount *felt.Felt `json:"amount"` + Unit FeeUnit `json:"unit"` + isLegacy bool +} + +func (f *FeePayment) MarshalJSON() ([]byte, error) { + if f.isLegacy { + return json.Marshal(f.Amount) + } + type fee FeePayment // Avoid infinite recursion with MarshalJSON. + return json.Marshal(fee(*f)) +} + type AddTxResponse struct { TransactionHash *felt.Felt `json:"transaction_hash"` ContractAddress *felt.Felt `json:"contract_address,omitempty"` @@ -288,3 +411,14 @@ func adaptBroadcastedTransaction(broadcastedTxn *BroadcastedTransaction, } return txn, declaredClass, paidFeeOnL1, nil } + +func adaptResourceBounds(rb map[core.Resource]core.ResourceBounds) map[Resource]ResourceBounds { + rpcResourceBounds := make(map[Resource]ResourceBounds) + for resource, bounds := range rb { + rpcResourceBounds[Resource(resource)] = ResourceBounds{ + MaxAmount: new(felt.Felt).SetUint64(bounds.MaxAmount), + MaxPricePerUnit: bounds.MaxPricePerUnit, + } + } + return rpcResourceBounds +}