github.com/theQRL/go-zond@v0.1.1/zondclient/zondclient_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 zondclient
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"errors"
    23  	"math/big"
    24  	"reflect"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/theQRL/go-zond"
    29  	"github.com/theQRL/go-zond/common"
    30  	"github.com/theQRL/go-zond/consensus/ethash"
    31  	"github.com/theQRL/go-zond/core"
    32  	"github.com/theQRL/go-zond/core/types"
    33  	"github.com/theQRL/go-zond/crypto"
    34  	"github.com/theQRL/go-zond/node"
    35  	"github.com/theQRL/go-zond/params"
    36  	"github.com/theQRL/go-zond/rpc"
    37  	"github.com/theQRL/go-zond/zond"
    38  	"github.com/theQRL/go-zond/zond/ethconfig"
    39  )
    40  
    41  // Verify that Client implements the ethereum interfaces.
    42  var (
    43  	_ = zond.ChainReader(&Client{})
    44  	_ = zond.TransactionReader(&Client{})
    45  	_ = zond.ChainStateReader(&Client{})
    46  	_ = zond.ChainSyncReader(&Client{})
    47  	_ = zond.ContractCaller(&Client{})
    48  	_ = zond.GasEstimator(&Client{})
    49  	_ = zond.GasPricer(&Client{})
    50  	_ = zond.LogFilterer(&Client{})
    51  	_ = zond.PendingStateReader(&Client{})
    52  	// _ = zond.PendingStateEventer(&Client{})
    53  	_ = zond.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  zond.FilterQuery
    68  		output interface{}
    69  		err    error
    70  	}{
    71  		{
    72  			"without BlockHash",
    73  			zond.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  			zond.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  			zond.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  			zond.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  			zond.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  			zond.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  			zond.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:     core.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 := zond.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  	return n, blocks
   235  }
   236  
   237  func generateTestChain() []*types.Block {
   238  	generate := func(i int, g *core.BlockGen) {
   239  		g.OffsetTime(5)
   240  		g.SetExtra([]byte("test"))
   241  		if i == 1 {
   242  			// Test transactions are included in block #2.
   243  			g.AddTx(testTx1)
   244  			g.AddTx(testTx2)
   245  		}
   246  	}
   247  	_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 2, generate)
   248  	return append([]*types.Block{genesis.ToBlock()}, blocks...)
   249  }
   250  
   251  func TestEthClient(t *testing.T) {
   252  	backend, chain := newTestBackend(t)
   253  	client := backend.Attach()
   254  	defer backend.Close()
   255  	defer client.Close()
   256  
   257  	tests := map[string]struct {
   258  		test func(t *testing.T)
   259  	}{
   260  		"Header": {
   261  			func(t *testing.T) { testHeader(t, chain, client) },
   262  		},
   263  		"BalanceAt": {
   264  			func(t *testing.T) { testBalanceAt(t, client) },
   265  		},
   266  		"TxInBlockInterrupted": {
   267  			func(t *testing.T) { testTransactionInBlockInterrupted(t, client) },
   268  		},
   269  		"ChainID": {
   270  			func(t *testing.T) { testChainID(t, client) },
   271  		},
   272  		"GetBlock": {
   273  			func(t *testing.T) { testGetBlock(t, client) },
   274  		},
   275  		"StatusFunctions": {
   276  			func(t *testing.T) { testStatusFunctions(t, client) },
   277  		},
   278  		"CallContract": {
   279  			func(t *testing.T) { testCallContract(t, client) },
   280  		},
   281  		"CallContractAtHash": {
   282  			func(t *testing.T) { testCallContractAtHash(t, client) },
   283  		},
   284  		"AtFunctions": {
   285  			func(t *testing.T) { testAtFunctions(t, client) },
   286  		},
   287  		"TransactionSender": {
   288  			func(t *testing.T) { testTransactionSender(t, client) },
   289  		},
   290  	}
   291  
   292  	t.Parallel()
   293  	for name, tt := range tests {
   294  		t.Run(name, tt.test)
   295  	}
   296  }
   297  
   298  func testHeader(t *testing.T, chain []*types.Block, client *rpc.Client) {
   299  	tests := map[string]struct {
   300  		block   *big.Int
   301  		want    *types.Header
   302  		wantErr error
   303  	}{
   304  		"genesis": {
   305  			block: big.NewInt(0),
   306  			want:  chain[0].Header(),
   307  		},
   308  		"first_block": {
   309  			block: big.NewInt(1),
   310  			want:  chain[1].Header(),
   311  		},
   312  		"future_block": {
   313  			block:   big.NewInt(1000000000),
   314  			want:    nil,
   315  			wantErr: zond.NotFound,
   316  		},
   317  	}
   318  	for name, tt := range tests {
   319  		t.Run(name, func(t *testing.T) {
   320  			ec := NewClient(client)
   321  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   322  			defer cancel()
   323  
   324  			got, err := ec.HeaderByNumber(ctx, tt.block)
   325  			if !errors.Is(err, tt.wantErr) {
   326  				t.Fatalf("HeaderByNumber(%v) error = %q, want %q", tt.block, err, tt.wantErr)
   327  			}
   328  			if got != nil && got.Number != nil && got.Number.Sign() == 0 {
   329  				got.Number = big.NewInt(0) // hack to make DeepEqual work
   330  			}
   331  			if !reflect.DeepEqual(got, tt.want) {
   332  				t.Fatalf("HeaderByNumber(%v)\n   = %v\nwant %v", tt.block, got, tt.want)
   333  			}
   334  		})
   335  	}
   336  }
   337  
   338  func testBalanceAt(t *testing.T, client *rpc.Client) {
   339  	tests := map[string]struct {
   340  		account common.Address
   341  		block   *big.Int
   342  		want    *big.Int
   343  		wantErr error
   344  	}{
   345  		"valid_account_genesis": {
   346  			account: testAddr,
   347  			block:   big.NewInt(0),
   348  			want:    testBalance,
   349  		},
   350  		"valid_account": {
   351  			account: testAddr,
   352  			block:   big.NewInt(1),
   353  			want:    testBalance,
   354  		},
   355  		"non_existent_account": {
   356  			account: common.Address{1},
   357  			block:   big.NewInt(1),
   358  			want:    big.NewInt(0),
   359  		},
   360  		"future_block": {
   361  			account: testAddr,
   362  			block:   big.NewInt(1000000000),
   363  			want:    big.NewInt(0),
   364  			wantErr: errors.New("header not found"),
   365  		},
   366  	}
   367  	for name, tt := range tests {
   368  		t.Run(name, func(t *testing.T) {
   369  			ec := NewClient(client)
   370  			ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
   371  			defer cancel()
   372  
   373  			got, err := ec.BalanceAt(ctx, tt.account, tt.block)
   374  			if tt.wantErr != nil && (err == nil || err.Error() != tt.wantErr.Error()) {
   375  				t.Fatalf("BalanceAt(%x, %v) error = %q, want %q", tt.account, tt.block, err, tt.wantErr)
   376  			}
   377  			if got.Cmp(tt.want) != 0 {
   378  				t.Fatalf("BalanceAt(%x, %v) = %v, want %v", tt.account, tt.block, got, tt.want)
   379  			}
   380  		})
   381  	}
   382  }
   383  
   384  func testTransactionInBlockInterrupted(t *testing.T, client *rpc.Client) {
   385  	ec := NewClient(client)
   386  
   387  	// Get current block by number.
   388  	block, err := ec.BlockByNumber(context.Background(), nil)
   389  	if err != nil {
   390  		t.Fatalf("unexpected error: %v", err)
   391  	}
   392  
   393  	// Test tx in block interrupted.
   394  	ctx, cancel := context.WithCancel(context.Background())
   395  	cancel()
   396  	tx, err := ec.TransactionInBlock(ctx, block.Hash(), 0)
   397  	if tx != nil {
   398  		t.Fatal("transaction should be nil")
   399  	}
   400  	if err == nil || err == zond.NotFound {
   401  		t.Fatal("error should not be nil/notfound")
   402  	}
   403  
   404  	// Test tx in block not found.
   405  	if _, err := ec.TransactionInBlock(context.Background(), block.Hash(), 20); err != zond.NotFound {
   406  		t.Fatal("error should be zond.NotFound")
   407  	}
   408  }
   409  
   410  func testChainID(t *testing.T, client *rpc.Client) {
   411  	ec := NewClient(client)
   412  	id, err := ec.ChainID(context.Background())
   413  	if err != nil {
   414  		t.Fatalf("unexpected error: %v", err)
   415  	}
   416  	if id == nil || id.Cmp(params.AllEthashProtocolChanges.ChainID) != 0 {
   417  		t.Fatalf("ChainID returned wrong number: %+v", id)
   418  	}
   419  }
   420  
   421  func testGetBlock(t *testing.T, client *rpc.Client) {
   422  	ec := NewClient(client)
   423  
   424  	// Get current block number
   425  	blockNumber, err := ec.BlockNumber(context.Background())
   426  	if err != nil {
   427  		t.Fatalf("unexpected error: %v", err)
   428  	}
   429  	if blockNumber != 2 {
   430  		t.Fatalf("BlockNumber returned wrong number: %d", blockNumber)
   431  	}
   432  	// Get current block by number
   433  	block, err := ec.BlockByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
   434  	if err != nil {
   435  		t.Fatalf("unexpected error: %v", err)
   436  	}
   437  	if block.NumberU64() != blockNumber {
   438  		t.Fatalf("BlockByNumber returned wrong block: want %d got %d", blockNumber, block.NumberU64())
   439  	}
   440  	// Get current block by hash
   441  	blockH, err := ec.BlockByHash(context.Background(), block.Hash())
   442  	if err != nil {
   443  		t.Fatalf("unexpected error: %v", err)
   444  	}
   445  	if block.Hash() != blockH.Hash() {
   446  		t.Fatalf("BlockByHash returned wrong block: want %v got %v", block.Hash().Hex(), blockH.Hash().Hex())
   447  	}
   448  	// Get header by number
   449  	header, err := ec.HeaderByNumber(context.Background(), new(big.Int).SetUint64(blockNumber))
   450  	if err != nil {
   451  		t.Fatalf("unexpected error: %v", err)
   452  	}
   453  	if block.Header().Hash() != header.Hash() {
   454  		t.Fatalf("HeaderByNumber returned wrong header: want %v got %v", block.Header().Hash().Hex(), header.Hash().Hex())
   455  	}
   456  	// Get header by hash
   457  	headerH, err := ec.HeaderByHash(context.Background(), block.Hash())
   458  	if err != nil {
   459  		t.Fatalf("unexpected error: %v", err)
   460  	}
   461  	if block.Header().Hash() != headerH.Hash() {
   462  		t.Fatalf("HeaderByHash returned wrong header: want %v got %v", block.Header().Hash().Hex(), headerH.Hash().Hex())
   463  	}
   464  }
   465  
   466  func testStatusFunctions(t *testing.T, client *rpc.Client) {
   467  	ec := NewClient(client)
   468  
   469  	// Sync progress
   470  	progress, err := ec.SyncProgress(context.Background())
   471  	if err != nil {
   472  		t.Fatalf("unexpected error: %v", err)
   473  	}
   474  	if progress != nil {
   475  		t.Fatalf("unexpected progress: %v", progress)
   476  	}
   477  
   478  	// NetworkID
   479  	networkID, err := ec.NetworkID(context.Background())
   480  	if err != nil {
   481  		t.Fatalf("unexpected error: %v", err)
   482  	}
   483  	if networkID.Cmp(big.NewInt(0)) != 0 {
   484  		t.Fatalf("unexpected networkID: %v", networkID)
   485  	}
   486  
   487  	// SuggestGasPrice
   488  	gasPrice, err := ec.SuggestGasPrice(context.Background())
   489  	if err != nil {
   490  		t.Fatalf("unexpected error: %v", err)
   491  	}
   492  	if gasPrice.Cmp(big.NewInt(1000000000)) != 0 {
   493  		t.Fatalf("unexpected gas price: %v", gasPrice)
   494  	}
   495  
   496  	// SuggestGasTipCap
   497  	gasTipCap, err := ec.SuggestGasTipCap(context.Background())
   498  	if err != nil {
   499  		t.Fatalf("unexpected error: %v", err)
   500  	}
   501  	if gasTipCap.Cmp(big.NewInt(234375000)) != 0 {
   502  		t.Fatalf("unexpected gas tip cap: %v", gasTipCap)
   503  	}
   504  
   505  	// FeeHistory
   506  	history, err := ec.FeeHistory(context.Background(), 1, big.NewInt(2), []float64{95, 99})
   507  	if err != nil {
   508  		t.Fatalf("unexpected error: %v", err)
   509  	}
   510  	want := &zond.FeeHistory{
   511  		OldestBlock: big.NewInt(2),
   512  		Reward: [][]*big.Int{
   513  			{
   514  				big.NewInt(234375000),
   515  				big.NewInt(234375000),
   516  			},
   517  		},
   518  		BaseFee: []*big.Int{
   519  			big.NewInt(765625000),
   520  			big.NewInt(671627818),
   521  		},
   522  		GasUsedRatio: []float64{0.008912678667376286},
   523  	}
   524  	if !reflect.DeepEqual(history, want) {
   525  		t.Fatalf("FeeHistory result doesn't match expected: (got: %v, want: %v)", history, want)
   526  	}
   527  }
   528  
   529  func testCallContractAtHash(t *testing.T, client *rpc.Client) {
   530  	ec := NewClient(client)
   531  
   532  	// EstimateGas
   533  	msg := zond.CallMsg{
   534  		From:  testAddr,
   535  		To:    &common.Address{},
   536  		Gas:   21000,
   537  		Value: big.NewInt(1),
   538  	}
   539  	gas, err := ec.EstimateGas(context.Background(), msg)
   540  	if err != nil {
   541  		t.Fatalf("unexpected error: %v", err)
   542  	}
   543  	if gas != 21000 {
   544  		t.Fatalf("unexpected gas price: %v", gas)
   545  	}
   546  	block, err := ec.HeaderByNumber(context.Background(), big.NewInt(1))
   547  	if err != nil {
   548  		t.Fatalf("BlockByNumber error: %v", err)
   549  	}
   550  	// CallContract
   551  	if _, err := ec.CallContractAtHash(context.Background(), msg, block.Hash()); err != nil {
   552  		t.Fatalf("unexpected error: %v", err)
   553  	}
   554  }
   555  
   556  func testCallContract(t *testing.T, client *rpc.Client) {
   557  	ec := NewClient(client)
   558  
   559  	// EstimateGas
   560  	msg := zond.CallMsg{
   561  		From:  testAddr,
   562  		To:    &common.Address{},
   563  		Gas:   21000,
   564  		Value: big.NewInt(1),
   565  	}
   566  	gas, err := ec.EstimateGas(context.Background(), msg)
   567  	if err != nil {
   568  		t.Fatalf("unexpected error: %v", err)
   569  	}
   570  	if gas != 21000 {
   571  		t.Fatalf("unexpected gas price: %v", gas)
   572  	}
   573  	// CallContract
   574  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(1)); err != nil {
   575  		t.Fatalf("unexpected error: %v", err)
   576  	}
   577  	// PendingCallContract
   578  	if _, err := ec.PendingCallContract(context.Background(), msg); err != nil {
   579  		t.Fatalf("unexpected error: %v", err)
   580  	}
   581  }
   582  
   583  func testAtFunctions(t *testing.T, client *rpc.Client) {
   584  	ec := NewClient(client)
   585  
   586  	// send a transaction for some interesting pending status
   587  	sendTransaction(ec)
   588  	time.Sleep(100 * time.Millisecond)
   589  
   590  	// Check pending transaction count
   591  	pending, err := ec.PendingTransactionCount(context.Background())
   592  	if err != nil {
   593  		t.Fatalf("unexpected error: %v", err)
   594  	}
   595  	if pending != 1 {
   596  		t.Fatalf("unexpected pending, wanted 1 got: %v", pending)
   597  	}
   598  	// Query balance
   599  	balance, err := ec.BalanceAt(context.Background(), testAddr, nil)
   600  	if err != nil {
   601  		t.Fatalf("unexpected error: %v", err)
   602  	}
   603  	penBalance, err := ec.PendingBalanceAt(context.Background(), testAddr)
   604  	if err != nil {
   605  		t.Fatalf("unexpected error: %v", err)
   606  	}
   607  	if balance.Cmp(penBalance) == 0 {
   608  		t.Fatalf("unexpected balance: %v %v", balance, penBalance)
   609  	}
   610  	// NonceAt
   611  	nonce, err := ec.NonceAt(context.Background(), testAddr, nil)
   612  	if err != nil {
   613  		t.Fatalf("unexpected error: %v", err)
   614  	}
   615  	penNonce, err := ec.PendingNonceAt(context.Background(), testAddr)
   616  	if err != nil {
   617  		t.Fatalf("unexpected error: %v", err)
   618  	}
   619  	if penNonce != nonce+1 {
   620  		t.Fatalf("unexpected nonce: %v %v", nonce, penNonce)
   621  	}
   622  	// StorageAt
   623  	storage, err := ec.StorageAt(context.Background(), testAddr, common.Hash{}, nil)
   624  	if err != nil {
   625  		t.Fatalf("unexpected error: %v", err)
   626  	}
   627  	penStorage, err := ec.PendingStorageAt(context.Background(), testAddr, common.Hash{})
   628  	if err != nil {
   629  		t.Fatalf("unexpected error: %v", err)
   630  	}
   631  	if !bytes.Equal(storage, penStorage) {
   632  		t.Fatalf("unexpected storage: %v %v", storage, penStorage)
   633  	}
   634  	// CodeAt
   635  	code, err := ec.CodeAt(context.Background(), testAddr, nil)
   636  	if err != nil {
   637  		t.Fatalf("unexpected error: %v", err)
   638  	}
   639  	penCode, err := ec.PendingCodeAt(context.Background(), testAddr)
   640  	if err != nil {
   641  		t.Fatalf("unexpected error: %v", err)
   642  	}
   643  	if !bytes.Equal(code, penCode) {
   644  		t.Fatalf("unexpected code: %v %v", code, penCode)
   645  	}
   646  }
   647  
   648  func testTransactionSender(t *testing.T, client *rpc.Client) {
   649  	ec := NewClient(client)
   650  	ctx := context.Background()
   651  
   652  	// Retrieve testTx1 via RPC.
   653  	block2, err := ec.HeaderByNumber(ctx, big.NewInt(2))
   654  	if err != nil {
   655  		t.Fatal("can't get block 1:", err)
   656  	}
   657  	tx1, err := ec.TransactionInBlock(ctx, block2.Hash(), 0)
   658  	if err != nil {
   659  		t.Fatal("can't get tx:", err)
   660  	}
   661  	if tx1.Hash() != testTx1.Hash() {
   662  		t.Fatalf("wrong tx hash %v, want %v", tx1.Hash(), testTx1.Hash())
   663  	}
   664  
   665  	// The sender address is cached in tx1, so no additional RPC should be required in
   666  	// TransactionSender. Ensure the server is not asked by canceling the context here.
   667  	canceledCtx, cancel := context.WithCancel(context.Background())
   668  	cancel()
   669  	sender1, err := ec.TransactionSender(canceledCtx, tx1, block2.Hash(), 0)
   670  	if err != nil {
   671  		t.Fatal(err)
   672  	}
   673  	if sender1 != testAddr {
   674  		t.Fatal("wrong sender:", sender1)
   675  	}
   676  
   677  	// Now try to get the sender of testTx2, which was not fetched through RPC.
   678  	// TransactionSender should query the server here.
   679  	sender2, err := ec.TransactionSender(ctx, testTx2, block2.Hash(), 1)
   680  	if err != nil {
   681  		t.Fatal(err)
   682  	}
   683  	if sender2 != testAddr {
   684  		t.Fatal("wrong sender:", sender2)
   685  	}
   686  }
   687  
   688  func sendTransaction(ec *Client) error {
   689  	chainID, err := ec.ChainID(context.Background())
   690  	if err != nil {
   691  		return err
   692  	}
   693  	nonce, err := ec.PendingNonceAt(context.Background(), testAddr)
   694  	if err != nil {
   695  		return err
   696  	}
   697  
   698  	signer := types.LatestSignerForChainID(chainID)
   699  	tx, err := types.SignNewTx(testKey, signer, &types.LegacyTx{
   700  		Nonce:    nonce,
   701  		To:       &common.Address{2},
   702  		Value:    big.NewInt(1),
   703  		Gas:      22000,
   704  		GasPrice: big.NewInt(params.InitialBaseFee),
   705  	})
   706  	if err != nil {
   707  		return err
   708  	}
   709  	return ec.SendTransaction(context.Background(), tx)
   710  }