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