github.com/ava-labs/subnet-evm@v0.6.4/internal/ethapi/api_test.go (about)

     1  // (c) 2023, Ava Labs, Inc.
     2  //
     3  // This file is a derived work, based on the go-ethereum library whose original
     4  // notices appear below.
     5  //
     6  // It is distributed under a license compatible with the licensing terms of the
     7  // original code from which it is derived.
     8  //
     9  // Much love to the original authors for their work.
    10  // **********
    11  // Copyright 2023 The go-ethereum Authors
    12  // This file is part of the go-ethereum library.
    13  //
    14  // The go-ethereum library is free software: you can redistribute it and/or modify
    15  // it under the terms of the GNU Lesser General Public License as published by
    16  // the Free Software Foundation, either version 3 of the License, or
    17  // (at your option) any later version.
    18  //
    19  // The go-ethereum library is distributed in the hope that it will be useful,
    20  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    21  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    22  // GNU Lesser General Public License for more details.
    23  //
    24  // You should have received a copy of the GNU Lesser General Public License
    25  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    26  
    27  package ethapi
    28  
    29  import (
    30  	"context"
    31  	"crypto/ecdsa"
    32  	"encoding/json"
    33  	"errors"
    34  	"fmt"
    35  	"math/big"
    36  	"os"
    37  	"path/filepath"
    38  	"reflect"
    39  	"testing"
    40  	"time"
    41  
    42  	"github.com/ava-labs/subnet-evm/accounts"
    43  	"github.com/ava-labs/subnet-evm/commontype"
    44  	"github.com/ava-labs/subnet-evm/consensus"
    45  	"github.com/ava-labs/subnet-evm/consensus/dummy"
    46  	"github.com/ava-labs/subnet-evm/core"
    47  	"github.com/ava-labs/subnet-evm/core/bloombits"
    48  	"github.com/ava-labs/subnet-evm/core/rawdb"
    49  	"github.com/ava-labs/subnet-evm/core/state"
    50  	"github.com/ava-labs/subnet-evm/core/types"
    51  	"github.com/ava-labs/subnet-evm/core/vm"
    52  	"github.com/ava-labs/subnet-evm/internal/blocktest"
    53  	"github.com/ava-labs/subnet-evm/params"
    54  	"github.com/ava-labs/subnet-evm/rpc"
    55  	"github.com/ethereum/go-ethereum/common"
    56  	"github.com/ethereum/go-ethereum/common/hexutil"
    57  	"github.com/ethereum/go-ethereum/crypto"
    58  	"github.com/ethereum/go-ethereum/ethdb"
    59  	"github.com/ethereum/go-ethereum/event"
    60  	"github.com/holiman/uint256"
    61  	"github.com/stretchr/testify/require"
    62  	"golang.org/x/exp/slices"
    63  )
    64  
    65  func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) {
    66  	t.Parallel()
    67  	var (
    68  		signer = types.LatestSigner(config)
    69  		key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    70  	)
    71  
    72  	for i, tt := range tests {
    73  		var tx2 types.Transaction
    74  		tx, err := types.SignNewTx(key, signer, tt.Tx)
    75  		if err != nil {
    76  			t.Fatalf("test %d: signing failed: %v", i, err)
    77  		}
    78  		// Regular transaction
    79  		if data, err := json.Marshal(tx); err != nil {
    80  			t.Fatalf("test %d: marshalling failed; %v", i, err)
    81  		} else if err = tx2.UnmarshalJSON(data); err != nil {
    82  			t.Fatalf("test %d: sunmarshal failed: %v", i, err)
    83  		} else if want, have := tx.Hash(), tx2.Hash(); want != have {
    84  			t.Fatalf("test %d: stx changed, want %x have %x", i, want, have)
    85  		}
    86  
    87  		// rpcTransaction
    88  		rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
    89  		if data, err := json.Marshal(rpcTx); err != nil {
    90  			t.Fatalf("test %d: marshalling failed; %v", i, err)
    91  		} else if err = tx2.UnmarshalJSON(data); err != nil {
    92  			t.Fatalf("test %d: unmarshal failed: %v", i, err)
    93  		} else if want, have := tx.Hash(), tx2.Hash(); want != have {
    94  			t.Fatalf("test %d: tx changed, want %x have %x", i, want, have)
    95  		} else {
    96  			want, have := tt.Want, string(data)
    97  			require.JSONEqf(t, want, have, "test %d: rpc json not match, want %s have %s", i, want, have)
    98  		}
    99  	}
   100  }
   101  
   102  func TestTransaction_RoundTripRpcJSON(t *testing.T) {
   103  	var (
   104  		config = params.TestChainConfig
   105  		tests  = allTransactionTypes(common.Address{0xde, 0xad}, config)
   106  	)
   107  	testTransactionMarshal(t, tests, config)
   108  }
   109  
   110  func TestTransactionBlobTx(t *testing.T) {
   111  	config := *params.TestChainConfig
   112  	// config.ShanghaiTime = new(uint64)
   113  	config.CancunTime = new(uint64)
   114  	tests := allBlobTxs(common.Address{0xde, 0xad}, &config)
   115  
   116  	testTransactionMarshal(t, tests, &config)
   117  }
   118  
   119  type txData struct {
   120  	Tx   types.TxData
   121  	Want string
   122  }
   123  
   124  func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txData {
   125  	return []txData{
   126  		{
   127  			Tx: &types.LegacyTx{
   128  				Nonce:    5,
   129  				GasPrice: big.NewInt(6),
   130  				Gas:      7,
   131  				To:       &addr,
   132  				Value:    big.NewInt(8),
   133  				Data:     []byte{0, 1, 2, 3, 4},
   134  				V:        big.NewInt(9),
   135  				R:        big.NewInt(10),
   136  				S:        big.NewInt(11),
   137  			},
   138  			Want: `{
   139  				"blockHash": null,
   140  				"blockNumber": null,
   141  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   142  				"gas": "0x7",
   143  				"gasPrice": "0x6",
   144  				"hash": "0x3fa586d2448ae279279fa7036da74eb932763661543428c1a0aba21b95b37bdb",
   145  				"input": "0x0001020304",
   146  				"nonce": "0x5",
   147  				"to": "0xdead000000000000000000000000000000000000",
   148  				"transactionIndex": null,
   149  				"value": "0x8",
   150  				"type": "0x0",
   151  				"chainId": "0x1",
   152  				"v": "0x25",
   153  				"r": "0xac639f4319e9268898e29444b97101f1225e2a0837151626da23e73dda2443fc",
   154  				"s": "0x4fcc3f4c3a75f70ee45bb42d4b0aad432cc8c0140efb3e2611d6a6dda8460907"
   155  			}`,
   156  		}, {
   157  			Tx: &types.LegacyTx{
   158  				Nonce:    5,
   159  				GasPrice: big.NewInt(6),
   160  				Gas:      7,
   161  				To:       nil,
   162  				Value:    big.NewInt(8),
   163  				Data:     []byte{0, 1, 2, 3, 4},
   164  				V:        big.NewInt(32),
   165  				R:        big.NewInt(10),
   166  				S:        big.NewInt(11),
   167  			},
   168  			Want: `{
   169  				"blockHash": null,
   170  				"blockNumber": null,
   171  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   172  				"gas": "0x7",
   173  				"gasPrice": "0x6",
   174  				"hash": "0x617a316c6ff7ed2aa6ead1b4bb28a1322c2156c1c72f376a976d2d2adb1748ee",
   175  				"input": "0x0001020304",
   176  				"nonce": "0x5",
   177  				"to": null,
   178  				"transactionIndex": null,
   179  				"value": "0x8",
   180  				"type": "0x0",
   181  				"chainId": "0x1",
   182  				"v": "0x25",
   183  				"r": "0xee8e89b513778d4815ae5969f3d55e0f7590f31b08f2a2290d5bc4ae37fce299",
   184  				"s": "0x663db5c74c10e2b6525e7026e7cfd569b819ec91a042322655ff2b35060784b1"
   185  			}`,
   186  		},
   187  		{
   188  			Tx: &types.AccessListTx{
   189  				ChainID:  config.ChainID,
   190  				Nonce:    5,
   191  				GasPrice: big.NewInt(6),
   192  				Gas:      7,
   193  				To:       &addr,
   194  				Value:    big.NewInt(8),
   195  				Data:     []byte{0, 1, 2, 3, 4},
   196  				AccessList: types.AccessList{
   197  					types.AccessTuple{
   198  						Address:     common.Address{0x2},
   199  						StorageKeys: []common.Hash{types.EmptyRootHash},
   200  					},
   201  				},
   202  				V: big.NewInt(32),
   203  				R: big.NewInt(10),
   204  				S: big.NewInt(11),
   205  			},
   206  			Want: `{
   207  				"blockHash": null,
   208  				"blockNumber": null,
   209  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   210  				"gas": "0x7",
   211  				"gasPrice": "0x6",
   212  				"hash": "0x6becb7b9c171aa0d6d0a90dcd97bc3529c4d521f9cc9b7e31616aa9afc178c10",
   213  				"input": "0x0001020304",
   214  				"nonce": "0x5",
   215  				"to": "0xdead000000000000000000000000000000000000",
   216  				"transactionIndex": null,
   217  				"value": "0x8",
   218  				"type": "0x1",
   219  				"accessList": [
   220  					{
   221  						"address": "0x0200000000000000000000000000000000000000",
   222  						"storageKeys": [
   223  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   224  						]
   225  					}
   226  				],
   227  				"chainId": "0x1",
   228  				"v": "0x1",
   229  				"r": "0xea2289ca0243beecbe69d337bbc53c618e1fb6bd2ec69fd4121df47149a4d4be",
   230  				"s": "0x2dc134b6bc43abbdfebef0b2d62c175459fc1e8ddff60c8e740c461d7ea1522f",
   231  				"yParity": "0x1"
   232  			}`,
   233  		}, {
   234  			Tx: &types.AccessListTx{
   235  				ChainID:  config.ChainID,
   236  				Nonce:    5,
   237  				GasPrice: big.NewInt(6),
   238  				Gas:      7,
   239  				To:       nil,
   240  				Value:    big.NewInt(8),
   241  				Data:     []byte{0, 1, 2, 3, 4},
   242  				AccessList: types.AccessList{
   243  					types.AccessTuple{
   244  						Address:     common.Address{0x2},
   245  						StorageKeys: []common.Hash{types.EmptyRootHash},
   246  					},
   247  				},
   248  				V: big.NewInt(32),
   249  				R: big.NewInt(10),
   250  				S: big.NewInt(11),
   251  			},
   252  			Want: `{
   253  				"blockHash": null,
   254  				"blockNumber": null,
   255  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   256  				"gas": "0x7",
   257  				"gasPrice": "0x6",
   258  				"hash": "0x22fbf81bae4640511c706e2c72d2f2ef1abc1e7861f2b82c4cae5b102a40709c",
   259  				"input": "0x0001020304",
   260  				"nonce": "0x5",
   261  				"to": null,
   262  				"transactionIndex": null,
   263  				"value": "0x8",
   264  				"type": "0x1",
   265  				"accessList": [
   266  					{
   267  						"address": "0x0200000000000000000000000000000000000000",
   268  						"storageKeys": [
   269  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   270  						]
   271  					}
   272  				],
   273  				"chainId": "0x1",
   274  				"v": "0x1",
   275  				"r": "0xc50e18edd861639735ec69ca12d82fcbb2c1921d2e2a8fd3a75f408d2d4b8118",
   276  				"s": "0x32a908d1bc2db0229354f4dd392ffc37934e24ae8b18a620c6588c72660b6238",
   277  				"yParity": "0x1"
   278  			}`,
   279  		}, {
   280  			Tx: &types.DynamicFeeTx{
   281  				ChainID:   config.ChainID,
   282  				Nonce:     5,
   283  				GasTipCap: big.NewInt(6),
   284  				GasFeeCap: big.NewInt(9),
   285  				Gas:       7,
   286  				To:        &addr,
   287  				Value:     big.NewInt(8),
   288  				Data:      []byte{0, 1, 2, 3, 4},
   289  				AccessList: types.AccessList{
   290  					types.AccessTuple{
   291  						Address:     common.Address{0x2},
   292  						StorageKeys: []common.Hash{types.EmptyRootHash},
   293  					},
   294  				},
   295  				V: big.NewInt(32),
   296  				R: big.NewInt(10),
   297  				S: big.NewInt(11),
   298  			},
   299  			Want: `{
   300  				"blockHash": null,
   301  				"blockNumber": null,
   302  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   303  				"gas": "0x7",
   304  				"gasPrice": "0x9",
   305  				"maxFeePerGas": "0x9",
   306  				"maxPriorityFeePerGas": "0x6",
   307  				"hash": "0xc5763d2ce6af3f694dcda8a9a50d4f75005a711edd382e993dd0406e0c54cfde",
   308  				"input": "0x0001020304",
   309  				"nonce": "0x5",
   310  				"to": "0xdead000000000000000000000000000000000000",
   311  				"transactionIndex": null,
   312  				"value": "0x8",
   313  				"type": "0x2",
   314  				"accessList": [
   315  					{
   316  						"address": "0x0200000000000000000000000000000000000000",
   317  						"storageKeys": [
   318  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   319  						]
   320  					}
   321  				],
   322  				"chainId": "0x1",
   323  				"v": "0x0",
   324  				"r": "0x740eb1e3bc206760182993845b7815fd8cf7a42f1a1ed26027f736e9eccfd20f",
   325  				"s": "0x31da567e2b3a83e58e42f7902c3706926c926625f6978c24fdaa21b9d143bbf7",
   326  				"yParity": "0x0"
   327  			}`,
   328  		}, {
   329  			Tx: &types.DynamicFeeTx{
   330  				ChainID:    config.ChainID,
   331  				Nonce:      5,
   332  				GasTipCap:  big.NewInt(6),
   333  				GasFeeCap:  big.NewInt(9),
   334  				Gas:        7,
   335  				To:         nil,
   336  				Value:      big.NewInt(8),
   337  				Data:       []byte{0, 1, 2, 3, 4},
   338  				AccessList: types.AccessList{},
   339  				V:          big.NewInt(32),
   340  				R:          big.NewInt(10),
   341  				S:          big.NewInt(11),
   342  			},
   343  			Want: `{
   344  				"blockHash": null,
   345  				"blockNumber": null,
   346  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   347  				"gas": "0x7",
   348  				"gasPrice": "0x9",
   349  				"maxFeePerGas": "0x9",
   350  				"maxPriorityFeePerGas": "0x6",
   351  				"hash": "0x85545f69b2410640fbbb7157b9a79adece45bac4b2803733d250d049e9501a28",
   352  				"input": "0x0001020304",
   353  				"nonce": "0x5",
   354  				"to": null,
   355  				"transactionIndex": null,
   356  				"value": "0x8",
   357  				"type": "0x2",
   358  				"accessList": [],
   359  				"chainId": "0x1",
   360  				"v": "0x1",
   361  				"r": "0x5004538adbe499313737033b22eb2b50a9450f02fab3971a591e6d57761b2cdf",
   362  				"s": "0x5f7b1f5d11bd467d84f32beb2e89629351b96c5204c4f72d5d2040bee369a73a",
   363  				"yParity": "0x1"
   364  			  }`,
   365  		},
   366  	}
   367  }
   368  
   369  func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData {
   370  	return []txData{
   371  		{
   372  			Tx: &types.BlobTx{
   373  				Nonce:      6,
   374  				GasTipCap:  uint256.NewInt(1),
   375  				GasFeeCap:  uint256.NewInt(5),
   376  				Gas:        6,
   377  				To:         addr,
   378  				BlobFeeCap: uint256.NewInt(1),
   379  				BlobHashes: []common.Hash{{1}},
   380  				Value:      new(uint256.Int),
   381  				V:          uint256.NewInt(32),
   382  				R:          uint256.NewInt(10),
   383  				S:          uint256.NewInt(11),
   384  			},
   385  			Want: `{
   386                  "blockHash": null,
   387                  "blockNumber": null,
   388                  "from": "0x71562b71999873db5b286df957af199ec94617f7",
   389                  "gas": "0x6",
   390                  "gasPrice": "0x5",
   391                  "maxFeePerGas": "0x5",
   392                  "maxPriorityFeePerGas": "0x1",
   393                  "maxFeePerBlobGas": "0x1",
   394                  "hash": "0x1f2b59a20e61efc615ad0cbe936379d6bbea6f938aafaf35eb1da05d8e7f46a3",
   395                  "input": "0x",
   396                  "nonce": "0x6",
   397                  "to": "0xdead000000000000000000000000000000000000",
   398                  "transactionIndex": null,
   399                  "value": "0x0",
   400                  "type": "0x3",
   401                  "accessList": [],
   402                  "chainId": "0x1",
   403                  "blobVersionedHashes": [
   404                      "0x0100000000000000000000000000000000000000000000000000000000000000"
   405                  ],
   406                  "v": "0x0",
   407                  "r": "0x618be8908e0e5320f8f3b48042a079fe5a335ebd4ed1422a7d2207cd45d872bc",
   408                  "s": "0x27b2bc6c80e849a8e8b764d4549d8c2efac3441e73cf37054eb0a9b9f8e89b27",
   409                  "yParity": "0x0"
   410              }`,
   411  		},
   412  	}
   413  }
   414  
   415  type testBackend struct {
   416  	db    ethdb.Database
   417  	chain *core.BlockChain
   418  }
   419  
   420  func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
   421  	var (
   422  		cacheConfig = &core.CacheConfig{
   423  			TrieCleanLimit: 256,
   424  			TrieDirtyLimit: 256,
   425  			SnapshotLimit:  0,
   426  			Pruning:        false, // Archive mode
   427  		}
   428  	)
   429  	// Generate blocks for testing
   430  	db, blocks, _, _ := core.GenerateChainWithGenesis(gspec, engine, n, 10, generator)
   431  	chain, err := core.NewBlockChain(db, cacheConfig, gspec, engine, vm.Config{}, gspec.ToBlock().Hash(), false)
   432  	if err != nil {
   433  		t.Fatalf("failed to create tester chain: %v", err)
   434  	}
   435  	if n, err := chain.InsertChain(blocks); err != nil {
   436  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
   437  	}
   438  	for _, block := range blocks {
   439  		if err := chain.Accept(block); err != nil {
   440  			t.Fatalf("block %d: failed to accept into chain: %v", block.NumberU64(), err)
   441  		}
   442  	}
   443  	chain.DrainAcceptorQueue()
   444  
   445  	backend := &testBackend{db: db, chain: chain}
   446  	return backend
   447  }
   448  
   449  func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
   450  	return big.NewInt(0), nil
   451  }
   452  func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
   453  	return nil, nil, nil, nil, nil
   454  }
   455  func (b testBackend) ChainDb() ethdb.Database                    { return b.db }
   456  func (b testBackend) AccountManager() *accounts.Manager          { return nil }
   457  func (b testBackend) ExtRPCEnabled() bool                        { return false }
   458  func (b testBackend) RPCGasCap() uint64                          { return 10000000 }
   459  func (b testBackend) RPCEVMTimeout() time.Duration               { return time.Second }
   460  func (b testBackend) RPCTxFeeCap() float64                       { return 0 }
   461  func (b testBackend) UnprotectedAllowed(*types.Transaction) bool { return false }
   462  func (b testBackend) SetHead(number uint64)                      {}
   463  func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
   464  	if number == rpc.LatestBlockNumber {
   465  		return b.chain.CurrentBlock(), nil
   466  	}
   467  	return b.chain.GetHeaderByNumber(uint64(number)), nil
   468  }
   469  func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   470  	return b.chain.GetHeaderByHash(hash), nil
   471  }
   472  func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
   473  	if blockNr, ok := blockNrOrHash.Number(); ok {
   474  		return b.HeaderByNumber(ctx, blockNr)
   475  	}
   476  	if blockHash, ok := blockNrOrHash.Hash(); ok {
   477  		return b.HeaderByHash(ctx, blockHash)
   478  	}
   479  	panic("unknown type rpc.BlockNumberOrHash")
   480  }
   481  func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentBlock() }
   482  func (b testBackend) CurrentBlock() *types.Header  { return b.chain.CurrentBlock() }
   483  func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   484  	if number == rpc.LatestBlockNumber {
   485  		head := b.chain.CurrentBlock()
   486  		return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil
   487  	}
   488  	return b.chain.GetBlockByNumber(uint64(number)), nil
   489  }
   490  func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   491  	return b.chain.GetBlockByHash(hash), nil
   492  }
   493  func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
   494  	if blockNr, ok := blockNrOrHash.Number(); ok {
   495  		return b.BlockByNumber(ctx, blockNr)
   496  	}
   497  	if blockHash, ok := blockNrOrHash.Hash(); ok {
   498  		return b.BlockByHash(ctx, blockHash)
   499  	}
   500  	panic("unknown type rpc.BlockNumberOrHash")
   501  }
   502  func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
   503  	return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil
   504  }
   505  func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
   506  	if number == rpc.PendingBlockNumber {
   507  		panic("pending state not implemented")
   508  	}
   509  	header, err := b.HeaderByNumber(ctx, number)
   510  	if err != nil {
   511  		return nil, nil, err
   512  	}
   513  	if header == nil {
   514  		return nil, nil, errors.New("header not found")
   515  	}
   516  	stateDb, err := b.chain.StateAt(header.Root)
   517  	return stateDb, header, err
   518  }
   519  func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
   520  	if blockNr, ok := blockNrOrHash.Number(); ok {
   521  		return b.StateAndHeaderByNumber(ctx, blockNr)
   522  	}
   523  	panic("only implemented for number")
   524  }
   525  func (b testBackend) PendingBlockAndReceipts() (*types.Block, types.Receipts) { panic("implement me") }
   526  func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
   527  	header, err := b.HeaderByHash(ctx, hash)
   528  	if header == nil || err != nil {
   529  		return nil, err
   530  	}
   531  	receipts := rawdb.ReadReceipts(b.db, hash, header.Number.Uint64(), header.Time, b.chain.Config())
   532  	return receipts, nil
   533  }
   534  func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) (*vm.EVM, func() error) {
   535  	vmError := func() error { return nil }
   536  	if vmConfig == nil {
   537  		vmConfig = b.chain.GetVMConfig()
   538  	}
   539  	txContext := core.NewEVMTxContext(msg)
   540  	context := core.NewEVMBlockContext(header, b.chain, nil)
   541  	if blockContext != nil {
   542  		context = *blockContext
   543  	}
   544  	return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig), vmError
   545  }
   546  func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   547  	panic("implement me")
   548  }
   549  func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
   550  	panic("implement me")
   551  }
   552  func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
   553  	panic("implement me")
   554  }
   555  func (b testBackend) GetFeeConfigAt(parent *types.Header) (commontype.FeeConfig, *big.Int, error) {
   556  	panic("implement me")
   557  }
   558  func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
   559  	panic("implement me")
   560  }
   561  func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (*types.Transaction, common.Hash, uint64, uint64, error) {
   562  	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash)
   563  	return tx, blockHash, blockNumber, index, nil
   564  }
   565  func (b testBackend) GetPoolTransactions() (types.Transactions, error)         { panic("implement me") }
   566  func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") }
   567  func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
   568  	panic("implement me")
   569  }
   570  func (b testBackend) Stats() (pending int, queued int) { panic("implement me") }
   571  func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
   572  	panic("implement me")
   573  }
   574  func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
   575  	panic("implement me")
   576  }
   577  func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
   578  	panic("implement me")
   579  }
   580  func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
   581  func (b testBackend) Engine() consensus.Engine         { return b.chain.Engine() }
   582  func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
   583  	panic("implement me")
   584  }
   585  func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   586  	panic("implement me")
   587  }
   588  func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   589  	panic("implement me")
   590  }
   591  func (b testBackend) SubscribePendingLogsEvent(ch chan<- []*types.Log) event.Subscription {
   592  	panic("implement me")
   593  }
   594  func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") }
   595  func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
   596  	panic("implement me")
   597  }
   598  func (b testBackend) BadBlocks() ([]*types.Block, []*core.BadBlockReason) { return nil, nil }
   599  func (b testBackend) EstimateBaseFee(ctx context.Context) (*big.Int, error) {
   600  	panic("implement me")
   601  }
   602  func (b testBackend) LastAcceptedBlock() *types.Block { panic("implement me") }
   603  func (b testBackend) SuggestPrice(ctx context.Context) (*big.Int, error) {
   604  	panic("implement me")
   605  }
   606  
   607  func TestEstimateGas(t *testing.T) {
   608  	t.Parallel()
   609  	// Initialize test accounts
   610  	var (
   611  		accounts = newAccounts(2)
   612  		genesis  = &core.Genesis{
   613  			Config: params.TestChainConfig,
   614  			Alloc: core.GenesisAlloc{
   615  				accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   616  				accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   617  			},
   618  		}
   619  		genBlocks      = 10
   620  		signer         = types.HomesteadSigner{}
   621  		randomAccounts = newAccounts(2)
   622  	)
   623  	api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) {
   624  		// Transfer from account[0] to account[1]
   625  		//    value: 1000 wei
   626  		//    fee:   0 wei
   627  		tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key)
   628  		b.AddTx(tx)
   629  	}))
   630  	var testSuite = []struct {
   631  		blockNumber rpc.BlockNumber
   632  		call        TransactionArgs
   633  		overrides   StateOverride
   634  		expectErr   error
   635  		want        uint64
   636  	}{
   637  		// simple transfer on latest block
   638  		{
   639  			blockNumber: rpc.LatestBlockNumber,
   640  			call: TransactionArgs{
   641  				From:  &accounts[0].addr,
   642  				To:    &accounts[1].addr,
   643  				Value: (*hexutil.Big)(big.NewInt(1000)),
   644  			},
   645  			expectErr: nil,
   646  			want:      21000,
   647  		},
   648  		// simple transfer with insufficient funds on latest block
   649  		{
   650  			blockNumber: rpc.LatestBlockNumber,
   651  			call: TransactionArgs{
   652  				From:  &randomAccounts[0].addr,
   653  				To:    &accounts[1].addr,
   654  				Value: (*hexutil.Big)(big.NewInt(1000)),
   655  			},
   656  			expectErr: core.ErrInsufficientFunds,
   657  			want:      21000,
   658  		},
   659  		// empty create
   660  		{
   661  			blockNumber: rpc.LatestBlockNumber,
   662  			call:        TransactionArgs{},
   663  			expectErr:   nil,
   664  			want:        53000,
   665  		},
   666  		{
   667  			blockNumber: rpc.LatestBlockNumber,
   668  			call:        TransactionArgs{},
   669  			overrides: StateOverride{
   670  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
   671  			},
   672  			expectErr: nil,
   673  			want:      53000,
   674  		},
   675  		{
   676  			blockNumber: rpc.LatestBlockNumber,
   677  			call: TransactionArgs{
   678  				From:  &randomAccounts[0].addr,
   679  				To:    &randomAccounts[1].addr,
   680  				Value: (*hexutil.Big)(big.NewInt(1000)),
   681  			},
   682  			overrides: StateOverride{
   683  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
   684  			},
   685  			expectErr: core.ErrInsufficientFunds,
   686  		},
   687  	}
   688  	for i, tc := range testSuite {
   689  		result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
   690  		if tc.expectErr != nil {
   691  			if err == nil {
   692  				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
   693  				continue
   694  			}
   695  			if !errors.Is(err, tc.expectErr) {
   696  				t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
   697  			}
   698  			continue
   699  		}
   700  		if err != nil {
   701  			t.Errorf("test %d: want no error, have %v", i, err)
   702  			continue
   703  		}
   704  		if uint64(result) != tc.want {
   705  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want)
   706  		}
   707  	}
   708  }
   709  
   710  func TestCall(t *testing.T) {
   711  	t.Parallel()
   712  	// Initialize test accounts
   713  	var (
   714  		accounts = newAccounts(3)
   715  		genesis  = &core.Genesis{
   716  			Config: params.TestChainConfig,
   717  			Alloc: core.GenesisAlloc{
   718  				accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   719  				accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   720  				accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   721  			},
   722  		}
   723  		genBlocks = 10
   724  		signer    = types.HomesteadSigner{}
   725  	)
   726  	api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) {
   727  		// Transfer from account[0] to account[1]
   728  		//    value: 1000 wei
   729  		//    fee:   0 wei
   730  		tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &accounts[1].addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, accounts[0].key)
   731  		b.AddTx(tx)
   732  	}))
   733  	randomAccounts := newAccounts(3)
   734  	var testSuite = []struct {
   735  		blockNumber    rpc.BlockNumber
   736  		overrides      StateOverride
   737  		call           TransactionArgs
   738  		blockOverrides BlockOverrides
   739  		expectErr      error
   740  		want           string
   741  	}{
   742  		// transfer on genesis
   743  		{
   744  			blockNumber: rpc.BlockNumber(0),
   745  			call: TransactionArgs{
   746  				From:  &accounts[0].addr,
   747  				To:    &accounts[1].addr,
   748  				Value: (*hexutil.Big)(big.NewInt(1000)),
   749  			},
   750  			expectErr: nil,
   751  			want:      "0x",
   752  		},
   753  		// transfer on the head
   754  		{
   755  			blockNumber: rpc.BlockNumber(genBlocks),
   756  			call: TransactionArgs{
   757  				From:  &accounts[0].addr,
   758  				To:    &accounts[1].addr,
   759  				Value: (*hexutil.Big)(big.NewInt(1000)),
   760  			},
   761  			expectErr: nil,
   762  			want:      "0x",
   763  		},
   764  		// transfer on a non-existent block, error expects
   765  		{
   766  			blockNumber: rpc.BlockNumber(genBlocks + 1),
   767  			call: TransactionArgs{
   768  				From:  &accounts[0].addr,
   769  				To:    &accounts[1].addr,
   770  				Value: (*hexutil.Big)(big.NewInt(1000)),
   771  			},
   772  			expectErr: errors.New("header not found"),
   773  		},
   774  		// transfer on the latest block
   775  		{
   776  			blockNumber: rpc.LatestBlockNumber,
   777  			call: TransactionArgs{
   778  				From:  &accounts[0].addr,
   779  				To:    &accounts[1].addr,
   780  				Value: (*hexutil.Big)(big.NewInt(1000)),
   781  			},
   782  			expectErr: nil,
   783  			want:      "0x",
   784  		},
   785  		// Call which can only succeed if state is state overridden
   786  		{
   787  			blockNumber: rpc.LatestBlockNumber,
   788  			call: TransactionArgs{
   789  				From:  &randomAccounts[0].addr,
   790  				To:    &randomAccounts[1].addr,
   791  				Value: (*hexutil.Big)(big.NewInt(1000)),
   792  			},
   793  			overrides: StateOverride{
   794  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
   795  			},
   796  			want: "0x",
   797  		},
   798  		// Invalid call without state overriding
   799  		{
   800  			blockNumber: rpc.LatestBlockNumber,
   801  			call: TransactionArgs{
   802  				From:  &randomAccounts[0].addr,
   803  				To:    &randomAccounts[1].addr,
   804  				Value: (*hexutil.Big)(big.NewInt(1000)),
   805  			},
   806  			expectErr: core.ErrInsufficientFunds,
   807  		},
   808  		// Successful simple contract call
   809  		//
   810  		// // SPDX-License-Identifier: GPL-3.0
   811  		//
   812  		//  pragma solidity >=0.7.0 <0.8.0;
   813  		//
   814  		//  /**
   815  		//   * @title Storage
   816  		//   * @dev Store & retrieve value in a variable
   817  		//   */
   818  		//  contract Storage {
   819  		//      uint256 public number;
   820  		//      constructor() {
   821  		//          number = block.number;
   822  		//      }
   823  		//  }
   824  		{
   825  			blockNumber: rpc.LatestBlockNumber,
   826  			call: TransactionArgs{
   827  				From: &randomAccounts[0].addr,
   828  				To:   &randomAccounts[2].addr,
   829  				Data: hex2Bytes("8381f58a"), // call number()
   830  			},
   831  			overrides: StateOverride{
   832  				randomAccounts[2].addr: OverrideAccount{
   833  					Code:      hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
   834  					StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
   835  				},
   836  			},
   837  			want: "0x000000000000000000000000000000000000000000000000000000000000007b",
   838  		},
   839  		// Block overrides should work
   840  		{
   841  			blockNumber: rpc.LatestBlockNumber,
   842  			call: TransactionArgs{
   843  				From: &accounts[1].addr,
   844  				Input: &hexutil.Bytes{
   845  					0x43,             // NUMBER
   846  					0x60, 0x00, 0x52, // MSTORE offset 0
   847  					0x60, 0x20, 0x60, 0x00, 0xf3,
   848  				},
   849  			},
   850  			blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
   851  			want:           "0x000000000000000000000000000000000000000000000000000000000000000b",
   852  		},
   853  	}
   854  	for i, tc := range testSuite {
   855  		result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
   856  		if tc.expectErr != nil {
   857  			if err == nil {
   858  				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
   859  				continue
   860  			}
   861  			if !errors.Is(err, tc.expectErr) {
   862  				// Second try
   863  				if !reflect.DeepEqual(err, tc.expectErr) {
   864  					t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
   865  				}
   866  			}
   867  			continue
   868  		}
   869  		if err != nil {
   870  			t.Errorf("test %d: want no error, have %v", i, err)
   871  			continue
   872  		}
   873  		if !reflect.DeepEqual(result.String(), tc.want) {
   874  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want)
   875  		}
   876  	}
   877  }
   878  
   879  type Account struct {
   880  	key  *ecdsa.PrivateKey
   881  	addr common.Address
   882  }
   883  
   884  func newAccounts(n int) (accounts []Account) {
   885  	for i := 0; i < n; i++ {
   886  		key, _ := crypto.GenerateKey()
   887  		addr := crypto.PubkeyToAddress(key.PublicKey)
   888  		accounts = append(accounts, Account{key: key, addr: addr})
   889  	}
   890  	slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
   891  	return accounts
   892  }
   893  
   894  func newRPCBalance(balance *big.Int) **hexutil.Big {
   895  	rpcBalance := (*hexutil.Big)(balance)
   896  	return &rpcBalance
   897  }
   898  
   899  func hex2Bytes(str string) *hexutil.Bytes {
   900  	rpcBytes := hexutil.Bytes(common.Hex2Bytes(str))
   901  	return &rpcBytes
   902  }
   903  
   904  func TestRPCMarshalBlock(t *testing.T) {
   905  	t.Parallel()
   906  	var (
   907  		txs []*types.Transaction
   908  		to  = common.BytesToAddress([]byte{0x11})
   909  	)
   910  	for i := uint64(1); i <= 4; i++ {
   911  		var tx *types.Transaction
   912  		if i%2 == 0 {
   913  			tx = types.NewTx(&types.LegacyTx{
   914  				Nonce:    i,
   915  				GasPrice: big.NewInt(11111),
   916  				Gas:      1111,
   917  				To:       &to,
   918  				Value:    big.NewInt(111),
   919  				Data:     []byte{0x11, 0x11, 0x11},
   920  			})
   921  		} else {
   922  			tx = types.NewTx(&types.AccessListTx{
   923  				ChainID:  big.NewInt(1337),
   924  				Nonce:    i,
   925  				GasPrice: big.NewInt(11111),
   926  				Gas:      1111,
   927  				To:       &to,
   928  				Value:    big.NewInt(111),
   929  				Data:     []byte{0x11, 0x11, 0x11},
   930  			})
   931  		}
   932  		txs = append(txs, tx)
   933  	}
   934  	block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, txs, nil, nil, blocktest.NewHasher())
   935  
   936  	var testSuite = []struct {
   937  		inclTx bool
   938  		fullTx bool
   939  		want   string
   940  	}{
   941  		// without txs
   942  		{
   943  			inclTx: false,
   944  			fullTx: false,
   945  			want: `{
   946  				"difficulty": "0x0",
   947  				"extraData": "0x",
   948  				"gasLimit": "0x0",
   949  				"gasUsed": "0x0",
   950  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
   951  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   952  				"miner": "0x0000000000000000000000000000000000000000",
   953  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   954  				"nonce": "0x0000000000000000",
   955  				"number": "0x64",
   956  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   957  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
   958  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
   959  				"size": "0x296",
   960  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
   961  				"timestamp": "0x0",
   962  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
   963  				"uncles": []
   964  			}`,
   965  		},
   966  		// only tx hashes
   967  		{
   968  			inclTx: true,
   969  			fullTx: false,
   970  			want: `{
   971  				"difficulty": "0x0",
   972  				"extraData": "0x",
   973  				"gasLimit": "0x0",
   974  				"gasUsed": "0x0",
   975  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
   976  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
   977  				"miner": "0x0000000000000000000000000000000000000000",
   978  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   979  				"nonce": "0x0000000000000000",
   980  				"number": "0x64",
   981  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
   982  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
   983  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
   984  				"size": "0x296",
   985  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
   986  				"timestamp": "0x0",
   987  				"transactions": [
   988  					"0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605",
   989  					"0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4",
   990  					"0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5",
   991  					"0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1"
   992  				],
   993  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
   994  				"uncles": []
   995  			}`,
   996  		},
   997  		// full tx details
   998  		{
   999  			inclTx: true,
  1000  			fullTx: true,
  1001  			want: `{
  1002  				"difficulty": "0x0",
  1003  				"extraData": "0x",
  1004  				"gasLimit": "0x0",
  1005  				"gasUsed": "0x0",
  1006  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1007  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  1008  				"miner": "0x0000000000000000000000000000000000000000",
  1009  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1010  				"nonce": "0x0000000000000000",
  1011  				"number": "0x64",
  1012  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1013  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  1014  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  1015  				"size": "0x296",
  1016  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1017  				"timestamp": "0x0",
  1018  				"transactions": [
  1019  					{
  1020  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1021  						"blockNumber": "0x64",
  1022  						"from": "0x0000000000000000000000000000000000000000",
  1023  						"gas": "0x457",
  1024  						"gasPrice": "0x2b67",
  1025  						"hash": "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605",
  1026  						"input": "0x111111",
  1027  						"nonce": "0x1",
  1028  						"to": "0x0000000000000000000000000000000000000011",
  1029  						"transactionIndex": "0x0",
  1030  						"value": "0x6f",
  1031  						"type": "0x1",
  1032  						"accessList": [],
  1033  						"chainId": "0x539",
  1034  						"v": "0x0",
  1035  						"r": "0x0",
  1036  						"s": "0x0",
  1037  						"yParity": "0x0"
  1038  					},
  1039  					{
  1040  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1041  						"blockNumber": "0x64",
  1042  						"from": "0x0000000000000000000000000000000000000000",
  1043  						"gas": "0x457",
  1044  						"gasPrice": "0x2b67",
  1045  						"hash": "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4",
  1046  						"input": "0x111111",
  1047  						"nonce": "0x2",
  1048  						"to": "0x0000000000000000000000000000000000000011",
  1049  						"transactionIndex": "0x1",
  1050  						"value": "0x6f",
  1051  						"type": "0x0",
  1052  						"chainId": "0x7fffffffffffffee",
  1053  						"v": "0x0",
  1054  						"r": "0x0",
  1055  						"s": "0x0"
  1056  					},
  1057  					{
  1058  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1059  						"blockNumber": "0x64",
  1060  						"from": "0x0000000000000000000000000000000000000000",
  1061  						"gas": "0x457",
  1062  						"gasPrice": "0x2b67",
  1063  						"hash": "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5",
  1064  						"input": "0x111111",
  1065  						"nonce": "0x3",
  1066  						"to": "0x0000000000000000000000000000000000000011",
  1067  						"transactionIndex": "0x2",
  1068  						"value": "0x6f",
  1069  						"type": "0x1",
  1070  						"accessList": [],
  1071  						"chainId": "0x539",
  1072  						"v": "0x0",
  1073  						"r": "0x0",
  1074  						"s": "0x0",
  1075  						"yParity": "0x0"
  1076  					},
  1077  					{
  1078  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1079  						"blockNumber": "0x64",
  1080  						"from": "0x0000000000000000000000000000000000000000",
  1081  						"gas": "0x457",
  1082  						"gasPrice": "0x2b67",
  1083  						"hash": "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1",
  1084  						"input": "0x111111",
  1085  						"nonce": "0x4",
  1086  						"to": "0x0000000000000000000000000000000000000011",
  1087  						"transactionIndex": "0x3",
  1088  						"value": "0x6f",
  1089  						"type": "0x0",
  1090  						"chainId": "0x7fffffffffffffee",
  1091  						"v": "0x0",
  1092  						"r": "0x0",
  1093  						"s": "0x0"
  1094  					}
  1095  				],
  1096  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
  1097  				"uncles": []
  1098  			}`,
  1099  		},
  1100  	}
  1101  
  1102  	for i, tc := range testSuite {
  1103  		resp := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.TestSubnetEVMConfig)
  1104  		out, err := json.Marshal(resp)
  1105  		if err != nil {
  1106  			t.Errorf("test %d: json marshal error: %v", i, err)
  1107  			continue
  1108  		}
  1109  		require.JSONEqf(t, tc.want, string(out), "test %d", i)
  1110  	}
  1111  }
  1112  
  1113  func TestRPCGetBlockOrHeader(t *testing.T) {
  1114  	t.Parallel()
  1115  
  1116  	// Initialize test accounts
  1117  	var (
  1118  		acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1119  		acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
  1120  		acc1Addr   = crypto.PubkeyToAddress(acc1Key.PublicKey)
  1121  		acc2Addr   = crypto.PubkeyToAddress(acc2Key.PublicKey)
  1122  		genesis    = &core.Genesis{
  1123  			Config: params.TestSubnetEVMConfig,
  1124  			Alloc: core.GenesisAlloc{
  1125  				acc1Addr: {Balance: big.NewInt(params.Ether)},
  1126  				acc2Addr: {Balance: big.NewInt(params.Ether)},
  1127  			},
  1128  		}
  1129  		genBlocks = 10
  1130  		signer    = types.HomesteadSigner{}
  1131  		tx        = types.NewTx(&types.LegacyTx{
  1132  			Nonce:    11,
  1133  			GasPrice: big.NewInt(11111),
  1134  			Gas:      1111,
  1135  			To:       &acc2Addr,
  1136  			Value:    big.NewInt(111),
  1137  			Data:     []byte{0x11, 0x11, 0x11},
  1138  		})
  1139  		pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, []*types.Transaction{tx}, nil, nil, blocktest.NewHasher())
  1140  	)
  1141  	backend := newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) {
  1142  		// Transfer from account[0] to account[1]
  1143  		//    value: 1000 wei
  1144  		//    fee:   0 wei
  1145  		tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), signer, acc1Key)
  1146  		b.AddTx(tx)
  1147  	})
  1148  	api := NewBlockChainAPI(backend)
  1149  	blockHashes := make([]common.Hash, genBlocks+1)
  1150  	ctx := context.Background()
  1151  	for i := 0; i <= genBlocks; i++ {
  1152  		header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i))
  1153  		if err != nil {
  1154  			t.Errorf("failed to get block: %d err: %v", i, err)
  1155  		}
  1156  		blockHashes[i] = header.Hash()
  1157  	}
  1158  	pendingHash := pending.Hash()
  1159  
  1160  	var testSuite = []struct {
  1161  		blockNumber rpc.BlockNumber
  1162  		blockHash   *common.Hash
  1163  		fullTx      bool
  1164  		reqHeader   bool
  1165  		file        string
  1166  		expectErr   error
  1167  	}{
  1168  		// 0. latest header
  1169  		{
  1170  			blockNumber: rpc.LatestBlockNumber,
  1171  			reqHeader:   true,
  1172  			file:        "tag-latest",
  1173  		},
  1174  		// 1. genesis header
  1175  		{
  1176  			blockNumber: rpc.BlockNumber(0),
  1177  			reqHeader:   true,
  1178  			file:        "number-0",
  1179  		},
  1180  		// 2. #1 header
  1181  		{
  1182  			blockNumber: rpc.BlockNumber(1),
  1183  			reqHeader:   true,
  1184  			file:        "number-1",
  1185  		},
  1186  		// 3. latest-1 header
  1187  		{
  1188  			blockNumber: rpc.BlockNumber(9),
  1189  			reqHeader:   true,
  1190  			file:        "number-latest-1",
  1191  		},
  1192  		// 4. latest+1 header
  1193  		{
  1194  			blockNumber: rpc.BlockNumber(11),
  1195  			reqHeader:   true,
  1196  			file:        "number-latest+1",
  1197  		},
  1198  		// 5. pending header
  1199  		{
  1200  			blockNumber: rpc.PendingBlockNumber,
  1201  			reqHeader:   true,
  1202  			file:        "tag-pending",
  1203  		},
  1204  		// 6. latest block
  1205  		{
  1206  			blockNumber: rpc.LatestBlockNumber,
  1207  			file:        "tag-latest",
  1208  		},
  1209  		// 7. genesis block
  1210  		{
  1211  			blockNumber: rpc.BlockNumber(0),
  1212  			file:        "number-0",
  1213  		},
  1214  		// 8. #1 block
  1215  		{
  1216  			blockNumber: rpc.BlockNumber(1),
  1217  			file:        "number-1",
  1218  		},
  1219  		// 9. latest-1 block
  1220  		{
  1221  			blockNumber: rpc.BlockNumber(9),
  1222  			fullTx:      true,
  1223  			file:        "number-latest-1",
  1224  		},
  1225  		// 10. latest+1 block
  1226  		{
  1227  			blockNumber: rpc.BlockNumber(11),
  1228  			fullTx:      true,
  1229  			file:        "number-latest+1",
  1230  		},
  1231  		// 11. pending block
  1232  		{
  1233  			blockNumber: rpc.PendingBlockNumber,
  1234  			file:        "tag-pending",
  1235  		},
  1236  		// 12. pending block + fullTx
  1237  		{
  1238  			blockNumber: rpc.PendingBlockNumber,
  1239  			fullTx:      true,
  1240  			file:        "tag-pending-fullTx",
  1241  		},
  1242  		// 13. latest header by hash
  1243  		{
  1244  			blockHash: &blockHashes[len(blockHashes)-1],
  1245  			reqHeader: true,
  1246  			file:      "hash-latest",
  1247  		},
  1248  		// 14. genesis header by hash
  1249  		{
  1250  			blockHash: &blockHashes[0],
  1251  			reqHeader: true,
  1252  			file:      "hash-0",
  1253  		},
  1254  		// 15. #1 header
  1255  		{
  1256  			blockHash: &blockHashes[1],
  1257  			reqHeader: true,
  1258  			file:      "hash-1",
  1259  		},
  1260  		// 16. latest-1 header
  1261  		{
  1262  			blockHash: &blockHashes[len(blockHashes)-2],
  1263  			reqHeader: true,
  1264  			file:      "hash-latest-1",
  1265  		},
  1266  		// 17. empty hash
  1267  		{
  1268  			blockHash: &common.Hash{},
  1269  			reqHeader: true,
  1270  			file:      "hash-empty",
  1271  		},
  1272  		// 18. pending hash
  1273  		{
  1274  			blockHash: &pendingHash,
  1275  			reqHeader: true,
  1276  			file:      `hash-pending`,
  1277  		},
  1278  		// 19. latest block
  1279  		{
  1280  			blockHash: &blockHashes[len(blockHashes)-1],
  1281  			file:      "hash-latest",
  1282  		},
  1283  		// 20. genesis block
  1284  		{
  1285  			blockHash: &blockHashes[0],
  1286  			file:      "hash-genesis",
  1287  		},
  1288  		// 21. #1 block
  1289  		{
  1290  			blockHash: &blockHashes[1],
  1291  			file:      "hash-1",
  1292  		},
  1293  		// 22. latest-1 block
  1294  		{
  1295  			blockHash: &blockHashes[len(blockHashes)-2],
  1296  			fullTx:    true,
  1297  			file:      "hash-latest-1-fullTx",
  1298  		},
  1299  		// 23. empty hash + body
  1300  		{
  1301  			blockHash: &common.Hash{},
  1302  			fullTx:    true,
  1303  			file:      "hash-empty-fullTx",
  1304  		},
  1305  		// 24. pending block
  1306  		{
  1307  			blockHash: &pendingHash,
  1308  			file:      `hash-pending`,
  1309  		},
  1310  		// 25. pending block + fullTx
  1311  		{
  1312  			blockHash: &pendingHash,
  1313  			fullTx:    true,
  1314  			file:      "hash-pending-fullTx",
  1315  		},
  1316  	}
  1317  
  1318  	for i, tt := range testSuite {
  1319  		var (
  1320  			result map[string]interface{}
  1321  			err    error
  1322  			rpc    string
  1323  		)
  1324  		if tt.blockHash != nil {
  1325  			if tt.reqHeader {
  1326  				result = api.GetHeaderByHash(context.Background(), *tt.blockHash)
  1327  				rpc = "eth_getHeaderByHash"
  1328  			} else {
  1329  				result, err = api.GetBlockByHash(context.Background(), *tt.blockHash, tt.fullTx)
  1330  				rpc = "eth_getBlockByHash"
  1331  			}
  1332  		} else {
  1333  			if tt.reqHeader {
  1334  				result, err = api.GetHeaderByNumber(context.Background(), tt.blockNumber)
  1335  				rpc = "eth_getHeaderByNumber"
  1336  			} else {
  1337  				result, err = api.GetBlockByNumber(context.Background(), tt.blockNumber, tt.fullTx)
  1338  				rpc = "eth_getBlockByNumber"
  1339  			}
  1340  		}
  1341  		if tt.expectErr != nil {
  1342  			if err == nil {
  1343  				t.Errorf("test %d: want error %v, have nothing", i, tt.expectErr)
  1344  				continue
  1345  			}
  1346  			if !errors.Is(err, tt.expectErr) {
  1347  				t.Errorf("test %d: error mismatch, want %v, have %v", i, tt.expectErr, err)
  1348  			}
  1349  			continue
  1350  		}
  1351  		if err != nil {
  1352  			t.Errorf("test %d: want no error, have %v", i, err)
  1353  			continue
  1354  		}
  1355  
  1356  		testRPCResponseWithFile(t, i, result, rpc, tt.file)
  1357  	}
  1358  }
  1359  
  1360  func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) {
  1361  	config := *params.TestChainConfig
  1362  	var (
  1363  		acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1364  		acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
  1365  		acc1Addr   = crypto.PubkeyToAddress(acc1Key.PublicKey)
  1366  		acc2Addr   = crypto.PubkeyToAddress(acc2Key.PublicKey)
  1367  		contract   = common.HexToAddress("0000000000000000000000000000000000031ec7")
  1368  		genesis    = &core.Genesis{
  1369  			Config:        &config,
  1370  			ExcessBlobGas: new(uint64),
  1371  			BlobGasUsed:   new(uint64),
  1372  			Timestamp:     uint64(params.DefaultGenesisTime.Unix()),
  1373  			Alloc: core.GenesisAlloc{
  1374  				acc1Addr: {Balance: big.NewInt(params.Ether)},
  1375  				acc2Addr: {Balance: big.NewInt(params.Ether)},
  1376  				// // SPDX-License-Identifier: GPL-3.0
  1377  				// pragma solidity >=0.7.0 <0.9.0;
  1378  				//
  1379  				// contract Token {
  1380  				//     event Transfer(address indexed from, address indexed to, uint256 value);
  1381  				//     function transfer(address to, uint256 value) public returns (bool) {
  1382  				//         emit Transfer(msg.sender, to, value);
  1383  				//         return true;
  1384  				//     }
  1385  				// }
  1386  				contract: {Balance: big.NewInt(params.Ether), Code: common.FromHex("0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9059cbb14610030575b600080fd5b61004a6004803603810190610045919061016a565b610060565b60405161005791906101c5565b60405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516100bf91906101ef565b60405180910390a36001905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610101826100d6565b9050919050565b610111816100f6565b811461011c57600080fd5b50565b60008135905061012e81610108565b92915050565b6000819050919050565b61014781610134565b811461015257600080fd5b50565b6000813590506101648161013e565b92915050565b60008060408385031215610181576101806100d1565b5b600061018f8582860161011f565b92505060206101a085828601610155565b9150509250929050565b60008115159050919050565b6101bf816101aa565b82525050565b60006020820190506101da60008301846101b6565b92915050565b6101e981610134565b82525050565b600060208201905061020460008301846101e0565b9291505056fea2646970667358221220b469033f4b77b9565ee84e0a2f04d496b18160d26034d54f9487e57788fd36d564736f6c63430008120033")},
  1387  			},
  1388  		}
  1389  		signer   = types.LatestSignerForChainID(params.TestChainConfig.ChainID)
  1390  		txHashes = make([]common.Hash, genBlocks)
  1391  	)
  1392  
  1393  	// Set the terminal total difficulty in the config
  1394  	// genesis.Config.TerminalTotalDifficulty = big.NewInt(0)
  1395  	// genesis.Config.TerminalTotalDifficultyPassed = true
  1396  	backend := newTestBackend(t, genBlocks, genesis, dummy.NewCoinbaseFaker(), func(i int, b *core.BlockGen) {
  1397  		var (
  1398  			tx  *types.Transaction
  1399  			err error
  1400  		)
  1401  		switch i {
  1402  		case 0:
  1403  			// transfer 1000wei
  1404  			tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &acc2Addr, Value: big.NewInt(1000), Gas: params.TxGas, GasPrice: b.BaseFee(), Data: nil}), types.HomesteadSigner{}, acc1Key)
  1405  		case 1:
  1406  			// create contract
  1407  			tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: nil, Gas: 53100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040")}), signer, acc1Key)
  1408  		case 2:
  1409  			// with logs
  1410  			// transfer(address to, uint256 value)
  1411  			data := fmt.Sprintf("0xa9059cbb%s%s", common.HexToHash(common.BigToAddress(big.NewInt(int64(i + 1))).Hex()).String()[2:], common.BytesToHash([]byte{byte(i + 11)}).String()[2:])
  1412  			tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &contract, Gas: 60000, GasPrice: b.BaseFee(), Data: common.FromHex(data)}), signer, acc1Key)
  1413  		case 3:
  1414  			// dynamic fee with logs
  1415  			// transfer(address to, uint256 value)
  1416  			data := fmt.Sprintf("0xa9059cbb%s%s", common.HexToHash(common.BigToAddress(big.NewInt(int64(i + 1))).Hex()).String()[2:], common.BytesToHash([]byte{byte(i + 11)}).String()[2:])
  1417  			fee := big.NewInt(500)
  1418  			fee.Add(fee, b.BaseFee())
  1419  			tx, err = types.SignTx(types.NewTx(&types.DynamicFeeTx{Nonce: uint64(i), To: &contract, Gas: 60000, Value: big.NewInt(1), GasTipCap: big.NewInt(500), GasFeeCap: fee, Data: common.FromHex(data)}), signer, acc1Key)
  1420  		case 4:
  1421  			// access list with contract create
  1422  			accessList := types.AccessList{{
  1423  				Address:     contract,
  1424  				StorageKeys: []common.Hash{{0}},
  1425  			}}
  1426  			tx, err = types.SignTx(types.NewTx(&types.AccessListTx{Nonce: uint64(i), To: nil, Gas: 58100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040"), AccessList: accessList}), signer, acc1Key)
  1427  		case 5:
  1428  			// blob tx
  1429  			fee := big.NewInt(500)
  1430  			fee.Add(fee, b.BaseFee())
  1431  			tx, err = types.SignTx(types.NewTx(&types.BlobTx{
  1432  				Nonce:      uint64(i),
  1433  				GasTipCap:  uint256.NewInt(1),
  1434  				GasFeeCap:  uint256.MustFromBig(fee),
  1435  				Gas:        params.TxGas,
  1436  				To:         acc2Addr,
  1437  				BlobFeeCap: uint256.NewInt(1),
  1438  				BlobHashes: []common.Hash{{1}},
  1439  				Value:      new(uint256.Int),
  1440  			}), signer, acc1Key)
  1441  		}
  1442  		if err != nil {
  1443  			t.Errorf("failed to sign tx: %v", err)
  1444  		}
  1445  		if tx != nil {
  1446  			b.AddTx(tx)
  1447  			txHashes[i] = tx.Hash()
  1448  		}
  1449  		if i == 5 {
  1450  			b.SetBlobGas(params.BlobTxBlobGasPerBlob)
  1451  		}
  1452  		// b.SetPoS()
  1453  	})
  1454  	return backend, txHashes
  1455  }
  1456  
  1457  func TestRPCGetTransactionReceipt(t *testing.T) {
  1458  	t.Parallel()
  1459  
  1460  	var (
  1461  		backend, txHashes = setupReceiptBackend(t, 6)
  1462  		api               = NewTransactionAPI(backend, new(AddrLocker))
  1463  	)
  1464  
  1465  	var testSuite = []struct {
  1466  		txHash common.Hash
  1467  		file   string
  1468  	}{
  1469  		// 0. normal success
  1470  		{
  1471  			txHash: txHashes[0],
  1472  			file:   "normal-transfer-tx",
  1473  		},
  1474  		// 1. create contract
  1475  		{
  1476  			txHash: txHashes[1],
  1477  			file:   "create-contract-tx",
  1478  		},
  1479  		// 2. with logs success
  1480  		{
  1481  			txHash: txHashes[2],
  1482  			file:   "with-logs",
  1483  		},
  1484  		// 3. dynamic tx with logs success
  1485  		{
  1486  			txHash: txHashes[3],
  1487  			file:   `dynamic-tx-with-logs`,
  1488  		},
  1489  		// 4. access list tx with create contract
  1490  		{
  1491  			txHash: txHashes[4],
  1492  			file:   "create-contract-with-access-list",
  1493  		},
  1494  		// 5. txhash empty
  1495  		{
  1496  			txHash: common.Hash{},
  1497  			file:   "txhash-empty",
  1498  		},
  1499  		// 6. txhash not found
  1500  		{
  1501  			txHash: common.HexToHash("deadbeef"),
  1502  			file:   "txhash-notfound",
  1503  		},
  1504  		// 7. blob tx
  1505  		{
  1506  			txHash: txHashes[5],
  1507  			file:   "blob-tx",
  1508  		},
  1509  	}
  1510  
  1511  	for i, tt := range testSuite {
  1512  		var (
  1513  			result interface{}
  1514  			err    error
  1515  		)
  1516  		result, err = api.GetTransactionReceipt(context.Background(), tt.txHash)
  1517  		if err != nil {
  1518  			t.Errorf("test %d: want no error, have %v", i, err)
  1519  			continue
  1520  		}
  1521  		testRPCResponseWithFile(t, i, result, "eth_getTransactionReceipt", tt.file)
  1522  	}
  1523  }
  1524  
  1525  func TestRPCGetBlockReceipts(t *testing.T) {
  1526  	t.Parallel()
  1527  
  1528  	var (
  1529  		genBlocks  = 6
  1530  		backend, _ = setupReceiptBackend(t, genBlocks)
  1531  		api        = NewBlockChainAPI(backend)
  1532  	)
  1533  	blockHashes := make([]common.Hash, genBlocks+1)
  1534  	ctx := context.Background()
  1535  	for i := 0; i <= genBlocks; i++ {
  1536  		header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i))
  1537  		if err != nil {
  1538  			t.Errorf("failed to get block: %d err: %v", i, err)
  1539  		}
  1540  		blockHashes[i] = header.Hash()
  1541  	}
  1542  
  1543  	var testSuite = []struct {
  1544  		test rpc.BlockNumberOrHash
  1545  		file string
  1546  	}{
  1547  		// 0. block without any txs(hash)
  1548  		{
  1549  			test: rpc.BlockNumberOrHashWithHash(blockHashes[0], false),
  1550  			file: "number-0",
  1551  		},
  1552  		// 1. block without any txs(number)
  1553  		{
  1554  			test: rpc.BlockNumberOrHashWithNumber(0),
  1555  			file: "number-1",
  1556  		},
  1557  		// 2. earliest tag
  1558  		{
  1559  			test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber),
  1560  			file: "tag-earliest",
  1561  		},
  1562  		// 3. latest tag
  1563  		{
  1564  			test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber),
  1565  			file: "tag-latest",
  1566  		},
  1567  		// 4. block with legacy transfer tx(hash)
  1568  		{
  1569  			test: rpc.BlockNumberOrHashWithHash(blockHashes[1], false),
  1570  			file: "block-with-legacy-transfer-tx",
  1571  		},
  1572  		// 5. block with contract create tx(number)
  1573  		{
  1574  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(2)),
  1575  			file: "block-with-contract-create-tx",
  1576  		},
  1577  		// 6. block with legacy contract call tx(hash)
  1578  		{
  1579  			test: rpc.BlockNumberOrHashWithHash(blockHashes[3], false),
  1580  			file: "block-with-legacy-contract-call-tx",
  1581  		},
  1582  		// 7. block with dynamic fee tx(number)
  1583  		{
  1584  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(4)),
  1585  			file: "block-with-dynamic-fee-tx",
  1586  		},
  1587  		// 8. block is empty
  1588  		{
  1589  			test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false),
  1590  			file: "hash-empty",
  1591  		},
  1592  		// 9. block is not found
  1593  		{
  1594  			test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false),
  1595  			file: "hash-notfound",
  1596  		},
  1597  		// 10. block is not found
  1598  		{
  1599  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)),
  1600  			file: "block-notfound",
  1601  		},
  1602  		// 11. block with blob tx
  1603  		{
  1604  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)),
  1605  			file: "block-with-blob-tx",
  1606  		},
  1607  	}
  1608  
  1609  	for i, tt := range testSuite {
  1610  		var (
  1611  			result interface{}
  1612  			err    error
  1613  		)
  1614  		result, err = api.GetBlockReceipts(context.Background(), tt.test)
  1615  		if err != nil {
  1616  			t.Errorf("test %d: want no error, have %v", i, err)
  1617  			continue
  1618  		}
  1619  		testRPCResponseWithFile(t, i, result, "eth_getBlockReceipts", tt.file)
  1620  	}
  1621  }
  1622  
  1623  func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) {
  1624  	data, err := json.MarshalIndent(result, "", "  ")
  1625  	if err != nil {
  1626  		t.Errorf("test %d: json marshal error", testid)
  1627  		return
  1628  	}
  1629  	outputFile := filepath.Join("testdata", fmt.Sprintf("%s-%s.json", rpc, file))
  1630  	if os.Getenv("WRITE_TEST_FILES") != "" {
  1631  		os.WriteFile(outputFile, data, 0644)
  1632  	}
  1633  	want, err := os.ReadFile(outputFile)
  1634  	if err != nil {
  1635  		t.Fatalf("error reading expected test file: %s output: %v", outputFile, err)
  1636  	}
  1637  	require.JSONEqf(t, string(want), string(data), "test %d: json not match, want: %s, have: %s", testid, string(want), string(data))
  1638  }