github.com/cryptotooltop/go-ethereum@v0.0.0-20231103184714-151d1922f3e5/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  	"math/big"
    23  	"testing"
    24  
    25  	"github.com/scroll-tech/go-ethereum"
    26  	"github.com/scroll-tech/go-ethereum/common"
    27  	"github.com/scroll-tech/go-ethereum/consensus/ethash"
    28  	"github.com/scroll-tech/go-ethereum/core"
    29  	"github.com/scroll-tech/go-ethereum/core/rawdb"
    30  	"github.com/scroll-tech/go-ethereum/core/types"
    31  	"github.com/scroll-tech/go-ethereum/crypto"
    32  	"github.com/scroll-tech/go-ethereum/eth"
    33  	"github.com/scroll-tech/go-ethereum/eth/ethconfig"
    34  	"github.com/scroll-tech/go-ethereum/ethclient"
    35  	"github.com/scroll-tech/go-ethereum/node"
    36  	"github.com/scroll-tech/go-ethereum/params"
    37  	"github.com/scroll-tech/go-ethereum/rollup/rcfg"
    38  	"github.com/scroll-tech/go-ethereum/rpc"
    39  )
    40  
    41  var (
    42  	testKey, _         = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    43  	testAddr           = crypto.PubkeyToAddress(testKey.PublicKey)
    44  	emptyAccountKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f292")
    45  	emptyAddr          = crypto.PubkeyToAddress(emptyAccountKey.PublicKey)
    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, nil)
    61  	if err != nil {
    62  		t.Fatalf("can't create new ethereum service: %v", err)
    63  	}
    64  	// Import the test chain.
    65  	if err := n.Start(); err != nil {
    66  		t.Fatalf("can't start test node: %v", err)
    67  	}
    68  	if _, err := ethservice.BlockChain().InsertChain(blocks[1:]); err != nil {
    69  		t.Fatalf("can't import test blocks: %v", err)
    70  	}
    71  	return n, blocks
    72  }
    73  
    74  func generateTestChain() (*core.Genesis, []*types.Block) {
    75  	db := rawdb.NewMemoryDatabase()
    76  	config := params.AllEthashProtocolChanges
    77  	genesis := &core.Genesis{
    78  		Config: config,
    79  		Alloc: core.GenesisAlloc{
    80  			testAddr: {Balance: testBalance},
    81  			rcfg.L1GasPriceOracleAddress: {
    82  				Balance: big.NewInt(0),
    83  				Storage: map[common.Hash]common.Hash{
    84  					rcfg.L1BaseFeeSlot: common.BigToHash(big.NewInt(10000)),
    85  					rcfg.OverheadSlot:  common.BigToHash(big.NewInt(10000)),
    86  					rcfg.ScalarSlot:    common.BigToHash(big.NewInt(10000)),
    87  				},
    88  			},
    89  		},
    90  		ExtraData: []byte("test genesis"),
    91  		Timestamp: 9000,
    92  	}
    93  	generate := func(i int, g *core.BlockGen) {
    94  		g.OffsetTime(5)
    95  		g.SetExtra([]byte("test"))
    96  	}
    97  	gblock := genesis.ToBlock(db)
    98  	engine := ethash.NewFaker()
    99  	blocks, _ := core.GenerateChain(config, gblock, engine, db, 1, generate)
   100  	blocks = append([]*types.Block{gblock}, blocks...)
   101  	return genesis, blocks
   102  }
   103  
   104  func TestGethClient(t *testing.T) {
   105  	backend, _ := newTestBackend(t)
   106  	client, err := backend.Attach()
   107  	if err != nil {
   108  		t.Fatal(err)
   109  	}
   110  	defer backend.Close()
   111  	defer client.Close()
   112  
   113  	tests := []struct {
   114  		name string
   115  		test func(t *testing.T)
   116  	}{
   117  		{
   118  			"TestAccessList",
   119  			func(t *testing.T) { testAccessList(t, client) },
   120  		},
   121  		{
   122  			"TestGetProof",
   123  			func(t *testing.T) { testGetProof(t, client) },
   124  		}, {
   125  			"TestGCStats",
   126  			func(t *testing.T) { testGCStats(t, client) },
   127  		}, {
   128  			"TestMemStats",
   129  			func(t *testing.T) { testMemStats(t, client) },
   130  		}, {
   131  			"TestGetNodeInfo",
   132  			func(t *testing.T) { testGetNodeInfo(t, client) },
   133  		}, {
   134  			"TestSetHead",
   135  			func(t *testing.T) { testSetHead(t, client) },
   136  		}, {
   137  			"TestSubscribePendingTxs",
   138  			func(t *testing.T) { testSubscribePendingTransactions(t, client) },
   139  		}, {
   140  			"TestCallContract",
   141  			func(t *testing.T) { testCallContract(t, client) },
   142  		}, {
   143  			"TestCallContractNoGas",
   144  			func(t *testing.T) { testCallContractNoGas(t, client) },
   145  		},
   146  	}
   147  	t.Parallel()
   148  	for _, tt := range tests {
   149  		t.Run(tt.name, tt.test)
   150  	}
   151  }
   152  
   153  func testAccessList(t *testing.T, client *rpc.Client) {
   154  	ec := New(client)
   155  	// Test transfer
   156  	msg := ethereum.CallMsg{
   157  		From:     testAddr,
   158  		To:       &common.Address{},
   159  		Gas:      21000,
   160  		GasPrice: big.NewInt(765625000),
   161  		Value:    big.NewInt(1),
   162  	}
   163  	al, gas, vmErr, err := ec.CreateAccessList(context.Background(), msg)
   164  	if err != nil {
   165  		t.Fatalf("unexpected error: %v", err)
   166  	}
   167  	if vmErr != "" {
   168  		t.Fatalf("unexpected vm error: %v", vmErr)
   169  	}
   170  	if gas != 21000 {
   171  		t.Fatalf("unexpected gas used: %v", gas)
   172  	}
   173  	if len(*al) != 0 {
   174  		t.Fatalf("unexpected length of accesslist: %v", len(*al))
   175  	}
   176  	// Test reverting transaction
   177  	msg = ethereum.CallMsg{
   178  		From:     testAddr,
   179  		To:       nil,
   180  		Gas:      100000,
   181  		GasPrice: big.NewInt(1000000000),
   182  		Value:    big.NewInt(1),
   183  		Data:     common.FromHex("0x608060806080608155fd"),
   184  	}
   185  	al, gas, vmErr, err = ec.CreateAccessList(context.Background(), msg)
   186  	if err != nil {
   187  		t.Fatalf("unexpected error: %v", err)
   188  	}
   189  	if vmErr == "" {
   190  		t.Fatalf("wanted vmErr, got none")
   191  	}
   192  	if gas == 21000 {
   193  		t.Fatalf("unexpected gas used: %v", gas)
   194  	}
   195  	if len(*al) != 1 || al.StorageKeys() != 1 {
   196  		t.Fatalf("unexpected length of accesslist: %v", len(*al))
   197  	}
   198  	// address changes between calls, so we can't test for it.
   199  	if (*al)[0].Address == common.HexToAddress("0x0") {
   200  		t.Fatalf("unexpected address: %v", (*al)[0].Address)
   201  	}
   202  	if (*al)[0].StorageKeys[0] != common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000081") {
   203  		t.Fatalf("unexpected storage key: %v", (*al)[0].StorageKeys[0])
   204  	}
   205  }
   206  
   207  func testGetProof(t *testing.T, client *rpc.Client) {
   208  	ec := New(client)
   209  	ethcl := ethclient.NewClient(client)
   210  	result, err := ec.GetProof(context.Background(), testAddr, []string{}, nil)
   211  	if err != nil {
   212  		t.Fatal(err)
   213  	}
   214  	if !bytes.Equal(result.Address[:], testAddr[:]) {
   215  		t.Fatalf("unexpected address, want: %v got: %v", testAddr, result.Address)
   216  	}
   217  	// test nonce
   218  	nonce, _ := ethcl.NonceAt(context.Background(), result.Address, nil)
   219  	if result.Nonce != nonce {
   220  		t.Fatalf("invalid nonce, want: %v got: %v", nonce, result.Nonce)
   221  	}
   222  	// test balance
   223  	balance, _ := ethcl.BalanceAt(context.Background(), result.Address, nil)
   224  	if result.Balance.Cmp(balance) != 0 {
   225  		t.Fatalf("invalid balance, want: %v got: %v", balance, result.Balance)
   226  	}
   227  }
   228  
   229  func testGCStats(t *testing.T, client *rpc.Client) {
   230  	ec := New(client)
   231  	_, err := ec.GCStats(context.Background())
   232  	if err != nil {
   233  		t.Fatal(err)
   234  	}
   235  }
   236  
   237  func testMemStats(t *testing.T, client *rpc.Client) {
   238  	ec := New(client)
   239  	stats, err := ec.MemStats(context.Background())
   240  	if err != nil {
   241  		t.Fatal(err)
   242  	}
   243  	if stats.Alloc == 0 {
   244  		t.Fatal("Invalid mem stats retrieved")
   245  	}
   246  }
   247  
   248  func testGetNodeInfo(t *testing.T, client *rpc.Client) {
   249  	ec := New(client)
   250  	info, err := ec.GetNodeInfo(context.Background())
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	if info.Name == "" {
   256  		t.Fatal("Invalid node info retrieved")
   257  	}
   258  }
   259  
   260  func testSetHead(t *testing.T, client *rpc.Client) {
   261  	ec := New(client)
   262  	err := ec.SetHead(context.Background(), big.NewInt(0))
   263  	if err != nil {
   264  		t.Fatal(err)
   265  	}
   266  }
   267  
   268  func testSubscribePendingTransactions(t *testing.T, client *rpc.Client) {
   269  	ec := New(client)
   270  	ethcl := ethclient.NewClient(client)
   271  	// Subscribe to Transactions
   272  	ch := make(chan common.Hash)
   273  	ec.SubscribePendingTransactions(context.Background(), ch)
   274  	// Send a transaction
   275  	chainID, err := ethcl.ChainID(context.Background())
   276  	if err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	// Create transaction
   280  	tx := types.NewTransaction(0, common.Address{1}, big.NewInt(1), 22000, big.NewInt(1), nil)
   281  	signer := types.LatestSignerForChainID(chainID)
   282  	signature, err := crypto.Sign(signer.Hash(tx).Bytes(), testKey)
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  	signedTx, err := tx.WithSignature(signer, signature)
   287  	if err != nil {
   288  		t.Fatal(err)
   289  	}
   290  	// Send transaction
   291  	err = ethcl.SendTransaction(context.Background(), signedTx)
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  	// Check that the transaction was send over the channel
   296  	hash := <-ch
   297  	if hash != signedTx.Hash() {
   298  		t.Fatalf("Invalid tx hash received, got %v, want %v", hash, signedTx.Hash())
   299  	}
   300  }
   301  
   302  func testCallContract(t *testing.T, client *rpc.Client) {
   303  	ec := New(client)
   304  	msg := ethereum.CallMsg{
   305  		From:     testAddr,
   306  		To:       &common.Address{},
   307  		Gas:      21000,
   308  		GasPrice: big.NewInt(1000000000),
   309  		Value:    big.NewInt(1),
   310  	}
   311  	// CallContract without override
   312  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil {
   313  		t.Fatalf("unexpected error: %v", err)
   314  	}
   315  	// CallContract with override
   316  	override := OverrideAccount{
   317  		Nonce: 1,
   318  	}
   319  	mapAcc := make(map[common.Address]OverrideAccount)
   320  	mapAcc[testAddr] = override
   321  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), &mapAcc); err != nil {
   322  		t.Fatalf("unexpected error: %v", err)
   323  	}
   324  }
   325  
   326  func testCallContractNoGas(t *testing.T, client *rpc.Client) {
   327  	ec := New(client)
   328  	msg := ethereum.CallMsg{
   329  		From:     emptyAddr, // 0 balance
   330  		To:       &common.Address{},
   331  		Gas:      21000,
   332  		GasPrice: big.NewInt(0), // gas price 0
   333  		Value:    big.NewInt(0),
   334  	}
   335  
   336  	// this would fail with `insufficient funds for gas * price + value`
   337  	// before we started considering l1DataFee for 0 gas calls.
   338  	if _, err := ec.CallContract(context.Background(), msg, big.NewInt(0), nil); err != nil {
   339  		t.Fatalf("unexpected error: %v", err)
   340  	}
   341  }