github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/ethclient/gethclient/gethclient_test.go (about)

     1  // Copyright 2021 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 gethclient
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"math/big"
    24  	"testing"
    25  
    26  	"github.com/tirogen/go-ethereum"
    27  	"github.com/tirogen/go-ethereum/common"
    28  	"github.com/tirogen/go-ethereum/consensus/ethash"
    29  	"github.com/tirogen/go-ethereum/core"
    30  	"github.com/tirogen/go-ethereum/core/types"
    31  	"github.com/tirogen/go-ethereum/crypto"
    32  	"github.com/tirogen/go-ethereum/eth"
    33  	"github.com/tirogen/go-ethereum/eth/ethconfig"
    34  	"github.com/tirogen/go-ethereum/eth/filters"
    35  	"github.com/tirogen/go-ethereum/ethclient"
    36  	"github.com/tirogen/go-ethereum/node"
    37  	"github.com/tirogen/go-ethereum/params"
    38  	"github.com/tirogen/go-ethereum/rpc"
    39  )
    40  
    41  var (
    42  	testKey, _  = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    43  	testAddr    = crypto.PubkeyToAddress(testKey.PublicKey)
    44  	testSlot    = common.HexToHash("0xdeadbeef")
    45  	testValue   = crypto.Keccak256Hash(testSlot[:])
    46  	testBalance = big.NewInt(2e15)
    47  )
    48  
    49  func newTestBackend(t *testing.T) (*node.Node, []*types.Block) {
    50  	// Generate test chain.
    51  	genesis, blocks := generateTestChain()
    52  	// Create node
    53  	n, err := node.New(&node.Config{})
    54  	if err != nil {
    55  		t.Fatalf("can't create new node: %v", err)
    56  	}
    57  	// Create Ethereum Service
    58  	config := &ethconfig.Config{Genesis: genesis}
    59  	config.Ethash.PowMode = ethash.ModeFake
    60  	ethservice, err := eth.New(n, config)
    61  	if err != nil {
    62  		t.Fatalf("can't create new ethereum service: %v", err)
    63  	}
    64  	filterSystem := filters.NewFilterSystem(ethservice.APIBackend, filters.Config{})
    65  	n.RegisterAPIs([]rpc.API{{
    66  		Namespace: "eth",
    67  		Service:   filters.NewFilterAPI(filterSystem, false),
    68  	}})
    69  
    70  	// Import the test chain.
    71  	if err := n.Start(); err != nil {
    72  		t.Fatalf("can't start test node: %v", err)
    73  	}
    74  	if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
    75  		t.Fatalf("can't import test blocks: %v", err)
    76  	}
    77  	return n, blocks
    78  }
    79  
    80  func generateTestChain() (*core.Genesis, []*types.Block) {
    81  	genesis := &core.Genesis{
    82  		Config:    params.AllEthashProtocolChanges,
    83  		Alloc:     core.GenesisAlloc{testAddr: {Balance: testBalance, Storage: map[common.Hash]common.Hash{testSlot: testValue}}},
    84  		ExtraData: []byte("test genesis"),
    85  		Timestamp: 9000,
    86  	}
    87  	generate := func(i int, g *core.BlockGen) {
    88  		g.OffsetTime(5)
    89  		g.SetExtra([]byte("test"))
    90  	}
    91  	_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), 1, generate)
    92  	blocks = append([]*types.Block{genesis.ToBlock()}, blocks...)
    93  	return genesis, blocks
    94  }
    95  
    96  func TestGethClient(t *testing.T) {
    97  	backend, _ := newTestBackend(t)
    98  	client, err := backend.Attach()
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  	defer backend.Close()
   103  	defer client.Close()
   104  
   105  	tests := []struct {
   106  		name string
   107  		test func(t *testing.T)
   108  	}{
   109  		{
   110  			"TestGetProof",
   111  			func(t *testing.T) { testGetProof(t, client) },
   112  		}, {
   113  			"TestGCStats",
   114  			func(t *testing.T) { testGCStats(t, client) },
   115  		}, {
   116  			"TestMemStats",
   117  			func(t *testing.T) { testMemStats(t, client) },
   118  		}, {
   119  			"TestGetNodeInfo",
   120  			func(t *testing.T) { testGetNodeInfo(t, client) },
   121  		}, {
   122  			"TestSetHead",
   123  			func(t *testing.T) { testSetHead(t, client) },
   124  		}, {
   125  			"TestSubscribePendingTxHashes",
   126  			func(t *testing.T) { testSubscribePendingTransactions(t, client) },
   127  		}, {
   128  			"TestSubscribePendingTxs",
   129  			func(t *testing.T) { testSubscribeFullPendingTransactions(t, client) },
   130  		}, {
   131  			"TestCallContract",
   132  			func(t *testing.T) { testCallContract(t, client) },
   133  		},
   134  		// The testaccesslist is a bit time-sensitive: the newTestBackend imports
   135  		// one block. The `testAcessList` fails if the miner has not yet created a
   136  		// new pending-block after the import event.
   137  		// Hence: this test should be last, execute the tests serially.
   138  		{
   139  			"TestAccessList",
   140  			func(t *testing.T) { testAccessList(t, client) },
   141  		},
   142  	}
   143  	for _, tt := range tests {
   144  		t.Run(tt.name, tt.test)
   145  	}
   146  }
   147  
   148  func testAccessList(t *testing.T, client *rpc.Client) {
   149  	ec := New(client)
   150  	// Test transfer
   151  	msg := ethereum.CallMsg{
   152  		From:     testAddr,
   153  		To:       &common.Address{},
   154  		Gas:      21000,
   155  		GasPrice: big.NewInt(765625000),
   156  		Value:    big.NewInt(1),
   157  	}
   158  	al, gas, vmErr, err := ec.CreateAccessList(context.Background(), msg)
   159  	if err != nil {
   160  		t.Fatalf("unexpected error: %v", err)
   161  	}
   162  	if vmErr != "" {
   163  		t.Fatalf("unexpected vm error: %v", vmErr)
   164  	}
   165  	if gas != 21000 {
   166  		t.Fatalf("unexpected gas used: %v", gas)
   167  	}
   168  	if len(*al) != 0 {
   169  		t.Fatalf("unexpected length of accesslist: %v", len(*al))
   170  	}
   171  	// Test reverting transaction
   172  	msg = ethereum.CallMsg{
   173  		From:     testAddr,
   174  		To:       nil,
   175  		Gas:      100000,
   176  		GasPrice: big.NewInt(1000000000),
   177  		Value:    big.NewInt(1),
   178  		Data:     common.FromHex("0x608060806080608155fd"),
   179  	}
   180  	al, gas, vmErr, err = ec.CreateAccessList(context.Background(), msg)
   181  	if err != nil {
   182  		t.Fatalf("unexpected error: %v", err)
   183  	}
   184  	if vmErr == "" {
   185  		t.Fatalf("wanted vmErr, got none")
   186  	}
   187  	if gas == 21000 {
   188  		t.Fatalf("unexpected gas used: %v", gas)
   189  	}
   190  	if len(*al) != 1 || al.StorageKeys() != 1 {
   191  		t.Fatalf("unexpected length of accesslist: %v", len(*al))
   192  	}
   193  	// address changes between calls, so we can't test for it.
   194  	if (*al)[0].Address == common.HexToAddress("0x0") {
   195  		t.Fatalf("unexpected address: %v", (*al)[0].Address)
   196  	}
   197  	if (*al)[0].StorageKeys[0] != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000081") {
   198  		t.Fatalf("unexpected storage key: %v", (*al)[0].StorageKeys[0])
   199  	}
   200  }
   201  
   202  func testGetProof(t *testing.T, client *rpc.Client) {
   203  	ec := New(client)
   204  	ethcl := ethclient.NewClient(client)
   205  	result, err := ec.GetProof(context.Background(), testAddr, []string{testSlot.String()}, nil)
   206  	if err != nil {
   207  		t.Fatal(err)
   208  	}
   209  	if !bytes.Equal(result.Address[:], testAddr[:]) {
   210  		t.Fatalf("unexpected address, want: %v got: %v", testAddr, result.Address)
   211  	}
   212  	// test nonce
   213  	nonce, _ := ethcl.NonceAt(context.Background(), result.Address, nil)
   214  	if result.Nonce != nonce {
   215  		t.Fatalf("invalid nonce, want: %v got: %v", nonce, result.Nonce)
   216  	}
   217  	// test balance
   218  	balance, _ := ethcl.BalanceAt(context.Background(), result.Address, nil)
   219  	if result.Balance.Cmp(balance) != 0 {
   220  		t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance)
   221  	}
   222  	// test storage
   223  	if len(result.StorageProof) != 1 {
   224  		t.Fatalf("invalid storage proof, want 1 proof, got %v proof(s)", len(result.StorageProof))
   225  	}
   226  	proof := result.StorageProof[0]
   227  	slotValue, _ := ethcl.StorageAt(context.Background(), testAddr, testSlot, nil)
   228  	if !bytes.Equal(slotValue, proof.Value.Bytes()) {
   229  		t.Fatalf("invalid storage proof value, want: %v, got: %v", slotValue, proof.Value.Bytes())
   230  	}
   231  	if proof.Key != testSlot.String() {
   232  		t.Fatalf("invalid storage proof key, want: %v, got: %v", testSlot.String(), proof.Key)
   233  	}
   234  }
   235  
   236  func testGCStats(t *testing.T, client *rpc.Client) {
   237  	ec := New(client)
   238  	_, err := ec.GCStats(context.Background())
   239  	if err != nil {
   240  		t.Fatal(err)
   241  	}
   242  }
   243  
   244  func testMemStats(t *testing.T, client *rpc.Client) {
   245  	ec := New(client)
   246  	stats, err := ec.MemStats(context.Background())
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	if stats.Alloc == 0 {
   251  		t.Fatal("Invalid mem stats retrieved")
   252  	}
   253  }
   254  
   255  func testGetNodeInfo(t *testing.T, client *rpc.Client) {
   256  	ec := New(client)
   257  	info, err := ec.GetNodeInfo(context.Background())
   258  	if err != nil {
   259  		t.Fatal(err)
   260  	}
   261  
   262  	if info.Name == "" {
   263  		t.Fatal("Invalid node info retrieved")
   264  	}
   265  }
   266  
   267  func testSetHead(t *testing.T, client *rpc.Client) {
   268  	ec := New(client)
   269  	err := ec.SetHead(context.Background(), big.NewInt(0))
   270  	if err != nil {
   271  		t.Fatal(err)
   272  	}
   273  }
   274  
   275  func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) {
   276  	ec := New(client)
   277  	ethcl := ethclient.NewClient(client)
   278  	// Subscribe to Transactions
   279  	ch := make(chan common.Hash)
   280  	ec.SubscribePendingTransactions(context.Background(), ch)
   281  	// Send a transaction
   282  	chainID, err := ethcl.ChainID(context.Background())
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  	// Create transaction
   287  	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
   288  	signer := types.LatestSignerForChainID(chainID)
   289  	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
   290  	if err != nil {
   291  		t.Fatal(err)
   292  	}
   293  	signedTx, err := tx.WithSignature(signer, signature)
   294  	if err != nil {
   295  		t.Fatal(err)
   296  	}
   297  	// Send transaction
   298  	err = ethcl.SendTransaction(context.Background(), signedTx)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  	// Check that the transaction was send over the channel
   303  	hash := <-ch
   304  	if hash != signedTx.Hash() {
   305  		t.Fatalf("Invalid tx hash received, got %v, want %v", hash, signedTx.Hash())
   306  	}
   307  }
   308  
   309  func testSubscribeFullPendingTransactions(t *testing.T, client *rpc.Client) {
   310  	ec := New(client)
   311  	ethcl := ethclient.NewClient(client)
   312  	// Subscribe to Transactions
   313  	ch := make(chan *types.Transaction)
   314  	ec.SubscribeFullPendingTransactions(context.Background(), ch)
   315  	// Send a transaction
   316  	chainID, err := ethcl.ChainID(context.Background())
   317  	if err != nil {
   318  		t.Fatal(err)
   319  	}
   320  	// Create transaction
   321  	tx := types.NewTransaction(1, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
   322  	signer := types.LatestSignerForChainID(chainID)
   323  	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  	signedTx, err := tx.WithSignature(signer, signature)
   328  	if err != nil {
   329  		t.Fatal(err)
   330  	}
   331  	// Send transaction
   332  	err = ethcl.SendTransaction(context.Background(), signedTx)
   333  	if err != nil {
   334  		t.Fatal(err)
   335  	}
   336  	// Check that the transaction was send over the channel
   337  	tx = <-ch
   338  	if tx.Hash() != signedTx.Hash() {
   339  		t.Fatalf("Invalid tx hash received, got %v, want %v", tx.Hash(), signedTx.Hash())
   340  	}
   341  }
   342  
   343  func testCallContract(t *testing.T, client *rpc.Client) {
   344  	ec := New(client)
   345  	msg := ethereum.CallMsg{
   346  		From:     testAddr,
   347  		To:       &common.Address{},
   348  		Gas:      21000,
   349  		GasPrice: big.NewInt(1000000000),
   350  		Value:    big.NewInt(1),
   351  	}
   352  	// CallContract without override
   353  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil {
   354  		t.Fatalf("unexpected error: %v", err)
   355  	}
   356  	// CallContract with override
   357  	override := OverrideAccount{
   358  		Nonce: 1,
   359  	}
   360  	mapAcc := make(map[common.Address]OverrideAccount)
   361  	mapAcc[testAddr] = override
   362  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc); err != nil {
   363  		t.Fatalf("unexpected error: %v", err)
   364  	}
   365  }
   366  
   367  func TestOverrideAccountMarshal(t *testing.T) {
   368  	om := map[common.Address]OverrideAccount{
   369  		common.Address{0x11}: OverrideAccount{
   370  			// Zero-valued nonce is not overriddden, but simply dropped by the encoder.
   371  			Nonce: 0,
   372  		},
   373  		common.Address{0xaa}: OverrideAccount{
   374  			Nonce: 5,
   375  		},
   376  		common.Address{0xbb}: OverrideAccount{
   377  			Code: []byte{1},
   378  		},
   379  		common.Address{0xcc}: OverrideAccount{
   380  			// 'code', 'balance', 'state' should be set when input is
   381  			// a non-nil but empty value.
   382  			Code:    []byte{},
   383  			Balance: big.NewInt(0),
   384  			State:   map[common.Hash]common.Hash{},
   385  			// For 'stateDiff' the behavior is different, empty map
   386  			// is ignored because it makes no difference.
   387  			StateDiff: map[common.Hash]common.Hash{},
   388  		},
   389  	}
   390  
   391  	marshalled, err := json.MarshalIndent(&om, "", "  ")
   392  	if err != nil {
   393  		t.Fatalf("unexpected error: %v", err)
   394  	}
   395  
   396  	expected := `{
   397    "0x1100000000000000000000000000000000000000": {},
   398    "0xaa00000000000000000000000000000000000000": {
   399      "nonce": "0x5"
   400    },
   401    "0xbb00000000000000000000000000000000000000": {
   402      "code": "0x01"
   403    },
   404    "0xcc00000000000000000000000000000000000000": {
   405      "code": "0x",
   406      "balance": "0x0",
   407      "state": {}
   408    }
   409  }`
   410  
   411  	if string(marshalled) != expected {
   412  		t.Error("wrong output:", string(marshalled))
   413  		t.Error("want:", expected)
   414  	}
   415  }