github.com/theQRL/go-zond@v0.1.1/internal/ethapi/api_test.go (about)

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