github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/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  	"bytes"
    21  	"context"
    22  	"crypto/ecdsa"
    23  	"crypto/sha256"
    24  	"encoding/json"
    25  	"errors"
    26  	"fmt"
    27  	"math/big"
    28  	"os"
    29  	"path/filepath"
    30  	"reflect"
    31  	"slices"
    32  	"testing"
    33  	"time"
    34  
    35  	"github.com/holiman/uint256"
    36  	"github.com/stretchr/testify/require"
    37  
    38  	"github.com/ethereum/go-ethereum"
    39  	"github.com/ethereum/go-ethereum/accounts"
    40  	"github.com/ethereum/go-ethereum/accounts/keystore"
    41  	"github.com/ethereum/go-ethereum/common"
    42  	"github.com/ethereum/go-ethereum/common/hexutil"
    43  	"github.com/ethereum/go-ethereum/consensus"
    44  	"github.com/ethereum/go-ethereum/consensus/beacon"
    45  	"github.com/ethereum/go-ethereum/consensus/ethash"
    46  	"github.com/ethereum/go-ethereum/core"
    47  	"github.com/ethereum/go-ethereum/core/bloombits"
    48  	"github.com/ethereum/go-ethereum/core/rawdb"
    49  	"github.com/ethereum/go-ethereum/core/state"
    50  	"github.com/ethereum/go-ethereum/core/types"
    51  	"github.com/ethereum/go-ethereum/core/vm"
    52  	"github.com/ethereum/go-ethereum/crypto"
    53  	"github.com/ethereum/go-ethereum/crypto/kzg4844"
    54  	"github.com/ethereum/go-ethereum/ethdb"
    55  	"github.com/ethereum/go-ethereum/event"
    56  	"github.com/ethereum/go-ethereum/internal/blocktest"
    57  	"github.com/ethereum/go-ethereum/params"
    58  	"github.com/ethereum/go-ethereum/rpc"
    59  )
    60  
    61  func testTransactionMarshal(t *testing.T, tests []txData, config *params.ChainConfig) {
    62  	t.Parallel()
    63  	var (
    64  		signer = types.LatestSigner(config)
    65  		key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    66  	)
    67  
    68  	for i, tt := range tests {
    69  		var tx2 types.Transaction
    70  		tx, err := types.SignNewTx(key, signer, tt.Tx)
    71  		if err != nil {
    72  			t.Fatalf("test %d: signing failed: %v", i, err)
    73  		}
    74  		// Regular transaction
    75  		if data, err := json.Marshal(tx); err != nil {
    76  			t.Fatalf("test %d: marshalling failed; %v", i, err)
    77  		} else if err = tx2.UnmarshalJSON(data); err != nil {
    78  			t.Fatalf("test %d: sunmarshal failed: %v", i, err)
    79  		} else if want, have := tx.Hash(), tx2.Hash(); want != have {
    80  			t.Fatalf("test %d: stx changed, want %x have %x", i, want, have)
    81  		}
    82  
    83  		// rpcTransaction
    84  		rpcTx := newRPCTransaction(tx, common.Hash{}, 0, 0, 0, nil, config)
    85  		if data, err := json.Marshal(rpcTx); err != nil {
    86  			t.Fatalf("test %d: marshalling failed; %v", i, err)
    87  		} else if err = tx2.UnmarshalJSON(data); err != nil {
    88  			t.Fatalf("test %d: unmarshal failed: %v", i, err)
    89  		} else if want, have := tx.Hash(), tx2.Hash(); want != have {
    90  			t.Fatalf("test %d: tx changed, want %x have %x", i, want, have)
    91  		} else {
    92  			want, have := tt.Want, string(data)
    93  			require.JSONEqf(t, want, have, "test %d: rpc json not match, want %s have %s", i, want, have)
    94  		}
    95  	}
    96  }
    97  
    98  func TestTransaction_RoundTripRpcJSON(t *testing.T) {
    99  	var (
   100  		config = params.AllEthashProtocolChanges
   101  		tests  = allTransactionTypes(common.Address{0xde, 0xad}, config)
   102  	)
   103  	testTransactionMarshal(t, tests, config)
   104  }
   105  
   106  func TestTransactionBlobTx(t *testing.T) {
   107  	config := *params.TestChainConfig
   108  	config.ShanghaiTime = new(uint64)
   109  	config.CancunTime = new(uint64)
   110  	tests := allBlobTxs(common.Address{0xde, 0xad}, &config)
   111  
   112  	testTransactionMarshal(t, tests, &config)
   113  }
   114  
   115  type txData struct {
   116  	Tx   types.TxData
   117  	Want string
   118  }
   119  
   120  func allTransactionTypes(addr common.Address, config *params.ChainConfig) []txData {
   121  	return []txData{
   122  		{
   123  			Tx: &types.LegacyTx{
   124  				Nonce:    5,
   125  				GasPrice: big.NewInt(6),
   126  				Gas:      7,
   127  				To:       &addr,
   128  				Value:    big.NewInt(8),
   129  				Data:     []byte{0, 1, 2, 3, 4},
   130  				V:        big.NewInt(9),
   131  				R:        big.NewInt(10),
   132  				S:        big.NewInt(11),
   133  			},
   134  			Want: `{
   135  				"blockHash": null,
   136  				"blockNumber": null,
   137  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   138  				"gas": "0x7",
   139  				"gasPrice": "0x6",
   140  				"hash": "0x5f3240454cd09a5d8b1c5d651eefae7a339262875bcd2d0e6676f3d989967008",
   141  				"input": "0x0001020304",
   142  				"nonce": "0x5",
   143  				"to": "0xdead000000000000000000000000000000000000",
   144  				"transactionIndex": null,
   145  				"value": "0x8",
   146  				"type": "0x0",
   147  				"chainId": "0x539",
   148  				"v": "0xa96",
   149  				"r": "0xbc85e96592b95f7160825d837abb407f009df9ebe8f1b9158a4b8dd093377f75",
   150  				"s": "0x1b55ea3af5574c536967b039ba6999ef6c89cf22fc04bcb296e0e8b0b9b576f5"
   151  			}`,
   152  		}, {
   153  			Tx: &types.LegacyTx{
   154  				Nonce:    5,
   155  				GasPrice: big.NewInt(6),
   156  				Gas:      7,
   157  				To:       nil,
   158  				Value:    big.NewInt(8),
   159  				Data:     []byte{0, 1, 2, 3, 4},
   160  				V:        big.NewInt(32),
   161  				R:        big.NewInt(10),
   162  				S:        big.NewInt(11),
   163  			},
   164  			Want: `{
   165  				"blockHash": null,
   166  				"blockNumber": null,
   167  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   168  				"gas": "0x7",
   169  				"gasPrice": "0x6",
   170  				"hash": "0x806e97f9d712b6cb7e781122001380a2837531b0fc1e5f5d78174ad4cb699873",
   171  				"input": "0x0001020304",
   172  				"nonce": "0x5",
   173  				"to": null,
   174  				"transactionIndex": null,
   175  				"value": "0x8",
   176  				"type": "0x0",
   177  				"chainId": "0x539",
   178  				"v": "0xa96",
   179  				"r": "0x9dc28b267b6ad4e4af6fe9289668f9305c2eb7a3241567860699e478af06835a",
   180  				"s": "0xa0b51a071aa9bed2cd70aedea859779dff039e3630ea38497d95202e9b1fec7"
   181  			}`,
   182  		},
   183  		{
   184  			Tx: &types.AccessListTx{
   185  				ChainID:  config.ChainID,
   186  				Nonce:    5,
   187  				GasPrice: big.NewInt(6),
   188  				Gas:      7,
   189  				To:       &addr,
   190  				Value:    big.NewInt(8),
   191  				Data:     []byte{0, 1, 2, 3, 4},
   192  				AccessList: types.AccessList{
   193  					types.AccessTuple{
   194  						Address:     common.Address{0x2},
   195  						StorageKeys: []common.Hash{types.EmptyRootHash},
   196  					},
   197  				},
   198  				V: big.NewInt(32),
   199  				R: big.NewInt(10),
   200  				S: big.NewInt(11),
   201  			},
   202  			Want: `{
   203  				"blockHash": null,
   204  				"blockNumber": null,
   205  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   206  				"gas": "0x7",
   207  				"gasPrice": "0x6",
   208  				"hash": "0x121347468ee5fe0a29f02b49b4ffd1c8342bc4255146bb686cd07117f79e7129",
   209  				"input": "0x0001020304",
   210  				"nonce": "0x5",
   211  				"to": "0xdead000000000000000000000000000000000000",
   212  				"transactionIndex": null,
   213  				"value": "0x8",
   214  				"type": "0x1",
   215  				"accessList": [
   216  					{
   217  						"address": "0x0200000000000000000000000000000000000000",
   218  						"storageKeys": [
   219  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   220  						]
   221  					}
   222  				],
   223  				"chainId": "0x539",
   224  				"v": "0x0",
   225  				"r": "0xf372ad499239ae11d91d34c559ffc5dab4daffc0069e03afcabdcdf231a0c16b",
   226  				"s": "0x28573161d1f9472fa0fd4752533609e72f06414f7ab5588699a7141f65d2abf",
   227  				"yParity": "0x0"
   228  			}`,
   229  		}, {
   230  			Tx: &types.AccessListTx{
   231  				ChainID:  config.ChainID,
   232  				Nonce:    5,
   233  				GasPrice: big.NewInt(6),
   234  				Gas:      7,
   235  				To:       nil,
   236  				Value:    big.NewInt(8),
   237  				Data:     []byte{0, 1, 2, 3, 4},
   238  				AccessList: types.AccessList{
   239  					types.AccessTuple{
   240  						Address:     common.Address{0x2},
   241  						StorageKeys: []common.Hash{types.EmptyRootHash},
   242  					},
   243  				},
   244  				V: big.NewInt(32),
   245  				R: big.NewInt(10),
   246  				S: big.NewInt(11),
   247  			},
   248  			Want: `{
   249  				"blockHash": null,
   250  				"blockNumber": null,
   251  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   252  				"gas": "0x7",
   253  				"gasPrice": "0x6",
   254  				"hash": "0x067c3baebede8027b0f828a9d933be545f7caaec623b00684ac0659726e2055b",
   255  				"input": "0x0001020304",
   256  				"nonce": "0x5",
   257  				"to": null,
   258  				"transactionIndex": null,
   259  				"value": "0x8",
   260  				"type": "0x1",
   261  				"accessList": [
   262  					{
   263  						"address": "0x0200000000000000000000000000000000000000",
   264  						"storageKeys": [
   265  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   266  						]
   267  					}
   268  				],
   269  				"chainId": "0x539",
   270  				"v": "0x1",
   271  				"r": "0x542981b5130d4613897fbab144796cb36d3cb3d7807d47d9c7f89ca7745b085c",
   272  				"s": "0x7425b9dd6c5deaa42e4ede35d0c4570c4624f68c28d812c10d806ffdf86ce63",
   273  				"yParity": "0x1"
   274  			}`,
   275  		}, {
   276  			Tx: &types.DynamicFeeTx{
   277  				ChainID:   config.ChainID,
   278  				Nonce:     5,
   279  				GasTipCap: big.NewInt(6),
   280  				GasFeeCap: big.NewInt(9),
   281  				Gas:       7,
   282  				To:        &addr,
   283  				Value:     big.NewInt(8),
   284  				Data:      []byte{0, 1, 2, 3, 4},
   285  				AccessList: types.AccessList{
   286  					types.AccessTuple{
   287  						Address:     common.Address{0x2},
   288  						StorageKeys: []common.Hash{types.EmptyRootHash},
   289  					},
   290  				},
   291  				V: big.NewInt(32),
   292  				R: big.NewInt(10),
   293  				S: big.NewInt(11),
   294  			},
   295  			Want: `{
   296  				"blockHash": null,
   297  				"blockNumber": null,
   298  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   299  				"gas": "0x7",
   300  				"gasPrice": "0x9",
   301  				"maxFeePerGas": "0x9",
   302  				"maxPriorityFeePerGas": "0x6",
   303  				"hash": "0xb63e0b146b34c3e9cb7fbabb5b3c081254a7ded6f1b65324b5898cc0545d79ff",
   304  				"input": "0x0001020304",
   305  				"nonce": "0x5",
   306  				"to": "0xdead000000000000000000000000000000000000",
   307  				"transactionIndex": null,
   308  				"value": "0x8",
   309  				"type": "0x2",
   310  				"accessList": [
   311  					{
   312  						"address": "0x0200000000000000000000000000000000000000",
   313  						"storageKeys": [
   314  							"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"
   315  						]
   316  					}
   317  				],
   318  				"chainId": "0x539",
   319  				"v": "0x1",
   320  				"r": "0x3b167e05418a8932cd53d7578711fe1a76b9b96c48642402bb94978b7a107e80",
   321  				"s": "0x22f98a332d15ea2cc80386c1ebaa31b0afebfa79ebc7d039a1e0074418301fef",
   322  				"yParity": "0x1"
   323  			}`,
   324  		}, {
   325  			Tx: &types.DynamicFeeTx{
   326  				ChainID:    config.ChainID,
   327  				Nonce:      5,
   328  				GasTipCap:  big.NewInt(6),
   329  				GasFeeCap:  big.NewInt(9),
   330  				Gas:        7,
   331  				To:         nil,
   332  				Value:      big.NewInt(8),
   333  				Data:       []byte{0, 1, 2, 3, 4},
   334  				AccessList: types.AccessList{},
   335  				V:          big.NewInt(32),
   336  				R:          big.NewInt(10),
   337  				S:          big.NewInt(11),
   338  			},
   339  			Want: `{
   340  				"blockHash": null,
   341  				"blockNumber": null,
   342  				"from": "0x71562b71999873db5b286df957af199ec94617f7",
   343  				"gas": "0x7",
   344  				"gasPrice": "0x9",
   345  				"maxFeePerGas": "0x9",
   346  				"maxPriorityFeePerGas": "0x6",
   347  				"hash": "0xcbab17ee031a9d5b5a09dff909f0a28aedb9b295ac0635d8710d11c7b806ec68",
   348  				"input": "0x0001020304",
   349  				"nonce": "0x5",
   350  				"to": null,
   351  				"transactionIndex": null,
   352  				"value": "0x8",
   353  				"type": "0x2",
   354  				"accessList": [],
   355  				"chainId": "0x539",
   356  				"v": "0x0",
   357  				"r": "0x6446b8a682db7e619fc6b4f6d1f708f6a17351a41c7fbd63665f469bc78b41b9",
   358  				"s": "0x7626abc15834f391a117c63450047309dbf84c5ce3e8e609b607062641e2de43",
   359  				"yParity": "0x0"
   360  			}`,
   361  		},
   362  	}
   363  }
   364  
   365  func allBlobTxs(addr common.Address, config *params.ChainConfig) []txData {
   366  	return []txData{
   367  		{
   368  			Tx: &types.BlobTx{
   369  				Nonce:      6,
   370  				GasTipCap:  uint256.NewInt(1),
   371  				GasFeeCap:  uint256.NewInt(5),
   372  				Gas:        6,
   373  				To:         addr,
   374  				BlobFeeCap: uint256.NewInt(1),
   375  				BlobHashes: []common.Hash{{1}},
   376  				Value:      new(uint256.Int),
   377  				V:          uint256.NewInt(32),
   378  				R:          uint256.NewInt(10),
   379  				S:          uint256.NewInt(11),
   380  			},
   381  			Want: `{
   382                  "blockHash": null,
   383                  "blockNumber": null,
   384                  "from": "0x71562b71999873db5b286df957af199ec94617f7",
   385                  "gas": "0x6",
   386                  "gasPrice": "0x5",
   387                  "maxFeePerGas": "0x5",
   388                  "maxPriorityFeePerGas": "0x1",
   389                  "maxFeePerBlobGas": "0x1",
   390                  "hash": "0x1f2b59a20e61efc615ad0cbe936379d6bbea6f938aafaf35eb1da05d8e7f46a3",
   391                  "input": "0x",
   392                  "nonce": "0x6",
   393                  "to": "0xdead000000000000000000000000000000000000",
   394                  "transactionIndex": null,
   395                  "value": "0x0",
   396                  "type": "0x3",
   397                  "accessList": [],
   398                  "chainId": "0x1",
   399                  "blobVersionedHashes": [
   400                      "0x0100000000000000000000000000000000000000000000000000000000000000"
   401                  ],
   402                  "v": "0x0",
   403                  "r": "0x618be8908e0e5320f8f3b48042a079fe5a335ebd4ed1422a7d2207cd45d872bc",
   404                  "s": "0x27b2bc6c80e849a8e8b764d4549d8c2efac3441e73cf37054eb0a9b9f8e89b27",
   405                  "yParity": "0x0"
   406              }`,
   407  		},
   408  	}
   409  }
   410  
   411  func newTestAccountManager(t *testing.T) (*accounts.Manager, accounts.Account) {
   412  	var (
   413  		dir        = t.TempDir()
   414  		am         = accounts.NewManager(&accounts.Config{InsecureUnlockAllowed: true})
   415  		b          = keystore.NewKeyStore(dir, 2, 1)
   416  		testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   417  	)
   418  	acc, err := b.ImportECDSA(testKey, "")
   419  	if err != nil {
   420  		t.Fatalf("failed to create test account: %v", err)
   421  	}
   422  	if err := b.Unlock(acc, ""); err != nil {
   423  		t.Fatalf("failed to unlock account: %v\n", err)
   424  	}
   425  	am.AddBackend(b)
   426  	return am, acc
   427  }
   428  
   429  type testBackend struct {
   430  	db      ethdb.Database
   431  	chain   *core.BlockChain
   432  	pending *types.Block
   433  	accman  *accounts.Manager
   434  	acc     accounts.Account
   435  }
   436  
   437  func newTestBackend(t *testing.T, n int, gspec *core.Genesis, engine consensus.Engine, generator func(i int, b *core.BlockGen)) *testBackend {
   438  	var (
   439  		cacheConfig = &core.CacheConfig{
   440  			TrieCleanLimit:    256,
   441  			TrieDirtyLimit:    256,
   442  			TrieTimeLimit:     5 * time.Minute,
   443  			SnapshotLimit:     0,
   444  			TrieDirtyDisabled: true, // Archive mode
   445  		}
   446  	)
   447  	accman, acc := newTestAccountManager(t)
   448  	gspec.Alloc[acc.Address] = types.Account{Balance: big.NewInt(params.Ether)}
   449  	// Generate blocks for testing
   450  	db, blocks, _ := core.GenerateChainWithGenesis(gspec, engine, n, generator)
   451  	txlookupLimit := uint64(0)
   452  	chain, err := core.NewBlockChain(db, cacheConfig, gspec, nil, engine, vm.Config{}, nil, &txlookupLimit)
   453  	if err != nil {
   454  		t.Fatalf("failed to create tester chain: %v", err)
   455  	}
   456  	if n, err := chain.InsertChain(blocks); err != nil {
   457  		t.Fatalf("block %d: failed to insert into chain: %v", n, err)
   458  	}
   459  
   460  	backend := &testBackend{db: db, chain: chain, accman: accman, acc: acc}
   461  	return backend
   462  }
   463  
   464  func (b *testBackend) setPendingBlock(block *types.Block) {
   465  	b.pending = block
   466  }
   467  
   468  func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.SyncProgress{} }
   469  func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
   470  	return big.NewInt(0), nil
   471  }
   472  func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, []*big.Int, []float64, error) {
   473  	return nil, nil, nil, nil, nil, nil, nil
   474  }
   475  func (b testBackend) BlobBaseFee(ctx context.Context) *big.Int { return new(big.Int) }
   476  func (b testBackend) ChainDb() ethdb.Database                  { return b.db }
   477  func (b testBackend) AccountManager() *accounts.Manager        { return b.accman }
   478  func (b testBackend) ExtRPCEnabled() bool                      { return false }
   479  func (b testBackend) RPCGasCap() uint64                        { return 10000000 }
   480  func (b testBackend) RPCEVMTimeout() time.Duration             { return time.Second }
   481  func (b testBackend) RPCTxFeeCap() float64                     { return 0 }
   482  func (b testBackend) UnprotectedAllowed() bool                 { return false }
   483  func (b testBackend) SetHead(number uint64)                    {}
   484  func (b testBackend) HeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Header, error) {
   485  	if number == rpc.LatestBlockNumber {
   486  		return b.chain.CurrentBlock(), nil
   487  	}
   488  	if number == rpc.PendingBlockNumber && b.pending != nil {
   489  		return b.pending.Header(), nil
   490  	}
   491  	return b.chain.GetHeaderByNumber(uint64(number)), nil
   492  }
   493  func (b testBackend) HeaderByHash(ctx context.Context, hash common.Hash) (*types.Header, error) {
   494  	return b.chain.GetHeaderByHash(hash), nil
   495  }
   496  func (b testBackend) HeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Header, error) {
   497  	if blockNr, ok := blockNrOrHash.Number(); ok {
   498  		return b.HeaderByNumber(ctx, blockNr)
   499  	}
   500  	if blockHash, ok := blockNrOrHash.Hash(); ok {
   501  		return b.HeaderByHash(ctx, blockHash)
   502  	}
   503  	panic("unknown type rpc.BlockNumberOrHash")
   504  }
   505  func (b testBackend) CurrentHeader() *types.Header { return b.chain.CurrentBlock() }
   506  func (b testBackend) CurrentBlock() *types.Header  { return b.chain.CurrentBlock() }
   507  func (b testBackend) BlockByNumber(ctx context.Context, number rpc.BlockNumber) (*types.Block, error) {
   508  	if number == rpc.LatestBlockNumber {
   509  		head := b.chain.CurrentBlock()
   510  		return b.chain.GetBlock(head.Hash(), head.Number.Uint64()), nil
   511  	}
   512  	if number == rpc.PendingBlockNumber {
   513  		return b.pending, nil
   514  	}
   515  	return b.chain.GetBlockByNumber(uint64(number)), nil
   516  }
   517  func (b testBackend) BlockByHash(ctx context.Context, hash common.Hash) (*types.Block, error) {
   518  	return b.chain.GetBlockByHash(hash), nil
   519  }
   520  func (b testBackend) BlockByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*types.Block, error) {
   521  	if blockNr, ok := blockNrOrHash.Number(); ok {
   522  		return b.BlockByNumber(ctx, blockNr)
   523  	}
   524  	if blockHash, ok := blockNrOrHash.Hash(); ok {
   525  		return b.BlockByHash(ctx, blockHash)
   526  	}
   527  	panic("unknown type rpc.BlockNumberOrHash")
   528  }
   529  func (b testBackend) GetBody(ctx context.Context, hash common.Hash, number rpc.BlockNumber) (*types.Body, error) {
   530  	return b.chain.GetBlock(hash, uint64(number.Int64())).Body(), nil
   531  }
   532  func (b testBackend) StateAndHeaderByNumber(ctx context.Context, number rpc.BlockNumber) (*state.StateDB, *types.Header, error) {
   533  	if number == rpc.PendingBlockNumber {
   534  		panic("pending state not implemented")
   535  	}
   536  	header, err := b.HeaderByNumber(ctx, number)
   537  	if err != nil {
   538  		return nil, nil, err
   539  	}
   540  	if header == nil {
   541  		return nil, nil, errors.New("header not found")
   542  	}
   543  	stateDb, err := b.chain.StateAt(header.Root)
   544  	return stateDb, header, err
   545  }
   546  func (b testBackend) StateAndHeaderByNumberOrHash(ctx context.Context, blockNrOrHash rpc.BlockNumberOrHash) (*state.StateDB, *types.Header, error) {
   547  	if blockNr, ok := blockNrOrHash.Number(); ok {
   548  		return b.StateAndHeaderByNumber(ctx, blockNr)
   549  	}
   550  	panic("only implemented for number")
   551  }
   552  func (b testBackend) Pending() (*types.Block, types.Receipts, *state.StateDB) { panic("implement me") }
   553  func (b testBackend) GetReceipts(ctx context.Context, hash common.Hash) (types.Receipts, error) {
   554  	header, err := b.HeaderByHash(ctx, hash)
   555  	if header == nil || err != nil {
   556  		return nil, err
   557  	}
   558  	receipts := rawdb.ReadReceipts(b.db, hash, header.Number.Uint64(), header.Time, b.chain.Config())
   559  	return receipts, nil
   560  }
   561  func (b testBackend) GetTd(ctx context.Context, hash common.Hash) *big.Int {
   562  	if b.pending != nil && hash == b.pending.Hash() {
   563  		return nil
   564  	}
   565  	return big.NewInt(1)
   566  }
   567  func (b testBackend) GetEVM(ctx context.Context, msg *core.Message, state *state.StateDB, header *types.Header, vmConfig *vm.Config, blockContext *vm.BlockContext) *vm.EVM {
   568  	if vmConfig == nil {
   569  		vmConfig = b.chain.GetVMConfig()
   570  	}
   571  	txContext := core.NewEVMTxContext(msg)
   572  	context := core.NewEVMBlockContext(header, b.chain, nil)
   573  	if blockContext != nil {
   574  		context = *blockContext
   575  	}
   576  	return vm.NewEVM(context, txContext, state, b.chain.Config(), *vmConfig)
   577  }
   578  func (b testBackend) SubscribeChainEvent(ch chan<- core.ChainEvent) event.Subscription {
   579  	panic("implement me")
   580  }
   581  func (b testBackend) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription {
   582  	panic("implement me")
   583  }
   584  func (b testBackend) SubscribeChainSideEvent(ch chan<- core.ChainSideEvent) event.Subscription {
   585  	panic("implement me")
   586  }
   587  func (b testBackend) SendTx(ctx context.Context, signedTx *types.Transaction) error {
   588  	panic("implement me")
   589  }
   590  func (b testBackend) GetTransaction(ctx context.Context, txHash common.Hash) (bool, *types.Transaction, common.Hash, uint64, uint64, error) {
   591  	tx, blockHash, blockNumber, index := rawdb.ReadTransaction(b.db, txHash)
   592  	return true, tx, blockHash, blockNumber, index, nil
   593  }
   594  func (b testBackend) GetPoolTransactions() (types.Transactions, error)         { panic("implement me") }
   595  func (b testBackend) GetPoolTransaction(txHash common.Hash) *types.Transaction { panic("implement me") }
   596  func (b testBackend) GetPoolNonce(ctx context.Context, addr common.Address) (uint64, error) {
   597  	return 0, nil
   598  }
   599  func (b testBackend) Stats() (pending int, queued int) { panic("implement me") }
   600  func (b testBackend) TxPoolContent() (map[common.Address][]*types.Transaction, map[common.Address][]*types.Transaction) {
   601  	panic("implement me")
   602  }
   603  func (b testBackend) TxPoolContentFrom(addr common.Address) ([]*types.Transaction, []*types.Transaction) {
   604  	panic("implement me")
   605  }
   606  func (b testBackend) SubscribeNewTxsEvent(events chan<- core.NewTxsEvent) event.Subscription {
   607  	panic("implement me")
   608  }
   609  func (b testBackend) ChainConfig() *params.ChainConfig { return b.chain.Config() }
   610  func (b testBackend) Engine() consensus.Engine         { return b.chain.Engine() }
   611  func (b testBackend) GetLogs(ctx context.Context, blockHash common.Hash, number uint64) ([][]*types.Log, error) {
   612  	panic("implement me")
   613  }
   614  func (b testBackend) SubscribeRemovedLogsEvent(ch chan<- core.RemovedLogsEvent) event.Subscription {
   615  	panic("implement me")
   616  }
   617  func (b testBackend) SubscribeLogsEvent(ch chan<- []*types.Log) event.Subscription {
   618  	panic("implement me")
   619  }
   620  func (b testBackend) BloomStatus() (uint64, uint64) { panic("implement me") }
   621  func (b testBackend) ServiceFilter(ctx context.Context, session *bloombits.MatcherSession) {
   622  	panic("implement me")
   623  }
   624  
   625  func TestEstimateGas(t *testing.T) {
   626  	t.Parallel()
   627  	// Initialize test accounts
   628  	var (
   629  		accounts = newAccounts(2)
   630  		genesis  = &core.Genesis{
   631  			Config: params.MergedTestChainConfig,
   632  			Alloc: types.GenesisAlloc{
   633  				accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   634  				accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   635  			},
   636  		}
   637  		genBlocks      = 10
   638  		signer         = types.HomesteadSigner{}
   639  		randomAccounts = newAccounts(2)
   640  	)
   641  	api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
   642  		// Transfer from account[0] to account[1]
   643  		//    value: 1000 wei
   644  		//    fee:   0 wei
   645  		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)
   646  		b.AddTx(tx)
   647  		b.SetPoS()
   648  	}))
   649  	var testSuite = []struct {
   650  		blockNumber rpc.BlockNumber
   651  		call        TransactionArgs
   652  		overrides   StateOverride
   653  		expectErr   error
   654  		want        uint64
   655  	}{
   656  		// simple transfer on latest block
   657  		{
   658  			blockNumber: rpc.LatestBlockNumber,
   659  			call: TransactionArgs{
   660  				From:  &accounts[0].addr,
   661  				To:    &accounts[1].addr,
   662  				Value: (*hexutil.Big)(big.NewInt(1000)),
   663  			},
   664  			expectErr: nil,
   665  			want:      21000,
   666  		},
   667  		// simple transfer with insufficient funds on latest block
   668  		{
   669  			blockNumber: rpc.LatestBlockNumber,
   670  			call: TransactionArgs{
   671  				From:  &randomAccounts[0].addr,
   672  				To:    &accounts[1].addr,
   673  				Value: (*hexutil.Big)(big.NewInt(1000)),
   674  			},
   675  			expectErr: core.ErrInsufficientFunds,
   676  			want:      21000,
   677  		},
   678  		// empty create
   679  		{
   680  			blockNumber: rpc.LatestBlockNumber,
   681  			call:        TransactionArgs{},
   682  			expectErr:   nil,
   683  			want:        53000,
   684  		},
   685  		{
   686  			blockNumber: rpc.LatestBlockNumber,
   687  			call:        TransactionArgs{},
   688  			overrides: StateOverride{
   689  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
   690  			},
   691  			expectErr: nil,
   692  			want:      53000,
   693  		},
   694  		{
   695  			blockNumber: rpc.LatestBlockNumber,
   696  			call: TransactionArgs{
   697  				From:  &randomAccounts[0].addr,
   698  				To:    &randomAccounts[1].addr,
   699  				Value: (*hexutil.Big)(big.NewInt(1000)),
   700  			},
   701  			overrides: StateOverride{
   702  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(big.NewInt(0))},
   703  			},
   704  			expectErr: core.ErrInsufficientFunds,
   705  		},
   706  		// Test for a bug where the gas price was set to zero but the basefee non-zero
   707  		//
   708  		// contract BasefeeChecker {
   709  		//    constructor() {
   710  		//        require(tx.gasprice >= block.basefee);
   711  		//        if (tx.gasprice > 0) {
   712  		//            require(block.basefee > 0);
   713  		//        }
   714  		//    }
   715  		//}
   716  		{
   717  			blockNumber: rpc.LatestBlockNumber,
   718  			call: TransactionArgs{
   719  				From:     &accounts[0].addr,
   720  				Input:    hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
   721  				GasPrice: (*hexutil.Big)(big.NewInt(1_000_000_000)), // Legacy as pricing
   722  			},
   723  			expectErr: nil,
   724  			want:      67617,
   725  		},
   726  		{
   727  			blockNumber: rpc.LatestBlockNumber,
   728  			call: TransactionArgs{
   729  				From:         &accounts[0].addr,
   730  				Input:        hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
   731  				MaxFeePerGas: (*hexutil.Big)(big.NewInt(1_000_000_000)), // 1559 gas pricing
   732  			},
   733  			expectErr: nil,
   734  			want:      67617,
   735  		},
   736  		{
   737  			blockNumber: rpc.LatestBlockNumber,
   738  			call: TransactionArgs{
   739  				From:         &accounts[0].addr,
   740  				Input:        hex2Bytes("6080604052348015600f57600080fd5b50483a1015601c57600080fd5b60003a111560315760004811603057600080fd5b5b603f80603e6000396000f3fe6080604052600080fdfea264697066735822122060729c2cee02b10748fae5200f1c9da4661963354973d9154c13a8e9ce9dee1564736f6c63430008130033"),
   741  				GasPrice:     nil, // No legacy gas pricing
   742  				MaxFeePerGas: nil, // No 1559 gas pricing
   743  			},
   744  			expectErr: nil,
   745  			want:      67595,
   746  		},
   747  		// Blobs should have no effect on gas estimate
   748  		{
   749  			blockNumber: rpc.LatestBlockNumber,
   750  			call: TransactionArgs{
   751  				From:       &accounts[0].addr,
   752  				To:         &accounts[1].addr,
   753  				Value:      (*hexutil.Big)(big.NewInt(1)),
   754  				BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
   755  				BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
   756  			},
   757  			want: 21000,
   758  		},
   759  	}
   760  	for i, tc := range testSuite {
   761  		result, err := api.EstimateGas(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides)
   762  		if tc.expectErr != nil {
   763  			if err == nil {
   764  				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
   765  				continue
   766  			}
   767  			if !errors.Is(err, tc.expectErr) {
   768  				t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
   769  			}
   770  			continue
   771  		}
   772  		if err != nil {
   773  			t.Errorf("test %d: want no error, have %v", i, err)
   774  			continue
   775  		}
   776  		if float64(result) > float64(tc.want)*(1+estimateGasErrorRatio) {
   777  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, uint64(result), tc.want)
   778  		}
   779  	}
   780  }
   781  
   782  func TestCall(t *testing.T) {
   783  	t.Parallel()
   784  	// Initialize test accounts
   785  	var (
   786  		accounts = newAccounts(3)
   787  		genesis  = &core.Genesis{
   788  			Config: params.MergedTestChainConfig,
   789  			Alloc: types.GenesisAlloc{
   790  				accounts[0].addr: {Balance: big.NewInt(params.Ether)},
   791  				accounts[1].addr: {Balance: big.NewInt(params.Ether)},
   792  				accounts[2].addr: {Balance: big.NewInt(params.Ether)},
   793  			},
   794  		}
   795  		genBlocks = 10
   796  		signer    = types.HomesteadSigner{}
   797  	)
   798  	api := NewBlockChainAPI(newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
   799  		// Transfer from account[0] to account[1]
   800  		//    value: 1000 wei
   801  		//    fee:   0 wei
   802  		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)
   803  		b.AddTx(tx)
   804  		b.SetPoS()
   805  	}))
   806  	randomAccounts := newAccounts(3)
   807  	var testSuite = []struct {
   808  		blockNumber    rpc.BlockNumber
   809  		overrides      StateOverride
   810  		call           TransactionArgs
   811  		blockOverrides BlockOverrides
   812  		expectErr      error
   813  		want           string
   814  	}{
   815  		// transfer on genesis
   816  		{
   817  			blockNumber: rpc.BlockNumber(0),
   818  			call: TransactionArgs{
   819  				From:  &accounts[0].addr,
   820  				To:    &accounts[1].addr,
   821  				Value: (*hexutil.Big)(big.NewInt(1000)),
   822  			},
   823  			expectErr: nil,
   824  			want:      "0x",
   825  		},
   826  		// transfer on the head
   827  		{
   828  			blockNumber: rpc.BlockNumber(genBlocks),
   829  			call: TransactionArgs{
   830  				From:  &accounts[0].addr,
   831  				To:    &accounts[1].addr,
   832  				Value: (*hexutil.Big)(big.NewInt(1000)),
   833  			},
   834  			expectErr: nil,
   835  			want:      "0x",
   836  		},
   837  		// transfer on a non-existent block, error expects
   838  		{
   839  			blockNumber: rpc.BlockNumber(genBlocks + 1),
   840  			call: TransactionArgs{
   841  				From:  &accounts[0].addr,
   842  				To:    &accounts[1].addr,
   843  				Value: (*hexutil.Big)(big.NewInt(1000)),
   844  			},
   845  			expectErr: errors.New("header not found"),
   846  		},
   847  		// transfer on the latest block
   848  		{
   849  			blockNumber: rpc.LatestBlockNumber,
   850  			call: TransactionArgs{
   851  				From:  &accounts[0].addr,
   852  				To:    &accounts[1].addr,
   853  				Value: (*hexutil.Big)(big.NewInt(1000)),
   854  			},
   855  			expectErr: nil,
   856  			want:      "0x",
   857  		},
   858  		// Call which can only succeed if state is state overridden
   859  		{
   860  			blockNumber: rpc.LatestBlockNumber,
   861  			call: TransactionArgs{
   862  				From:  &randomAccounts[0].addr,
   863  				To:    &randomAccounts[1].addr,
   864  				Value: (*hexutil.Big)(big.NewInt(1000)),
   865  			},
   866  			overrides: StateOverride{
   867  				randomAccounts[0].addr: OverrideAccount{Balance: newRPCBalance(new(big.Int).Mul(big.NewInt(1), big.NewInt(params.Ether)))},
   868  			},
   869  			want: "0x",
   870  		},
   871  		// Invalid call without state overriding
   872  		{
   873  			blockNumber: rpc.LatestBlockNumber,
   874  			call: TransactionArgs{
   875  				From:  &randomAccounts[0].addr,
   876  				To:    &randomAccounts[1].addr,
   877  				Value: (*hexutil.Big)(big.NewInt(1000)),
   878  			},
   879  			expectErr: core.ErrInsufficientFunds,
   880  		},
   881  		// Successful simple contract call
   882  		//
   883  		// // SPDX-License-Identifier: GPL-3.0
   884  		//
   885  		//  pragma solidity >=0.7.0 <0.8.0;
   886  		//
   887  		//  /**
   888  		//   * @title Storage
   889  		//   * @dev Store & retrieve value in a variable
   890  		//   */
   891  		//  contract Storage {
   892  		//      uint256 public number;
   893  		//      constructor() {
   894  		//          number = block.number;
   895  		//      }
   896  		//  }
   897  		{
   898  			blockNumber: rpc.LatestBlockNumber,
   899  			call: TransactionArgs{
   900  				From: &randomAccounts[0].addr,
   901  				To:   &randomAccounts[2].addr,
   902  				Data: hex2Bytes("8381f58a"), // call number()
   903  			},
   904  			overrides: StateOverride{
   905  				randomAccounts[2].addr: OverrideAccount{
   906  					Code:      hex2Bytes("6080604052348015600f57600080fd5b506004361060285760003560e01c80638381f58a14602d575b600080fd5b60336049565b6040518082815260200191505060405180910390f35b6000548156fea2646970667358221220eab35ffa6ab2adfe380772a48b8ba78e82a1b820a18fcb6f59aa4efb20a5f60064736f6c63430007040033"),
   907  					StateDiff: &map[common.Hash]common.Hash{{}: common.BigToHash(big.NewInt(123))},
   908  				},
   909  			},
   910  			want: "0x000000000000000000000000000000000000000000000000000000000000007b",
   911  		},
   912  		// Block overrides should work
   913  		{
   914  			blockNumber: rpc.LatestBlockNumber,
   915  			call: TransactionArgs{
   916  				From: &accounts[1].addr,
   917  				Input: &hexutil.Bytes{
   918  					0x43,             // NUMBER
   919  					0x60, 0x00, 0x52, // MSTORE offset 0
   920  					0x60, 0x20, 0x60, 0x00, 0xf3,
   921  				},
   922  			},
   923  			blockOverrides: BlockOverrides{Number: (*hexutil.Big)(big.NewInt(11))},
   924  			want:           "0x000000000000000000000000000000000000000000000000000000000000000b",
   925  		},
   926  		// Invalid blob tx
   927  		{
   928  			blockNumber: rpc.LatestBlockNumber,
   929  			call: TransactionArgs{
   930  				From:       &accounts[1].addr,
   931  				Input:      &hexutil.Bytes{0x00},
   932  				BlobHashes: []common.Hash{},
   933  			},
   934  			expectErr: core.ErrBlobTxCreate,
   935  		},
   936  		// BLOBHASH opcode
   937  		{
   938  			blockNumber: rpc.LatestBlockNumber,
   939  			call: TransactionArgs{
   940  				From:       &accounts[1].addr,
   941  				To:         &randomAccounts[2].addr,
   942  				BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
   943  				BlobFeeCap: (*hexutil.Big)(big.NewInt(1)),
   944  			},
   945  			overrides: StateOverride{
   946  				randomAccounts[2].addr: {
   947  					Code: hex2Bytes("60004960005260206000f3"),
   948  				},
   949  			},
   950  			want: "0x0122000000000000000000000000000000000000000000000000000000000000",
   951  		},
   952  	}
   953  	for i, tc := range testSuite {
   954  		result, err := api.Call(context.Background(), tc.call, &rpc.BlockNumberOrHash{BlockNumber: &tc.blockNumber}, &tc.overrides, &tc.blockOverrides)
   955  		if tc.expectErr != nil {
   956  			if err == nil {
   957  				t.Errorf("test %d: want error %v, have nothing", i, tc.expectErr)
   958  				continue
   959  			}
   960  			if !errors.Is(err, tc.expectErr) {
   961  				// Second try
   962  				if !reflect.DeepEqual(err, tc.expectErr) {
   963  					t.Errorf("test %d: error mismatch, want %v, have %v", i, tc.expectErr, err)
   964  				}
   965  			}
   966  			continue
   967  		}
   968  		if err != nil {
   969  			t.Errorf("test %d: want no error, have %v", i, err)
   970  			continue
   971  		}
   972  		if !reflect.DeepEqual(result.String(), tc.want) {
   973  			t.Errorf("test %d, result mismatch, have\n%v\n, want\n%v\n", i, result.String(), tc.want)
   974  		}
   975  	}
   976  }
   977  
   978  func TestSignTransaction(t *testing.T) {
   979  	t.Parallel()
   980  	// Initialize test accounts
   981  	var (
   982  		key, _  = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   983  		to      = crypto.PubkeyToAddress(key.PublicKey)
   984  		genesis = &core.Genesis{
   985  			Config: params.MergedTestChainConfig,
   986  			Alloc:  types.GenesisAlloc{},
   987  		}
   988  	)
   989  	b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
   990  		b.SetPoS()
   991  	})
   992  	api := NewTransactionAPI(b, nil)
   993  	res, err := api.FillTransaction(context.Background(), TransactionArgs{
   994  		From:  &b.acc.Address,
   995  		To:    &to,
   996  		Value: (*hexutil.Big)(big.NewInt(1)),
   997  	})
   998  	if err != nil {
   999  		t.Fatalf("failed to fill tx defaults: %v\n", err)
  1000  	}
  1001  
  1002  	res, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
  1003  	if err != nil {
  1004  		t.Fatalf("failed to sign tx: %v\n", err)
  1005  	}
  1006  	tx, err := json.Marshal(res.Tx)
  1007  	if err != nil {
  1008  		t.Fatal(err)
  1009  	}
  1010  	expect := `{"type":"0x2","chainId":"0x1","nonce":"0x0","to":"0x703c4b2bd70c169f5717101caee543299fc946c7","gas":"0x5208","gasPrice":null,"maxPriorityFeePerGas":"0x0","maxFeePerGas":"0x684ee180","value":"0x1","input":"0x","accessList":[],"v":"0x0","r":"0x8fabeb142d585dd9247f459f7e6fe77e2520c88d50ba5d220da1533cea8b34e1","s":"0x582dd68b21aef36ba23f34e49607329c20d981d30404daf749077f5606785ce7","yParity":"0x0","hash":"0x93927839207cfbec395da84b8a2bc38b7b65d2cb2819e9fef1f091f5b1d4cc8f"}`
  1011  	if !bytes.Equal(tx, []byte(expect)) {
  1012  		t.Errorf("result mismatch. Have:\n%s\nWant:\n%s\n", tx, expect)
  1013  	}
  1014  }
  1015  
  1016  func TestSignBlobTransaction(t *testing.T) {
  1017  	t.Parallel()
  1018  	// Initialize test accounts
  1019  	var (
  1020  		key, _  = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1021  		to      = crypto.PubkeyToAddress(key.PublicKey)
  1022  		genesis = &core.Genesis{
  1023  			Config: params.MergedTestChainConfig,
  1024  			Alloc:  types.GenesisAlloc{},
  1025  		}
  1026  	)
  1027  	b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
  1028  		b.SetPoS()
  1029  	})
  1030  	api := NewTransactionAPI(b, nil)
  1031  	res, err := api.FillTransaction(context.Background(), TransactionArgs{
  1032  		From:       &b.acc.Address,
  1033  		To:         &to,
  1034  		Value:      (*hexutil.Big)(big.NewInt(1)),
  1035  		BlobHashes: []common.Hash{{0x01, 0x22}},
  1036  	})
  1037  	if err != nil {
  1038  		t.Fatalf("failed to fill tx defaults: %v\n", err)
  1039  	}
  1040  
  1041  	_, err = api.SignTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
  1042  	if err != nil {
  1043  		t.Fatalf("should not fail on blob transaction")
  1044  	}
  1045  }
  1046  
  1047  func TestSendBlobTransaction(t *testing.T) {
  1048  	t.Parallel()
  1049  	// Initialize test accounts
  1050  	var (
  1051  		key, _  = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1052  		to      = crypto.PubkeyToAddress(key.PublicKey)
  1053  		genesis = &core.Genesis{
  1054  			Config: params.MergedTestChainConfig,
  1055  			Alloc:  types.GenesisAlloc{},
  1056  		}
  1057  	)
  1058  	b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
  1059  		b.SetPoS()
  1060  	})
  1061  	api := NewTransactionAPI(b, nil)
  1062  	res, err := api.FillTransaction(context.Background(), TransactionArgs{
  1063  		From:       &b.acc.Address,
  1064  		To:         &to,
  1065  		Value:      (*hexutil.Big)(big.NewInt(1)),
  1066  		BlobHashes: []common.Hash{common.Hash{0x01, 0x22}},
  1067  	})
  1068  	if err != nil {
  1069  		t.Fatalf("failed to fill tx defaults: %v\n", err)
  1070  	}
  1071  
  1072  	_, err = api.SendTransaction(context.Background(), argsFromTransaction(res.Tx, b.acc.Address))
  1073  	if err == nil {
  1074  		t.Errorf("sending tx should have failed")
  1075  	} else if !errors.Is(err, errBlobTxNotSupported) {
  1076  		t.Errorf("unexpected error. Have %v, want %v\n", err, errBlobTxNotSupported)
  1077  	}
  1078  }
  1079  
  1080  func TestFillBlobTransaction(t *testing.T) {
  1081  	t.Parallel()
  1082  	// Initialize test accounts
  1083  	var (
  1084  		key, _  = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1085  		to      = crypto.PubkeyToAddress(key.PublicKey)
  1086  		genesis = &core.Genesis{
  1087  			Config: params.MergedTestChainConfig,
  1088  			Alloc:  types.GenesisAlloc{},
  1089  		}
  1090  		emptyBlob                      = new(kzg4844.Blob)
  1091  		emptyBlobs                     = []kzg4844.Blob{*emptyBlob}
  1092  		emptyBlobCommit, _             = kzg4844.BlobToCommitment(emptyBlob)
  1093  		emptyBlobProof, _              = kzg4844.ComputeBlobProof(emptyBlob, emptyBlobCommit)
  1094  		emptyBlobHash      common.Hash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
  1095  	)
  1096  	b := newTestBackend(t, 1, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
  1097  		b.SetPoS()
  1098  	})
  1099  	api := NewTransactionAPI(b, nil)
  1100  	type result struct {
  1101  		Hashes  []common.Hash
  1102  		Sidecar *types.BlobTxSidecar
  1103  	}
  1104  	suite := []struct {
  1105  		name string
  1106  		args TransactionArgs
  1107  		err  string
  1108  		want *result
  1109  	}{
  1110  		{
  1111  			name: "TestInvalidParamsCombination1",
  1112  			args: TransactionArgs{
  1113  				From:   &b.acc.Address,
  1114  				To:     &to,
  1115  				Value:  (*hexutil.Big)(big.NewInt(1)),
  1116  				Blobs:  []kzg4844.Blob{{}},
  1117  				Proofs: []kzg4844.Proof{{}},
  1118  			},
  1119  			err: `blob proofs provided while commitments were not`,
  1120  		},
  1121  		{
  1122  			name: "TestInvalidParamsCombination2",
  1123  			args: TransactionArgs{
  1124  				From:        &b.acc.Address,
  1125  				To:          &to,
  1126  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1127  				Blobs:       []kzg4844.Blob{{}},
  1128  				Commitments: []kzg4844.Commitment{{}},
  1129  			},
  1130  			err: `blob commitments provided while proofs were not`,
  1131  		},
  1132  		{
  1133  			name: "TestInvalidParamsCount1",
  1134  			args: TransactionArgs{
  1135  				From:        &b.acc.Address,
  1136  				To:          &to,
  1137  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1138  				Blobs:       []kzg4844.Blob{{}},
  1139  				Commitments: []kzg4844.Commitment{{}, {}},
  1140  				Proofs:      []kzg4844.Proof{{}, {}},
  1141  			},
  1142  			err: `number of blobs and commitments mismatch (have=2, want=1)`,
  1143  		},
  1144  		{
  1145  			name: "TestInvalidParamsCount2",
  1146  			args: TransactionArgs{
  1147  				From:        &b.acc.Address,
  1148  				To:          &to,
  1149  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1150  				Blobs:       []kzg4844.Blob{{}, {}},
  1151  				Commitments: []kzg4844.Commitment{{}, {}},
  1152  				Proofs:      []kzg4844.Proof{{}},
  1153  			},
  1154  			err: `number of blobs and proofs mismatch (have=1, want=2)`,
  1155  		},
  1156  		{
  1157  			name: "TestInvalidProofVerification",
  1158  			args: TransactionArgs{
  1159  				From:        &b.acc.Address,
  1160  				To:          &to,
  1161  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1162  				Blobs:       []kzg4844.Blob{{}, {}},
  1163  				Commitments: []kzg4844.Commitment{{}, {}},
  1164  				Proofs:      []kzg4844.Proof{{}, {}},
  1165  			},
  1166  			err: `failed to verify blob proof: short buffer`,
  1167  		},
  1168  		{
  1169  			name: "TestGenerateBlobHashes",
  1170  			args: TransactionArgs{
  1171  				From:        &b.acc.Address,
  1172  				To:          &to,
  1173  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1174  				Blobs:       emptyBlobs,
  1175  				Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1176  				Proofs:      []kzg4844.Proof{emptyBlobProof},
  1177  			},
  1178  			want: &result{
  1179  				Hashes: []common.Hash{emptyBlobHash},
  1180  				Sidecar: &types.BlobTxSidecar{
  1181  					Blobs:       emptyBlobs,
  1182  					Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1183  					Proofs:      []kzg4844.Proof{emptyBlobProof},
  1184  				},
  1185  			},
  1186  		},
  1187  		{
  1188  			name: "TestValidBlobHashes",
  1189  			args: TransactionArgs{
  1190  				From:        &b.acc.Address,
  1191  				To:          &to,
  1192  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1193  				BlobHashes:  []common.Hash{emptyBlobHash},
  1194  				Blobs:       emptyBlobs,
  1195  				Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1196  				Proofs:      []kzg4844.Proof{emptyBlobProof},
  1197  			},
  1198  			want: &result{
  1199  				Hashes: []common.Hash{emptyBlobHash},
  1200  				Sidecar: &types.BlobTxSidecar{
  1201  					Blobs:       emptyBlobs,
  1202  					Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1203  					Proofs:      []kzg4844.Proof{emptyBlobProof},
  1204  				},
  1205  			},
  1206  		},
  1207  		{
  1208  			name: "TestInvalidBlobHashes",
  1209  			args: TransactionArgs{
  1210  				From:        &b.acc.Address,
  1211  				To:          &to,
  1212  				Value:       (*hexutil.Big)(big.NewInt(1)),
  1213  				BlobHashes:  []common.Hash{{0x01, 0x22}},
  1214  				Blobs:       emptyBlobs,
  1215  				Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1216  				Proofs:      []kzg4844.Proof{emptyBlobProof},
  1217  			},
  1218  			err: fmt.Sprintf("blob hash verification failed (have=%s, want=%s)", common.Hash{0x01, 0x22}, emptyBlobHash),
  1219  		},
  1220  		{
  1221  			name: "TestGenerateBlobProofs",
  1222  			args: TransactionArgs{
  1223  				From:  &b.acc.Address,
  1224  				To:    &to,
  1225  				Value: (*hexutil.Big)(big.NewInt(1)),
  1226  				Blobs: emptyBlobs,
  1227  			},
  1228  			want: &result{
  1229  				Hashes: []common.Hash{emptyBlobHash},
  1230  				Sidecar: &types.BlobTxSidecar{
  1231  					Blobs:       emptyBlobs,
  1232  					Commitments: []kzg4844.Commitment{emptyBlobCommit},
  1233  					Proofs:      []kzg4844.Proof{emptyBlobProof},
  1234  				},
  1235  			},
  1236  		},
  1237  	}
  1238  	for _, tc := range suite {
  1239  		t.Run(tc.name, func(t *testing.T) {
  1240  			res, err := api.FillTransaction(context.Background(), tc.args)
  1241  			if len(tc.err) > 0 {
  1242  				if err == nil {
  1243  					t.Fatalf("missing error. want: %s", tc.err)
  1244  				} else if err.Error() != tc.err {
  1245  					t.Fatalf("error mismatch. want: %s, have: %s", tc.err, err.Error())
  1246  				}
  1247  				return
  1248  			}
  1249  			if err != nil && len(tc.err) == 0 {
  1250  				t.Fatalf("expected no error. have: %s", err)
  1251  			}
  1252  			if res == nil {
  1253  				t.Fatal("result missing")
  1254  			}
  1255  			want, err := json.Marshal(tc.want)
  1256  			if err != nil {
  1257  				t.Fatalf("failed to encode expected: %v", err)
  1258  			}
  1259  			have, err := json.Marshal(result{Hashes: res.Tx.BlobHashes(), Sidecar: res.Tx.BlobTxSidecar()})
  1260  			if err != nil {
  1261  				t.Fatalf("failed to encode computed sidecar: %v", err)
  1262  			}
  1263  			if !bytes.Equal(have, want) {
  1264  				t.Errorf("blob sidecar mismatch. Have: %s, want: %s", have, want)
  1265  			}
  1266  		})
  1267  	}
  1268  }
  1269  
  1270  func argsFromTransaction(tx *types.Transaction, from common.Address) TransactionArgs {
  1271  	var (
  1272  		gas        = tx.Gas()
  1273  		nonce      = tx.Nonce()
  1274  		input      = tx.Data()
  1275  		accessList *types.AccessList
  1276  	)
  1277  	if acl := tx.AccessList(); acl != nil {
  1278  		accessList = &acl
  1279  	}
  1280  	return TransactionArgs{
  1281  		From:                 &from,
  1282  		To:                   tx.To(),
  1283  		Gas:                  (*hexutil.Uint64)(&gas),
  1284  		MaxFeePerGas:         (*hexutil.Big)(tx.GasFeeCap()),
  1285  		MaxPriorityFeePerGas: (*hexutil.Big)(tx.GasTipCap()),
  1286  		Value:                (*hexutil.Big)(tx.Value()),
  1287  		Nonce:                (*hexutil.Uint64)(&nonce),
  1288  		Input:                (*hexutil.Bytes)(&input),
  1289  		ChainID:              (*hexutil.Big)(tx.ChainId()),
  1290  		AccessList:           accessList,
  1291  		BlobFeeCap:           (*hexutil.Big)(tx.BlobGasFeeCap()),
  1292  		BlobHashes:           tx.BlobHashes(),
  1293  	}
  1294  }
  1295  
  1296  type account struct {
  1297  	key  *ecdsa.PrivateKey
  1298  	addr common.Address
  1299  }
  1300  
  1301  func newAccounts(n int) (accounts []account) {
  1302  	for i := 0; i < n; i++ {
  1303  		key, _ := crypto.GenerateKey()
  1304  		addr := crypto.PubkeyToAddress(key.PublicKey)
  1305  		accounts = append(accounts, account{key: key, addr: addr})
  1306  	}
  1307  	slices.SortFunc(accounts, func(a, b account) int { return a.addr.Cmp(b.addr) })
  1308  	return accounts
  1309  }
  1310  
  1311  func newRPCBalance(balance *big.Int) **hexutil.Big {
  1312  	rpcBalance := (*hexutil.Big)(balance)
  1313  	return &rpcBalance
  1314  }
  1315  
  1316  func hex2Bytes(str string) *hexutil.Bytes {
  1317  	rpcBytes := hexutil.Bytes(common.Hex2Bytes(str))
  1318  	return &rpcBytes
  1319  }
  1320  
  1321  func TestRPCMarshalBlock(t *testing.T) {
  1322  	t.Parallel()
  1323  	var (
  1324  		txs []*types.Transaction
  1325  		to  = common.BytesToAddress([]byte{0x11})
  1326  	)
  1327  	for i := uint64(1); i <= 4; i++ {
  1328  		var tx *types.Transaction
  1329  		if i%2 == 0 {
  1330  			tx = types.NewTx(&types.LegacyTx{
  1331  				Nonce:    i,
  1332  				GasPrice: big.NewInt(11111),
  1333  				Gas:      1111,
  1334  				To:       &to,
  1335  				Value:    big.NewInt(111),
  1336  				Data:     []byte{0x11, 0x11, 0x11},
  1337  			})
  1338  		} else {
  1339  			tx = types.NewTx(&types.AccessListTx{
  1340  				ChainID:  big.NewInt(1337),
  1341  				Nonce:    i,
  1342  				GasPrice: big.NewInt(11111),
  1343  				Gas:      1111,
  1344  				To:       &to,
  1345  				Value:    big.NewInt(111),
  1346  				Data:     []byte{0x11, 0x11, 0x11},
  1347  			})
  1348  		}
  1349  		txs = append(txs, tx)
  1350  	}
  1351  	block := types.NewBlock(&types.Header{Number: big.NewInt(100)}, &types.Body{Transactions: txs}, nil, blocktest.NewHasher())
  1352  
  1353  	var testSuite = []struct {
  1354  		inclTx bool
  1355  		fullTx bool
  1356  		want   string
  1357  	}{
  1358  		// without txs
  1359  		{
  1360  			inclTx: false,
  1361  			fullTx: false,
  1362  			want: `{
  1363  				"difficulty": "0x0",
  1364  				"extraData": "0x",
  1365  				"gasLimit": "0x0",
  1366  				"gasUsed": "0x0",
  1367  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1368  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  1369  				"miner": "0x0000000000000000000000000000000000000000",
  1370  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1371  				"nonce": "0x0000000000000000",
  1372  				"number": "0x64",
  1373  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1374  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  1375  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  1376  				"size": "0x296",
  1377  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1378  				"timestamp": "0x0",
  1379  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
  1380  				"uncles": []
  1381  			}`,
  1382  		},
  1383  		// only tx hashes
  1384  		{
  1385  			inclTx: true,
  1386  			fullTx: false,
  1387  			want: `{
  1388  				"difficulty": "0x0",
  1389  				"extraData": "0x",
  1390  				"gasLimit": "0x0",
  1391  				"gasUsed": "0x0",
  1392  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1393  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  1394  				"miner": "0x0000000000000000000000000000000000000000",
  1395  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1396  				"nonce": "0x0000000000000000",
  1397  				"number": "0x64",
  1398  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1399  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  1400  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  1401  				"size": "0x296",
  1402  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1403  				"timestamp": "0x0",
  1404  				"transactions": [
  1405  					"0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605",
  1406  					"0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4",
  1407  					"0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5",
  1408  					"0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1"
  1409  				],
  1410  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
  1411  				"uncles": []
  1412  			}`,
  1413  		},
  1414  		// full tx details
  1415  		{
  1416  			inclTx: true,
  1417  			fullTx: true,
  1418  			want: `{
  1419  				"difficulty": "0x0",
  1420  				"extraData": "0x",
  1421  				"gasLimit": "0x0",
  1422  				"gasUsed": "0x0",
  1423  				"hash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1424  				"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
  1425  				"miner": "0x0000000000000000000000000000000000000000",
  1426  				"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1427  				"nonce": "0x0000000000000000",
  1428  				"number": "0x64",
  1429  				"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1430  				"receiptsRoot": "0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421",
  1431  				"sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
  1432  				"size": "0x296",
  1433  				"stateRoot": "0x0000000000000000000000000000000000000000000000000000000000000000",
  1434  				"timestamp": "0x0",
  1435  				"transactions": [
  1436  					{
  1437  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1438  						"blockNumber": "0x64",
  1439  						"from": "0x0000000000000000000000000000000000000000",
  1440  						"gas": "0x457",
  1441  						"gasPrice": "0x2b67",
  1442  						"hash": "0x7d39df979e34172322c64983a9ad48302c2b889e55bda35324afecf043a77605",
  1443  						"input": "0x111111",
  1444  						"nonce": "0x1",
  1445  						"to": "0x0000000000000000000000000000000000000011",
  1446  						"transactionIndex": "0x0",
  1447  						"value": "0x6f",
  1448  						"type": "0x1",
  1449  						"accessList": [],
  1450  						"chainId": "0x539",
  1451  						"v": "0x0",
  1452  						"r": "0x0",
  1453  						"s": "0x0",
  1454  						"yParity": "0x0"
  1455  					},
  1456  					{
  1457  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1458  						"blockNumber": "0x64",
  1459  						"from": "0x0000000000000000000000000000000000000000",
  1460  						"gas": "0x457",
  1461  						"gasPrice": "0x2b67",
  1462  						"hash": "0x9bba4c34e57c875ff57ac8d172805a26ae912006985395dc1bdf8f44140a7bf4",
  1463  						"input": "0x111111",
  1464  						"nonce": "0x2",
  1465  						"to": "0x0000000000000000000000000000000000000011",
  1466  						"transactionIndex": "0x1",
  1467  						"value": "0x6f",
  1468  						"type": "0x0",
  1469  						"chainId": "0x7fffffffffffffee",
  1470  						"v": "0x0",
  1471  						"r": "0x0",
  1472  						"s": "0x0"
  1473  					},
  1474  					{
  1475  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1476  						"blockNumber": "0x64",
  1477  						"from": "0x0000000000000000000000000000000000000000",
  1478  						"gas": "0x457",
  1479  						"gasPrice": "0x2b67",
  1480  						"hash": "0x98909ea1ff040da6be56bc4231d484de1414b3c1dac372d69293a4beb9032cb5",
  1481  						"input": "0x111111",
  1482  						"nonce": "0x3",
  1483  						"to": "0x0000000000000000000000000000000000000011",
  1484  						"transactionIndex": "0x2",
  1485  						"value": "0x6f",
  1486  						"type": "0x1",
  1487  						"accessList": [],
  1488  						"chainId": "0x539",
  1489  						"v": "0x0",
  1490  						"r": "0x0",
  1491  						"s": "0x0",
  1492  						"yParity": "0x0"
  1493  					},
  1494  					{
  1495  						"blockHash": "0x9b73c83b25d0faf7eab854e3684c7e394336d6e135625aafa5c183f27baa8fee",
  1496  						"blockNumber": "0x64",
  1497  						"from": "0x0000000000000000000000000000000000000000",
  1498  						"gas": "0x457",
  1499  						"gasPrice": "0x2b67",
  1500  						"hash": "0x12e1f81207b40c3bdcc13c0ee18f5f86af6d31754d57a0ea1b0d4cfef21abef1",
  1501  						"input": "0x111111",
  1502  						"nonce": "0x4",
  1503  						"to": "0x0000000000000000000000000000000000000011",
  1504  						"transactionIndex": "0x3",
  1505  						"value": "0x6f",
  1506  						"type": "0x0",
  1507  						"chainId": "0x7fffffffffffffee",
  1508  						"v": "0x0",
  1509  						"r": "0x0",
  1510  						"s": "0x0"
  1511  					}
  1512  				],
  1513  				"transactionsRoot": "0x661a9febcfa8f1890af549b874faf9fa274aede26ef489d9db0b25daa569450e",
  1514  				"uncles": []
  1515  			}`,
  1516  		},
  1517  	}
  1518  
  1519  	for i, tc := range testSuite {
  1520  		resp := RPCMarshalBlock(block, tc.inclTx, tc.fullTx, params.MainnetChainConfig)
  1521  		out, err := json.Marshal(resp)
  1522  		if err != nil {
  1523  			t.Errorf("test %d: json marshal error: %v", i, err)
  1524  			continue
  1525  		}
  1526  		require.JSONEqf(t, tc.want, string(out), "test %d", i)
  1527  	}
  1528  }
  1529  
  1530  func TestRPCGetBlockOrHeader(t *testing.T) {
  1531  	t.Parallel()
  1532  
  1533  	// Initialize test accounts
  1534  	var (
  1535  		acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1536  		acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
  1537  		acc1Addr   = crypto.PubkeyToAddress(acc1Key.PublicKey)
  1538  		acc2Addr   = crypto.PubkeyToAddress(acc2Key.PublicKey)
  1539  		genesis    = &core.Genesis{
  1540  			Config: params.TestChainConfig,
  1541  			Alloc: types.GenesisAlloc{
  1542  				acc1Addr: {Balance: big.NewInt(params.Ether)},
  1543  				acc2Addr: {Balance: big.NewInt(params.Ether)},
  1544  			},
  1545  		}
  1546  		genBlocks = 10
  1547  		signer    = types.HomesteadSigner{}
  1548  		tx        = types.NewTx(&types.LegacyTx{
  1549  			Nonce:    11,
  1550  			GasPrice: big.NewInt(11111),
  1551  			Gas:      1111,
  1552  			To:       &acc2Addr,
  1553  			Value:    big.NewInt(111),
  1554  			Data:     []byte{0x11, 0x11, 0x11},
  1555  		})
  1556  		withdrawal = &types.Withdrawal{
  1557  			Index:     0,
  1558  			Validator: 1,
  1559  			Address:   common.Address{0x12, 0x34},
  1560  			Amount:    10,
  1561  		}
  1562  		pending = types.NewBlock(&types.Header{Number: big.NewInt(11), Time: 42}, &types.Body{Transactions: types.Transactions{tx}, Withdrawals: types.Withdrawals{withdrawal}}, nil, blocktest.NewHasher())
  1563  	)
  1564  	backend := newTestBackend(t, genBlocks, genesis, ethash.NewFaker(), func(i int, b *core.BlockGen) {
  1565  		// Transfer from account[0] to account[1]
  1566  		//    value: 1000 wei
  1567  		//    fee:   0 wei
  1568  		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)
  1569  		b.AddTx(tx)
  1570  	})
  1571  	backend.setPendingBlock(pending)
  1572  	api := NewBlockChainAPI(backend)
  1573  	blockHashes := make([]common.Hash, genBlocks+1)
  1574  	ctx := context.Background()
  1575  	for i := 0; i <= genBlocks; i++ {
  1576  		header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i))
  1577  		if err != nil {
  1578  			t.Errorf("failed to get block: %d err: %v", i, err)
  1579  		}
  1580  		blockHashes[i] = header.Hash()
  1581  	}
  1582  	pendingHash := pending.Hash()
  1583  
  1584  	var testSuite = []struct {
  1585  		blockNumber rpc.BlockNumber
  1586  		blockHash   *common.Hash
  1587  		fullTx      bool
  1588  		reqHeader   bool
  1589  		file        string
  1590  		expectErr   error
  1591  	}{
  1592  		// 0. latest header
  1593  		{
  1594  			blockNumber: rpc.LatestBlockNumber,
  1595  			reqHeader:   true,
  1596  			file:        "tag-latest",
  1597  		},
  1598  		// 1. genesis header
  1599  		{
  1600  			blockNumber: rpc.BlockNumber(0),
  1601  			reqHeader:   true,
  1602  			file:        "number-0",
  1603  		},
  1604  		// 2. #1 header
  1605  		{
  1606  			blockNumber: rpc.BlockNumber(1),
  1607  			reqHeader:   true,
  1608  			file:        "number-1",
  1609  		},
  1610  		// 3. latest-1 header
  1611  		{
  1612  			blockNumber: rpc.BlockNumber(9),
  1613  			reqHeader:   true,
  1614  			file:        "number-latest-1",
  1615  		},
  1616  		// 4. latest+1 header
  1617  		{
  1618  			blockNumber: rpc.BlockNumber(11),
  1619  			reqHeader:   true,
  1620  			file:        "number-latest+1",
  1621  		},
  1622  		// 5. pending header
  1623  		{
  1624  			blockNumber: rpc.PendingBlockNumber,
  1625  			reqHeader:   true,
  1626  			file:        "tag-pending",
  1627  		},
  1628  		// 6. latest block
  1629  		{
  1630  			blockNumber: rpc.LatestBlockNumber,
  1631  			file:        "tag-latest",
  1632  		},
  1633  		// 7. genesis block
  1634  		{
  1635  			blockNumber: rpc.BlockNumber(0),
  1636  			file:        "number-0",
  1637  		},
  1638  		// 8. #1 block
  1639  		{
  1640  			blockNumber: rpc.BlockNumber(1),
  1641  			file:        "number-1",
  1642  		},
  1643  		// 9. latest-1 block
  1644  		{
  1645  			blockNumber: rpc.BlockNumber(9),
  1646  			fullTx:      true,
  1647  			file:        "number-latest-1",
  1648  		},
  1649  		// 10. latest+1 block
  1650  		{
  1651  			blockNumber: rpc.BlockNumber(11),
  1652  			fullTx:      true,
  1653  			file:        "number-latest+1",
  1654  		},
  1655  		// 11. pending block
  1656  		{
  1657  			blockNumber: rpc.PendingBlockNumber,
  1658  			file:        "tag-pending",
  1659  		},
  1660  		// 12. pending block + fullTx
  1661  		{
  1662  			blockNumber: rpc.PendingBlockNumber,
  1663  			fullTx:      true,
  1664  			file:        "tag-pending-fullTx",
  1665  		},
  1666  		// 13. latest header by hash
  1667  		{
  1668  			blockHash: &blockHashes[len(blockHashes)-1],
  1669  			reqHeader: true,
  1670  			file:      "hash-latest",
  1671  		},
  1672  		// 14. genesis header by hash
  1673  		{
  1674  			blockHash: &blockHashes[0],
  1675  			reqHeader: true,
  1676  			file:      "hash-0",
  1677  		},
  1678  		// 15. #1 header
  1679  		{
  1680  			blockHash: &blockHashes[1],
  1681  			reqHeader: true,
  1682  			file:      "hash-1",
  1683  		},
  1684  		// 16. latest-1 header
  1685  		{
  1686  			blockHash: &blockHashes[len(blockHashes)-2],
  1687  			reqHeader: true,
  1688  			file:      "hash-latest-1",
  1689  		},
  1690  		// 17. empty hash
  1691  		{
  1692  			blockHash: &common.Hash{},
  1693  			reqHeader: true,
  1694  			file:      "hash-empty",
  1695  		},
  1696  		// 18. pending hash
  1697  		{
  1698  			blockHash: &pendingHash,
  1699  			reqHeader: true,
  1700  			file:      `hash-pending`,
  1701  		},
  1702  		// 19. latest block
  1703  		{
  1704  			blockHash: &blockHashes[len(blockHashes)-1],
  1705  			file:      "hash-latest",
  1706  		},
  1707  		// 20. genesis block
  1708  		{
  1709  			blockHash: &blockHashes[0],
  1710  			file:      "hash-genesis",
  1711  		},
  1712  		// 21. #1 block
  1713  		{
  1714  			blockHash: &blockHashes[1],
  1715  			file:      "hash-1",
  1716  		},
  1717  		// 22. latest-1 block
  1718  		{
  1719  			blockHash: &blockHashes[len(blockHashes)-2],
  1720  			fullTx:    true,
  1721  			file:      "hash-latest-1-fullTx",
  1722  		},
  1723  		// 23. empty hash + body
  1724  		{
  1725  			blockHash: &common.Hash{},
  1726  			fullTx:    true,
  1727  			file:      "hash-empty-fullTx",
  1728  		},
  1729  		// 24. pending block
  1730  		{
  1731  			blockHash: &pendingHash,
  1732  			file:      `hash-pending`,
  1733  		},
  1734  		// 25. pending block + fullTx
  1735  		{
  1736  			blockHash: &pendingHash,
  1737  			fullTx:    true,
  1738  			file:      "hash-pending-fullTx",
  1739  		},
  1740  	}
  1741  
  1742  	for i, tt := range testSuite {
  1743  		var (
  1744  			result map[string]interface{}
  1745  			err    error
  1746  			rpc    string
  1747  		)
  1748  		if tt.blockHash != nil {
  1749  			if tt.reqHeader {
  1750  				result = api.GetHeaderByHash(context.Background(), *tt.blockHash)
  1751  				rpc = "eth_getHeaderByHash"
  1752  			} else {
  1753  				result, err = api.GetBlockByHash(context.Background(), *tt.blockHash, tt.fullTx)
  1754  				rpc = "eth_getBlockByHash"
  1755  			}
  1756  		} else {
  1757  			if tt.reqHeader {
  1758  				result, err = api.GetHeaderByNumber(context.Background(), tt.blockNumber)
  1759  				rpc = "eth_getHeaderByNumber"
  1760  			} else {
  1761  				result, err = api.GetBlockByNumber(context.Background(), tt.blockNumber, tt.fullTx)
  1762  				rpc = "eth_getBlockByNumber"
  1763  			}
  1764  		}
  1765  		if tt.expectErr != nil {
  1766  			if err == nil {
  1767  				t.Errorf("test %d: want error %v, have nothing", i, tt.expectErr)
  1768  				continue
  1769  			}
  1770  			if !errors.Is(err, tt.expectErr) {
  1771  				t.Errorf("test %d: error mismatch, want %v, have %v", i, tt.expectErr, err)
  1772  			}
  1773  			continue
  1774  		}
  1775  		if err != nil {
  1776  			t.Errorf("test %d: want no error, have %v", i, err)
  1777  			continue
  1778  		}
  1779  
  1780  		testRPCResponseWithFile(t, i, result, rpc, tt.file)
  1781  	}
  1782  }
  1783  
  1784  func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Hash) {
  1785  	config := *params.MergedTestChainConfig
  1786  	var (
  1787  		acc1Key, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
  1788  		acc2Key, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
  1789  		acc1Addr   = crypto.PubkeyToAddress(acc1Key.PublicKey)
  1790  		acc2Addr   = crypto.PubkeyToAddress(acc2Key.PublicKey)
  1791  		contract   = common.HexToAddress("0000000000000000000000000000000000031ec7")
  1792  		genesis    = &core.Genesis{
  1793  			Config:        &config,
  1794  			ExcessBlobGas: new(uint64),
  1795  			BlobGasUsed:   new(uint64),
  1796  			Alloc: types.GenesisAlloc{
  1797  				acc1Addr: {Balance: big.NewInt(params.Ether)},
  1798  				acc2Addr: {Balance: big.NewInt(params.Ether)},
  1799  				// // SPDX-License-Identifier: GPL-3.0
  1800  				// pragma solidity >=0.7.0 <0.9.0;
  1801  				//
  1802  				// contract Token {
  1803  				//     event Transfer(address indexed from, address indexed to, uint256 value);
  1804  				//     function transfer(address to, uint256 value) public returns (bool) {
  1805  				//         emit Transfer(msg.sender, to, value);
  1806  				//         return true;
  1807  				//     }
  1808  				// }
  1809  				contract: {Balance: big.NewInt(params.Ether), Code: common.FromHex("0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063a9059cbb14610030575b600080fd5b61004a6004803603810190610045919061016a565b610060565b60405161005791906101c5565b60405180910390f35b60008273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef846040516100bf91906101ef565b60405180910390a36001905092915050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000610101826100d6565b9050919050565b610111816100f6565b811461011c57600080fd5b50565b60008135905061012e81610108565b92915050565b6000819050919050565b61014781610134565b811461015257600080fd5b50565b6000813590506101648161013e565b92915050565b60008060408385031215610181576101806100d1565b5b600061018f8582860161011f565b92505060206101a085828601610155565b9150509250929050565b60008115159050919050565b6101bf816101aa565b82525050565b60006020820190506101da60008301846101b6565b92915050565b6101e981610134565b82525050565b600060208201905061020460008301846101e0565b9291505056fea2646970667358221220b469033f4b77b9565ee84e0a2f04d496b18160d26034d54f9487e57788fd36d564736f6c63430008120033")},
  1810  			},
  1811  		}
  1812  		signer   = types.LatestSignerForChainID(params.TestChainConfig.ChainID)
  1813  		txHashes = make([]common.Hash, genBlocks)
  1814  	)
  1815  
  1816  	backend := newTestBackend(t, genBlocks, genesis, beacon.New(ethash.NewFaker()), func(i int, b *core.BlockGen) {
  1817  		var (
  1818  			tx  *types.Transaction
  1819  			err error
  1820  		)
  1821  		b.SetPoS()
  1822  		switch i {
  1823  		case 0:
  1824  			// transfer 1000wei
  1825  			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)
  1826  		case 1:
  1827  			// create contract
  1828  			tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: nil, Gas: 53100, GasPrice: b.BaseFee(), Data: common.FromHex("0x60806040")}), signer, acc1Key)
  1829  		case 2:
  1830  			// with logs
  1831  			// transfer(address to, uint256 value)
  1832  			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:])
  1833  			tx, err = types.SignTx(types.NewTx(&types.LegacyTx{Nonce: uint64(i), To: &contract, Gas: 60000, GasPrice: b.BaseFee(), Data: common.FromHex(data)}), signer, acc1Key)
  1834  		case 3:
  1835  			// dynamic fee with logs
  1836  			// transfer(address to, uint256 value)
  1837  			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:])
  1838  			fee := big.NewInt(500)
  1839  			fee.Add(fee, b.BaseFee())
  1840  			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)
  1841  		case 4:
  1842  			// access list with contract create
  1843  			accessList := types.AccessList{{
  1844  				Address:     contract,
  1845  				StorageKeys: []common.Hash{{0}},
  1846  			}}
  1847  			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)
  1848  		case 5:
  1849  			// blob tx
  1850  			fee := big.NewInt(500)
  1851  			fee.Add(fee, b.BaseFee())
  1852  			tx, err = types.SignTx(types.NewTx(&types.BlobTx{
  1853  				Nonce:      uint64(i),
  1854  				GasTipCap:  uint256.NewInt(1),
  1855  				GasFeeCap:  uint256.MustFromBig(fee),
  1856  				Gas:        params.TxGas,
  1857  				To:         acc2Addr,
  1858  				BlobFeeCap: uint256.NewInt(1),
  1859  				BlobHashes: []common.Hash{{1}},
  1860  				Value:      new(uint256.Int),
  1861  			}), signer, acc1Key)
  1862  		}
  1863  		if err != nil {
  1864  			t.Errorf("failed to sign tx: %v", err)
  1865  		}
  1866  		if tx != nil {
  1867  			b.AddTx(tx)
  1868  			txHashes[i] = tx.Hash()
  1869  		}
  1870  	})
  1871  	return backend, txHashes
  1872  }
  1873  
  1874  func TestRPCGetTransactionReceipt(t *testing.T) {
  1875  	t.Parallel()
  1876  
  1877  	var (
  1878  		backend, txHashes = setupReceiptBackend(t, 6)
  1879  		api               = NewTransactionAPI(backend, new(AddrLocker))
  1880  	)
  1881  
  1882  	var testSuite = []struct {
  1883  		txHash common.Hash
  1884  		file   string
  1885  	}{
  1886  		// 0. normal success
  1887  		{
  1888  			txHash: txHashes[0],
  1889  			file:   "normal-transfer-tx",
  1890  		},
  1891  		// 1. create contract
  1892  		{
  1893  			txHash: txHashes[1],
  1894  			file:   "create-contract-tx",
  1895  		},
  1896  		// 2. with logs success
  1897  		{
  1898  			txHash: txHashes[2],
  1899  			file:   "with-logs",
  1900  		},
  1901  		// 3. dynamic tx with logs success
  1902  		{
  1903  			txHash: txHashes[3],
  1904  			file:   `dynamic-tx-with-logs`,
  1905  		},
  1906  		// 4. access list tx with create contract
  1907  		{
  1908  			txHash: txHashes[4],
  1909  			file:   "create-contract-with-access-list",
  1910  		},
  1911  		// 5. txhash empty
  1912  		{
  1913  			txHash: common.Hash{},
  1914  			file:   "txhash-empty",
  1915  		},
  1916  		// 6. txhash not found
  1917  		{
  1918  			txHash: common.HexToHash("deadbeef"),
  1919  			file:   "txhash-notfound",
  1920  		},
  1921  		// 7. blob tx
  1922  		{
  1923  			txHash: txHashes[5],
  1924  			file:   "blob-tx",
  1925  		},
  1926  	}
  1927  
  1928  	for i, tt := range testSuite {
  1929  		var (
  1930  			result interface{}
  1931  			err    error
  1932  		)
  1933  		result, err = api.GetTransactionReceipt(context.Background(), tt.txHash)
  1934  		if err != nil {
  1935  			t.Errorf("test %d: want no error, have %v", i, err)
  1936  			continue
  1937  		}
  1938  		testRPCResponseWithFile(t, i, result, "eth_getTransactionReceipt", tt.file)
  1939  	}
  1940  }
  1941  
  1942  func TestRPCGetBlockReceipts(t *testing.T) {
  1943  	t.Parallel()
  1944  
  1945  	var (
  1946  		genBlocks  = 6
  1947  		backend, _ = setupReceiptBackend(t, genBlocks)
  1948  		api        = NewBlockChainAPI(backend)
  1949  	)
  1950  	blockHashes := make([]common.Hash, genBlocks+1)
  1951  	ctx := context.Background()
  1952  	for i := 0; i <= genBlocks; i++ {
  1953  		header, err := backend.HeaderByNumber(ctx, rpc.BlockNumber(i))
  1954  		if err != nil {
  1955  			t.Errorf("failed to get block: %d err: %v", i, err)
  1956  		}
  1957  		blockHashes[i] = header.Hash()
  1958  	}
  1959  
  1960  	var testSuite = []struct {
  1961  		test rpc.BlockNumberOrHash
  1962  		file string
  1963  	}{
  1964  		// 0. block without any txs(hash)
  1965  		{
  1966  			test: rpc.BlockNumberOrHashWithHash(blockHashes[0], false),
  1967  			file: "number-0",
  1968  		},
  1969  		// 1. block without any txs(number)
  1970  		{
  1971  			test: rpc.BlockNumberOrHashWithNumber(0),
  1972  			file: "number-1",
  1973  		},
  1974  		// 2. earliest tag
  1975  		{
  1976  			test: rpc.BlockNumberOrHashWithNumber(rpc.EarliestBlockNumber),
  1977  			file: "tag-earliest",
  1978  		},
  1979  		// 3. latest tag
  1980  		{
  1981  			test: rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber),
  1982  			file: "tag-latest",
  1983  		},
  1984  		// 4. block with legacy transfer tx(hash)
  1985  		{
  1986  			test: rpc.BlockNumberOrHashWithHash(blockHashes[1], false),
  1987  			file: "block-with-legacy-transfer-tx",
  1988  		},
  1989  		// 5. block with contract create tx(number)
  1990  		{
  1991  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(2)),
  1992  			file: "block-with-contract-create-tx",
  1993  		},
  1994  		// 6. block with legacy contract call tx(hash)
  1995  		{
  1996  			test: rpc.BlockNumberOrHashWithHash(blockHashes[3], false),
  1997  			file: "block-with-legacy-contract-call-tx",
  1998  		},
  1999  		// 7. block with dynamic fee tx(number)
  2000  		{
  2001  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(4)),
  2002  			file: "block-with-dynamic-fee-tx",
  2003  		},
  2004  		// 8. block is empty
  2005  		{
  2006  			test: rpc.BlockNumberOrHashWithHash(common.Hash{}, false),
  2007  			file: "hash-empty",
  2008  		},
  2009  		// 9. block is not found
  2010  		{
  2011  			test: rpc.BlockNumberOrHashWithHash(common.HexToHash("deadbeef"), false),
  2012  			file: "hash-notfound",
  2013  		},
  2014  		// 10. block is not found
  2015  		{
  2016  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(genBlocks + 1)),
  2017  			file: "block-notfound",
  2018  		},
  2019  		// 11. block with blob tx
  2020  		{
  2021  			test: rpc.BlockNumberOrHashWithNumber(rpc.BlockNumber(6)),
  2022  			file: "block-with-blob-tx",
  2023  		},
  2024  	}
  2025  
  2026  	for i, tt := range testSuite {
  2027  		var (
  2028  			result interface{}
  2029  			err    error
  2030  		)
  2031  		result, err = api.GetBlockReceipts(context.Background(), tt.test)
  2032  		if err != nil {
  2033  			t.Errorf("test %d: want no error, have %v", i, err)
  2034  			continue
  2035  		}
  2036  		testRPCResponseWithFile(t, i, result, "eth_getBlockReceipts", tt.file)
  2037  	}
  2038  }
  2039  
  2040  func testRPCResponseWithFile(t *testing.T, testid int, result interface{}, rpc string, file string) {
  2041  	data, err := json.MarshalIndent(result, "", "  ")
  2042  	if err != nil {
  2043  		t.Errorf("test %d: json marshal error", testid)
  2044  		return
  2045  	}
  2046  	outputFile := filepath.Join("testdata", fmt.Sprintf("%s-%s.json", rpc, file))
  2047  	if os.Getenv("WRITE_TEST_FILES") != "" {
  2048  		os.WriteFile(outputFile, data, 0644)
  2049  	}
  2050  	want, err := os.ReadFile(outputFile)
  2051  	if err != nil {
  2052  		t.Fatalf("error reading expected test file: %s output: %v", outputFile, err)
  2053  	}
  2054  	require.JSONEqf(t, string(want), string(data), "test %d: json not match, want: %s, have: %s", testid, string(want), string(data))
  2055  }