From 32d647d6bcdce6c06cc298d7496cc41959a8fa44 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Tue, 28 Jan 2025 17:18:06 +0300 Subject: [PATCH 01/14] Fix e2e --- adapters/core2p2p/receipt.go | 1 - adapters/p2p2core/receipt.go | 1 - core/transaction.go | 1 - rpc/block.go | 10 +- rpc/block_test.go | 4 +- rpc/estimate_fee.go | 68 ++-- rpc/estimate_fee_pkg_test.go | 43 --- rpc/handlers.go | 15 +- rpc/helpers.go | 56 ++- rpc/simulation.go | 9 +- rpc/simulation_pkg_test.go | 2 +- rpc/transaction.go | 41 ++- rpc/transaction_test.go | 661 +++++++++++++++++++++++++---------- starknet/transaction.go | 1 - 14 files changed, 612 insertions(+), 301 deletions(-) delete mode 100644 rpc/estimate_fee_pkg_test.go diff --git a/adapters/core2p2p/receipt.go b/adapters/core2p2p/receipt.go index 8a3c36f244..76734de675 100644 --- a/adapters/core2p2p/receipt.go +++ b/adapters/core2p2p/receipt.go @@ -107,7 +107,6 @@ func AdaptExecutionResources(er *core.ExecutionResources) *gen.Receipt_Execution var l1Gas, l1DataGas, l2Gas, totalL1Gas, totalL1DataGas *felt.Felt if da := er.DataAvailability; da != nil { // todo(kirill) check that it might be null l1Gas = new(felt.Felt).SetUint64(da.L1Gas) - l2Gas = new(felt.Felt).SetUint64(da.L2Gas) l1DataGas = new(felt.Felt).SetUint64(da.L1DataGas) } if tgs := er.TotalGasConsumed; tgs != nil { diff --git a/adapters/p2p2core/receipt.go b/adapters/p2p2core/receipt.go index e804cca9b8..05753b391b 100644 --- a/adapters/p2p2core/receipt.go +++ b/adapters/p2p2core/receipt.go @@ -58,7 +58,6 @@ func adaptExecutionResources(er *gen.Receipt_ExecutionResources) *core.Execution }, DataAvailability: &core.DataAvailability{ L1Gas: feltToUint64(er.L1Gas), - L2Gas: feltToUint64(er.L2Gas), L1DataGas: feltToUint64(er.L1DataGas), }, MemoryHoles: uint64(er.MemoryHoles), diff --git a/core/transaction.go b/core/transaction.go index 38d2fe67cf..c65bc0d205 100644 --- a/core/transaction.go +++ b/core/transaction.go @@ -105,7 +105,6 @@ type ExecutionResources struct { type DataAvailability struct { L1Gas uint64 L1DataGas uint64 - L2Gas uint64 } type BuiltinInstanceCounter struct { diff --git a/rpc/block.go b/rpc/block.go index 936f3f8a53..0f0678eef7 100644 --- a/rpc/block.go +++ b/rpc/block.go @@ -207,7 +207,15 @@ func (h *Handler) BlockTransactionCount(id BlockID) (uint64, *jsonrpc.Error) { return header.TransactionCount, nil } +func (h *Handler) BlockWithReceiptsV0_7(id BlockID) (*BlockWithReceipts, *jsonrpc.Error) { + return h.blockWithReceipts(id, V0_7) +} + func (h *Handler) BlockWithReceipts(id BlockID) (*BlockWithReceipts, *jsonrpc.Error) { + return h.blockWithReceipts(id, V0_8) +} + +func (h *Handler) blockWithReceipts(id BlockID, rpcVersion version) (*BlockWithReceipts, *jsonrpc.Error) { block, rpcErr := h.blockByID(&id) if rpcErr != nil { return nil, rpcErr @@ -232,7 +240,7 @@ func (h *Handler) BlockWithReceipts(id BlockID) (*BlockWithReceipts, *jsonrpc.Er txsWithReceipts[index] = TransactionWithReceipt{ Transaction: t, // block_hash, block_number are optional in BlockWithReceipts response - Receipt: AdaptReceipt(r, txn, finalityStatus, nil, 0), + Receipt: AdaptReceipt(r, txn, finalityStatus, nil, 0, rpcVersion), } } diff --git a/rpc/block_test.go b/rpc/block_test.go index 5a89f07c0a..b42388077d 100644 --- a/rpc/block_test.go +++ b/rpc/block_test.go @@ -632,7 +632,7 @@ func TestBlockWithReceipts(t *testing.T) { txsWithReceipt = append(txsWithReceipt, rpc.TransactionWithReceipt{ Transaction: adaptedTx, - Receipt: rpc.AdaptReceipt(receipt, tx, rpc.TxnAcceptedOnL2, nil, 0), + Receipt: rpc.AdaptReceipt(receipt, tx, rpc.TxnAcceptedOnL2, nil, 0, rpc.V0_8), }) } @@ -678,7 +678,7 @@ func TestBlockWithReceipts(t *testing.T) { transactions = append(transactions, rpc.TransactionWithReceipt{ Transaction: adaptedTx, - Receipt: rpc.AdaptReceipt(receipt, tx, rpc.TxnAcceptedOnL1, nil, 0), + Receipt: rpc.AdaptReceipt(receipt, tx, rpc.TxnAcceptedOnL1, nil, 0, rpc.V0_8), }) } diff --git a/rpc/estimate_fee.go b/rpc/estimate_fee.go index 5923703dd8..ab311344a6 100644 --- a/rpc/estimate_fee.go +++ b/rpc/estimate_fee.go @@ -1,6 +1,7 @@ package rpc import ( + "encoding/json" "errors" "fmt" "net/http" @@ -28,15 +29,6 @@ func (u FeeUnit) MarshalText() ([]byte, error) { } } -type FeeEstimateV0_7 struct { - GasConsumed *felt.Felt `json:"gas_consumed"` - GasPrice *felt.Felt `json:"gas_price"` - DataGasConsumed *felt.Felt `json:"data_gas_consumed"` - DataGasPrice *felt.Felt `json:"data_gas_price"` - OverallFee *felt.Felt `json:"overall_fee"` - Unit *FeeUnit `json:"unit,omitempty"` -} - type FeeEstimate struct { L1GasConsumed *felt.Felt `json:"l1_gas_consumed,omitempty"` L1GasPrice *felt.Felt `json:"l1_gas_price,omitempty"` @@ -46,40 +38,55 @@ type FeeEstimate struct { L1DataGasPrice *felt.Felt `json:"l1_data_gas_price,omitempty"` OverallFee *felt.Felt `json:"overall_fee"` Unit *FeeUnit `json:"unit,omitempty"` + rpcVersion version +} + +func (f FeeEstimate) MarshalJSON() ([]byte, error) { + switch f.rpcVersion { + case V0_7: + return json.Marshal(struct { + GasConsumed *felt.Felt `json:"gas_consumed"` + GasPrice *felt.Felt `json:"gas_price"` + DataGasConsumed *felt.Felt `json:"data_gas_consumed"` + DataGasPrice *felt.Felt `json:"data_gas_price"` + OverallFee *felt.Felt `json:"overall_fee"` + Unit *FeeUnit `json:"unit,omitempty"` + }{ + GasConsumed: f.L1GasConsumed, + GasPrice: f.L1GasPrice, + DataGasConsumed: f.L1DataGasConsumed, + DataGasPrice: f.L1DataGasPrice, + OverallFee: f.OverallFee, + Unit: f.Unit, + }) + case V0_8: + type alias FeeEstimate // avoid infinite recursion + return json.Marshal(alias(f)) + default: + return nil, errors.New("unknown FeeEstimate version") + } } /**************************************************** Estimate Fee Handlers *****************************************************/ -func feeEstimateToV0_7(feeEstimate FeeEstimate) FeeEstimateV0_7 { - return FeeEstimateV0_7{ - GasConsumed: feeEstimate.L1GasConsumed, - GasPrice: feeEstimate.L1GasPrice, - DataGasConsumed: feeEstimate.L1DataGasConsumed, - DataGasPrice: feeEstimate.L1DataGasPrice, - OverallFee: feeEstimate.OverallFee, - Unit: feeEstimate.Unit, - } -} - func (h *Handler) EstimateFeeV0_7(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, -) ([]FeeEstimateV0_7, http.Header, *jsonrpc.Error) { - result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true) +) ([]FeeEstimate, http.Header, *jsonrpc.Error) { + result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, V0_7) if err != nil { return nil, httpHeader, err } - return utils.Map(result, func(tx SimulatedTransaction) FeeEstimateV0_7 { - return feeEstimateToV0_7(tx.FeeEstimation) + return utils.Map(result, func(tx SimulatedTransaction) FeeEstimate { + return tx.FeeEstimation }), httpHeader, nil } - func (h *Handler) EstimateFee(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, ) ([]FeeEstimate, http.Header, *jsonrpc.Error) { - result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true) + result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, V0_8) if err != nil { return nil, httpHeader, err } @@ -90,13 +97,8 @@ func (h *Handler) EstimateFee(broadcastedTxns []BroadcastedTransaction, } //nolint:gocritic -func (h *Handler) EstimateMessageFeeV0_7(msg MsgFromL1, id BlockID) (*FeeEstimateV0_7, http.Header, *jsonrpc.Error) { - estimate, header, err := estimateMessageFee(msg, id, h.EstimateFee) - if err != nil { - return nil, header, err - } - estimateV0_7 := feeEstimateToV0_7(*estimate) - return &estimateV0_7, header, nil +func (h *Handler) EstimateMessageFeeV0_7(msg MsgFromL1, id BlockID) (*FeeEstimate, http.Header, *jsonrpc.Error) { + return estimateMessageFee(msg, id, h.EstimateFeeV0_7) } //nolint:gocritic diff --git a/rpc/estimate_fee_pkg_test.go b/rpc/estimate_fee_pkg_test.go deleted file mode 100644 index 43530e545a..0000000000 --- a/rpc/estimate_fee_pkg_test.go +++ /dev/null @@ -1,43 +0,0 @@ -package rpc - -import ( - "testing" - - "github.com/NethermindEth/juno/core/felt" - "github.com/stretchr/testify/assert" -) - -func TestFeeEstimateToV0_7(t *testing.T) { - t.Run("empty", func(t *testing.T) { - assert.Equal(t, FeeEstimateV0_7{}, feeEstimateToV0_7(FeeEstimate{})) - }) - - t.Run("full", func(t *testing.T) { - gasConsumed := new(felt.Felt).SetUint64(1) - gasPrice := new(felt.Felt).SetUint64(2) - dataGasConsumed := new(felt.Felt).SetUint64(3) - dataGasPrice := new(felt.Felt).SetUint64(4) - overallFee := new(felt.Felt).SetUint64(5) - unit := WEI - assert.Equal( - t, - FeeEstimateV0_7{ - GasConsumed: gasConsumed, - GasPrice: gasPrice, - DataGasConsumed: dataGasConsumed, - DataGasPrice: dataGasPrice, - OverallFee: overallFee, - Unit: &unit, - }, - feeEstimateToV0_7(FeeEstimate{ - L1GasConsumed: gasConsumed, - L1GasPrice: gasPrice, - L2GasConsumed: new(felt.Felt).SetUint64(6), - L2GasPrice: new(felt.Felt).SetUint64(7), - L1DataGasConsumed: dataGasConsumed, - L1DataGasPrice: dataGasPrice, - OverallFee: overallFee, - Unit: &unit, - })) - }) -} diff --git a/rpc/handlers.go b/rpc/handlers.go index cba34ed396..83759b9528 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -7,6 +7,7 @@ import ( "encoding/json" "fmt" "log" + "maps" "math" "strings" stdsync "sync" @@ -81,6 +82,13 @@ const ( throttledVMErr = "VM throughput limit reached" ) +type version uint32 + +const ( + V0_7 version = iota + 1 + V0_8 +) + type traceCacheKey struct { blockHash felt.Felt } @@ -195,7 +203,12 @@ func (h *Handler) Run(ctx context.Context) error { feed.Tee(l1HeadsSub, h.l1Heads) <-ctx.Done() - for _, sub := range h.subscriptions { + + h.mu.Lock() + subscriptions := maps.Values(h.subscriptions) + h.mu.Unlock() + + for sub := range subscriptions { sub.wg.Wait() } return nil diff --git a/rpc/helpers.go b/rpc/helpers.go index 4408ef00dc..7f5a981869 100644 --- a/rpc/helpers.go +++ b/rpc/helpers.go @@ -90,41 +90,39 @@ func (h *Handler) blockHeaderByID(id *BlockID) (*core.Header, *jsonrpc.Error) { return header, nil } -func adaptExecutionResources(resources *core.ExecutionResources) *ExecutionResources { - if resources == nil { - return &ExecutionResources{ - DataAvailability: &DataAvailability{}, - } - } - - res := &ExecutionResources{ - ComputationResources: ComputationResources{ - 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 adaptExecutionResources(coreResources *core.ExecutionResources, rpcVersion version) *ExecutionResources { + resources := &ExecutionResources{ DataAvailability: &DataAvailability{}, - } - if da := resources.DataAvailability; da != nil { - res.DataAvailability = &DataAvailability{ + rpcVersion: rpcVersion, + } + if coreResources == nil { + return resources + } + + resources.ComputationResources = ComputationResources{ + Steps: coreResources.Steps, + MemoryHoles: coreResources.MemoryHoles, + Pedersen: coreResources.BuiltinInstanceCounter.Pedersen, + RangeCheck: coreResources.BuiltinInstanceCounter.RangeCheck, + Bitwise: coreResources.BuiltinInstanceCounter.Bitwise, + Ecsda: coreResources.BuiltinInstanceCounter.Ecsda, + EcOp: coreResources.BuiltinInstanceCounter.EcOp, + Keccak: coreResources.BuiltinInstanceCounter.Keccak, + Poseidon: coreResources.BuiltinInstanceCounter.Poseidon, + SegmentArena: coreResources.BuiltinInstanceCounter.SegmentArena, + } + if da := coreResources.DataAvailability; da != nil { + resources.DataAvailability = &DataAvailability{ L1Gas: da.L1Gas, - L2Gas: da.L2Gas, L1DataGas: da.L1DataGas, } } - if tgc := resources.TotalGasConsumed; tgc != nil { - res.L1Gas = tgc.L1Gas - res.L2Gas = tgc.L2Gas - res.L1DataGas = tgc.L1DataGas + if tgc := coreResources.TotalGasConsumed; tgc != nil { + resources.L1Gas = tgc.L1Gas + resources.L2Gas = tgc.L2Gas + resources.L1DataGas = tgc.L1DataGas } - return res + return resources } func (h *Handler) getRevealedBlockHash(blockNumber uint64) (*felt.Felt, error) { diff --git a/rpc/simulation.go b/rpc/simulation.go index 2327662193..743610b3f6 100644 --- a/rpc/simulation.go +++ b/rpc/simulation.go @@ -53,11 +53,11 @@ type TracedBlockTransaction struct { func (h *Handler) SimulateTransactions(id BlockID, transactions []BroadcastedTransaction, simulationFlags []SimulationFlag, ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { - return h.simulateTransactions(id, transactions, simulationFlags, false) + return h.simulateTransactions(id, transactions, simulationFlags, false, V0_8) } func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTransaction, - simulationFlags []SimulationFlag, errOnRevert bool, + simulationFlags []SimulationFlag, errOnRevert bool, rpcVersion version, ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { skipFeeCharge := slices.Contains(simulationFlags, SkipFeeChargeFlag) skipValidate := slices.Contains(simulationFlags, SkipValidateFlag) @@ -124,7 +124,7 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra for i, overallFee := range overallFees { feeUnit := feeUnit(txns[i]) - estimate := calculateFeeEstimate(overallFee, daGas[i].L1DataGas, feeUnit, header) + estimate := calculateFeeEstimate(overallFee, daGas[i].L1DataGas, feeUnit, header, rpcVersion) trace := traces[i] executionResources := trace.TotalExecutionResources() @@ -143,7 +143,7 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra return result, httpHeader, nil } -func calculateFeeEstimate(overallFee *felt.Felt, l1DataGas uint64, feeUnit FeeUnit, header *core.Header) FeeEstimate { +func calculateFeeEstimate(overallFee *felt.Felt, l1DataGas uint64, feeUnit FeeUnit, header *core.Header, rpcVersion version) FeeEstimate { var l1GasPrice, l2GasPrice, l1DataGasPrice *felt.Felt switch feeUnit { @@ -171,6 +171,7 @@ func calculateFeeEstimate(overallFee *felt.Felt, l1DataGas uint64, feeUnit FeeUn L1DataGasPrice: l1DataGasPrice, OverallFee: overallFee, Unit: utils.Ptr(feeUnit), + rpcVersion: rpcVersion, } } diff --git a/rpc/simulation_pkg_test.go b/rpc/simulation_pkg_test.go index c167fefed3..ad29be9f36 100644 --- a/rpc/simulation_pkg_test.go +++ b/rpc/simulation_pkg_test.go @@ -28,7 +28,7 @@ func TestCalculateFeeEstimate(t *testing.T) { l1DataGas := uint64(500) overallFee := new(felt.Felt).SetUint64(6000) - feeEstimate := calculateFeeEstimate(overallFee, l1DataGas, FRI, header) + feeEstimate := calculateFeeEstimate(overallFee, l1DataGas, FRI, header, V0_8) assert.Equal(t, l1GasPriceSTRK, feeEstimate.L1GasPrice) assert.Equal(t, l2GasPrice.PriceInFri, feeEstimate.L2GasPrice) diff --git a/rpc/transaction.go b/rpc/transaction.go index 0aad707896..e2281dc77a 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -262,7 +262,6 @@ type ComputationResources struct { type DataAvailability struct { L1Gas uint64 `json:"l1_gas"` L1DataGas uint64 `json:"l1_data_gas"` - L2Gas uint64 `json:"l2_gas"` } type ExecutionResources struct { @@ -273,6 +272,32 @@ type ExecutionResources struct { // TODO: Remove this field once the API is updated. ComputationResources DataAvailability *DataAvailability `json:"data_availability,omitempty"` + rpcVersion version +} + +func (r ExecutionResources) MarshalJSON() ([]byte, error) { //nolint:gocritic + switch r.rpcVersion { + case V0_7: + return json.Marshal(struct { + ComputationResources + DataAvailability *DataAvailability `json:"data_availability,omitempty"` + }{ + ComputationResources: r.ComputationResources, + DataAvailability: r.DataAvailability, + }) + case V0_8: + return json.Marshal(struct { + L1Gas uint64 `json:"l1_gas"` + L1DataGas uint64 `json:"l1_data_gas"` + L2Gas uint64 `json:"l2_gas"` + }{ + L1Gas: r.L1Gas, + L1DataGas: r.L1DataGas, + L2Gas: r.L2Gas, + }) + default: + return nil, fmt.Errorf("unknown rpc version %v", r.rpcVersion) + } } // https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L1871 @@ -498,6 +523,14 @@ func (h *Handler) TransactionByBlockIDAndIndex(id BlockID, txIndex int) (*Transa // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/master/api/starknet_api_openrpc.json#L222 func (h *Handler) TransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, *jsonrpc.Error) { + return h.transactionReceiptByHash(hash, V0_8) +} + +func (h *Handler) TransactionReceiptByHashV0_7(hash felt.Felt) (*TransactionReceipt, *jsonrpc.Error) { + return h.transactionReceiptByHash(hash, V0_7) +} + +func (h *Handler) transactionReceiptByHash(hash felt.Felt, rpcVersion version) (*TransactionReceipt, *jsonrpc.Error) { var ( pendingB *core.Block pendingBIndex int @@ -555,7 +588,7 @@ func (h *Handler) TransactionReceiptByHash(hash felt.Felt) (*TransactionReceipt, } } - return AdaptReceipt(receipt, txn, status, blockHash, blockNumber), nil + return AdaptReceipt(receipt, txn, status, blockHash, blockNumber, rpcVersion), nil } // AddTransaction relays a transaction to the gateway. @@ -758,7 +791,7 @@ func AdaptTransaction(t core.Transaction) *Transaction { // todo(Kirill): try to replace core.Transaction with rpc.Transaction type func AdaptReceipt(receipt *core.TransactionReceipt, txn core.Transaction, finalityStatus TxnFinalityStatus, - blockHash *felt.Felt, blockNumber uint64, + blockHash *felt.Felt, blockNumber uint64, rpcVersion version, ) *TransactionReceipt { messages := make([]*MsgToL1, len(receipt.L2ToL1Message)) for idx, msg := range receipt.L2ToL1Message { @@ -817,7 +850,7 @@ func AdaptReceipt(receipt *core.TransactionReceipt, txn core.Transaction, finali Events: events, ContractAddress: contractAddress, RevertReason: receipt.RevertReason, - ExecutionResources: adaptExecutionResources(receipt.ExecutionResources), + ExecutionResources: adaptExecutionResources(receipt.ExecutionResources, rpcVersion), MessageHash: messageHash, } } diff --git a/rpc/transaction_test.go b/rpc/transaction_test.go index 56cb07f9a0..0170bf55b7 100644 --- a/rpc/transaction_test.go +++ b/rpc/transaction_test.go @@ -11,6 +11,7 @@ import ( "github.com/NethermindEth/juno/core" "github.com/NethermindEth/juno/core/felt" "github.com/NethermindEth/juno/db" + "github.com/NethermindEth/juno/jsonrpc" "github.com/NethermindEth/juno/mocks" "github.com/NethermindEth/juno/rpc" "github.com/NethermindEth/juno/starknet" @@ -519,15 +520,14 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { //nolint:dupl func TestTransactionReceiptByHash(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) + t.Run("transaction not found", func(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) - n := utils.Ptr(utils.Mainnet) - mockReader := mocks.NewMockReader(mockCtrl) - mockSyncReader := mocks.NewMockSyncReader(mockCtrl) - handler := rpc.New(mockReader, mockSyncReader, nil, "", nil) + mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + handler := rpc.New(mockReader, mockSyncReader, 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, db.ErrKeyNotFound) mockSyncReader.EXPECT().PendingBlock().Return(nil) @@ -537,34 +537,53 @@ func TestTransactionReceiptByHash(t *testing.T) { assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) }) - client := feeder.NewTestClient(t, n) - 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.TransactionReceiptByHash(*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 + tests := []struct { + name string + network *utils.Network + blockNumber uint64 + index int + expected string + mockBehavior func(*mocks.MockReader, int, *core.Block) *felt.Felt + rpcVersion string }{ - "with contract addr": { - index: 0, + { + name: "with contract addr 0.7", + network: &utils.Mainnet, + blockNumber: 0, + 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": { + "data_availability": { + "l1_data_gas": 0, + "l1_gas": 0 + }, + "steps": 29 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.7", + }, + { + name: "with contract addr 0.8", + network: &utils.Mainnet, + blockNumber: 0, + index: 0, expected: `{ "type": "DEPLOY", "transaction_hash": "0xe0a2e45a80bb827967e096bcf58874f6c01c191e0a0530624cba66a508ae75", @@ -579,18 +598,65 @@ func TestTransactionReceiptByHash(t *testing.T) { "execution_resources": { "l1_data_gas": 0, "l1_gas": 0, - "l2_gas": 0, + "l2_gas": 0 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + + rpcVersion: "0.8", + }, + { + name: "without contract addr 0.7", + network: &utils.Mainnet, + blockNumber: 0, + 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": { "data_availability": { "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 + "l1_gas": 0 }, - "steps": 29 + "steps": 31 } }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.7", }, - "without contract addr": { - index: 2, + { + name: "without contract addr 0.8", + network: &utils.Mainnet, + blockNumber: 0, + index: 2, expected: `{ "type": "INVOKE", "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", @@ -613,31 +679,62 @@ func TestTransactionReceiptByHash(t *testing.T) { "execution_resources": { "l1_data_gas": 0, "l1_gas": 0, - "l2_gas": 0, + "l2_gas": 0 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.8", + }, + { + name: "pending receipt 0.7", + network: &utils.Mainnet, + blockNumber: 0, + index: 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": { "data_availability": { "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 + "l1_gas": 0 }, "steps": 31 } }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], nil, uint64(0), nil) + return txHash + }, + rpcVersion: "0.7", }, - } - 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 := `{ + { + name: "pending receipt 0.8", + network: &utils.Mainnet, + blockNumber: 0, + index: 2, + expected: `{ "type": "INVOKE", "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", "actual_fee": {"amount": "0x0", "unit": "WEI"}, @@ -657,26 +754,68 @@ func TestTransactionReceiptByHash(t *testing.T) { "execution_resources": { "l1_data_gas": 0, "l1_gas": 0, - "l2_gas": 0, + "l2_gas": 0 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], nil, uint64(0), nil) + return txHash + }, + rpcVersion: "0.8", + }, + { + name: "accepted on l1 receipt 0.7", + network: &utils.Mainnet, + blockNumber: 0, + index: 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": { "data_availability": { "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 + "l1_gas": 0 }, "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 := `{ + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{ + BlockNumber: block.Number, + BlockHash: block.Hash, + StateRoot: block.GlobalStateRoot, + }, nil) + return txHash + }, + rpcVersion: "0.7", + }, + { + name: "accepted on l1 receipt 0.8", + network: &utils.Mainnet, + blockNumber: 0, + index: 2, + expected: `{ "type": "INVOKE", "transaction_hash": "0xce54bbc5647e1c1ea4276c01a708523f740db0ff5474c77734f73beec2624", "actual_fee": {"amount": "0x0", "unit": "WEI"}, @@ -698,71 +837,170 @@ func TestTransactionReceiptByHash(t *testing.T) { "execution_resources": { "l1_data_gas": 0, "l1_gas": 0, - "l2_gas": 0, - "data_availability": { - "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 + "l2_gas": 0 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{ + BlockNumber: block.Number, + BlockHash: block.Hash, + StateRoot: block.GlobalStateRoot, + }, nil) + return txHash + }, + rpcVersion: "0.8", + }, + { + name: "reverted 0.7", + network: &utils.Integration, + blockNumber: 304740, + index: 1, + 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":{ + "data_availability":{ + "l1_data_gas":0, + "l1_gas":0 }, - "steps": 31 + "steps":0 } - }` - - 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", + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.7", + }, + { + name: "reverted 0.8", + network: &utils.Integration, + blockNumber: 304740, + index: 1, + 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":{ + "l1_data_gas":0, + "l1_gas":0, + "l2_gas":0 + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.8", + }, + { + name: "v3 tx 0.7", + network: &utils.Integration, + blockNumber: 319132, + index: 0, + expected: `{ + "block_hash": "0x50e864db6b81ce69fbeb70e6a7284ee2febbb9a2e707415de7adab83525e9cd", + "block_number": 319132, + "execution_status": "SUCCEEDED", "finality_status": "ACCEPTED_ON_L2", - "block_hash": "0x76e0229fd0c36dda2ee7905f7e4c9b3ebb78d98c4bfab550bcb3a03bf859a6", - "block_number": 304740, + "transaction_hash": "0x49728601e0bb2f48ce506b0cbd9c0e2a9e50d95858aa41463f46386dca489fd", "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", + "events": [ + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x3f6f3bc663aedc5285d6013cc3ffcbc4341d86ab488b8b68d297f8258793c41", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x16d8b4ad4000", + "0x0" + ] + }, + { + "from_address": "0x4718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", + "keys": [ + "0xa9fa878c35cd3d0191318f89033ca3e5501a3d90e21e3cc9256bdd5cd17fdd" + ], + "data": [ + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0x18ad8494375bc00", + "0x0", + "0x18aef21f822fc00", + "0x0" + ] + } + ], "execution_resources": { - "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0, + "steps": 615, + "range_check_builtin_applications": 19, + "memory_holes": 4, "data_availability": { "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 - }, - "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 := `{ + "l1_gas": 0 + } + }, + "actual_fee": { + "amount": "0x16d8b4ad4000", + "unit": "FRI" + }, + "type": "INVOKE" + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.7", + }, + { + name: "v3 tx 0.8", + network: &utils.Integration, + blockNumber: 319132, + index: 0, + expected: `{ "block_hash": "0x50e864db6b81ce69fbeb70e6a7284ee2febbb9a2e707415de7adab83525e9cd", "block_number": 319132, "execution_status": "SUCCEEDED", @@ -797,44 +1035,32 @@ func TestTransactionReceiptByHash(t *testing.T) { } ], "execution_resources": { - "steps": 615, - "range_check_builtin_applications": 19, - "memory_holes": 4, "l1_data_gas": 0, "l1_gas": 0, - "l2_gas": 0, - "data_availability": { - "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0 - } + "l2_gas": 0 }, "actual_fee": { "amount": "0x16d8b4ad4000", "unit": "FRI" }, "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) - }) - - t.Run("tx with non empty data_availability", func(t *testing.T) { - expected := `{ + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.8", + }, + { + name: "tx with non empty data_availability 0.7", + network: &utils.SepoliaIntegration, + blockNumber: 35748, + index: 0, + expected: `{ "type": "DECLARE", "transaction_hash": "0x5ac644bbd6ae98d3be2d988439854e33f0961e24f349a63b43e16d172bfe747", "actual_fee": { @@ -866,32 +1092,109 @@ func TestTransactionReceiptByHash(t *testing.T) { "pedersen_builtin_applications": 16, "poseidon_builtin_applications": 4, "range_check_builtin_applications": 157, - "l1_data_gas": 192, - "l1_gas": 117620, - "l2_gas": 0, "data_availability": { "l1_gas": 0, - "l1_data_gas": 192, - "l2_gas": 0 + "l1_data_gas": 192 + } + } + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.7", + }, + { + name: "tx with non empty data_availability 0.8", + network: &utils.SepoliaIntegration, + blockNumber: 35748, + index: 0, + expected: `{ + "type": "DECLARE", + "transaction_hash": "0x5ac644bbd6ae98d3be2d988439854e33f0961e24f349a63b43e16d172bfe747", + "actual_fee": { + "amount": "0xd07af45c84550", + "unit": "WEI" + }, + "execution_status": "SUCCEEDED", + "finality_status": "ACCEPTED_ON_L2", + "block_hash": "0x1ea2a9cfa3df5297d58c0a04d09d276bc68d40fe64701305bbe2ed8f417e869", + "block_number": 35748, + "messages_sent": [], + "events": [ + { + "from_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", + "keys": [ + "0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9" + ], + "data": [ + "0x472aa8128e01eb0df145810c9511a92852d62a68ba8198ce5fa414e6337a365", + "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", + "0xd07af45c84550", + "0x0" + ] } + ], + "execution_resources": { + "l1_data_gas": 192, + "l1_gas": 117620, + "l2_gas": 0 } - }` + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.8", + }, + } - netClient := feeder.NewTestClient(t, utils.Ptr(utils.SepoliaIntegration)) - netGW := adaptfeeder.New(netClient) + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) - block, err := netGW.BlockByNumber(context.Background(), 35748) - require.NoError(t, err) + mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + handler := rpc.New(mockReader, mockSyncReader, nil, "", nil) - 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) + client := feeder.NewTestClient(t, test.network) + mainnetGw := adaptfeeder.New(client) - checkTxReceipt(t, txnHash, expected) - }) + block, err := mainnetGw.BlockByNumber(context.Background(), test.blockNumber) + require.NoError(t, err) + + txHash := test.mockBehavior(mockReader, test.index, block) + expectedMap := make(map[string]any) + require.NoError(t, json.Unmarshal([]byte(test.expected), &expectedMap)) + + var receipt *rpc.TransactionReceipt + var rErr *jsonrpc.Error + switch test.rpcVersion { + case "0.7": + receipt, rErr = handler.TransactionReceiptByHashV0_7(*txHash) + case "0.8": + receipt, rErr = handler.TransactionReceiptByHash(*txHash) + default: + t.Fatalf("unsupported rpc version: %s", test.rpcVersion) + } + require.Nil(t, rErr) + 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) + }) + } } func TestAddTransactionUnmarshal(t *testing.T) { diff --git a/starknet/transaction.go b/starknet/transaction.go index 9b35a083a7..baa81d015d 100644 --- a/starknet/transaction.go +++ b/starknet/transaction.go @@ -220,7 +220,6 @@ type ExecutionResources struct { type DataAvailability struct { L1Gas uint64 `json:"l1_gas"` L1DataGas uint64 `json:"l1_data_gas"` - L2Gas uint64 `json:"l2_gas"` } type BuiltinInstanceCounter struct { From fa1702cd66e03f3f733183d6d17a99a97054a1f0 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Tue, 28 Jan 2025 18:03:51 +0300 Subject: [PATCH 02/14] Fix e2e --- rpc/handlers.go | 6 +++--- rpc/simulation.go | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/rpc/handlers.go b/rpc/handlers.go index 83759b9528..6fbc3d4028 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -442,7 +442,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getTransactionReceipt", Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, - Handler: h.TransactionReceiptByHash, + Handler: h.TransactionReceiptByHashV0_7, }, { Name: "starknet_getBlockTransactionCount", @@ -550,7 +550,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_simulateTransactions", Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "transactions"}, {Name: "simulation_flags"}}, - Handler: h.SimulateTransactions, + Handler: h.SimulateTransactionsV0_7, }, { Name: "starknet_traceBlockTransactions", @@ -574,7 +574,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getBlockWithReceipts", Params: []jsonrpc.Parameter{{Name: "block_id"}}, - Handler: h.BlockWithReceipts, + Handler: h.BlockWithReceiptsV0_7, }, }, "/v0_7" } diff --git a/rpc/simulation.go b/rpc/simulation.go index 743610b3f6..92afe4b96a 100644 --- a/rpc/simulation.go +++ b/rpc/simulation.go @@ -56,6 +56,12 @@ func (h *Handler) SimulateTransactions(id BlockID, transactions []BroadcastedTra return h.simulateTransactions(id, transactions, simulationFlags, false, V0_8) } +func (h *Handler) SimulateTransactionsV0_7(id BlockID, transactions []BroadcastedTransaction, + simulationFlags []SimulationFlag, +) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { + return h.simulateTransactions(id, transactions, simulationFlags, false, V0_7) +} + func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTransaction, simulationFlags []SimulationFlag, errOnRevert bool, rpcVersion version, ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { From 4fe88be1aa97a68fbeb579e5581ae0217c7fcf73 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Tue, 28 Jan 2025 19:47:02 +0300 Subject: [PATCH 03/14] Fix e2e --- rpc/block.go | 60 +++++++++++++++++++++++++++++++++++++++++--- rpc/estimate_fee.go | 18 ++++++------- rpc/handlers.go | 4 +-- rpc/subscriptions.go | 23 +++++++++++------ 4 files changed, 83 insertions(+), 22 deletions(-) diff --git a/rpc/block.go b/rpc/block.go index 0f0678eef7..fcbebab10d 100644 --- a/rpc/block.go +++ b/rpc/block.go @@ -111,6 +111,41 @@ type BlockHeader struct { L1DataGasPrice *ResourcePrice `json:"l1_data_gas_price,omitempty"` L1DAMode *L1DAMode `json:"l1_da_mode,omitempty"` StarknetVersion string `json:"starknet_version"` + rpcVersion version +} + +func (h BlockHeader) MarshalJSON() ([]byte, error) { //nolint:gocritic + switch h.rpcVersion { + case V0_7: + return json.Marshal(struct { + Hash *felt.Felt `json:"block_hash,omitempty"` + ParentHash *felt.Felt `json:"parent_hash"` + Number *uint64 `json:"block_number,omitempty"` + NewRoot *felt.Felt `json:"new_root,omitempty"` + Timestamp uint64 `json:"timestamp"` + SequencerAddress *felt.Felt `json:"sequencer_address,omitempty"` + L1GasPrice *ResourcePrice `json:"l1_gas_price"` + L1DataGasPrice *ResourcePrice `json:"l1_data_gas_price,omitempty"` + L1DAMode *L1DAMode `json:"l1_da_mode,omitempty"` + StarknetVersion string `json:"starknet_version"` + }{ + Hash: h.Hash, + ParentHash: h.ParentHash, + Number: h.Number, + NewRoot: h.NewRoot, + Timestamp: h.Timestamp, + SequencerAddress: h.SequencerAddress, + L1GasPrice: h.L1GasPrice, + L1DataGasPrice: h.L1DataGasPrice, + L1DAMode: h.L1DAMode, + StarknetVersion: h.StarknetVersion, + }) + case V0_8: + type alias BlockHeader // avoid infinite recursion + return json.Marshal(alias(h)) + default: + return nil, errors.New("unknown BlockHeader version") + } } // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1131 @@ -172,6 +207,14 @@ func (h *Handler) BlockHashAndNumber() (*BlockHashAndNumber, *jsonrpc.Error) { // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L11 func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { + return h.blockWithTxHashes(id, V0_8) +} + +func (h *Handler) BlockWithTxHashesV0_7(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { + return h.blockWithTxHashes(id, V0_7) +} + +func (h *Handler) blockWithTxHashes(id BlockID, rpcVersion version) (*BlockWithTxHashes, *jsonrpc.Error) { block, rpcErr := h.blockByID(&id) if rpcErr != nil { return nil, rpcErr @@ -189,7 +232,7 @@ func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Er return &BlockWithTxHashes{ Status: status, - BlockHeader: adaptBlockHeader(block.Header), + BlockHeader: adaptBlockHeader(block.Header, rpcVersion), TxnHashes: txnHashes, }, nil } @@ -246,7 +289,7 @@ func (h *Handler) blockWithReceipts(id BlockID, rpcVersion version) (*BlockWithR return &BlockWithReceipts{ Status: blockStatus, - BlockHeader: adaptBlockHeader(block.Header), + BlockHeader: adaptBlockHeader(block.Header, rpcVersion), Transactions: txsWithReceipts, }, nil } @@ -256,6 +299,14 @@ func (h *Handler) blockWithReceipts(id BlockID, rpcVersion version) (*BlockWithR // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L44 func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { + return h.blockWithTxs(id, V0_8) +} + +func (h *Handler) BlockWithTxsV0_7(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { + return h.blockWithTxs(id, V0_7) +} + +func (h *Handler) blockWithTxs(id BlockID, rpcVersion version) (*BlockWithTxs, *jsonrpc.Error) { block, rpcErr := h.blockByID(&id) if rpcErr != nil { return nil, rpcErr @@ -273,7 +324,7 @@ func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { return &BlockWithTxs{ Status: status, - BlockHeader: adaptBlockHeader(block.Header), + BlockHeader: adaptBlockHeader(block.Header, rpcVersion), Transactions: txs, }, nil } @@ -294,7 +345,7 @@ func (h *Handler) blockStatus(id BlockID, block *core.Block) (BlockStatus, *json return status, nil } -func adaptBlockHeader(header *core.Header) BlockHeader { +func adaptBlockHeader(header *core.Header, rpcVersion version) BlockHeader { var blockNumber *uint64 // if header.Hash == nil it's a pending block if header.Hash != nil { @@ -355,6 +406,7 @@ func adaptBlockHeader(header *core.Header) BlockHeader { L1DataGasPrice: &l1DataGasPrice, L1DAMode: &l1DAMode, StarknetVersion: header.ProtocolVersion, + rpcVersion: rpcVersion, } } diff --git a/rpc/estimate_fee.go b/rpc/estimate_fee.go index ab311344a6..5bf077c75a 100644 --- a/rpc/estimate_fee.go +++ b/rpc/estimate_fee.go @@ -74,19 +74,19 @@ func (f FeeEstimate) MarshalJSON() ([]byte, error) { func (h *Handler) EstimateFeeV0_7(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, ) ([]FeeEstimate, http.Header, *jsonrpc.Error) { - result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, V0_7) - if err != nil { - return nil, httpHeader, err - } - - return utils.Map(result, func(tx SimulatedTransaction) FeeEstimate { - return tx.FeeEstimation - }), httpHeader, nil + return h.estimateFee(broadcastedTxns, simulationFlags, id, V0_7) } + func (h *Handler) EstimateFee(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, ) ([]FeeEstimate, http.Header, *jsonrpc.Error) { - result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, V0_8) + return h.estimateFee(broadcastedTxns, simulationFlags, id, V0_8) +} + +func (h *Handler) estimateFee(broadcastedTxns []BroadcastedTransaction, + simulationFlags []SimulationFlag, id BlockID, rpcVersion version, +) ([]FeeEstimate, http.Header, *jsonrpc.Error) { + result, httpHeader, err := h.simulateTransactions(id, broadcastedTxns, append(simulationFlags, SkipFeeChargeFlag), true, rpcVersion) if err != nil { return nil, httpHeader, err } diff --git a/rpc/handlers.go b/rpc/handlers.go index 6fbc3d4028..2ab8f04fd5 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -427,7 +427,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getBlockWithTxHashes", Params: []jsonrpc.Parameter{{Name: "block_id"}}, - Handler: h.BlockWithTxHashes, + Handler: h.BlockWithTxHashesV0_7, }, { Name: "starknet_getBlockWithTxs", @@ -564,7 +564,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_subscribeNewHeads", Params: []jsonrpc.Parameter{{Name: "block", Optional: true}}, - Handler: h.SubscribeNewHeads, + Handler: h.SubscribeNewHeadsV0_7, }, { Name: "starknet_unsubscribe", diff --git a/rpc/subscriptions.go b/rpc/subscriptions.go index 13e2a6f43b..9cd882a813 100644 --- a/rpc/subscriptions.go +++ b/rpc/subscriptions.go @@ -331,6 +331,14 @@ func sendEvents(ctx context.Context, w jsonrpc.Conn, events []*blockchain.Filter // SubscribeNewHeads creates a WebSocket stream which will fire events when a new block header is added. func (h *Handler) SubscribeNewHeads(ctx context.Context, blockID *BlockID) (*SubscriptionID, *jsonrpc.Error) { + return h.subscribeNewHeads(ctx, blockID, V0_8) +} + +func (h *Handler) SubscribeNewHeadsV0_7(ctx context.Context, blockID *BlockID) (*SubscriptionID, *jsonrpc.Error) { + return h.subscribeNewHeads(ctx, blockID, V0_7) +} + +func (h *Handler) subscribeNewHeads(ctx context.Context, blockID *BlockID, rpcVersion version) (*SubscriptionID, *jsonrpc.Error) { w, ok := jsonrpc.ConnFromContext(ctx) if !ok { return nil, jsonrpc.Err(jsonrpc.MethodNotFound, nil) @@ -367,7 +375,7 @@ func (h *Handler) SubscribeNewHeads(ctx context.Context, blockID *BlockID) (*Sub var wg conc.WaitGroup wg.Go(func() { - if err := h.sendHistoricalHeaders(subscriptionCtx, startHeader, latestHeader, w, id); err != nil { + if err := h.sendHistoricalHeaders(subscriptionCtx, startHeader, latestHeader, w, id, rpcVersion); err != nil { h.log.Errorw("Error sending old headers", "err", err) return } @@ -378,7 +386,7 @@ func (h *Handler) SubscribeNewHeads(ctx context.Context, blockID *BlockID) (*Sub }) wg.Go(func() { - h.processNewHeaders(subscriptionCtx, headerSub, w, id) + h.processNewHeaders(subscriptionCtx, headerSub, w, id, rpcVersion) }) wg.Wait() @@ -546,6 +554,7 @@ func (h *Handler) sendHistoricalHeaders( startHeader, latestHeader *core.Header, w jsonrpc.Conn, id uint64, + rpcVersion version, ) error { var ( err error @@ -557,7 +566,7 @@ func (h *Handler) sendHistoricalHeaders( case <-ctx.Done(): return ctx.Err() default: - if err := h.sendHeader(w, curHeader, id); err != nil { + if err := h.sendHeader(w, curHeader, id, rpcVersion); err != nil { return err } @@ -573,13 +582,13 @@ func (h *Handler) sendHistoricalHeaders( } } -func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscription[*core.Header], w jsonrpc.Conn, id uint64) { +func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscription[*core.Header], w jsonrpc.Conn, id uint64, rpcVersion version) { for { select { case <-ctx.Done(): return case header := <-headerSub.Recv(): - if err := h.sendHeader(w, header, id); err != nil { + if err := h.sendHeader(w, header, id, rpcVersion); err != nil { h.log.Warnw("Error sending header", "err", err) return } @@ -588,13 +597,13 @@ func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscri } // sendHeader creates a request and sends it to the client -func (h *Handler) sendHeader(w jsonrpc.Conn, header *core.Header, id uint64) error { +func (h *Handler) sendHeader(w jsonrpc.Conn, header *core.Header, id uint64, rpcVersion version) error { resp, err := json.Marshal(SubscriptionResponse{ Version: "2.0", Method: "starknet_subscriptionNewHeads", Params: map[string]any{ "subscription_id": id, - "result": adaptBlockHeader(header), + "result": adaptBlockHeader(header, rpcVersion), }, }) if err != nil { From 197154c34fdf4cd1e4adf338605815ca3a9b3b5c Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Tue, 28 Jan 2025 19:49:27 +0300 Subject: [PATCH 04/14] Fix e2e --- rpc/handlers.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rpc/handlers.go b/rpc/handlers.go index 2ab8f04fd5..374af7953f 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -432,7 +432,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_getBlockWithTxs", Params: []jsonrpc.Parameter{{Name: "block_id"}}, - Handler: h.BlockWithTxs, + Handler: h.BlockWithTxsV0_7, }, { Name: "starknet_getTransactionByHash", From ad930716a03f208ba08d94dc5332a34f9ba0a5a0 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Tue, 28 Jan 2025 20:50:21 +0300 Subject: [PATCH 05/14] Fix e2e --- rpc/simulation.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/rpc/simulation.go b/rpc/simulation.go index 92afe4b96a..1638ca93cd 100644 --- a/rpc/simulation.go +++ b/rpc/simulation.go @@ -150,17 +150,29 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra } func calculateFeeEstimate(overallFee *felt.Felt, l1DataGas uint64, feeUnit FeeUnit, header *core.Header, rpcVersion version) FeeEstimate { - var l1GasPrice, l2GasPrice, l1DataGasPrice *felt.Felt + var l1GasPrice *felt.Felt + l2GasPrice := &felt.Zero + l1DataGasPrice := &felt.Zero switch feeUnit { case FRI: - l1GasPrice = header.L1GasPriceSTRK - l2GasPrice = header.L2GasPrice.PriceInFri - l1DataGasPrice = header.L1DataGasPrice.PriceInFri + if l1GasPrice = header.L1GasPriceSTRK; l1GasPrice == nil { + l1GasPrice = &felt.Zero + } + if gasPrice := header.L2GasPrice; gasPrice != nil { + l2GasPrice = gasPrice.PriceInFri + } + if gasPrice := header.L1DataGasPrice; gasPrice != nil { + l1DataGasPrice = gasPrice.PriceInFri + } case WEI: l1GasPrice = header.L1GasPriceETH - l2GasPrice = header.L2GasPrice.PriceInWei - l1DataGasPrice = header.L1DataGasPrice.PriceInWei + if gasPrice := header.L2GasPrice; gasPrice != nil { + l2GasPrice = gasPrice.PriceInWei + } + if gasPrice := header.L1DataGasPrice; gasPrice != nil { + l1DataGasPrice = gasPrice.PriceInWei + } } l1DataGasConsumed := new(felt.Felt).SetUint64(l1DataGas) From e26176154ee4fc0ec82ece38d93b0946e0db89e1 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Wed, 29 Jan 2025 10:22:02 +0300 Subject: [PATCH 06/14] Fix e2e --- rpc/block.go | 79 ++++++++++++++------------------------------ rpc/subscriptions.go | 8 ++--- 2 files changed, 29 insertions(+), 58 deletions(-) diff --git a/rpc/block.go b/rpc/block.go index fcbebab10d..7a6c606e01 100644 --- a/rpc/block.go +++ b/rpc/block.go @@ -107,45 +107,10 @@ type BlockHeader struct { Timestamp uint64 `json:"timestamp"` SequencerAddress *felt.Felt `json:"sequencer_address,omitempty"` L1GasPrice *ResourcePrice `json:"l1_gas_price"` - L2GasPrice *ResourcePrice `json:"l2_gas_price"` + L2GasPrice *ResourcePrice `json:"l2_gas_price,omitempty"` L1DataGasPrice *ResourcePrice `json:"l1_data_gas_price,omitempty"` L1DAMode *L1DAMode `json:"l1_da_mode,omitempty"` StarknetVersion string `json:"starknet_version"` - rpcVersion version -} - -func (h BlockHeader) MarshalJSON() ([]byte, error) { //nolint:gocritic - switch h.rpcVersion { - case V0_7: - return json.Marshal(struct { - Hash *felt.Felt `json:"block_hash,omitempty"` - ParentHash *felt.Felt `json:"parent_hash"` - Number *uint64 `json:"block_number,omitempty"` - NewRoot *felt.Felt `json:"new_root,omitempty"` - Timestamp uint64 `json:"timestamp"` - SequencerAddress *felt.Felt `json:"sequencer_address,omitempty"` - L1GasPrice *ResourcePrice `json:"l1_gas_price"` - L1DataGasPrice *ResourcePrice `json:"l1_data_gas_price,omitempty"` - L1DAMode *L1DAMode `json:"l1_da_mode,omitempty"` - StarknetVersion string `json:"starknet_version"` - }{ - Hash: h.Hash, - ParentHash: h.ParentHash, - Number: h.Number, - NewRoot: h.NewRoot, - Timestamp: h.Timestamp, - SequencerAddress: h.SequencerAddress, - L1GasPrice: h.L1GasPrice, - L1DataGasPrice: h.L1DataGasPrice, - L1DAMode: h.L1DAMode, - StarknetVersion: h.StarknetVersion, - }) - case V0_8: - type alias BlockHeader // avoid infinite recursion - return json.Marshal(alias(h)) - default: - return nil, errors.New("unknown BlockHeader version") - } } // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L1131 @@ -206,15 +171,16 @@ func (h *Handler) BlockHashAndNumber() (*BlockHashAndNumber, *jsonrpc.Error) { // // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L11 -func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { - return h.blockWithTxHashes(id, V0_8) -} - func (h *Handler) BlockWithTxHashesV0_7(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { - return h.blockWithTxHashes(id, V0_7) + blockWithTxHashes, rpcErr := h.BlockWithTxHashes(id) + if rpcErr != nil { + return nil, rpcErr + } + blockWithTxHashes.L2GasPrice = nil + return blockWithTxHashes, nil } -func (h *Handler) blockWithTxHashes(id BlockID, rpcVersion version) (*BlockWithTxHashes, *jsonrpc.Error) { +func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { block, rpcErr := h.blockByID(&id) if rpcErr != nil { return nil, rpcErr @@ -232,7 +198,7 @@ func (h *Handler) blockWithTxHashes(id BlockID, rpcVersion version) (*BlockWithT return &BlockWithTxHashes{ Status: status, - BlockHeader: adaptBlockHeader(block.Header, rpcVersion), + BlockHeader: adaptBlockHeader(block.Header), TxnHashes: txnHashes, }, nil } @@ -251,7 +217,12 @@ func (h *Handler) BlockTransactionCount(id BlockID) (uint64, *jsonrpc.Error) { } func (h *Handler) BlockWithReceiptsV0_7(id BlockID) (*BlockWithReceipts, *jsonrpc.Error) { - return h.blockWithReceipts(id, V0_7) + blockWithReceipts, err := h.blockWithReceipts(id, V0_7) + if err != nil { + return nil, err + } + blockWithReceipts.L2GasPrice = nil + return blockWithReceipts, nil } func (h *Handler) BlockWithReceipts(id BlockID) (*BlockWithReceipts, *jsonrpc.Error) { @@ -289,7 +260,7 @@ func (h *Handler) blockWithReceipts(id BlockID, rpcVersion version) (*BlockWithR return &BlockWithReceipts{ Status: blockStatus, - BlockHeader: adaptBlockHeader(block.Header, rpcVersion), + BlockHeader: adaptBlockHeader(block.Header), Transactions: txsWithReceipts, }, nil } @@ -298,15 +269,16 @@ func (h *Handler) blockWithReceipts(id BlockID, rpcVersion version) (*BlockWithR // // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/a789ccc3432c57777beceaa53a34a7ae2f25fda0/api/starknet_api_openrpc.json#L44 -func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { - return h.blockWithTxs(id, V0_8) -} - func (h *Handler) BlockWithTxsV0_7(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { - return h.blockWithTxs(id, V0_7) + blockWithTxs, rpcErr := h.BlockWithTxs(id) + if rpcErr != nil { + return nil, rpcErr + } + blockWithTxs.L2GasPrice = nil + return blockWithTxs, nil } -func (h *Handler) blockWithTxs(id BlockID, rpcVersion version) (*BlockWithTxs, *jsonrpc.Error) { +func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { block, rpcErr := h.blockByID(&id) if rpcErr != nil { return nil, rpcErr @@ -324,7 +296,7 @@ func (h *Handler) blockWithTxs(id BlockID, rpcVersion version) (*BlockWithTxs, * return &BlockWithTxs{ Status: status, - BlockHeader: adaptBlockHeader(block.Header, rpcVersion), + BlockHeader: adaptBlockHeader(block.Header), Transactions: txs, }, nil } @@ -345,7 +317,7 @@ func (h *Handler) blockStatus(id BlockID, block *core.Block) (BlockStatus, *json return status, nil } -func adaptBlockHeader(header *core.Header, rpcVersion version) BlockHeader { +func adaptBlockHeader(header *core.Header) BlockHeader { var blockNumber *uint64 // if header.Hash == nil it's a pending block if header.Hash != nil { @@ -406,7 +378,6 @@ func adaptBlockHeader(header *core.Header, rpcVersion version) BlockHeader { L1DataGasPrice: &l1DataGasPrice, L1DAMode: &l1DAMode, StarknetVersion: header.ProtocolVersion, - rpcVersion: rpcVersion, } } diff --git a/rpc/subscriptions.go b/rpc/subscriptions.go index 9cd882a813..33b1cb9782 100644 --- a/rpc/subscriptions.go +++ b/rpc/subscriptions.go @@ -566,7 +566,7 @@ func (h *Handler) sendHistoricalHeaders( case <-ctx.Done(): return ctx.Err() default: - if err := h.sendHeader(w, curHeader, id, rpcVersion); err != nil { + if err := h.sendHeader(w, curHeader, id); err != nil { return err } @@ -588,7 +588,7 @@ func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscri case <-ctx.Done(): return case header := <-headerSub.Recv(): - if err := h.sendHeader(w, header, id, rpcVersion); err != nil { + if err := h.sendHeader(w, header, id); err != nil { h.log.Warnw("Error sending header", "err", err) return } @@ -597,13 +597,13 @@ func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscri } // sendHeader creates a request and sends it to the client -func (h *Handler) sendHeader(w jsonrpc.Conn, header *core.Header, id uint64, rpcVersion version) error { +func (h *Handler) sendHeader(w jsonrpc.Conn, header *core.Header, id uint64) error { resp, err := json.Marshal(SubscriptionResponse{ Version: "2.0", Method: "starknet_subscriptionNewHeads", Params: map[string]any{ "subscription_id": id, - "result": adaptBlockHeader(header, rpcVersion), + "result": adaptBlockHeader(header), }, }) if err != nil { From af290e899aeb0c143864b49ade29462f310cd119 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Wed, 29 Jan 2025 10:33:28 +0300 Subject: [PATCH 07/14] Fix e2e --- rpc/handlers.go | 2 +- rpc/subscriptions.go | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/rpc/handlers.go b/rpc/handlers.go index 374af7953f..e27b76b835 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -564,7 +564,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen { Name: "starknet_subscribeNewHeads", Params: []jsonrpc.Parameter{{Name: "block", Optional: true}}, - Handler: h.SubscribeNewHeadsV0_7, + Handler: h.SubscribeNewHeads, }, { Name: "starknet_unsubscribe", diff --git a/rpc/subscriptions.go b/rpc/subscriptions.go index 33b1cb9782..13e2a6f43b 100644 --- a/rpc/subscriptions.go +++ b/rpc/subscriptions.go @@ -331,14 +331,6 @@ func sendEvents(ctx context.Context, w jsonrpc.Conn, events []*blockchain.Filter // SubscribeNewHeads creates a WebSocket stream which will fire events when a new block header is added. func (h *Handler) SubscribeNewHeads(ctx context.Context, blockID *BlockID) (*SubscriptionID, *jsonrpc.Error) { - return h.subscribeNewHeads(ctx, blockID, V0_8) -} - -func (h *Handler) SubscribeNewHeadsV0_7(ctx context.Context, blockID *BlockID) (*SubscriptionID, *jsonrpc.Error) { - return h.subscribeNewHeads(ctx, blockID, V0_7) -} - -func (h *Handler) subscribeNewHeads(ctx context.Context, blockID *BlockID, rpcVersion version) (*SubscriptionID, *jsonrpc.Error) { w, ok := jsonrpc.ConnFromContext(ctx) if !ok { return nil, jsonrpc.Err(jsonrpc.MethodNotFound, nil) @@ -375,7 +367,7 @@ func (h *Handler) subscribeNewHeads(ctx context.Context, blockID *BlockID, rpcVe var wg conc.WaitGroup wg.Go(func() { - if err := h.sendHistoricalHeaders(subscriptionCtx, startHeader, latestHeader, w, id, rpcVersion); err != nil { + if err := h.sendHistoricalHeaders(subscriptionCtx, startHeader, latestHeader, w, id); err != nil { h.log.Errorw("Error sending old headers", "err", err) return } @@ -386,7 +378,7 @@ func (h *Handler) subscribeNewHeads(ctx context.Context, blockID *BlockID, rpcVe }) wg.Go(func() { - h.processNewHeaders(subscriptionCtx, headerSub, w, id, rpcVersion) + h.processNewHeaders(subscriptionCtx, headerSub, w, id) }) wg.Wait() @@ -554,7 +546,6 @@ func (h *Handler) sendHistoricalHeaders( startHeader, latestHeader *core.Header, w jsonrpc.Conn, id uint64, - rpcVersion version, ) error { var ( err error @@ -582,7 +573,7 @@ func (h *Handler) sendHistoricalHeaders( } } -func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscription[*core.Header], w jsonrpc.Conn, id uint64, rpcVersion version) { +func (h *Handler) processNewHeaders(ctx context.Context, headerSub *feed.Subscription[*core.Header], w jsonrpc.Conn, id uint64) { for { select { case <-ctx.Done(): From b464d425f9f1b373c4c92c62060f0cfceb1e3e96 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Wed, 29 Jan 2025 11:28:28 +0300 Subject: [PATCH 08/14] Fix e2e --- rpc/estimate_fee_pkg_test.go | 55 ++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 rpc/estimate_fee_pkg_test.go diff --git a/rpc/estimate_fee_pkg_test.go b/rpc/estimate_fee_pkg_test.go new file mode 100644 index 0000000000..5f323c6921 --- /dev/null +++ b/rpc/estimate_fee_pkg_test.go @@ -0,0 +1,55 @@ +package rpc + +import ( + "testing" + + "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/utils" + "github.com/stretchr/testify/require" +) + +func TestEstimateFeeMarshalJson(t *testing.T) { + tests := []struct { + name string + f FeeEstimate + want []byte + }{ + { //nolint:dupl + name: "V0_7", + f: FeeEstimate{ + L1GasConsumed: new(felt.Felt).SetUint64(1), + L1GasPrice: new(felt.Felt).SetUint64(2), + L2GasConsumed: new(felt.Felt).SetUint64(3), + L2GasPrice: new(felt.Felt).SetUint64(4), + L1DataGasConsumed: new(felt.Felt).SetUint64(5), + L1DataGasPrice: new(felt.Felt).SetUint64(6), + OverallFee: new(felt.Felt).SetUint64(7), + Unit: utils.Ptr(WEI), + rpcVersion: V0_7, + }, + want: []byte(`{"gas_consumed":"0x1","gas_price":"0x2","data_gas_consumed":"0x5","data_gas_price":"0x6","overall_fee":"0x7","unit":"WEI"}`), + }, + { //nolint:dupl + name: "V0_8", + f: FeeEstimate{ + L1GasConsumed: new(felt.Felt).SetUint64(8), + L1GasPrice: new(felt.Felt).SetUint64(9), + L2GasConsumed: new(felt.Felt).SetUint64(10), + L2GasPrice: new(felt.Felt).SetUint64(11), + L1DataGasConsumed: new(felt.Felt).SetUint64(12), + L1DataGasPrice: new(felt.Felt).SetUint64(13), + OverallFee: new(felt.Felt).SetUint64(14), + Unit: utils.Ptr(WEI), + rpcVersion: V0_8, + }, + want: []byte(`{"l1_gas_consumed":"0x8","l1_gas_price":"0x9","l2_gas_consumed":"0xa","l2_gas_price":"0xb","l1_data_gas_consumed":"0xc","l1_data_gas_price":"0xd","overall_fee":"0xe","unit":"WEI"}`), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := tt.f.MarshalJSON() + require.NoError(t, err) + require.Equal(t, tt.want, got) + }) + } +} From efb926f0b01adf880e1ceb2e6c60862ab29d4c98 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Thu, 23 Jan 2025 16:12:47 +0300 Subject: [PATCH 09/14] Add 0.6 endpoints back in --- mocks/mock_vm.go | 17 +- node/node.go | 32 ++-- node/throttled_vm.go | 9 +- rpc/block.go | 22 +++ rpc/block_test.go | 73 ++++++++- rpc/estimate_fee.go | 23 +++ rpc/estimate_fee_test.go | 88 ++++++++++- rpc/handlers.go | 168 +++++++++++++++++++- rpc/handlers_test.go | 8 +- rpc/simulation.go | 34 ++-- rpc/simulation_test.go | 27 +++- rpc/trace.go | 56 +++++-- rpc/trace_test.go | 330 ++++++++++++++++++++++++++++++++++++++- rpc/transaction.go | 31 ++++ rpc/transaction_test.go | 261 +++++++++++++++++++++++++++++++ vm/vm.go | 23 +-- vm/vm_test.go | 14 +- 17 files changed, 1135 insertions(+), 81 deletions(-) diff --git a/mocks/mock_vm.go b/mocks/mock_vm.go index fce753bd37..463532d978 100644 --- a/mocks/mock_vm.go +++ b/mocks/mock_vm.go @@ -23,6 +23,7 @@ import ( type MockVM struct { ctrl *gomock.Controller recorder *MockVMMockRecorder + isgomock struct{} } // MockVMMockRecorder is the mock recorder for MockVM. @@ -43,24 +44,24 @@ func (m *MockVM) EXPECT() *MockVMMockRecorder { } // Call mocks base method. -func (m *MockVM) Call(arg0 *vm.CallInfo, arg1 *vm.BlockInfo, arg2 core.StateReader, arg3 *utils.Network, arg4 uint64) ([]*felt.Felt, error) { +func (m *MockVM) Call(arg0 *vm.CallInfo, arg1 *vm.BlockInfo, arg2 core.StateReader, arg3 *utils.Network, arg4 uint64, arg5 bool) ([]*felt.Felt, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3, arg4) + ret := m.ctrl.Call(m, "Call", arg0, arg1, arg2, arg3, arg4, arg5) ret0, _ := ret[0].([]*felt.Felt) ret1, _ := ret[1].(error) return ret0, ret1 } // Call indicates an expected call of Call. -func (mr *MockVMMockRecorder) Call(arg0, arg1, arg2, arg3, arg4 any) *gomock.Call { +func (mr *MockVMMockRecorder) Call(arg0, arg1, arg2, arg3, arg4, arg5 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockVM)(nil).Call), arg0, arg1, arg2, arg3, arg4) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Call", reflect.TypeOf((*MockVM)(nil).Call), arg0, arg1, arg2, arg3, arg4, arg5) } // Execute mocks base method. -func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2 []*felt.Felt, arg3 *vm.BlockInfo, arg4 core.StateReader, arg5 *utils.Network, arg6, arg7, arg8 bool) ([]*felt.Felt, []core.GasConsumed, []vm.TransactionTrace, uint64, error) { +func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2 []*felt.Felt, arg3 *vm.BlockInfo, arg4 core.StateReader, arg5 *utils.Network, arg6, arg7, arg8, arg9 bool) ([]*felt.Felt, []core.GasConsumed, []vm.TransactionTrace, uint64, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + ret := m.ctrl.Call(m, "Execute", arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) ret0, _ := ret[0].([]*felt.Felt) ret1, _ := ret[1].([]core.GasConsumed) ret2, _ := ret[2].([]vm.TransactionTrace) @@ -70,7 +71,7 @@ func (m *MockVM) Execute(arg0 []core.Transaction, arg1 []core.Class, arg2 []*fel } // Execute indicates an expected call of Execute. -func (mr *MockVMMockRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8 any) *gomock.Call { +func (mr *MockVMMockRecorder) Execute(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Execute", reflect.TypeOf((*MockVM)(nil).Execute), arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9) } diff --git a/node/node.go b/node/node.go index 586876b4ee..428e1b1e2f 100644 --- a/node/node.go +++ b/node/node.go @@ -210,18 +210,28 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen if err = jsonrpcServer.RegisterMethods(methods...); err != nil { return nil, err } - jsonrpcServerLegacy := jsonrpc.NewServer(maxGoroutines, log).WithValidator(validator.Validator()) - legacyMethods, legacyPath := rpcHandler.MethodsV0_7() - if err = jsonrpcServerLegacy.RegisterMethods(legacyMethods...); err != nil { + + jsonrpcServerV0_6 := jsonrpc.NewServer(maxGoroutines, log).WithValidator(validator.Validator()) + methodsV0_6, pathV0_6 := rpcHandler.MethodsV0_6() + if err = jsonrpcServerV0_6.RegisterMethods(methodsV0_6...); err != nil { return nil, err } + + jsonrpcServerV0_7 := jsonrpc.NewServer(maxGoroutines, log).WithValidator(validator.Validator()) + methodsV0_7, pathV0_7 := rpcHandler.MethodsV0_7() + if err = jsonrpcServerV0_7.RegisterMethods(methodsV0_7...); err != nil { + return nil, err + } + rpcServers := map[string]*jsonrpc.Server{ - "/": jsonrpcServer, - path: jsonrpcServer, - legacyPath: jsonrpcServerLegacy, - "/rpc": jsonrpcServer, - "/rpc" + path: jsonrpcServer, - "/rpc" + legacyPath: jsonrpcServerLegacy, + "/": jsonrpcServer, + path: jsonrpcServer, + pathV0_7: jsonrpcServerV0_7, + pathV0_6: jsonrpcServerV0_6, + "/rpc": jsonrpcServer, + "/rpc" + path: jsonrpcServer, + "/rpc" + pathV0_7: jsonrpcServerV0_7, + "/rpc" + pathV0_6: jsonrpcServerV0_6, } if cfg.HTTP { readinessHandlers := NewReadinessHandlers(chain, synchronizer) @@ -242,9 +252,9 @@ func New(cfg *Config, version string) (*Node, error) { //nolint:gocyclo,funlen chain.WithListener(makeBlockchainMetrics()) makeJunoMetrics(version) database.WithListener(makeDBMetrics()) - rpcMetrics, legacyRPCMetrics := makeRPCMetrics(path, legacyPath) + rpcMetrics, legacyRPCMetrics := makeRPCMetrics(path, pathV0_7) jsonrpcServer.WithListener(rpcMetrics) - jsonrpcServerLegacy.WithListener(legacyRPCMetrics) + jsonrpcServerV0_7.WithListener(legacyRPCMetrics) client.WithListener(makeFeederMetrics()) gatewayClient.WithListener(makeGatewayMetrics()) metricsService = makeMetrics(cfg.MetricsHost, cfg.MetricsPort) diff --git a/node/throttled_vm.go b/node/throttled_vm.go index f50c66be1c..fea42104cb 100644 --- a/node/throttled_vm.go +++ b/node/throttled_vm.go @@ -15,23 +15,24 @@ type ThrottledVM struct { func NewThrottledVM(res vm.VM, concurrenyBudget uint, maxQueueLen int32) *ThrottledVM { return &ThrottledVM{ - Throttler: utils.NewThrottler[vm.VM](concurrenyBudget, &res).WithMaxQueueLen(maxQueueLen), + Throttler: utils.NewThrottler(concurrenyBudget, &res).WithMaxQueueLen(maxQueueLen), } } func (tvm *ThrottledVM) Call(callInfo *vm.CallInfo, blockInfo *vm.BlockInfo, state core.StateReader, - network *utils.Network, maxSteps uint64, + network *utils.Network, maxSteps uint64, useBlobData bool, ) ([]*felt.Felt, error) { var ret []*felt.Felt return ret, tvm.Do(func(vm *vm.VM) error { var err error - ret, err = (*vm).Call(callInfo, blockInfo, state, network, maxSteps) + ret, err = (*vm).Call(callInfo, blockInfo, state, network, maxSteps, useBlobData) return err }) } func (tvm *ThrottledVM) Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool, + useBlobData bool, ) ([]*felt.Felt, []core.GasConsumed, []vm.TransactionTrace, uint64, error) { var ret []*felt.Felt var traces []vm.TransactionTrace @@ -40,7 +41,7 @@ func (tvm *ThrottledVM) Execute(txns []core.Transaction, declaredClasses []core. return ret, daGas, traces, numSteps, tvm.Do(func(vm *vm.VM) error { var err error ret, daGas, traces, numSteps, err = (*vm).Execute(txns, declaredClasses, paidFeesOnL1, blockInfo, state, network, - skipChargeFee, skipValidate, errOnRevert) + skipChargeFee, skipValidate, errOnRevert, useBlobData) return err }) } diff --git a/rpc/block.go b/rpc/block.go index 7a6c606e01..c1122fc2a4 100644 --- a/rpc/block.go +++ b/rpc/block.go @@ -203,6 +203,17 @@ func (h *Handler) BlockWithTxHashes(id BlockID) (*BlockWithTxHashes, *jsonrpc.Er }, nil } +func (h *Handler) BlockWithTxHashesV0_6(id BlockID) (*BlockWithTxHashes, *jsonrpc.Error) { + resp, err := h.BlockWithTxHashes(id) + if err != nil { + return nil, err + } + + resp.L1DAMode = nil + resp.L1DataGasPrice = nil + return resp, nil +} + // BlockTransactionCount returns the number of transactions in a block // identified by the given BlockID. // @@ -301,6 +312,17 @@ func (h *Handler) BlockWithTxs(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { }, nil } +func (h *Handler) BlockWithTxsV0_6(id BlockID) (*BlockWithTxs, *jsonrpc.Error) { + resp, err := h.BlockWithTxs(id) + if err != nil { + return nil, err + } + + resp.L1DAMode = nil + resp.L1DataGasPrice = nil + return resp, nil +} + func (h *Handler) blockStatus(id BlockID, block *core.Block) (BlockStatus, *jsonrpc.Error) { l1H, jsonErr := h.l1Head() if jsonErr != nil { diff --git a/rpc/block_test.go b/rpc/block_test.go index b42388077d..1e8c44afc8 100644 --- a/rpc/block_test.go +++ b/rpc/block_test.go @@ -546,7 +546,78 @@ func TestBlockWithTxHashesV013(t *testing.T) { Timestamp: coreBlock.Timestamp, }, Status: rpc.BlockAcceptedL2, - Transactions: []*rpc.Transaction{ + Transactions: []*rpc.Transaction{ //nolint:dupl + { + 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) +} + +func TestBlockWithTxHashesV013_V06(t *testing.T) { + n := utils.Ptr(utils.SepoliaIntegration) + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + mockReader := mocks.NewMockReader(mockCtrl) + handler := rpc.New(mockReader, nil, nil, "", nil) + + blockNumber := uint64(16350) + gw := adaptfeeder.New(feeder.NewTestClient(t, n)) + coreBlock, err := gw.BlockByNumber(context.Background(), blockNumber) + require.NoError(t, err) + tx, ok := coreBlock.Transactions[0].(*core.InvokeTransaction) + require.True(t, ok) + + mockReader.EXPECT().BlockByNumber(gomock.Any()).Return(coreBlock, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{}, nil) + got, rpcErr := handler.BlockWithTxsV0_6(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{ + InFri: utils.HexToFelt(t, "0x17882b6aa74"), + InWei: utils.HexToFelt(t, "0x3b9aca10"), + }, + L2GasPrice: &rpc.ResourcePrice{ + InFri: &felt.Zero, + InWei: &felt.Zero, + }, + SequencerAddress: coreBlock.SequencerAddress, + Timestamp: coreBlock.Timestamp, + }, + Status: rpc.BlockAcceptedL2, + Transactions: []*rpc.Transaction{ //nolint:dupl { Hash: tx.Hash(), Type: rpc.TxnInvoke, diff --git a/rpc/estimate_fee.go b/rpc/estimate_fee.go index 5bf077c75a..4b8a94f411 100644 --- a/rpc/estimate_fee.go +++ b/rpc/estimate_fee.go @@ -43,6 +43,18 @@ type FeeEstimate struct { func (f FeeEstimate) MarshalJSON() ([]byte, error) { switch f.rpcVersion { + case V0_6: + return json.Marshal(struct { + GasConsumed *felt.Felt `json:"gas_consumed"` + GasPrice *felt.Felt `json:"gas_price"` + OverallFee *felt.Felt `json:"overall_fee"` + Unit *FeeUnit `json:"unit,omitempty"` + }{ + GasConsumed: f.L1GasConsumed, + GasPrice: f.L1GasPrice, + OverallFee: f.OverallFee, + Unit: f.Unit, + }) case V0_7: return json.Marshal(struct { GasConsumed *felt.Felt `json:"gas_consumed"` @@ -77,6 +89,12 @@ func (h *Handler) EstimateFeeV0_7(broadcastedTxns []BroadcastedTransaction, return h.estimateFee(broadcastedTxns, simulationFlags, id, V0_7) } +func (h *Handler) EstimateFeeV0_6(broadcastedTxns []BroadcastedTransaction, + simulationFlags []SimulationFlag, id BlockID, +) ([]FeeEstimate, http.Header, *jsonrpc.Error) { + return h.estimateFee(broadcastedTxns, simulationFlags, id, V0_6) +} + func (h *Handler) EstimateFee(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, ) ([]FeeEstimate, http.Header, *jsonrpc.Error) { @@ -96,6 +114,11 @@ func (h *Handler) estimateFee(broadcastedTxns []BroadcastedTransaction, }), httpHeader, nil } +//nolint:gocritic +func (h *Handler) EstimateMessageFeeV0_6(msg MsgFromL1, id BlockID) (*FeeEstimate, http.Header, *jsonrpc.Error) { + return estimateMessageFee(msg, id, h.EstimateFeeV0_6) +} + //nolint:gocritic func (h *Handler) EstimateMessageFeeV0_7(msg MsgFromL1, id BlockID) (*FeeEstimate, http.Header, *jsonrpc.Error) { return estimateMessageFee(msg, id, h.EstimateFeeV0_7) diff --git a/rpc/estimate_fee_test.go b/rpc/estimate_fee_test.go index c1ade1b8cf..fc7a655278 100644 --- a/rpc/estimate_fee_test.go +++ b/rpc/estimate_fee_test.go @@ -3,20 +3,102 @@ package rpc_test import ( "encoding/json" "errors" + "fmt" "testing" "github.com/NethermindEth/juno/core" "github.com/NethermindEth/juno/core/felt" + "github.com/NethermindEth/juno/db" "github.com/NethermindEth/juno/jsonrpc" "github.com/NethermindEth/juno/mocks" "github.com/NethermindEth/juno/rpc" "github.com/NethermindEth/juno/utils" "github.com/NethermindEth/juno/vm" + "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" ) +func TestEstimateMessageFeeV0_6(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + n := utils.Ptr(utils.Mainnet) + mockReader := mocks.NewMockReader(mockCtrl) + mockReader.EXPECT().Network().Return(n).AnyTimes() + mockVM := mocks.NewMockVM(mockCtrl) + + handler := rpc.New(mockReader, nil, mockVM, "", utils.NewNopZapLogger()) + msg := rpc.MsgFromL1{ + From: common.HexToAddress("0xDEADBEEF"), + To: *new(felt.Felt).SetUint64(1337), + Payload: []felt.Felt{*new(felt.Felt).SetUint64(1), *new(felt.Felt).SetUint64(2)}, + Selector: *new(felt.Felt).SetUint64(44), + } + + t.Run("block not found", func(t *testing.T) { + mockReader.EXPECT().HeadState().Return(nil, nil, db.ErrKeyNotFound) + _, httpHeader, err := handler.EstimateMessageFeeV0_6(msg, rpc.BlockID{Latest: true}) + require.Equal(t, rpc.ErrBlockNotFound, err) + require.NotEmpty(t, httpHeader.Get(rpc.ExecutionStepsHeader)) + }) + + latestHeader := &core.Header{ + Number: 9, + Timestamp: 456, + L1GasPriceETH: new(felt.Felt).SetUint64(42), + } + mockState := mocks.NewMockStateHistoryReader(mockCtrl) + + mockReader.EXPECT().HeadState().Return(mockState, nopCloser, nil) + mockReader.EXPECT().HeadsHeader().Return(latestHeader, nil) + + expectedGasConsumed := new(felt.Felt).SetUint64(37) + mockVM.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), &vm.BlockInfo{ + Header: latestHeader, + }, gomock.Any(), &utils.Mainnet, gomock.Any(), false, true, true).DoAndReturn( + func(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, + state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert, useBlobData bool, + ) ([]*felt.Felt, []core.GasConsumed, []vm.TransactionTrace, uint64, error) { + require.Len(t, txns, 1) + assert.NotNil(t, txns[0].(*core.L1HandlerTransaction)) + + assert.Empty(t, declaredClasses) + assert.Len(t, paidFeesOnL1, 1) + + actualFee := new(felt.Felt).Mul(expectedGasConsumed, blockInfo.Header.L1GasPriceETH) + daGas := []core.GasConsumed{{L1Gas: 0, L1DataGas: 0}} + return []*felt.Felt{actualFee}, daGas, []vm.TransactionTrace{{ + StateDiff: &vm.StateDiff{ + StorageDiffs: []vm.StorageDiff{}, + Nonces: []vm.Nonce{}, + DeployedContracts: []vm.DeployedContract{}, + DeprecatedDeclaredClasses: []*felt.Felt{}, + DeclaredClasses: []vm.DeclaredClass{}, + ReplacedClasses: []vm.ReplacedClass{}, + }, + }}, uint64(123), nil + }, + ) + + estimateFee, httpHeader, err := handler.EstimateMessageFeeV0_6(msg, rpc.BlockID{Latest: true}) + require.Nil(t, err) + expectedJSON := fmt.Sprintf( + `{"gas_consumed":%q,"gas_price":%q,"overall_fee":%q,"unit":"WEI"}`, + expectedGasConsumed, + latestHeader.L1GasPriceETH, + new(felt.Felt).Mul(expectedGasConsumed, latestHeader.L1GasPriceETH), + ) + + // we check json response here because some fields are private and we can't set them and assert.Equal fails + // also in 0.6 response some fields should not be presented + estimateFeeJSON, jsonErr := json.Marshal(estimateFee) + require.NoError(t, jsonErr) + require.Equal(t, expectedJSON, string(estimateFeeJSON)) + require.NotEmpty(t, httpHeader.Get(rpc.ExecutionStepsHeader)) +} + func TestEstimateFee(t *testing.T) { mockCtrl := gomock.NewController(t) defer mockCtrl.Finish() @@ -35,7 +117,7 @@ func TestEstimateFee(t *testing.T) { blockInfo := vm.BlockInfo{Header: &core.Header{}} t.Run("ok with zero values", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, false, true). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, false, true, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, uint64(123), nil).Times(2) _, httpHeader, err := handler.EstimateFee([]rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{}, rpc.BlockID{Latest: true}) @@ -49,7 +131,7 @@ func TestEstimateFee(t *testing.T) { }) t.Run("ok with zero values, skip validate", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, false). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, uint64(123), nil).Times(2) _, httpHeader, err := handler.EstimateFee([]rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}, rpc.BlockID{Latest: true}) @@ -63,7 +145,7 @@ func TestEstimateFee(t *testing.T) { }) t.Run("transaction execution error", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, false). Return(nil, nil, nil, uint64(0), vm.TransactionExecutionError{ Index: 44, Cause: errors.New("oops"), diff --git a/rpc/handlers.go b/rpc/handlers.go index e27b76b835..73ca0d630a 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -85,7 +85,8 @@ const ( type version uint32 const ( - V0_7 version = iota + 1 + V0_6 version = iota + 1 + V0_7 V0_8 ) @@ -222,6 +223,10 @@ func (h *Handler) SpecVersion() (string, *jsonrpc.Error) { return "0.8.0", nil } +func (h *Handler) SpecVersionV0_6() (string, *jsonrpc.Error) { + return "0.6.0", nil +} + func (h *Handler) SpecVersionV0_7() (string, *jsonrpc.Error) { return "0.7.1", nil } @@ -410,7 +415,7 @@ func (h *Handler) Methods() ([]jsonrpc.Method, string) { //nolint: funlen }, "/v0_8" } -func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen +func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen, dupl return []jsonrpc.Method{ { Name: "starknet_chainId", @@ -578,3 +583,162 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen }, }, "/v0_7" } + +func (h *Handler) MethodsV0_6() ([]jsonrpc.Method, string) { //nolint: funlen, dupl + return []jsonrpc.Method{ + { + Name: "starknet_chainId", + Handler: h.ChainID, + }, + { + Name: "starknet_blockNumber", + Handler: h.BlockNumber, + }, + { + Name: "starknet_blockHashAndNumber", + Handler: h.BlockHashAndNumber, + }, + { + Name: "starknet_getBlockWithTxHashes", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.BlockWithTxHashesV0_6, + }, + { + Name: "starknet_getBlockWithTxs", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.BlockWithTxsV0_6, + }, + { + Name: "starknet_getTransactionByHash", + Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, + Handler: h.TransactionByHash, + }, + { + Name: "starknet_getTransactionReceipt", + Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, + Handler: h.TransactionReceiptByHashV0_6, + }, + { + Name: "starknet_getBlockTransactionCount", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.BlockTransactionCount, + }, + { + Name: "starknet_getTransactionByBlockIdAndIndex", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "index"}}, + Handler: h.TransactionByBlockIDAndIndex, + }, + { + Name: "starknet_getStateUpdate", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.StateUpdate, + }, + { + Name: "starknet_syncing", + Handler: h.Syncing, + }, + { + Name: "starknet_getNonce", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "contract_address"}}, + Handler: h.Nonce, + }, + { + Name: "starknet_getStorageAt", + Params: []jsonrpc.Parameter{{Name: "contract_address"}, {Name: "key"}, {Name: "block_id"}}, + Handler: h.StorageAt, + }, + { + Name: "starknet_getClassHashAt", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "contract_address"}}, + Handler: h.ClassHashAt, + }, + { + Name: "starknet_getClass", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "class_hash"}}, + Handler: h.Class, + }, + { + Name: "starknet_getClassAt", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "contract_address"}}, + Handler: h.ClassAt, + }, + { + Name: "starknet_addInvokeTransaction", + Params: []jsonrpc.Parameter{{Name: "invoke_transaction"}}, + Handler: h.AddTransaction, + }, + { + Name: "starknet_addDeployAccountTransaction", + Params: []jsonrpc.Parameter{{Name: "deploy_account_transaction"}}, + Handler: h.AddTransaction, + }, + { + Name: "starknet_addDeclareTransaction", + Params: []jsonrpc.Parameter{{Name: "declare_transaction"}}, + Handler: h.AddTransaction, + }, + { + Name: "starknet_getEvents", + Params: []jsonrpc.Parameter{{Name: "filter"}}, + Handler: h.Events, + }, + { + Name: "juno_version", + Handler: h.Version, + }, + { + Name: "starknet_getTransactionStatus", + Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, + Handler: h.TransactionStatusV0_7, + }, + { + Name: "starknet_call", + Params: []jsonrpc.Parameter{{Name: "request"}, {Name: "block_id"}}, + Handler: h.CallV0_6, + }, + { + Name: "starknet_estimateFee", + Params: []jsonrpc.Parameter{{Name: "request"}, {Name: "simulation_flags"}, {Name: "block_id"}}, + Handler: h.EstimateFeeV0_6, + }, + { + Name: "starknet_estimateMessageFee", + Params: []jsonrpc.Parameter{{Name: "message"}, {Name: "block_id"}}, + Handler: h.EstimateMessageFeeV0_6, + }, + { + Name: "starknet_traceTransaction", + Params: []jsonrpc.Parameter{{Name: "transaction_hash"}}, + Handler: h.TraceTransactionV0_6, + }, + { + Name: "starknet_simulateTransactions", + Params: []jsonrpc.Parameter{{Name: "block_id"}, {Name: "transactions"}, {Name: "simulation_flags"}}, + Handler: h.SimulateTransactionsV0_6, + }, + { + Name: "starknet_traceBlockTransactions", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.TraceBlockTransactionsV0_6, + }, + { + Name: "starknet_specVersion", + Handler: h.SpecVersionV0_6, + }, + { + Name: "starknet_subscribeNewHeads", + Params: []jsonrpc.Parameter{{Name: "block", Optional: true}}, + Handler: h.SubscribeNewHeads, + }, + { + Name: "starknet_unsubscribe", + Params: []jsonrpc.Parameter{{Name: "id"}}, + Handler: h.Unsubscribe, + }, + { + Name: "starknet_getBlockWithReceipts", + Params: []jsonrpc.Parameter{{Name: "block_id"}}, + Handler: h.BlockWithReceipts, + }, + }, "/v0_6" +} diff --git a/rpc/handlers_test.go b/rpc/handlers_test.go index 433845f7c1..70d23e84f6 100644 --- a/rpc/handlers_test.go +++ b/rpc/handlers_test.go @@ -32,9 +32,13 @@ func TestSpecVersion(t *testing.T) { require.Nil(t, rpcErr) require.Equal(t, "0.8.0", version) - legacyVersion, rpcErr := handler.SpecVersionV0_7() + versionV0_7, rpcErr := handler.SpecVersionV0_7() require.Nil(t, rpcErr) - require.Equal(t, "0.7.1", legacyVersion) + require.Equal(t, "0.7.1", versionV0_7) + + versionV0_6, rpcErr := handler.SpecVersionV0_6() + require.Nil(t, rpcErr) + require.Equal(t, "0.6.0", versionV0_6) } func TestThrottledVMError(t *testing.T) { diff --git a/rpc/simulation.go b/rpc/simulation.go index 1638ca93cd..bbfb699832 100644 --- a/rpc/simulation.go +++ b/rpc/simulation.go @@ -62,6 +62,11 @@ func (h *Handler) SimulateTransactionsV0_7(id BlockID, transactions []Broadcaste return h.simulateTransactions(id, transactions, simulationFlags, false, V0_7) } +func (h *Handler) SimulateTransactionsV0_6(id BlockID, transactions []BroadcastedTransaction, + simulationFlags []SimulationFlag, +) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { + return h.simulateTransactions(id, transactions, simulationFlags, false, V0_6) +} func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTransaction, simulationFlags []SimulationFlag, errOnRevert bool, rpcVersion version, ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { @@ -110,8 +115,9 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra Header: header, BlockHashToBeRevealed: blockHashToBeRevealed, } + useBlobData := rpcVersion != V0_6 overallFees, daGas, traces, numSteps, err := h.vm.Execute(txns, classes, paidFeesOnL1, &blockInfo, - state, h.bcReader.Network(), skipFeeCharge, skipValidate, errOnRevert) + state, h.bcReader.Network(), skipFeeCharge, skipValidate, errOnRevert, useBlobData) httpHeader.Set(ExecutionStepsHeader, strconv.FormatUint(numSteps, 10)) @@ -132,13 +138,17 @@ func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTra estimate := calculateFeeEstimate(overallFee, daGas[i].L1DataGas, feeUnit, header, rpcVersion) - trace := traces[i] - executionResources := trace.TotalExecutionResources() - executionResources.DataAvailability = &vm.DataAvailability{ - L1Gas: daGas[i].L1Gas, - L1DataGas: daGas[i].L1DataGas, + switch rpcVersion { + case V0_6: + default: + trace := traces[i] + executionResources := trace.TotalExecutionResources() + executionResources.DataAvailability = &vm.DataAvailability{ + L1Gas: daGas[i].L1Gas, + L1DataGas: daGas[i].L1DataGas, + } + traces[i].ExecutionResources = executionResources } - traces[i].ExecutionResources = executionResources result = append(result, SimulatedTransaction{ TransactionTrace: &traces[i], @@ -176,8 +186,14 @@ func calculateFeeEstimate(overallFee *felt.Felt, l1DataGas uint64, feeUnit FeeUn } l1DataGasConsumed := new(felt.Felt).SetUint64(l1DataGas) - dataGasFee := new(felt.Felt).Mul(l1DataGasConsumed, l1DataGasPrice) - l1GasConsumed := new(felt.Felt).Sub(overallFee, dataGasFee) + var l1GasConsumed *felt.Felt + switch rpcVersion { + case V0_6: + l1GasConsumed = overallFee.Clone() + default: + dataGasFee := new(felt.Felt).Mul(l1DataGasConsumed, l1DataGasPrice) + l1GasConsumed = new(felt.Felt).Sub(overallFee, dataGasFee) + } l1GasConsumed = l1GasConsumed.Div(l1GasConsumed, l1GasPrice) return FeeEstimate{ diff --git a/rpc/simulation_test.go b/rpc/simulation_test.go index 8798bdfa09..a563bf5651 100644 --- a/rpc/simulation_test.go +++ b/rpc/simulation_test.go @@ -38,10 +38,10 @@ func TestSimulateTransactions(t *testing.T) { stepsUsed := uint64(123) mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ Header: headsHeader, - }, mockState, n, true, false, false). + }, mockState, n, true, false, false, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, stepsUsed, nil) - _, httpHeader, err := handler.SimulateTransactions(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipFeeChargeFlag}) + _, httpHeader, err := handler.SimulateTransactionsV0_6(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipFeeChargeFlag}) require.Nil(t, err) assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), "123") }) @@ -50,24 +50,39 @@ func TestSimulateTransactions(t *testing.T) { stepsUsed := uint64(123) mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ Header: headsHeader, - }, mockState, n, false, true, false). + }, mockState, n, false, true, false, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, stepsUsed, nil) - _, httpHeader, err := handler.SimulateTransactions(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}) + _, httpHeader, err := handler.SimulateTransactionsV0_6(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}) require.Nil(t, err) assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), "123") }) t.Run("transaction execution error", func(t *testing.T) { - t.Run("v0_7, v0_8", func(t *testing.T) { //nolint:dupl + t.Run("v0_6", func(t *testing.T) { //nolint:dupl mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ Header: headsHeader, - }, mockState, n, false, true, false). + }, mockState, n, false, true, false, false). Return(nil, nil, nil, uint64(0), vm.TransactionExecutionError{ Index: 44, Cause: errors.New("oops"), }) + _, httpHeader, err := handler.SimulateTransactionsV0_6(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}) + require.Equal(t, rpc.ErrTransactionExecutionError.CloneWithData(rpc.TransactionExecutionErrorData{ + TransactionIndex: 44, + ExecutionError: "oops", + }), err) + require.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), "0") + }) + t.Run("v0_7, v0_8", func(t *testing.T) { //nolint:dupl + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ + Header: headsHeader, + }, mockState, n, false, true, false, true). + Return(nil, nil, nil, uint64(0), vm.TransactionExecutionError{ + Index: 44, + Cause: errors.New("oops"), + }) _, httpHeader, err := handler.SimulateTransactions(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}) require.Equal(t, rpc.ErrTransactionExecutionError.CloneWithData(rpc.TransactionExecutionErrorData{ TransactionIndex: 44, diff --git a/rpc/trace.go b/rpc/trace.go index 449acd28d2..2f257a716f 100644 --- a/rpc/trace.go +++ b/rpc/trace.go @@ -134,10 +134,16 @@ func adaptFeederExecutionResources(resources *starknet.ExecutionResources) *vm.E // It follows the specification defined here: // https://github.com/starkware-libs/starknet-specs/blob/1ae810e0137cc5d175ace4554892a4f43052be56/api/starknet_trace_api_openrpc.json#L11 func (h *Handler) TraceTransaction(ctx context.Context, hash felt.Felt) (*vm.TransactionTrace, http.Header, *jsonrpc.Error) { - return h.traceTransaction(ctx, &hash) + return h.traceTransaction(ctx, &hash, false) } -func (h *Handler) traceTransaction(ctx context.Context, hash *felt.Felt) (*vm.TransactionTrace, http.Header, *jsonrpc.Error) { +func (h *Handler) TraceTransactionV0_6(ctx context.Context, hash felt.Felt) (*vm.TransactionTrace, http.Header, *jsonrpc.Error) { + return h.traceTransaction(ctx, &hash, true) +} + +func (h *Handler) traceTransaction(ctx context.Context, hash *felt.Felt, v0_6Response bool) (*vm.TransactionTrace, + http.Header, *jsonrpc.Error, +) { _, blockHash, _, err := h.bcReader.Receipt(hash) httpHeader := http.Header{} httpHeader.Set(ExecutionStepsHeader, "0") @@ -171,7 +177,7 @@ func (h *Handler) traceTransaction(ctx context.Context, hash *felt.Felt) (*vm.Tr return nil, httpHeader, ErrTxnHashNotFound } - traceResults, header, traceBlockErr := h.traceBlockTransactions(ctx, block) + traceResults, header, traceBlockErr := h.traceBlockTransactions(ctx, block, v0_6Response) if traceBlockErr != nil { return nil, header, traceBlockErr } @@ -187,11 +193,22 @@ func (h *Handler) TraceBlockTransactions(ctx context.Context, id BlockID) ([]Tra return nil, httpHeader, rpcErr } - return h.traceBlockTransactions(ctx, block) + return h.traceBlockTransactions(ctx, block, false) +} + +func (h *Handler) TraceBlockTransactionsV0_6(ctx context.Context, id BlockID) ([]TracedBlockTransaction, http.Header, *jsonrpc.Error) { + block, rpcErr := h.blockByID(&id) + if rpcErr != nil { + return nil, nil, rpcErr + } + + return h.traceBlockTransactions(ctx, block, true) } //nolint:funlen,gocyclo -func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block) ([]TracedBlockTransaction, http.Header, *jsonrpc.Error) { +func (h *Handler) traceBlockTransactions( + ctx context.Context, block *core.Block, v0_6Response bool, //nolint: gocyclo, funlen +) ([]TracedBlockTransaction, http.Header, *jsonrpc.Error) { httpHeader := http.Header{} httpHeader.Set(ExecutionStepsHeader, "0") @@ -206,6 +223,10 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block) return nil, httpHeader, err } + if v0_6Response { + return result, httpHeader, nil + } + txDataAvailability := make(map[felt.Felt]vm.DataAvailability, len(block.Receipts)) for _, receipt := range block.Receipts { if receipt.ExecutionResources == nil { @@ -288,8 +309,9 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block) BlockHashToBeRevealed: blockHashToBeRevealed, } + useBlobData := !v0_6Response _, daGas, traces, numSteps, err := h.vm.Execute(block.Transactions, classes, paidFeesOnL1, - &blockInfo, state, network, false, false, false) + &blockInfo, state, network, false, false, false, useBlobData) httpHeader.Set(ExecutionStepsHeader, strconv.FormatUint(numSteps, 10)) @@ -304,12 +326,14 @@ func (h *Handler) traceBlockTransactions(ctx context.Context, block *core.Block) result := make([]TracedBlockTransaction, 0, len(traces)) for index, trace := range traces { - executionResources := trace.TotalExecutionResources() - executionResources.DataAvailability = &vm.DataAvailability{ - L1Gas: daGas[index].L1Gas, - L1DataGas: daGas[index].L1DataGas, + if !v0_6Response { + executionResources := trace.TotalExecutionResources() + executionResources.DataAvailability = &vm.DataAvailability{ + L1Gas: daGas[index].L1Gas, + L1DataGas: daGas[index].L1DataGas, + } + traces[index].ExecutionResources = executionResources } - traces[index].ExecutionResources = executionResources result = append(result, TracedBlockTransaction{ TraceRoot: &traces[index], TransactionHash: block.Transactions[index].Hash(), @@ -352,6 +376,14 @@ func (h *Handler) fetchTraces(ctx context.Context, blockHash *felt.Felt) ([]Trac // https://github.com/starkware-libs/starknet-specs/blob/e0b76ed0d8d8eba405e182371f9edac8b2bcbc5a/api/starknet_api_openrpc.json#L401-L445 func (h *Handler) Call(funcCall FunctionCall, id BlockID) ([]*felt.Felt, *jsonrpc.Error) { //nolint:gocritic + return h.call(funcCall, id, true) +} + +func (h *Handler) CallV0_6(call FunctionCall, id BlockID) ([]*felt.Felt, *jsonrpc.Error) { //nolint:gocritic + return h.call(call, id, false) +} + +func (h *Handler) call(funcCall FunctionCall, id BlockID, useBlobData bool) ([]*felt.Felt, *jsonrpc.Error) { //nolint:gocritic state, closer, rpcErr := h.stateByBlockID(&id) if rpcErr != nil { return nil, rpcErr @@ -381,7 +413,7 @@ func (h *Handler) Call(funcCall FunctionCall, id BlockID) ([]*felt.Felt, *jsonrp }, &vm.BlockInfo{ Header: header, BlockHashToBeRevealed: blockHashToBeRevealed, - }, state, h.bcReader.Network(), h.callMaxSteps) + }, state, h.bcReader.Network(), h.callMaxSteps, useBlobData) if err != nil { if errors.Is(err, utils.ErrResourceBusy) { return nil, ErrInternal.CloneWithData(throttledVMErr) diff --git a/rpc/trace_test.go b/rpc/trace_test.go index 373379bc69..190497ef1d 100644 --- a/rpc/trace_test.go +++ b/rpc/trace_test.go @@ -180,7 +180,7 @@ func TestTraceTransaction(t *testing.T) { stepsUsedStr := "123" mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, &vm.BlockInfo{Header: header}, gomock.Any(), &utils.Mainnet, false, false, - false).Return(overallFee, consumedGas, []vm.TransactionTrace{*vmTrace}, stepsUsed, nil) + false, true).Return(overallFee, consumedGas, []vm.TransactionTrace{*vmTrace}, stepsUsed, nil) trace, httpHeader, err := handler.TraceTransaction(context.Background(), *hash) require.Nil(t, err) @@ -270,7 +270,7 @@ func TestTraceTransaction(t *testing.T) { stepsUsed := uint64(123) stepsUsedStr := "123" mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, - &vm.BlockInfo{Header: header}, gomock.Any(), &utils.Mainnet, false, false, false). + &vm.BlockInfo{Header: header}, gomock.Any(), &utils.Mainnet, false, false, false, true). Return(overallFee, consumedGas, []vm.TransactionTrace{*vmTrace}, stepsUsed, nil) trace, httpHeader, err := handler.TraceTransaction(context.Background(), *hash) @@ -287,6 +287,144 @@ func TestTraceTransaction(t *testing.T) { }) } +func TestTraceTransactionV0_6(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + mockReader.EXPECT().Network().Return(&utils.Mainnet).AnyTimes() + mockVM := mocks.NewMockVM(mockCtrl) + handler := rpc.New(mockReader, mockSyncReader, mockVM, "", utils.NewNopZapLogger()) + + t.Run("not found", func(t *testing.T) { + hash := utils.HexToFelt(t, "0xBBBB") + // Receipt() returns error related to db + mockReader.EXPECT().Receipt(hash).Return(nil, nil, uint64(0), db.ErrKeyNotFound) + mockSyncReader.EXPECT().Pending().Return(nil, nil) + + trace, httpHeader, err := handler.TraceTransactionV0_6(context.Background(), *hash) + assert.Nil(t, trace) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), "0") + assert.Equal(t, rpc.ErrTxnHashNotFound, err) + }) + t.Run("ok", func(t *testing.T) { + hash := utils.HexToFelt(t, "0x37b244ea7dc6b3f9735fba02d183ef0d6807a572dd91a63cc1b14b923c1ac0") + tx := &core.DeclareTransaction{ + TransactionHash: hash, + ClassHash: utils.HexToFelt(t, "0x000000000"), + } + + header := &core.Header{ + Hash: utils.HexToFelt(t, "0xCAFEBABE"), + ParentHash: utils.HexToFelt(t, "0x0"), + SequencerAddress: utils.HexToFelt(t, "0X111"), + ProtocolVersion: "99.12.3", + } + block := &core.Block{ + Header: header, + Transactions: []core.Transaction{tx}, + } + declaredClass := &core.DeclaredClass{ + At: 3002, + Class: &core.Cairo1Class{}, + } + + mockReader.EXPECT().Receipt(hash).Return(nil, header.Hash, header.Number, nil) + mockReader.EXPECT().BlockByHash(header.Hash).Return(block, nil) + + mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil) + headState := mocks.NewMockStateHistoryReader(mockCtrl) + headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil) + mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil) + + vmTraceJSON := json.RawMessage(`{ + "validate_invocation": {"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": [], "calls": [{"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": [], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, + "execute_invocation": {"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1", "0x1"], "calls": [{"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1", "0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x134692b230b9e1ffa39098904722134159652b09c5bc41d88d6698779d228ff"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "calldata": ["0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x5ee939756c1a60b029c594da00e637bf5923bf04a86ff163e877e899c0840eb", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "calldata": ["0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x38627c278c0b3cb3c84ddee2c783fb22c3c3a3f0e667ea2b82be0ea2253bce4", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x1ed6790cdca923073adc728080b06c159d9784cc9bf8fb26181acfdbe4256e6", "entry_point_selector": "0x260bb04cf90403013190e77d7e75f3d40d3d307180364da33c63ff53061d4e8", "calldata": [], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x5ee939756c1a60b029c594da00e637bf5923bf04a86ff163e877e899c0840eb", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x0", "0x0", "0x5"], "calls": [{"contract_address": "0x1ed6790cdca923073adc728080b06c159d9784cc9bf8fb26181acfdbe4256e6", "entry_point_selector": "0x260bb04cf90403013190e77d7e75f3d40d3d307180364da33c63ff53061d4e8", "calldata": [], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x46668cd07d83af5d7158e7cd62c710f1a7573501bcd4f4092c6a4e1ecd2bf61", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x0", "0x0", "0x5"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1e8480", "0x0"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1e8480", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x15543c3708653cda9d418b4ccd3be11368e40636c10c44b18cfe756b6d88b29", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2ceb6369dba6af865bca639f9f1342dfb1ae4e5d0d0723de98028b812e7cdd2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": [], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x134692b230b9e1ffa39098904722134159652b09c5bc41d88d6698779d228ff"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "entry_point_selector": "0x2c0f7bf2d6cf5304c29171bf493feb222fef84bdaf17805a6574b0c2e8bcc87", "calldata": ["0x1e8480", "0x0", "0x0", "0x0", "0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x648f780a"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x514718bb56ed2a8607554c7d393c2ffd73cbab971c120b00a2ce27cc58dd1c1", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x2", "0x1e8480", "0x0", "0x417c36e4fc16d", "0x0"], "calls": [{"contract_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "entry_point_selector": "0x3c388f7eb137a89061c6f0b6e78bae453202258b0b3c419f8dd9814a547d406", "calldata": [], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x231adde42526bad434ca2eb983efdd64472638702f87f97e6e3c084f264e06f", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x178b60b3a0bcc4aa98", "0xaf07589b7c", "0x648f7422"], "calls": [], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "entry_point_selector": "0x15543c3708653cda9d418b4ccd3be11368e40636c10c44b18cfe756b6d88b29", "calldata": ["0x417c36e4fc16d", "0x0", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x231adde42526bad434ca2eb983efdd64472638702f87f97e6e3c084f264e06f", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": [], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x178b5c9bdd4e74e92b", "0x0"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x178b5c9bdd4e74e92b", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0xaf07771ffc", "0x0"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0xaf07771ffc", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0xe14a408baf7f453312eec68e9b7d728ec5337fbdf671f917ee8c80f3255232"], "data": ["0x178b5c9bdd4e74e92b", "0xaf07771ffc"]}, {"keys": ["0xe316f0d9d2a3affa97de1d99bb2aac0538e2666d0d8545545ead241ef0ccab"], "data": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x0", "0x0", "0x1e8480", "0x0", "0x417c36e4fc16d", "0x0", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"]}], "messages": []}], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x417c36e4fc16d", "0x0"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x417c36e4fc16d", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"]}], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0xe316f0d9d2a3affa97de1d99bb2aac0538e2666d0d8545545ead241ef0ccab"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x417c36e4fc16d", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a"]}], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0x5ad857f66a5b55f1301ff1ed7e098ac6d4433148f0b72ebc4a2945ab85ad53"], "data": ["0x2fc5e96de394697c1311606c96ec14840e408493fd42cf0c54b73b39d312b81", "0x2", "0x1", "0x1"]}], "messages": []}], "events": [], "messages": []}, + "fee_transfer_invocation": {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"]}], "messages": []}], "events": [], "messages": []}, + "state_diff": { + "storage_diffs": [], + "nonces": [], + "deployed_contracts": [], + "deprecated_declared_classes": [], + "declared_classes": [], + "replaced_classes": [] + } + }`) + vmTrace := new(vm.TransactionTrace) + stepsUsed := uint64(123) + stepsUsedStr := "123" + require.NoError(t, json.Unmarshal(vmTraceJSON, vmTrace)) + mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, + &vm.BlockInfo{Header: header}, gomock.Any(), &utils.Mainnet, false, false, false, false). + Return(nil, nil, []vm.TransactionTrace{*vmTrace}, stepsUsed, nil) + + trace, httpHeader, err := handler.TraceTransactionV0_6(context.Background(), *hash) + require.Nil(t, err) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), stepsUsedStr) + assert.Equal(t, vmTrace, trace) + }) + t.Run("pending block", func(t *testing.T) { + hash := utils.HexToFelt(t, "0xceb6a374aff2bbb3537cf35f50df8634b2354a21") + tx := &core.DeclareTransaction{ + TransactionHash: hash, + ClassHash: utils.HexToFelt(t, "0x000000000"), + } + + header := &core.Header{ + ParentHash: utils.HexToFelt(t, "0x0"), + SequencerAddress: utils.HexToFelt(t, "0X111"), + ProtocolVersion: "99.12.3", + } + require.Nil(t, header.Hash, "hash must be nil for pending block") + + block := &core.Block{ + Header: header, + Transactions: []core.Transaction{tx}, + } + declaredClass := &core.DeclaredClass{ + At: 3002, + Class: &core.Cairo1Class{}, + } + + mockReader.EXPECT().Receipt(hash).Return(nil, header.Hash, header.Number, nil) + mockSyncReader.EXPECT().Pending().Return(&sync.Pending{ + Block: block, + }, nil) + + mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil) + headState := mocks.NewMockStateHistoryReader(mockCtrl) + headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil) + mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil) + + vmTraceJSON := json.RawMessage(`{ + "validate_invocation": {"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": [], "calls": [{"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x162da33a4585851fe8d3af3c2a9c60b557814e221e0d4f30ff0b2189d9c7775", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": [], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, + "execute_invocation": {"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1", "0x1"], "calls": [{"contract_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "entry_point_selector": "0x15d40a3d6ca2ac30f4031e42be28da9b056fef9bb7357ac5e85627ee876e5ad", "calldata": ["0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "0x0", "0x3", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "0x3", "0x10", "0x13", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0x0", "class_hash": "0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1", "0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x134692b230b9e1ffa39098904722134159652b09c5bc41d88d6698779d228ff"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "calldata": ["0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x5ee939756c1a60b029c594da00e637bf5923bf04a86ff163e877e899c0840eb", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x1171593aa5bdadda4d6b0efde6cc94ee7649c3163d5efeb19da6c16d63a2a63", "calldata": ["0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x420eeb770f7a4", "0x0", "0x40139799e37e4", "0x0", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x0", "0x0", "0x1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x64"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x38627c278c0b3cb3c84ddee2c783fb22c3c3a3f0e667ea2b82be0ea2253bce4", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x1ed6790cdca923073adc728080b06c159d9784cc9bf8fb26181acfdbe4256e6", "entry_point_selector": "0x260bb04cf90403013190e77d7e75f3d40d3d307180364da33c63ff53061d4e8", "calldata": [], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x5ee939756c1a60b029c594da00e637bf5923bf04a86ff163e877e899c0840eb", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x0", "0x0", "0x5"], "calls": [{"contract_address": "0x1ed6790cdca923073adc728080b06c159d9784cc9bf8fb26181acfdbe4256e6", "entry_point_selector": "0x260bb04cf90403013190e77d7e75f3d40d3d307180364da33c63ff53061d4e8", "calldata": [], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x46668cd07d83af5d7158e7cd62c710f1a7573501bcd4f4092c6a4e1ecd2bf61", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x0", "0x0", "0x5"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1e8480", "0x0"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1e8480", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "entry_point_selector": "0x15543c3708653cda9d418b4ccd3be11368e40636c10c44b18cfe756b6d88b29", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x0", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2ceb6369dba6af865bca639f9f1342dfb1ae4e5d0d0723de98028b812e7cdd2", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": [], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", "calldata": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x134692b230b9e1ffa39098904722134159652b09c5bc41d88d6698779d228ff"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "entry_point_selector": "0x2c0f7bf2d6cf5304c29171bf493feb222fef84bdaf17805a6574b0c2e8bcc87", "calldata": ["0x1e8480", "0x0", "0x0", "0x0", "0x2", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x648f780a"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x514718bb56ed2a8607554c7d393c2ffd73cbab971c120b00a2ce27cc58dd1c1", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x2", "0x1e8480", "0x0", "0x417c36e4fc16d", "0x0"], "calls": [{"contract_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "entry_point_selector": "0x3c388f7eb137a89061c6f0b6e78bae453202258b0b3c419f8dd9814a547d406", "calldata": [], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x231adde42526bad434ca2eb983efdd64472638702f87f97e6e3c084f264e06f", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x178b60b3a0bcc4aa98", "0xaf07589b7c", "0x648f7422"], "calls": [], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x41b033f4a31df8067c24d1e9b550a2ce75fd4a29e1147af9752174f0e6cb20", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x1e8480", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "entry_point_selector": "0x15543c3708653cda9d418b4ccd3be11368e40636c10c44b18cfe756b6d88b29", "calldata": ["0x417c36e4fc16d", "0x0", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "class_hash": "0x231adde42526bad434ca2eb983efdd64472638702f87f97e6e3c084f264e06f", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": [], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0x417c36e4fc16d", "0x0"]}], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x178b5c9bdd4e74e92b", "0x0"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x178b5c9bdd4e74e92b", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x52c7ba99c77fc38dd3346beea6c0753c3471f2e3135af5bb837d6c9523fff62", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0xaf07771ffc", "0x0"], "calls": [{"contract_address": "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325"], "caller_address": "0x23c72abdf49dffc85ae3ede714f2168ad384cc67d08524732acea90df325", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0xaf07771ffc", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0xe14a408baf7f453312eec68e9b7d728ec5337fbdf671f917ee8c80f3255232"], "data": ["0x178b5c9bdd4e74e92b", "0xaf07771ffc"]}, {"keys": ["0xe316f0d9d2a3affa97de1d99bb2aac0538e2666d0d8545545ead241ef0ccab"], "data": ["0x7a6f98c03379b9513ca84cca1373ff452a7462a3b61598f0af5bb27ad7f76d1", "0x0", "0x0", "0x1e8480", "0x0", "0x417c36e4fc16d", "0x0", "0x0", "0x0", "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"]}], "messages": []}], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x417c36e4fc16d", "0x0"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x2e4263afad30923c891518314c3c95dbe830a16874e8abc5777a9a20b54c76e", "calldata": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x417c36e4fc16d", "0x0"], "calls": [], "events": [], "messages": []}], "events": [], "messages": []}, {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"], "caller_address": "0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0x4270219d365d6b017231b52e92b3fb5d7c8378b05e9abc97724537a80e93b0f", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x417c36e4fc16d", "0x0"]}], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0xe316f0d9d2a3affa97de1d99bb2aac0538e2666d0d8545545ead241ef0ccab"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x53c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8", "0x1e8480", "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "0x417c36e4fc16d", "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a"]}], "messages": []}], "events": [], "messages": []}], "events": [{"keys": ["0x5ad857f66a5b55f1301ff1ed7e098ac6d4433148f0b72ebc4a2945ab85ad53"], "data": ["0x2fc5e96de394697c1311606c96ec14840e408493fd42cf0c54b73b39d312b81", "0x2", "0x1", "0x1"]}], "messages": []}], "events": [], "messages": []}, + "fee_transfer_invocation": {"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3", "entry_point_type": "EXTERNAL", "call_type": "CALL", "result": ["0x1"], "calls": [{"contract_address": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7", "entry_point_selector": "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", "calldata": ["0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"], "caller_address": "0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "class_hash": "0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0", "entry_point_type": "EXTERNAL", "call_type": "DELEGATE", "result": ["0x1"], "calls": [], "events": [{"keys": ["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"], "data": ["0xd747220b2744d8d8d48c8a52bd3869fb98aea915665ab2485d5eadb49def6a", "0x1176a1bd84444c89232ec27754698e5d2e7e1a7f1539f12027f28b23ec9f3d8", "0x2cb6", "0x0"]}], "messages": []}], "events": [], "messages": []}, + "state_diff": { + "storage_diffs": [], + "nonces": [], + "deployed_contracts": [], + "deprecated_declared_classes": [], + "declared_classes": [], + "replaced_classes": [] + } + }`) + vmTrace := new(vm.TransactionTrace) + stepsUsed := uint64(123) + stepsUsedStr := "123" + require.NoError(t, json.Unmarshal(vmTraceJSON, vmTrace)) + mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, + &vm.BlockInfo{Header: header}, gomock.Any(), &utils.Mainnet, false, false, false, false). + Return(nil, nil, []vm.TransactionTrace{*vmTrace}, stepsUsed, nil) + + trace, httpHeader, err := handler.TraceTransactionV0_6(context.Background(), *hash) + require.Nil(t, err) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), stepsUsedStr) + assert.Equal(t, vmTrace, trace) + }) +} + func TestTraceBlockTransactions(t *testing.T) { errTests := map[string]rpc.BlockID{ "latest": {Latest: true}, @@ -295,7 +433,7 @@ func TestTraceBlockTransactions(t *testing.T) { "number": {Number: 1}, } - for description, id := range errTests { + for description, id := range errTests { //nolint:dupl t.Run(description, func(t *testing.T) { log := utils.NewNopZapLogger() n := utils.Ptr(utils.Mainnet) @@ -382,7 +520,7 @@ func TestTraceBlockTransactions(t *testing.T) { stepsUsedStr := "123" require.NoError(t, json.Unmarshal(vmTraceJSON, &vmTrace)) mockVM.EXPECT().Execute(block.Transactions, []core.Class{declaredClass.Class}, paidL1Fees, &vm.BlockInfo{Header: header}, - gomock.Any(), n, false, false, false). + gomock.Any(), n, false, false, false, false). Return(nil, []core.GasConsumed{{}, {}}, []vm.TransactionTrace{vmTrace, vmTrace}, stepsUsed, nil) result, httpHeader, err := handler.TraceBlockTransactions(context.Background(), rpc.BlockID{Hash: blockHash}) @@ -458,7 +596,7 @@ func TestTraceBlockTransactions(t *testing.T) { stepsUsed := uint64(123) stepsUsedStr := "123" mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, &vm.BlockInfo{Header: header}, - gomock.Any(), n, false, false, false). + gomock.Any(), n, false, false, false, false). Return(nil, []core.GasConsumed{{}, {}}, []vm.TransactionTrace{vmTrace}, stepsUsed, nil) expectedResult := []rpc.TracedBlockTransaction{ @@ -474,6 +612,186 @@ func TestTraceBlockTransactions(t *testing.T) { }) } +func TestTraceBlockTransactionsV0_6(t *testing.T) { + errTests := map[string]rpc.BlockID{ + "latest": {Latest: true}, + "pending": {Pending: true}, + "hash": {Hash: new(felt.Felt).SetUint64(1)}, + "number": {Number: 1}, + } + + for description, id := range errTests { //nolint:dupl + t.Run(description, func(t *testing.T) { + log := utils.NewNopZapLogger() + n := utils.Ptr(utils.Mainnet) + chain := blockchain.New(pebble.NewMemTest(t), n, nil) + handler := rpc.New(chain, nil, nil, "", log) + + if description == "pending" { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + mockSyncReader.EXPECT().Pending().Return(nil, sync.ErrPendingBlockNotFound) + + handler = rpc.New(chain, mockSyncReader, nil, "", log) + } + + update, httpHeader, rpcErr := handler.TraceBlockTransactions(context.Background(), id) + assert.Nil(t, update) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), "0") + assert.Equal(t, rpc.ErrBlockNotFound, rpcErr) + }) + } + + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + n := utils.Ptr(utils.Mainnet) + + mockReader := mocks.NewMockReader(mockCtrl) + mockSyncReader := mocks.NewMockSyncReader(mockCtrl) + mockReader.EXPECT().Network().Return(n).AnyTimes() + mockVM := mocks.NewMockVM(mockCtrl) + log := utils.NewNopZapLogger() + + handler := rpc.New(mockReader, mockSyncReader, mockVM, "", log) + + t.Run("pending block", func(t *testing.T) { + blockHash := utils.HexToFelt(t, "0x0001") + header := &core.Header{ + // hash is not set because it's pending block + ParentHash: utils.HexToFelt(t, "0x0C3"), + Number: 0, + L1GasPriceETH: utils.HexToFelt(t, "0x777"), + ProtocolVersion: "99.12.3", + } + l1Tx := &core.L1HandlerTransaction{ + TransactionHash: utils.HexToFelt(t, "0x000000C"), + } + declaredClass := &core.DeclaredClass{ + At: 3002, + Class: &core.Cairo1Class{}, + } + declareTx := &core.DeclareTransaction{ + TransactionHash: utils.HexToFelt(t, "0x000000001"), + ClassHash: utils.HexToFelt(t, "0x00000BC00"), + } + block := &core.Block{ + Header: header, + Transactions: []core.Transaction{l1Tx, declareTx}, + } + + mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil) + state := mocks.NewMockStateHistoryReader(mockCtrl) + mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(state, nopCloser, nil) + headState := mocks.NewMockStateHistoryReader(mockCtrl) + headState.EXPECT().Class(declareTx.ClassHash).Return(declaredClass, nil) + mockSyncReader.EXPECT().PendingState().Return(headState, nopCloser, nil) + + paidL1Fees := []*felt.Felt{(&felt.Felt{}).SetUint64(1)} + vmTraceJSON := json.RawMessage(`{ + "validate_invocation": {}, + "execute_invocation": {}, + "fee_transfer_invocation": {}, + "state_diff": { + "storage_diffs": [], + "nonces": [], + "deployed_contracts": [], + "deprecated_declared_classes": [], + "declared_classes": [], + "replaced_classes": [] + } + }`) + vmTrace := vm.TransactionTrace{} + stepsUsed := uint64(123) + stepsUsedStr := "123" + require.NoError(t, json.Unmarshal(vmTraceJSON, &vmTrace)) + mockVM.EXPECT().Execute(block.Transactions, []core.Class{declaredClass.Class}, paidL1Fees, &vm.BlockInfo{Header: header}, + gomock.Any(), n, false, false, false, false). + Return(nil, nil, []vm.TransactionTrace{vmTrace, vmTrace}, stepsUsed, nil) + + result, httpHeader, err := handler.TraceBlockTransactionsV0_6(context.Background(), rpc.BlockID{Hash: blockHash}) + require.Nil(t, err) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), stepsUsedStr) + assert.Equal(t, &vm.TransactionTrace{ + ValidateInvocation: &vm.FunctionInvocation{}, + ExecuteInvocation: &vm.ExecuteInvocation{}, + FeeTransferInvocation: &vm.FunctionInvocation{}, + StateDiff: &vm.StateDiff{ + StorageDiffs: []vm.StorageDiff{}, + Nonces: []vm.Nonce{}, + DeployedContracts: []vm.DeployedContract{}, + DeprecatedDeclaredClasses: []*felt.Felt{}, + DeclaredClasses: []vm.DeclaredClass{}, + ReplacedClasses: []vm.ReplacedClass{}, + }, + }, result[0].TraceRoot) + assert.Equal(t, l1Tx.TransactionHash, result[0].TransactionHash) + }) + t.Run("regular block", func(t *testing.T) { + blockHash := utils.HexToFelt(t, "0x37b244ea7dc6b3f9735fba02d183ef0d6807a572dd91a63cc1b14b923c1ac0") + tx := &core.DeclareTransaction{ + TransactionHash: utils.HexToFelt(t, "0x000000001"), + ClassHash: utils.HexToFelt(t, "0x000000000"), + } + + header := &core.Header{ + Hash: blockHash, + ParentHash: utils.HexToFelt(t, "0x0"), + Number: 0, + SequencerAddress: utils.HexToFelt(t, "0X111"), + L1GasPriceETH: utils.HexToFelt(t, "0x777"), + ProtocolVersion: "99.12.3", + } + block := &core.Block{ + Header: header, + Transactions: []core.Transaction{tx}, + } + declaredClass := &core.DeclaredClass{ + At: 3002, + Class: &core.Cairo1Class{}, + } + + mockReader.EXPECT().BlockByHash(blockHash).Return(block, nil) + + mockReader.EXPECT().StateAtBlockHash(header.ParentHash).Return(nil, nopCloser, nil) + headState := mocks.NewMockStateHistoryReader(mockCtrl) + headState.EXPECT().Class(tx.ClassHash).Return(declaredClass, nil) + mockReader.EXPECT().HeadState().Return(headState, nopCloser, nil) + + vmTraceJSON := json.RawMessage(`{ + "validate_invocation":{"entry_point_selector":"0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895","calldata":["0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2","0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463","0x2","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x0"],"caller_address":"0x0","class_hash":"0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918","entry_point_type":"EXTERNAL","call_type":"CALL","result":[],"calls":[{"entry_point_selector":"0x36fcbf06cd96843058359e1a75928beacfac10727dab22a3972f0af8aa92895","calldata":["0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2","0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463","0x2","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x0"],"caller_address":"0x0","class_hash":"0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":[],"calls":[],"events":[],"messages":[]}],"events":[],"messages":[]}, + "execute_invocation":{"entry_point_selector":"0x28ffe4ff0f226a9107253e17a904099aa4f63a02a5621de0576e5aa71bc5194","calldata":["0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2","0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463","0x2","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x0"],"caller_address":"0x0","class_hash":"0x25ec026985a3bf9d0cc1fe17326b245dfdc3ff89b8fde106542a3ea56c5a918","entry_point_type":"CONSTRUCTOR","call_type":"CALL","result":[],"calls":[{"entry_point_selector":"0x79dc0da7c54b95f10aa182ad0a46400db63156920adb65eca2654c0945a463","calldata":["0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x0"],"caller_address":"0x0","class_hash":"0x33434ad846cdd5f23eb73ff09fe6fddd568284a0fb7d1be20ee482f044dabe2","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":[],"calls":[],"events":[{"keys":["0x10c19bef19acd19b2c9f4caa40fd47c9fbe1d9f91324d44dcd36be2dae96784"],"data":["0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","0x322258135d04971e96b747a5551061aa046ad5d8be11a35c67029d96b23f98","0x0"]}],"messages":[]}],"events":[],"messages":[]}, + "fee_transfer_invocation":{"entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"],"caller_address":"0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","class_hash":"0xd0e183745e9dae3e4e78a8ffedcce0903fc4900beace4e0abf192d4c202da3","entry_point_type":"EXTERNAL","call_type":"CALL","result":["0x1"],"calls":[{"entry_point_selector":"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e","calldata":["0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"],"caller_address":"0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","class_hash":"0x2760f25d5a4fb2bdde5f561fd0b44a3dee78c28903577d37d669939d97036a0","entry_point_type":"EXTERNAL","call_type":"DELEGATE","result":["0x1"],"calls":[],"events":[{"keys":["0x99cd8bde557814842a3121e8ddfd433a539b8c9f14bf31ebf108d12e6196e9"],"data":["0xdac9bcffb3d967f19a7fe21002c98c984d5a9458a88e6fc5d1c478a97ed412","0x5dcd266a80b8a5f29f04d779c6b166b80150c24f2180a75e82427242dab20a9","0x15be","0x0"]}],"messages":[]}],"events":[],"messages":[]},"state_diff": { + "storage_diffs": [], + "nonces": [], + "deployed_contracts": [], + "deprecated_declared_classes": [], + "declared_classes": [], + "replaced_classes": [] + } + }`) + vmTrace := vm.TransactionTrace{} + require.NoError(t, json.Unmarshal(vmTraceJSON, &vmTrace)) + stepsUsed := uint64(123) + stepsUsedStr := "123" + mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, &vm.BlockInfo{Header: header}, + gomock.Any(), n, false, false, false, false). + Return(nil, nil, []vm.TransactionTrace{vmTrace}, stepsUsed, nil) + + expectedResult := []rpc.TracedBlockTransaction{ + { + TransactionHash: tx.Hash(), + TraceRoot: &vmTrace, + }, + } + result, httpHeader, err := handler.TraceBlockTransactionsV0_6(context.Background(), rpc.BlockID{Hash: blockHash}) + require.Nil(t, err) + assert.Equal(t, httpHeader.Get(rpc.ExecutionStepsHeader), stepsUsedStr) + assert.Equal(t, expectedResult, result) + }) +} + func TestCall(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -547,7 +865,7 @@ func TestCall(t *testing.T) { ClassHash: classHash, Selector: selector, Calldata: calldata, - }, &vm.BlockInfo{Header: headsHeader}, gomock.Any(), &utils.Mainnet, uint64(1337)).Return(expectedRes, nil) + }, &vm.BlockInfo{Header: headsHeader}, gomock.Any(), &utils.Mainnet, uint64(1337), true).Return(expectedRes, nil) res, rpcErr := handler.Call(rpc.FunctionCall{ ContractAddress: *contractAddr, diff --git a/rpc/transaction.go b/rpc/transaction.go index e2281dc77a..a49736a0df 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -591,6 +591,37 @@ func (h *Handler) transactionReceiptByHash(hash felt.Felt, rpcVersion version) ( return AdaptReceipt(receipt, txn, status, blockHash, blockNumber, rpcVersion), nil } +// TransactionReceiptByHash returns the receipt 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#L222 +func (h *Handler) TransactionReceiptByHashV0_6(hash felt.Felt) (*TransactionReceipt, *jsonrpc.Error) { + txn, err := h.bcReader.TransactionByHash(&hash) + if err != nil { + return nil, ErrTxnHashNotFound + } + + receipt, blockHash, blockNumber, err := h.bcReader.Receipt(&hash) + if err != nil { + return nil, ErrTxnHashNotFound + } + + status := TxnAcceptedOnL2 + + if blockHash != nil { + l1H, jsonErr := h.l1Head() + if jsonErr != nil { + return nil, jsonErr + } + + if isL1Verified(blockNumber, l1H) { + status = TxnAcceptedOnL1 + } + } + + return AdaptReceipt(receipt, txn, status, blockHash, blockNumber, V0_6), nil +} + // AddTransaction relays a transaction to the gateway. func (h *Handler) AddTransaction(ctx context.Context, tx BroadcastedTransaction) (*AddTxResponse, *jsonrpc.Error) { //nolint:gocritic if tx.Type == TxnDeclare && tx.Version.Cmp(new(felt.Felt).SetUint64(2)) != -1 { diff --git a/rpc/transaction_test.go b/rpc/transaction_test.go index 0170bf55b7..432c3e2231 100644 --- a/rpc/transaction_test.go +++ b/rpc/transaction_test.go @@ -518,6 +518,267 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { }) } +//nolint:dupl +func TestTransactionReceiptByHashV0_6(t *testing.T) { + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) + + n := utils.Ptr(utils.Mainnet) + mockReader := mocks.NewMockReader(mockCtrl) + handler := rpc.New(mockReader, 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.TransactionReceiptByHashV0_6(*txHash) + assert.Nil(t, tx) + assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) + }) + + client := feeder.NewTestClient(t, n) + 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.TransactionReceiptByHashV0_6(*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 + }{ + "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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": { + "l1_data_gas": 0, + "l1_gas": 0, + "l2_gas": 0, + "steps": 615, + "range_check_builtin_applications": 19, + "memory_holes": 4 + }, + "actual_fee": { + "amount": "0x16d8b4ad4000", + "unit": "FRI" + }, + "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 TestTransactionReceiptByHash(t *testing.T) { t.Run("transaction not found", func(t *testing.T) { diff --git a/vm/vm.go b/vm/vm.go index 6f0f00155a..b26f1e3324 100644 --- a/vm/vm.go +++ b/vm/vm.go @@ -61,10 +61,9 @@ import ( //go:generate mockgen -destination=../mocks/mock_vm.go -package=mocks github.com/NethermindEth/juno/vm VM type VM interface { - Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateReader, network *utils.Network, - maxSteps uint64) ([]*felt.Felt, error) - Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *BlockInfo, - state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert bool, + Call(*CallInfo, *BlockInfo, core.StateReader, *utils.Network, uint64, bool) ([]*felt.Felt, error) + Execute([]core.Transaction, []core.Class, []*felt.Felt, *BlockInfo, + core.StateReader, *utils.Network, bool, bool, bool, bool, ) ([]*felt.Felt, []core.GasConsumed, []TransactionTrace, uint64, error) } @@ -200,7 +199,7 @@ func makeCCallInfo(callInfo *CallInfo) (C.CallInfo, runtime.Pinner) { return cCallInfo, pinner } -func makeCBlockInfo(blockInfo *BlockInfo) C.BlockInfo { +func makeCBlockInfo(blockInfo *BlockInfo, useBlobData bool) C.BlockInfo { var cBlockInfo C.BlockInfo cBlockInfo.block_number = C.ulonglong(blockInfo.Header.Number) @@ -213,13 +212,17 @@ func makeCBlockInfo(blockInfo *BlockInfo) C.BlockInfo { if blockInfo.Header.L1DAMode == core.Blob { copyFeltIntoCArray(blockInfo.Header.L1DataGasPrice.PriceInWei, &cBlockInfo.data_gas_price_wei[0]) copyFeltIntoCArray(blockInfo.Header.L1DataGasPrice.PriceInFri, &cBlockInfo.data_gas_price_fri[0]) - cBlockInfo.use_blob_data = 1 + if useBlobData { + cBlockInfo.use_blob_data = 1 + } else { + cBlockInfo.use_blob_data = 0 + } } return cBlockInfo } func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateReader, - network *utils.Network, maxSteps uint64, + network *utils.Network, maxSteps uint64, useBlobData bool, ) ([]*felt.Felt, error) { context := &callContext{ state: state, @@ -236,7 +239,7 @@ func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateRead C.setVersionedConstants(C.CString("my_json")) cCallInfo, callInfoPinner := makeCCallInfo(callInfo) - cBlockInfo := makeCBlockInfo(blockInfo) + cBlockInfo := makeCBlockInfo(blockInfo, useBlobData) chainID := C.CString(network.L2ChainID) C.cairoVMCall( &cCallInfo, @@ -259,7 +262,7 @@ func (v *vm) Call(callInfo *CallInfo, blockInfo *BlockInfo, state core.StateRead // Execute executes a given transaction set and returns the gas spent per transaction func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *BlockInfo, state core.StateReader, network *utils.Network, - skipChargeFee, skipValidate, errOnRevert bool, + skipChargeFee, skipValidate, errOnRevert, useBlobData bool, ) ([]*felt.Felt, []core.GasConsumed, []TransactionTrace, uint64, error) { context := &callContext{ state: state, @@ -302,7 +305,7 @@ func (v *vm) Execute(txns []core.Transaction, declaredClasses []core.Class, paid concurrencyModeByte = 1 } - cBlockInfo := makeCBlockInfo(blockInfo) + cBlockInfo := makeCBlockInfo(blockInfo, useBlobData) chainID := C.CString(network.L2ChainID) C.cairoVMExecute(txnsJSONCstr, classesJSONCStr, diff --git a/vm/vm_test.go b/vm/vm_test.go index 3305f669f9..39c06e2b72 100644 --- a/vm/vm_test.go +++ b/vm/vm_test.go @@ -50,7 +50,7 @@ func TestV0Call(t *testing.T) { ContractAddress: contractAddr, ClassHash: classHash, Selector: entryPoint, - }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Mainnet, 1_000_000) + }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Mainnet, 1_000_000, true) require.NoError(t, err) assert.Equal(t, []*felt.Felt{&felt.Zero}, ret) @@ -70,7 +70,7 @@ func TestV0Call(t *testing.T) { ContractAddress: contractAddr, ClassHash: classHash, Selector: entryPoint, - }, &BlockInfo{Header: &core.Header{Number: 1}}, testState, &utils.Mainnet, 1_000_000) + }, &BlockInfo{Header: &core.Header{Number: 1}}, testState, &utils.Mainnet, 1_000_000, true) require.NoError(t, err) assert.Equal(t, []*felt.Felt{new(felt.Felt).SetUint64(1337)}, ret) } @@ -116,7 +116,7 @@ func TestV1Call(t *testing.T) { Calldata: []felt.Felt{ *storageLocation, }, - }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Goerli, 1_000_000) + }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Goerli, 1_000_000, true) require.NoError(t, err) assert.Equal(t, []*felt.Felt{&felt.Zero}, ret) @@ -138,7 +138,7 @@ func TestV1Call(t *testing.T) { Calldata: []felt.Felt{ *storageLocation, }, - }, &BlockInfo{Header: &core.Header{Number: 1}}, testState, &utils.Goerli, 1_000_000) + }, &BlockInfo{Header: &core.Header{Number: 1}}, testState, &utils.Goerli, 1_000_000, true) require.NoError(t, err) assert.Equal(t, []*felt.Felt{new(felt.Felt).SetUint64(37)}, ret) } @@ -178,7 +178,7 @@ func TestCall_MaxSteps(t *testing.T) { ContractAddress: contractAddr, ClassHash: classHash, Selector: entryPoint, - }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Mainnet, 0) + }, &BlockInfo{Header: &core.Header{}}, testState, &utils.Mainnet, 0, true) assert.ErrorContains(t, err, "RunResources has no remaining steps") } @@ -203,7 +203,7 @@ func TestExecute(t *testing.T) { L1GasPriceSTRK: &felt.Zero, }, }, state, - &network, false, false, false) + &network, false, false, false, false) require.NoError(t, err) }) t.Run("zero data", func(t *testing.T) { @@ -213,7 +213,7 @@ func TestExecute(t *testing.T) { L1GasPriceETH: &felt.Zero, L1GasPriceSTRK: &felt.Zero, }, - }, state, &network, false, false, false) + }, state, &network, false, false, false, false) require.NoError(t, err) }) } From 399b2b4ce1784499371d61221476145c9cb48486 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 24 Jan 2025 23:06:30 +0300 Subject: [PATCH 10/14] Fix some tests --- rpc/estimate_fee.go | 6 +++--- rpc/estimate_fee_test.go | 8 ++++---- rpc/simulation_test.go | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/rpc/estimate_fee.go b/rpc/estimate_fee.go index 4b8a94f411..c5d0e38eaf 100644 --- a/rpc/estimate_fee.go +++ b/rpc/estimate_fee.go @@ -129,12 +129,12 @@ func (h *Handler) EstimateMessageFee(msg MsgFromL1, id BlockID) (*FeeEstimate, h return estimateMessageFee(msg, id, h.EstimateFee) } -type estimateFeeHandler func(broadcastedTxns []BroadcastedTransaction, +type estimateFeeHandler[T any] func(broadcastedTxns []BroadcastedTransaction, simulationFlags []SimulationFlag, id BlockID, -) ([]FeeEstimate, http.Header, *jsonrpc.Error) +) ([]T, http.Header, *jsonrpc.Error) //nolint:gocritic -func estimateMessageFee(msg MsgFromL1, id BlockID, f estimateFeeHandler) (*FeeEstimate, http.Header, *jsonrpc.Error) { +func estimateMessageFee[T any](msg MsgFromL1, id BlockID, f estimateFeeHandler[T]) (*T, http.Header, *jsonrpc.Error) { calldata := make([]*felt.Felt, 0, len(msg.Payload)+1) // The order of the calldata parameters matters. msg.From must be prepended. calldata = append(calldata, new(felt.Felt).SetBytes(msg.From.Bytes())) diff --git a/rpc/estimate_fee_test.go b/rpc/estimate_fee_test.go index fc7a655278..6bedf39bcb 100644 --- a/rpc/estimate_fee_test.go +++ b/rpc/estimate_fee_test.go @@ -57,7 +57,7 @@ func TestEstimateMessageFeeV0_6(t *testing.T) { expectedGasConsumed := new(felt.Felt).SetUint64(37) mockVM.EXPECT().Execute(gomock.Any(), gomock.Any(), gomock.Any(), &vm.BlockInfo{ Header: latestHeader, - }, gomock.Any(), &utils.Mainnet, gomock.Any(), false, true, true).DoAndReturn( + }, gomock.Any(), &utils.Mainnet, gomock.Any(), false, true, false).DoAndReturn( func(txns []core.Transaction, declaredClasses []core.Class, paidFeesOnL1 []*felt.Felt, blockInfo *vm.BlockInfo, state core.StateReader, network *utils.Network, skipChargeFee, skipValidate, errOnRevert, useBlobData bool, ) ([]*felt.Felt, []core.GasConsumed, []vm.TransactionTrace, uint64, error) { @@ -117,7 +117,7 @@ func TestEstimateFee(t *testing.T) { blockInfo := vm.BlockInfo{Header: &core.Header{}} t.Run("ok with zero values", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, false, true, true). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, uint64(123), nil).Times(2) _, httpHeader, err := handler.EstimateFee([]rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{}, rpc.BlockID{Latest: true}) @@ -131,7 +131,7 @@ func TestEstimateFee(t *testing.T) { }) t.Run("ok with zero values, skip validate", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, false). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, uint64(123), nil).Times(2) _, httpHeader, err := handler.EstimateFee([]rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}, rpc.BlockID{Latest: true}) @@ -145,7 +145,7 @@ func TestEstimateFee(t *testing.T) { }) t.Run("transaction execution error", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, false). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, true). Return(nil, nil, nil, uint64(0), vm.TransactionExecutionError{ Index: 44, Cause: errors.New("oops"), diff --git a/rpc/simulation_test.go b/rpc/simulation_test.go index a563bf5651..6725329355 100644 --- a/rpc/simulation_test.go +++ b/rpc/simulation_test.go @@ -38,7 +38,7 @@ func TestSimulateTransactions(t *testing.T) { stepsUsed := uint64(123) mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ Header: headsHeader, - }, mockState, n, true, false, false, true). + }, mockState, n, true, false, false, false). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, stepsUsed, nil) _, httpHeader, err := handler.SimulateTransactionsV0_6(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipFeeChargeFlag}) @@ -50,7 +50,7 @@ func TestSimulateTransactions(t *testing.T) { stepsUsed := uint64(123) mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &vm.BlockInfo{ Header: headsHeader, - }, mockState, n, false, true, false, true). + }, mockState, n, false, true, false, false). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, stepsUsed, nil) _, httpHeader, err := handler.SimulateTransactionsV0_6(rpc.BlockID{Latest: true}, []rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{rpc.SkipValidateFlag}) From ad75deda18745e967976298449e7fffe1e07bfc5 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Sat, 25 Jan 2025 09:31:04 +0300 Subject: [PATCH 11/14] Fix tests --- rpc/estimate_fee_test.go | 2 +- rpc/subscriptions_test.go | 199 +++++++++++++++++--------------------- rpc/trace_test.go | 6 +- 3 files changed, 92 insertions(+), 115 deletions(-) diff --git a/rpc/estimate_fee_test.go b/rpc/estimate_fee_test.go index 6bedf39bcb..d8c038d2c3 100644 --- a/rpc/estimate_fee_test.go +++ b/rpc/estimate_fee_test.go @@ -117,7 +117,7 @@ func TestEstimateFee(t *testing.T) { blockInfo := vm.BlockInfo{Header: &core.Header{}} t.Run("ok with zero values", func(t *testing.T) { - mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, true, true, true). + mockVM.EXPECT().Execute([]core.Transaction{}, nil, []*felt.Felt{}, &blockInfo, mockState, n, true, false, true, true). Return([]*felt.Felt{}, []core.GasConsumed{}, []vm.TransactionTrace{}, uint64(123), nil).Times(2) _, httpHeader, err := handler.EstimateFee([]rpc.BroadcastedTransaction{}, []rpc.SimulationFlag{}, rpc.BlockID{Latest: true}) diff --git a/rpc/subscriptions_test.go b/rpc/subscriptions_test.go index cf012abaf0..5def2f9f03 100644 --- a/rpc/subscriptions_test.go +++ b/rpc/subscriptions_test.go @@ -824,130 +824,107 @@ func TestSubscriptionReorg(t *testing.T) { } func TestSubscribePendingTxs(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - t.Cleanup(cancel) - - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - - mockChain := mocks.NewMockReader(mockCtrl) - l1Feed := feed.New[*core.L1Head]() - mockChain.EXPECT().SubscribeL1Head().Return(blockchain.L1HeadSubscription{Subscription: l1Feed.Subscribe()}) - - syncer := newFakeSyncer() - handler, server := setupRPC(t, ctx, mockChain, syncer) - - t.Run("Basic subscription", func(t *testing.T) { - conn := createWsConn(t, ctx, server) - - subMsg := `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions"}` - id := uint64(1) - handler.WithIDGen(func() uint64 { return id }) - got := sendWsMessage(t, ctx, conn, subMsg) - require.Equal(t, subResp(id), got) - - hash1 := new(felt.Felt).SetUint64(1) - addr1 := new(felt.Felt).SetUint64(11) - - hash2 := new(felt.Felt).SetUint64(2) - addr2 := new(felt.Felt).SetUint64(22) - - hash3 := new(felt.Felt).SetUint64(3) - hash4 := new(felt.Felt).SetUint64(4) - hash5 := new(felt.Felt).SetUint64(5) - - syncer.pendingTxs.Send([]core.Transaction{ - &core.InvokeTransaction{TransactionHash: hash1, SenderAddress: addr1}, - &core.DeclareTransaction{TransactionHash: hash2, SenderAddress: addr2}, - &core.DeployTransaction{TransactionHash: hash3}, - &core.DeployAccountTransaction{DeployTransaction: core.DeployTransaction{TransactionHash: hash4}}, - &core.L1HandlerTransaction{TransactionHash: hash5}, - }) - - want := `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":["0x1","0x2","0x3","0x4","0x5"],"subscription_id":%d}}` - want = fmt.Sprintf(want, id) - _, pendingTxsGot, err := conn.Read(ctx) - require.NoError(t, err) - require.Equal(t, want, string(pendingTxsGot)) - }) - - t.Run("Filtered subscription", func(t *testing.T) { - conn := createWsConn(t, ctx, server) + tests := []struct { + name string + subscribeMsg string + expectedTxs []core.Transaction + want string + }{ + { + name: "Basic subscription", + subscribeMsg: `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions"}`, + expectedTxs: []core.Transaction{ + &core.InvokeTransaction{TransactionHash: new(felt.Felt).SetUint64(1), SenderAddress: new(felt.Felt).SetUint64(11)}, + &core.DeclareTransaction{TransactionHash: new(felt.Felt).SetUint64(2), SenderAddress: new(felt.Felt).SetUint64(22)}, + &core.DeployTransaction{TransactionHash: new(felt.Felt).SetUint64(3)}, + &core.DeployAccountTransaction{DeployTransaction: core.DeployTransaction{TransactionHash: new(felt.Felt).SetUint64(4)}}, + &core.L1HandlerTransaction{TransactionHash: new(felt.Felt).SetUint64(5)}, + }, + want: `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":["0x1","0x2","0x3","0x4","0x5"],"subscription_id":%d}}`, + }, + { + name: "Filtered subscription", + subscribeMsg: `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions", "params":{"sender_address":["0xb", "0x16"]}}`, + expectedTxs: []core.Transaction{ + &core.InvokeTransaction{TransactionHash: new(felt.Felt).SetUint64(1), SenderAddress: new(felt.Felt).SetUint64(11)}, + &core.DeclareTransaction{TransactionHash: new(felt.Felt).SetUint64(2), SenderAddress: new(felt.Felt).SetUint64(22)}, + &core.DeployTransaction{TransactionHash: new(felt.Felt).SetUint64(3)}, + &core.DeployAccountTransaction{DeployTransaction: core.DeployTransaction{TransactionHash: new(felt.Felt).SetUint64(4)}}, + &core.L1HandlerTransaction{TransactionHash: new(felt.Felt).SetUint64(5)}, + &core.InvokeTransaction{TransactionHash: new(felt.Felt).SetUint64(6), SenderAddress: new(felt.Felt).SetUint64(66)}, + &core.InvokeTransaction{TransactionHash: new(felt.Felt).SetUint64(7), SenderAddress: new(felt.Felt).SetUint64(77)}, + }, + want: `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":["0x1","0x2"],"subscription_id":%d}}`, + }, + { + name: "Full details subscription", + subscribeMsg: `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions", "params":{"transaction_details": true}}`, + expectedTxs: []core.Transaction{ + &core.InvokeTransaction{ + TransactionHash: new(felt.Felt).SetUint64(1), + CallData: []*felt.Felt{new(felt.Felt).SetUint64(2)}, + TransactionSignature: []*felt.Felt{new(felt.Felt).SetUint64(3)}, + MaxFee: new(felt.Felt).SetUint64(4), + ContractAddress: new(felt.Felt).SetUint64(5), + Version: new(core.TransactionVersion).SetUint64(3), + EntryPointSelector: new(felt.Felt).SetUint64(6), + Nonce: new(felt.Felt).SetUint64(7), + SenderAddress: new(felt.Felt).SetUint64(8), + ResourceBounds: map[core.Resource]core.ResourceBounds{}, + Tip: 9, + PaymasterData: []*felt.Felt{new(felt.Felt).SetUint64(10)}, + AccountDeploymentData: []*felt.Felt{new(felt.Felt).SetUint64(11)}, + }, + }, + want: `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":[{"transaction_hash":"0x1","type":"INVOKE","version":"0x3","nonce":"0x7","max_fee":"0x4","contract_address":"0x5","sender_address":"0x8","signature":["0x3"],"calldata":["0x2"],"entry_point_selector":"0x6","resource_bounds":{},"tip":"0x9","paymaster_data":["0xa"],"account_deployment_data":["0xb"],"nonce_data_availability_mode":"L1","fee_data_availability_mode":"L1"}],"subscription_id":%d}}`, + }, + } - subMsg := `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions", "params":{"sender_address":["0xb", "0x16"]}}` - id := uint64(1) - handler.WithIDGen(func() uint64 { return id }) - got := sendWsMessage(t, ctx, conn, subMsg) - require.Equal(t, subResp(id), got) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) - hash1 := new(felt.Felt).SetUint64(1) - addr1 := new(felt.Felt).SetUint64(11) + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) - hash2 := new(felt.Felt).SetUint64(2) - addr2 := new(felt.Felt).SetUint64(22) + mockChain := mocks.NewMockReader(mockCtrl) + l1Feed := feed.New[*core.L1Head]() + mockChain.EXPECT().SubscribeL1Head().Return(blockchain.L1HeadSubscription{Subscription: l1Feed.Subscribe()}) - hash3 := new(felt.Felt).SetUint64(3) - hash4 := new(felt.Felt).SetUint64(4) - hash5 := new(felt.Felt).SetUint64(5) + syncer := newFakeSyncer() + handler, server := setupRPC(t, ctx, mockChain, syncer) - hash6 := new(felt.Felt).SetUint64(6) - addr6 := new(felt.Felt).SetUint64(66) + conn := createWsConn(t, ctx, server) - hash7 := new(felt.Felt).SetUint64(7) - addr7 := new(felt.Felt).SetUint64(77) + id := uint64(1) + handler.WithIDGen(func() uint64 { return id }) + got := sendWsMessage(t, ctx, conn, tt.subscribeMsg) + require.Equal(t, subResp(id), got) - syncer.pendingTxs.Send([]core.Transaction{ - &core.InvokeTransaction{TransactionHash: hash1, SenderAddress: addr1}, - &core.DeclareTransaction{TransactionHash: hash2, SenderAddress: addr2}, - &core.DeployTransaction{TransactionHash: hash3}, - &core.DeployAccountTransaction{DeployTransaction: core.DeployTransaction{TransactionHash: hash4}}, - &core.L1HandlerTransaction{TransactionHash: hash5}, - &core.InvokeTransaction{TransactionHash: hash6, SenderAddress: addr6}, - &core.DeclareTransaction{TransactionHash: hash7, SenderAddress: addr7}, + syncer.pendingTxs.Send(tt.expectedTxs) + _, pendingTxsGot, err := conn.Read(ctx) + require.NoError(t, err) + want := fmt.Sprintf(tt.want, id) + require.Equal(t, want, string(pendingTxsGot)) }) + } - want := `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":["0x1","0x2"],"subscription_id":%d}}` - want = fmt.Sprintf(want, id) - _, pendingTxsGot, err := conn.Read(ctx) - require.NoError(t, err) - require.Equal(t, want, string(pendingTxsGot)) - }) - - t.Run("Full details subscription", func(t *testing.T) { - conn := createWsConn(t, ctx, server) + t.Run("Return error if too many addresses in filter", func(t *testing.T) { + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) - subMsg := `{"jsonrpc":"2.0","id":1,"method":"starknet_subscribePendingTransactions", "params":{"transaction_details": true}}` - id := uint64(1) - handler.WithIDGen(func() uint64 { return id }) - got := sendWsMessage(t, ctx, conn, subMsg) - require.Equal(t, subResp(id), got) + mockCtrl := gomock.NewController(t) + t.Cleanup(mockCtrl.Finish) - syncer.pendingTxs.Send([]core.Transaction{ - &core.InvokeTransaction{ - TransactionHash: new(felt.Felt).SetUint64(1), - CallData: []*felt.Felt{new(felt.Felt).SetUint64(2)}, - TransactionSignature: []*felt.Felt{new(felt.Felt).SetUint64(3)}, - MaxFee: new(felt.Felt).SetUint64(4), - ContractAddress: new(felt.Felt).SetUint64(5), - Version: new(core.TransactionVersion).SetUint64(3), - EntryPointSelector: new(felt.Felt).SetUint64(6), - Nonce: new(felt.Felt).SetUint64(7), - SenderAddress: new(felt.Felt).SetUint64(8), - ResourceBounds: map[core.Resource]core.ResourceBounds{}, - Tip: 9, - PaymasterData: []*felt.Felt{new(felt.Felt).SetUint64(10)}, - AccountDeploymentData: []*felt.Felt{new(felt.Felt).SetUint64(11)}, - }, - }) + mockChain := mocks.NewMockReader(mockCtrl) + l1Feed := feed.New[*core.L1Head]() + mockChain.EXPECT().SubscribeL1Head().Return(blockchain.L1HeadSubscription{Subscription: l1Feed.Subscribe()}) - want := `{"jsonrpc":"2.0","method":"starknet_subscriptionPendingTransactions","params":{"result":[{"transaction_hash":"0x1","type":"INVOKE","version":"0x3","nonce":"0x7","max_fee":"0x4","contract_address":"0x5","sender_address":"0x8","signature":["0x3"],"calldata":["0x2"],"entry_point_selector":"0x6","resource_bounds":{},"tip":"0x9","paymaster_data":["0xa"],"account_deployment_data":["0xb"],"nonce_data_availability_mode":"L1","fee_data_availability_mode":"L1"}],"subscription_id":%d}}` - want = fmt.Sprintf(want, id) - _, pendingTxsGot, err := conn.Read(ctx) - require.NoError(t, err) - require.Equal(t, want, string(pendingTxsGot)) - }) + syncer := newFakeSyncer() + handler, _ := setupRPC(t, ctx, mockChain, syncer) - t.Run("Return error if too many addresses in filter", func(t *testing.T) { addresses := make([]felt.Felt, 1024+1) serverConn, _ := net.Pipe() diff --git a/rpc/trace_test.go b/rpc/trace_test.go index 190497ef1d..a13258d403 100644 --- a/rpc/trace_test.go +++ b/rpc/trace_test.go @@ -301,7 +301,7 @@ func TestTraceTransactionV0_6(t *testing.T) { hash := utils.HexToFelt(t, "0xBBBB") // Receipt() returns error related to db mockReader.EXPECT().Receipt(hash).Return(nil, nil, uint64(0), db.ErrKeyNotFound) - mockSyncReader.EXPECT().Pending().Return(nil, nil) + mockSyncReader.EXPECT().Pending().Return(&sync.Pending{Block: &core.Block{}}, nil) trace, httpHeader, err := handler.TraceTransactionV0_6(context.Background(), *hash) assert.Nil(t, trace) @@ -520,7 +520,7 @@ func TestTraceBlockTransactions(t *testing.T) { stepsUsedStr := "123" require.NoError(t, json.Unmarshal(vmTraceJSON, &vmTrace)) mockVM.EXPECT().Execute(block.Transactions, []core.Class{declaredClass.Class}, paidL1Fees, &vm.BlockInfo{Header: header}, - gomock.Any(), n, false, false, false, false). + gomock.Any(), n, false, false, false, true). Return(nil, []core.GasConsumed{{}, {}}, []vm.TransactionTrace{vmTrace, vmTrace}, stepsUsed, nil) result, httpHeader, err := handler.TraceBlockTransactions(context.Background(), rpc.BlockID{Hash: blockHash}) @@ -596,7 +596,7 @@ func TestTraceBlockTransactions(t *testing.T) { stepsUsed := uint64(123) stepsUsedStr := "123" mockVM.EXPECT().Execute([]core.Transaction{tx}, []core.Class{declaredClass.Class}, []*felt.Felt{}, &vm.BlockInfo{Header: header}, - gomock.Any(), n, false, false, false, false). + gomock.Any(), n, false, false, false, true). Return(nil, []core.GasConsumed{{}, {}}, []vm.TransactionTrace{vmTrace}, stepsUsed, nil) expectedResult := []rpc.TracedBlockTransaction{ From 50bf8e24ac878722d5803eb62d10f6c7793d7d47 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Sat, 25 Jan 2025 16:59:01 +0300 Subject: [PATCH 12/14] Fix linter: --- rpc/handlers.go | 4 ++-- rpc/subscriptions_test.go | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rpc/handlers.go b/rpc/handlers.go index 73ca0d630a..ea41ce41c6 100644 --- a/rpc/handlers.go +++ b/rpc/handlers.go @@ -415,7 +415,7 @@ func (h *Handler) Methods() ([]jsonrpc.Method, string) { //nolint: funlen }, "/v0_8" } -func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen, dupl +func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen return []jsonrpc.Method{ { Name: "starknet_chainId", @@ -584,7 +584,7 @@ func (h *Handler) MethodsV0_7() ([]jsonrpc.Method, string) { //nolint: funlen, d }, "/v0_7" } -func (h *Handler) MethodsV0_6() ([]jsonrpc.Method, string) { //nolint: funlen, dupl +func (h *Handler) MethodsV0_6() ([]jsonrpc.Method, string) { //nolint: funlen return []jsonrpc.Method{ { Name: "starknet_chainId", diff --git a/rpc/subscriptions_test.go b/rpc/subscriptions_test.go index 5def2f9f03..dcaa67760c 100644 --- a/rpc/subscriptions_test.go +++ b/rpc/subscriptions_test.go @@ -824,6 +824,7 @@ func TestSubscriptionReorg(t *testing.T) { } func TestSubscribePendingTxs(t *testing.T) { + t.Parallel() tests := []struct { name string subscribeMsg string From 08c4de0bc81f8f31831a2d62cd8d131e60de846c Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 31 Jan 2025 14:40:11 +0300 Subject: [PATCH 13/14] Fix linter --- rpc/simulation.go | 1 + 1 file changed, 1 insertion(+) diff --git a/rpc/simulation.go b/rpc/simulation.go index bbfb699832..c663b696c9 100644 --- a/rpc/simulation.go +++ b/rpc/simulation.go @@ -67,6 +67,7 @@ func (h *Handler) SimulateTransactionsV0_6(id BlockID, transactions []Broadcaste ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { return h.simulateTransactions(id, transactions, simulationFlags, false, V0_6) } + func (h *Handler) simulateTransactions(id BlockID, transactions []BroadcastedTransaction, simulationFlags []SimulationFlag, errOnRevert bool, rpcVersion version, ) ([]SimulatedTransaction, http.Header, *jsonrpc.Error) { From 621940561ef11aa51862d0c1def2c3f32b6f0722 Mon Sep 17 00:00:00 2001 From: AnkushinDaniil Date: Fri, 31 Jan 2025 15:37:58 +0300 Subject: [PATCH 14/14] Update tests --- go.mod | 2 +- rpc/transaction.go | 6 + rpc/transaction_test.go | 516 +++++++++++++++++++--------------------- 3 files changed, 246 insertions(+), 278 deletions(-) diff --git a/go.mod b/go.mod index 47813b328e..8550702f92 100644 --- a/go.mod +++ b/go.mod @@ -33,6 +33,7 @@ require ( go.uber.org/mock v0.5.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.32.0 + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 google.golang.org/grpc v1.70.0 google.golang.org/protobuf v1.36.4 gopkg.in/yaml.v3 v3.0.1 @@ -188,7 +189,6 @@ require ( go.uber.org/dig v1.18.0 // indirect go.uber.org/fx v1.23.0 // indirect go.uber.org/multierr v1.11.0 // indirect - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.34.0 // indirect golang.org/x/sync v0.10.0 // indirect diff --git a/rpc/transaction.go b/rpc/transaction.go index a49736a0df..9aab2d4420 100644 --- a/rpc/transaction.go +++ b/rpc/transaction.go @@ -277,6 +277,12 @@ type ExecutionResources struct { func (r ExecutionResources) MarshalJSON() ([]byte, error) { //nolint:gocritic switch r.rpcVersion { + case V0_6: + return json.Marshal(struct { + ComputationResources + }{ + ComputationResources: r.ComputationResources, + }) case V0_7: return json.Marshal(struct { ComputationResources diff --git a/rpc/transaction_test.go b/rpc/transaction_test.go index 432c3e2231..5970f46605 100644 --- a/rpc/transaction_test.go +++ b/rpc/transaction_test.go @@ -4,7 +4,7 @@ import ( "context" "encoding/json" "errors" - "math/rand" + "fmt" "testing" "github.com/NethermindEth/juno/clients/feeder" @@ -21,6 +21,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/mock/gomock" + "golang.org/x/exp/rand" ) func TestTransactionByHashNotFound(t *testing.T) { @@ -518,267 +519,6 @@ func TestTransactionByBlockIdAndIndex(t *testing.T) { }) } -//nolint:dupl -func TestTransactionReceiptByHashV0_6(t *testing.T) { - mockCtrl := gomock.NewController(t) - t.Cleanup(mockCtrl.Finish) - - n := utils.Ptr(utils.Mainnet) - mockReader := mocks.NewMockReader(mockCtrl) - handler := rpc.New(mockReader, 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.TransactionReceiptByHashV0_6(*txHash) - assert.Nil(t, tx) - assert.Equal(t, rpc.ErrTxnHashNotFound, rpcErr) - }) - - client := feeder.NewTestClient(t, n) - 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.TransactionReceiptByHashV0_6(*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 - }{ - "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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":{"l1_data_gas":0, "l1_gas":0, "l2_gas":0, "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": { - "l1_data_gas": 0, - "l1_gas": 0, - "l2_gas": 0, - "steps": 615, - "range_check_builtin_applications": 19, - "memory_holes": 4 - }, - "actual_fee": { - "amount": "0x16d8b4ad4000", - "unit": "FRI" - }, - "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 TestTransactionReceiptByHash(t *testing.T) { t.Run("transaction not found", func(t *testing.T) { @@ -808,7 +548,34 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion string }{ { - name: "with contract addr 0.7", + name: "with contract addr", + network: &utils.Mainnet, + blockNumber: 0, + 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} + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "with contract addr", network: &utils.Mainnet, blockNumber: 0, index: 0, @@ -841,7 +608,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "with contract addr 0.8", + name: "with contract addr", network: &utils.Mainnet, blockNumber: 0, index: 0, @@ -873,7 +640,42 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "without contract addr 0.7", + name: "without contract addr", + network: &utils.Mainnet, + blockNumber: 0, + 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} + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "without contract addr", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -914,7 +716,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "without contract addr 0.8", + name: "without contract addr", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -953,7 +755,39 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "pending receipt 0.7", + name: "pending receipt", + network: &utils.Mainnet, + blockNumber: 0, + index: 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} + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], nil, uint64(0), nil) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "pending receipt", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -991,7 +825,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "pending receipt 0.8", + name: "pending receipt", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -1027,7 +861,46 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "accepted on l1 receipt 0.7", + name: "accepted on l1 receipt", + network: &utils.Mainnet, + blockNumber: 0, + index: 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} + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(&core.L1Head{ + BlockNumber: block.Number, + BlockHash: block.Hash, + StateRoot: block.GlobalStateRoot, + }, nil) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "accepted on l1 receipt", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -1072,7 +945,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "accepted on l1 receipt 0.8", + name: "accepted on l1 receipt", network: &utils.Mainnet, blockNumber: 0, index: 2, @@ -1115,7 +988,34 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "reverted 0.7", + name: "reverted", + network: &utils.Integration, + blockNumber: 304740, + index: 1, + 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} + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "reverted", network: &utils.Integration, blockNumber: 304740, index: 1, @@ -1155,7 +1055,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "reverted 0.8", + name: "reverted", network: &utils.Integration, blockNumber: 304740, index: 1, @@ -1193,7 +1093,67 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "v3 tx 0.7", + name: "v3 tx", + network: &utils.Integration, + blockNumber: 319132, + index: 0, + 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": "FRI" + }, + "type": "INVOKE" + }`, + mockBehavior: func(mockReader *mocks.MockReader, index int, block *core.Block) *felt.Felt { + txHash := block.Transactions[index].Hash() + mockReader.EXPECT().TransactionByHash(txHash).Return(block.Transactions[index], nil) + mockReader.EXPECT().Receipt(txHash).Return(block.Receipts[index], + block.Hash, block.Number, nil) + mockReader.EXPECT().L1Head().Return(nil, db.ErrKeyNotFound) + return txHash + }, + rpcVersion: "0.6", + }, + { + name: "v3 tx", network: &utils.Integration, blockNumber: 319132, index: 0, @@ -1257,7 +1217,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "v3 tx 0.8", + name: "v3 tx", network: &utils.Integration, blockNumber: 319132, index: 0, @@ -1317,7 +1277,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.8", }, { - name: "tx with non empty data_availability 0.7", + name: "tx with non empty data_availability", network: &utils.SepoliaIntegration, blockNumber: 35748, index: 0, @@ -1370,7 +1330,7 @@ func TestTransactionReceiptByHash(t *testing.T) { rpcVersion: "0.7", }, { - name: "tx with non empty data_availability 0.8", + name: "tx with non empty data_availability", network: &utils.SepoliaIntegration, blockNumber: 35748, index: 0, @@ -1419,7 +1379,7 @@ func TestTransactionReceiptByHash(t *testing.T) { } for _, test := range tests { - t.Run(test.name, func(t *testing.T) { + t.Run(fmt.Sprintf("%s %s", test.name, test.rpcVersion), func(t *testing.T) { mockCtrl := gomock.NewController(t) t.Cleanup(mockCtrl.Finish) @@ -1440,6 +1400,8 @@ func TestTransactionReceiptByHash(t *testing.T) { var receipt *rpc.TransactionReceipt var rErr *jsonrpc.Error switch test.rpcVersion { + case "0.6": + receipt, rErr = handler.TransactionReceiptByHashV0_6(*txHash) case "0.7": receipt, rErr = handler.TransactionReceiptByHashV0_7(*txHash) case "0.8":