github.com/ethereum/go-ethereum@v1.14.3/ethclient/ethclient_test.go (about)

     1  // Copyright 2016 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 ethclient
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"errors"
    23  	"math/big"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/ethereum/go-ethereum"
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/consensus/ethash"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  	"github.com/ethereum/go-ethereum/eth"
    35  	"github.com/ethereum/go-ethereum/eth/ethconfig"
    36  	"github.com/ethereum/go-ethereum/node"
    37  	"github.com/ethereum/go-ethereum/params"
    38  	"github.com/ethereum/go-ethereum/rpc"
    39  )
    40  
    41  // Verify that Client implements the ethereum interfaces.
    42  var (
    43  	_ = ethereum.ChainReader(&Client{})
    44  	_ = ethereum.TransactionReader(&Client{})
    45  	_ = ethereum.ChainStateReader(&Client{})
    46  	_ = ethereum.ChainSyncReader(&Client{})
    47  	_ = ethereum.ContractCaller(&Client{})
    48  	_ = ethereum.GasEstimator(&Client{})
    49  	_ = ethereum.GasPricer(&Client{})
    50  	_ = ethereum.LogFilterer(&Client{})
    51  	_ = ethereum.PendingStateReader(&Client{})
    52  	// _ = ethereum.PendingStateEventer(&Client{})
    53  	_ = ethereum.PendingContractCaller(&Client{})
    54  )
    55  
    56  func TestToFilterArg(t *testing.T) {
    57  	blockHashErr := errors.New("cannot specify both BlockHash and FromBlock/ToBlock")
    58  	addresses := []common.Address{
    59  		common.HexToAddress("0xD36722ADeC3EdCB29c8e7b5a47f352D701393462"),
    60  	}
    61  	blockHash := common.HexToHash(
    62  		"0xeb94bb7d78b73657a9d7a99792413f50c0a45c51fc62bdcb08a53f18e9a2b4eb",
    63  	)
    64  
    65  	for _, testCase := range []struct {
    66  		name   string
    67  		input  ethereum.FilterQuery
    68  		output interface{}
    69  		err    error
    70  	}{
    71  		{
    72  			"without BlockHash",
    73  			ethereum.FilterQuery{
    74  				Addresses: addresses,
    75  				FromBlock: big.NewInt(1),
    76  				ToBlock:   big.NewInt(2),
    77  				Topics:    [][]common.Hash{},
    78  			},
    79  			map[string]interface{}{
    80  				"address":   addresses,
    81  				"fromBlock": "0x1",
    82  				"toBlock":   "0x2",
    83  				"topics":    [][]common.Hash{},
    84  			},
    85  			nil,
    86  		},
    87  		{
    88  			"with nil fromBlock and nil toBlock",
    89  			ethereum.FilterQuery{
    90  				Addresses: addresses,
    91  				Topics:    [][]common.Hash{},
    92  			},
    93  			map[string]interface{}{
    94  				"address":   addresses,
    95  				"fromBlock": "0x0",
    96  				"toBlock":   "latest",
    97  				"topics":    [][]common.Hash{},
    98  			},
    99  			nil,
   100  		},
   101  		{
   102  			"with negative fromBlock and negative toBlock",
   103  			ethereum.FilterQuery{
   104  				Addresses: addresses,
   105  				FromBlock: big.NewInt(-1),
   106  				ToBlock:   big.NewInt(-1),
   107  				Topics:    [][]common.Hash{},
   108  			},
   109  			map[string]interface{}{
   110  				"address":   addresses,
   111  				"fromBlock": "pending",
   112  				"toBlock":   "pending",
   113  				"topics":    [][]common.Hash{},
   114  			},
   115  			nil,
   116  		},
   117  		{
   118  			"with blockhash",
   119  			ethereum.FilterQuery{
   120  				Addresses: addresses,
   121  				BlockHash: &blockHash,
   122  				Topics:    [][]common.Hash{},
   123  			},
   124  			map[string]interface{}{
   125  				"address":   addresses,
   126  				"blockHash": blockHash,
   127  				"topics":    [][]common.Hash{},
   128  			},
   129  			nil,
   130  		},
   131  		{
   132  			"with blockhash and from block",
   133  			ethereum.FilterQuery{
   134  				Addresses: addresses,
   135  				BlockHash: &blockHash,
   136  				FromBlock: big.NewInt(1),
   137  				Topics:    [][]common.Hash{},
   138  			},
   139  			nil,
   140  			blockHashErr,
   141  		},
   142  		{
   143  			"with blockhash and to block",
   144  			ethereum.FilterQuery{
   145  				Addresses: addresses,
   146  				BlockHash: &blockHash,
   147  				ToBlock:   big.NewInt(1),
   148  				Topics:    [][]common.Hash{},
   149  			},
   150  			nil,
   151  			blockHashErr,
   152  		},
   153  		{
   154  			"with blockhash and both from / to block",
   155  			ethereum.FilterQuery{
   156  				Addresses: addresses,
   157  				BlockHash: &blockHash,
   158  				FromBlock: big.NewInt(1),
   159  				ToBlock:   big.NewInt(2),
   160  				Topics:    [][]common.Hash{},
   161  			},
   162  			nil,
   163  			blockHashErr,
   164  		},
   165  	} {
   166  		t.Run(testCase.name, func(t *testing.T) {
   167  			output, err := toFilterArg(testCase.input)
   168  			if (testCase.err == nil) != (err == nil) {
   169  				t.Fatalf("expected error %v but got %v", testCase.err, err)
   170  			}
   171  			if testCase.err != nil {
   172  				if testCase.err.Error() != err.Error() {
   173  					t.Fatalf("expected error %v but got %v", testCase.err, err)
   174  				}
   175  			} else if !reflect.DeepEqual(testCase.output, output) {
   176  				t.Fatalf("expected filter arg %v but got %v", testCase.output, output)
   177  			}
   178  		})
   179  	}
   180  }
   181  
   182  var (
   183  	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   184  	testAddr    = crypto.PubkeyToAddress(testKey.PublicKey)
   185  	testBalance = big.NewInt(2e15)
   186  )
   187  
   188  var genesis = &core.Genesis{
   189  	Config:    params.AllEthashProtocolChanges,
   190  	Alloc:     types.GenesisAlloc{testAddr: {Balance: testBalance}},
   191  	ExtraData: []byte("test genesis"),
   192  	Timestamp: 9000,
   193  	BaseFee:   big.NewInt(params.InitialBaseFee),
   194  }
   195  
   196  var testTx1 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
   197  	Nonce:    0,
   198  	Value:    big.NewInt(12),
   199  	GasPrice: big.NewInt(params.InitialBaseFee),
   200  	Gas:      params.TxGas,
   201  	To:       &common.Address{2},
   202  })
   203  
   204  var testTx2 = types.MustSignNewTx(testKey, types.LatestSigner(genesis.Config), &types.LegacyTx{
   205  	Nonce:    1,
   206  	Value:    big.NewInt(8),
   207  	GasPrice: big.NewInt(params.InitialBaseFee),
   208  	Gas:      params.TxGas,
   209  	To:       &common.Address{2},
   210  })
   211  
   212  func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
   213  	// Generate test chain.
   214  	blocks := generateTestChain()
   215  
   216  	// Create node
   217  	n, err := node.New(&node.Config{})
   218  	if err != nil {
   219  		t.Fatalf("can't create new node: %v", err)
   220  	}
   221  	// Create Ethereum Service
   222  	config := &ethconfig.Config{Genesis: genesis}
   223  	ethservice, err := eth.New(n, config)
   224  	if err != nil {
   225  		t.Fatalf("can't create new ethereum service: %v", err)
   226  	}
   227  	// Import the test chain.
   228  	if err := n.Start(); err != nil {
   229  		t.Fatalf("can't start test node: %v", err)
   230  	}
   231  	if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
   232  		t.Fatalf("can't import test blocks: %v", err)
   233  	}
   234  	// Ensure the tx indexing is fully generated
   235  	for ; ; time.Sleep(time.Millisecond * 100) {
   236  		progress, err := ethservice.BlockChain().TxIndexProgress()
   237  		if err == nil && progress.Done() {
   238  			break
   239  		}
   240  	}
   241  	return n, blocks
   242  }
   243  
   244  func generateTestChain() []*types.Block {
   245  	generate := func(i int, g *core.BlockGen) {
   246  		g.OffsetTime(5)
   247  		g.SetExtra([]byte("test"))
   248  		if i == 1 {
   249  			// Test transactions are included in block #2.
   250  			g.AddTx(testTx1)
   251  			g.AddTx(testTx2)
   252  		}
   253  	}
   254  	_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate)
   255  	return append([]*types.Block{genesis.ToBlock()}, blocks...)
   256  }
   257  
   258  func TestEthClient(t *testing.T) {
   259  	backend, chain := newTestBackend(t)
   260  	client := backend.Attach()
   261  	defer backend.Close()
   262  	defer client.Close()
   263  
   264  	tests := map[string]struct {
   265  		test func(t *testing.T)
   266  	}{
   267  		"Header": {
   268  			func(t *testing.T) { testHeader(t, chain, client) },
   269  		},
   270  		"BalanceAt": {
   271  			func(t *testing.T) { testBalanceAt(t, client) },
   272  		},
   273  		"TxInBlockInterrupted": {
   274  			func(t *testing.T) { testTransactionInBlock(t, client) },
   275  		},
   276  		"ChainID": {
   277  			func(t *testing.T) { testChainID(t, client) },
   278  		},
   279  		"GetBlock": {
   280  			func(t *testing.T) { testGetBlock(t, client) },
   281  		},
   282  		"StatusFunctions": {
   283  			func(t *testing.T) { testStatusFunctions(t, client) },
   284  		},
   285  		"CallContract": {
   286  			func(t *testing.T) { testCallContract(t, client) },
   287  		},
   288  		"CallContractAtHash": {
   289  			func(t *testing.T) { testCallContractAtHash(t, client) },
   290  		},
   291  		"AtFunctions": {
   292  			func(t *testing.T) { testAtFunctions(t, client) },
   293  		},
   294  		"TransactionSender": {
   295  			func(t *testing.T) { testTransactionSender(t, client) },
   296  		},
   297  	}
   298  
   299  	t.Parallel()
   300  	for name, tt := range tests {
   301  		t.Run(name, tt.test)
   302  	}
   303  }
   304  
   305  func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
   306  	tests := map[string]struct {
   307  		block   *big.Int
   308  		want    *types.Header
   309  		wantErr error
   310  	}{
   311  		"genesis": {
   312  			block: big.NewInt(0),
   313  			want:  chain[0].Header(),
   314  		},
   315  		"first_block": {
   316  			block: big.NewInt(1),
   317  			want:  chain[1].Header(),
   318  		},
   319  		"future_block": {
   320  			block:   big.NewInt(1000000000),
   321  			want:    nil,
   322  			wantErr: ethereum.NotFound,
   323  		},
   324  	}
   325  	for name, tt := range tests {
   326  		t.Run(name, func(t *testing.T) {
   327  			ec := NewClient(client)
   328  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   329  			defer cancel()
   330  
   331  			got, err := ec.HeaderByNumber(ctx, tt.block)
   332  			if !errors.Is(err, tt.wantErr) {
   333  				t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
   334  			}
   335  			if got != nil && got.Number != nil && got.Number.Sign() == 0 {
   336  				got.Number = big.NewInt(0) // hack to make DeepEqual work
   337  			}
   338  			if !reflect.DeepEqual(got, tt.want) {
   339  				t.Fatalf("HeaderByNumber(%v) got = %v, want %v", tt.block, got, tt.want)
   340  			}
   341  		})
   342  	}
   343  }
   344  
   345  func testBalanceAt(t *testing.T, client *rpc.Client) {
   346  	tests := map[string]struct {
   347  		account common.Address
   348  		block   *big.Int
   349  		want    *big.Int
   350  		wantErr error
   351  	}{
   352  		"valid_account_genesis": {
   353  			account: testAddr,
   354  			block:   big.NewInt(0),
   355  			want:    testBalance,
   356  		},
   357  		"valid_account": {
   358  			account: testAddr,
   359  			block:   big.NewInt(1),
   360  			want:    testBalance,
   361  		},
   362  		"non_existent_account": {
   363  			account: common.Address{1},
   364  			block:   big.NewInt(1),
   365  			want:    big.NewInt(0),
   366  		},
   367  		"future_block": {
   368  			account: testAddr,
   369  			block:   big.NewInt(1000000000),
   370  			want:    big.NewInt(0),
   371  			wantErr: errors.New("header not found"),
   372  		},
   373  	}
   374  	for name, tt := range tests {
   375  		t.Run(name, func(t *testing.T) {
   376  			ec := NewClient(client)
   377  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   378  			defer cancel()
   379  
   380  			got, err := ec.BalanceAt(ctx, tt.account, tt.block)
   381  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   382  				t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
   383  			}
   384  			if got.Cmp(tt.want) != 0 {
   385  				t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
   386  			}
   387  		})
   388  	}
   389  }
   390  
   391  func testTransactionInBlock(t *testing.T, client *rpc.Client) {
   392  	ec := NewClient(client)
   393  
   394  	// Get current block by number.
   395  	block, err := ec.BlockByNumber(context.Background(), nil)
   396  	if err != nil {
   397  		t.Fatalf("unexpected error: %v", err)
   398  	}
   399  
   400  	// Test tx in block not found.
   401  	if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != ethereum.NotFound {
   402  		t.Fatal("error should be ethereum.NotFound")
   403  	}
   404  
   405  	// Test tx in block found.
   406  	tx, err := ec.TransactionInBlock(context.Background(), block.Hash(), 0)
   407  	if err != nil {
   408  		t.Fatalf("unexpected error: %v", err)
   409  	}
   410  	if tx.Hash() != testTx1.Hash() {
   411  		t.Fatalf("unexpected transaction: %v", tx)
   412  	}
   413  
   414  	tx, err = ec.TransactionInBlock(context.Background(), block.Hash(), 1)
   415  	if err != nil {
   416  		t.Fatalf("unexpected error: %v", err)
   417  	}
   418  	if tx.Hash() != testTx2.Hash() {
   419  		t.Fatalf("unexpected transaction: %v", tx)
   420  	}
   421  }
   422  
   423  func testChainID(t *testing.T, client *rpc.Client) {
   424  	ec := NewClient(client)
   425  	id, err := ec.ChainID(context.Background())
   426  	if err != nil {
   427  		t.Fatalf("unexpected error: %v", err)
   428  	}
   429  	if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
   430  		t.Fatalf("ChainID returned wrong number: %+v", id)
   431  	}
   432  }
   433  
   434  func testGetBlock(t *testing.T, client *rpc.Client) {
   435  	ec := NewClient(client)
   436  
   437  	// Get current block number
   438  	blockNumber, err := ec.BlockNumber(context.Background())
   439  	if err != nil {
   440  		t.Fatalf("unexpected error: %v", err)
   441  	}
   442  	if blockNumber != 2 {
   443  		t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
   444  	}
   445  	// Get current block by number
   446  	block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
   447  	if err != nil {
   448  		t.Fatalf("unexpected error: %v", err)
   449  	}
   450  	if block.NumberU64() != blockNumber {
   451  		t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
   452  	}
   453  	// Get current block by hash
   454  	blockH, err := ec.BlockByHash(context.Background(), block.Hash())
   455  	if err != nil {
   456  		t.Fatalf("unexpected error: %v", err)
   457  	}
   458  	if block.Hash() != blockH.Hash() {
   459  		t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
   460  	}
   461  	// Get header by number
   462  	header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
   463  	if err != nil {
   464  		t.Fatalf("unexpected error: %v", err)
   465  	}
   466  	if block.Header().Hash() != header.Hash() {
   467  		t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
   468  	}
   469  	// Get header by hash
   470  	headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
   471  	if err != nil {
   472  		t.Fatalf("unexpected error: %v", err)
   473  	}
   474  	if block.Header().Hash() != headerH.Hash() {
   475  		t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
   476  	}
   477  }
   478  
   479  func testStatusFunctions(t *testing.T, client *rpc.Client) {
   480  	ec := NewClient(client)
   481  
   482  	// Sync progress
   483  	progress, err := ec.SyncProgress(context.Background())
   484  	if err != nil {
   485  		t.Fatalf("unexpected error: %v", err)
   486  	}
   487  	if progress != nil {
   488  		t.Fatalf("unexpected progress: %v", progress)
   489  	}
   490  
   491  	// NetworkID
   492  	networkID, err := ec.NetworkID(context.Background())
   493  	if err != nil {
   494  		t.Fatalf("unexpected error: %v", err)
   495  	}
   496  	if networkID.Cmp(big.NewInt(1337)) != 0 {
   497  		t.Fatalf("unexpected networkID: %v", networkID)
   498  	}
   499  
   500  	// SuggestGasPrice
   501  	gasPrice, err := ec.SuggestGasPrice(context.Background())
   502  	if err != nil {
   503  		t.Fatalf("unexpected error: %v", err)
   504  	}
   505  	if gasPrice.Cmp(big.NewInt(1000000000)) != 0 {
   506  		t.Fatalf("unexpected gas price: %v", gasPrice)
   507  	}
   508  
   509  	// SuggestGasTipCap
   510  	gasTipCap, err := ec.SuggestGasTipCap(context.Background())
   511  	if err != nil {
   512  		t.Fatalf("unexpected error: %v", err)
   513  	}
   514  	if gasTipCap.Cmp(big.NewInt(234375000)) != 0 {
   515  		t.Fatalf("unexpected gas tip cap: %v", gasTipCap)
   516  	}
   517  
   518  	// FeeHistory
   519  	history, err := ec.FeeHistory(context.Background(), 1, big.NewInt(2), []float64{95, 99})
   520  	if err != nil {
   521  		t.Fatalf("unexpected error: %v", err)
   522  	}
   523  	want := &ethereum.FeeHistory{
   524  		OldestBlock: big.NewInt(2),
   525  		Reward: [][]*big.Int{
   526  			{
   527  				big.NewInt(234375000),
   528  				big.NewInt(234375000),
   529  			},
   530  		},
   531  		BaseFee: []*big.Int{
   532  			big.NewInt(765625000),
   533  			big.NewInt(671627818),
   534  		},
   535  		GasUsedRatio: []float64{0.008912678667376286},
   536  	}
   537  	if !reflect.DeepEqual(history, want) {
   538  		t.Fatalf("FeeHistory result doesn't match expected: (got: %v, want: %v)", history, want)
   539  	}
   540  }
   541  
   542  func testCallContractAtHash(t *testing.T, client *rpc.Client) {
   543  	ec := NewClient(client)
   544  
   545  	// EstimateGas
   546  	msg := ethereum.CallMsg{
   547  		From:  testAddr,
   548  		To:    &common.Address{},
   549  		Gas:   21000,
   550  		Value: big.NewInt(1),
   551  	}
   552  	gas, err := ec.EstimateGas(context.Background(), msg)
   553  	if err != nil {
   554  		t.Fatalf("unexpected error: %v", err)
   555  	}
   556  	if gas != 21000 {
   557  		t.Fatalf("unexpected gas price: %v", gas)
   558  	}
   559  	block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
   560  	if err != nil {
   561  		t.Fatalf("BlockByNumber error: %v", err)
   562  	}
   563  	// CallContract
   564  	if _, err := ec.CallContractAtHash(context.Background(), msg, block.Hash()); err != nil {
   565  		t.Fatalf("unexpected error: %v", err)
   566  	}
   567  }
   568  
   569  func testCallContract(t *testing.T, client *rpc.Client) {
   570  	ec := NewClient(client)
   571  
   572  	// EstimateGas
   573  	msg := ethereum.CallMsg{
   574  		From:  testAddr,
   575  		To:    &common.Address{},
   576  		Gas:   21000,
   577  		Value: big.NewInt(1),
   578  	}
   579  	gas, err := ec.EstimateGas(context.Background(), msg)
   580  	if err != nil {
   581  		t.Fatalf("unexpected error: %v", err)
   582  	}
   583  	if gas != 21000 {
   584  		t.Fatalf("unexpected gas price: %v", gas)
   585  	}
   586  	// CallContract
   587  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil {
   588  		t.Fatalf("unexpected error: %v", err)
   589  	}
   590  	// PendingCallContract
   591  	if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
   592  		t.Fatalf("unexpected error: %v", err)
   593  	}
   594  }
   595  
   596  func testAtFunctions(t *testing.T, client *rpc.Client) {
   597  	ec := NewClient(client)
   598  
   599  	block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
   600  	if err != nil {
   601  		t.Fatalf("BlockByNumber error: %v", err)
   602  	}
   603  
   604  	// send a transaction for some interesting pending status
   605  	// and wait for the transaction to be included in the pending block
   606  	sendTransaction(ec)
   607  
   608  	// wait for the transaction to be included in the pending block
   609  	for {
   610  		// Check pending transaction count
   611  		pending, err := ec.PendingTransactionCount(context.Background())
   612  		if err != nil {
   613  			t.Fatalf("unexpected error: %v", err)
   614  		}
   615  		if pending == 1 {
   616  			break
   617  		}
   618  		time.Sleep(100 * time.Millisecond)
   619  	}
   620  
   621  	// Query balance
   622  	balance, err := ec.BalanceAt(context.Background(), testAddr, nil)
   623  	if err != nil {
   624  		t.Fatalf("unexpected error: %v", err)
   625  	}
   626  	hashBalance, err := ec.BalanceAtHash(context.Background(), testAddr, block.Hash())
   627  	if err != nil {
   628  		t.Fatalf("unexpected error: %v", err)
   629  	}
   630  	if balance.Cmp(hashBalance) == 0 {
   631  		t.Fatalf("unexpected balance at hash: %v %v", balance, hashBalance)
   632  	}
   633  	penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr)
   634  	if err != nil {
   635  		t.Fatalf("unexpected error: %v", err)
   636  	}
   637  	if balance.Cmp(penBalance) == 0 {
   638  		t.Fatalf("unexpected balance: %v %v", balance, penBalance)
   639  	}
   640  	// NonceAt
   641  	nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
   642  	if err != nil {
   643  		t.Fatalf("unexpected error: %v", err)
   644  	}
   645  	hashNonce, err := ec.NonceAtHash(context.Background(), testAddr, block.Hash())
   646  	if err != nil {
   647  		t.Fatalf("unexpected error: %v", err)
   648  	}
   649  	if hashNonce == nonce {
   650  		t.Fatalf("unexpected nonce at hash: %v %v", nonce, hashNonce)
   651  	}
   652  	penNonce, err := ec.PendingNonceAt(context.Background(), testAddr)
   653  	if err != nil {
   654  		t.Fatalf("unexpected error: %v", err)
   655  	}
   656  	if penNonce != nonce+1 {
   657  		t.Fatalf("unexpected nonce: %v %v", nonce, penNonce)
   658  	}
   659  	// StorageAt
   660  	storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil)
   661  	if err != nil {
   662  		t.Fatalf("unexpected error: %v", err)
   663  	}
   664  	hashStorage, err := ec.StorageAtHash(context.Background(), testAddr, common.Hash{}, block.Hash())
   665  	if err != nil {
   666  		t.Fatalf("unexpected error: %v", err)
   667  	}
   668  	if !bytes.Equal(storage, hashStorage) {
   669  		t.Fatalf("unexpected storage at hash: %v %v", storage, hashStorage)
   670  	}
   671  	penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{})
   672  	if err != nil {
   673  		t.Fatalf("unexpected error: %v", err)
   674  	}
   675  	if !bytes.Equal(storage, penStorage) {
   676  		t.Fatalf("unexpected storage: %v %v", storage, penStorage)
   677  	}
   678  	// CodeAt
   679  	code, err := ec.CodeAt(context.Background(), testAddr, nil)
   680  	if err != nil {
   681  		t.Fatalf("unexpected error: %v", err)
   682  	}
   683  	hashCode, err := ec.CodeAtHash(context.Background(), common.Address{}, block.Hash())
   684  	if err != nil {
   685  		t.Fatalf("unexpected error: %v", err)
   686  	}
   687  	if !bytes.Equal(code, hashCode) {
   688  		t.Fatalf("unexpected code at hash: %v %v", code, hashCode)
   689  	}
   690  	penCode, err := ec.PendingCodeAt(context.Background(), testAddr)
   691  	if err != nil {
   692  		t.Fatalf("unexpected error: %v", err)
   693  	}
   694  	if !bytes.Equal(code, penCode) {
   695  		t.Fatalf("unexpected code: %v %v", code, penCode)
   696  	}
   697  }
   698  
   699  func testTransactionSender(t *testing.T, client *rpc.Client) {
   700  	ec := NewClient(client)
   701  	ctx := context.Background()
   702  
   703  	// Retrieve testTx1 via RPC.
   704  	block2, err := ec.HeaderByNumber(ctx, big.NewInt(2))
   705  	if err != nil {
   706  		t.Fatal("can't get block 1:", err)
   707  	}
   708  	tx1, err := ec.TransactionInBlock(ctx, block2.Hash(), 0)
   709  	if err != nil {
   710  		t.Fatal("can't get tx:", err)
   711  	}
   712  	if tx1.Hash() != testTx1.Hash() {
   713  		t.Fatalf("wrong tx hash %v, want %v", tx1.Hash(), testTx1.Hash())
   714  	}
   715  
   716  	// The sender address is cached in tx1, so no additional RPC should be required in
   717  	// TransactionSender. Ensure the server is not asked by canceling the context here.
   718  	canceledCtx, cancel := context.WithCancel(context.Background())
   719  	cancel()
   720  	<-canceledCtx.Done() // Ensure the close of the Done channel
   721  	sender1, err := ec.TransactionSender(canceledCtx, tx1, block2.Hash(), 0)
   722  	if err != nil {
   723  		t.Fatal(err)
   724  	}
   725  	if sender1 != testAddr {
   726  		t.Fatal("wrong sender:", sender1)
   727  	}
   728  
   729  	// Now try to get the sender of testTx2, which was not fetched through RPC.
   730  	// TransactionSender should query the server here.
   731  	sender2, err := ec.TransactionSender(ctx, testTx2, block2.Hash(), 1)
   732  	if err != nil {
   733  		t.Fatal(err)
   734  	}
   735  	if sender2 != testAddr {
   736  		t.Fatal("wrong sender:", sender2)
   737  	}
   738  }
   739  
   740  func sendTransaction(ec *Client) error {
   741  	chainID, err := ec.ChainID(context.Background())
   742  	if err != nil {
   743  		return err
   744  	}
   745  	nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
   746  	if err != nil {
   747  		return err
   748  	}
   749  
   750  	signer := types.LatestSignerForChainID(chainID)
   751  	tx, err := types.SignNewTx(testKey, signer, &types.LegacyTx{
   752  		Nonce:    nonce,
   753  		To:       &common.Address{2},
   754  		Value:    big.NewInt(1),
   755  		Gas:      22000,
   756  		GasPrice: big.NewInt(params.InitialBaseFee),
   757  	})
   758  	if err != nil {
   759  		return err
   760  	}
   761  	return ec.SendTransaction(context.Background(), tx)
   762  }