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

     1  // Copyright 2019 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 simulated
    18  
    19  import (
    20  	"context"
    21  	"crypto/ecdsa"
    22  	"math/big"
    23  	"math/rand"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/accounts/abi/bind"
    28  	"github.com/ethereum/go-ethereum/common"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/params"
    32  )
    33  
    34  var _ bind.ContractBackend = (Client)(nil)
    35  
    36  var (
    37  	testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    38  	testAddr   = crypto.PubkeyToAddress(testKey.PublicKey)
    39  )
    40  
    41  func simTestBackend(testAddr common.Address) *Backend {
    42  	return NewBackend(
    43  		types.GenesisAlloc{
    44  			testAddr: {Balance: big.NewInt(10000000000000000)},
    45  		},
    46  	)
    47  }
    48  
    49  func newTx(sim *Backend, key *ecdsa.PrivateKey) (*types.Transaction, error) {
    50  	client := sim.Client()
    51  
    52  	// create a signed transaction to send
    53  	head, _ := client.HeaderByNumber(context.Background(), nil) // Should be child's, good enough
    54  	gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(params.GWei))
    55  	addr := crypto.PubkeyToAddress(key.PublicKey)
    56  	chainid, _ := client.ChainID(context.Background())
    57  	nonce, err := client.PendingNonceAt(context.Background(), addr)
    58  	if err != nil {
    59  		return nil, err
    60  	}
    61  	tx := types.NewTx(&types.DynamicFeeTx{
    62  		ChainID:   chainid,
    63  		Nonce:     nonce,
    64  		GasTipCap: big.NewInt(params.GWei),
    65  		GasFeeCap: gasPrice,
    66  		Gas:       21000,
    67  		To:        &addr,
    68  	})
    69  	return types.SignTx(tx, types.LatestSignerForChainID(chainid), key)
    70  }
    71  
    72  func TestNewBackend(t *testing.T) {
    73  	sim := NewBackend(types.GenesisAlloc{})
    74  	defer sim.Close()
    75  
    76  	client := sim.Client()
    77  	num, err := client.BlockNumber(context.Background())
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  	if num != 0 {
    82  		t.Fatalf("expected 0 got %v", num)
    83  	}
    84  	// Create a block
    85  	sim.Commit()
    86  	num, err = client.BlockNumber(context.Background())
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  	if num != 1 {
    91  		t.Fatalf("expected 1 got %v", num)
    92  	}
    93  }
    94  
    95  func TestAdjustTime(t *testing.T) {
    96  	sim := NewBackend(types.GenesisAlloc{})
    97  	defer sim.Close()
    98  
    99  	client := sim.Client()
   100  	block1, _ := client.BlockByNumber(context.Background(), nil)
   101  
   102  	// Create a block
   103  	if err := sim.AdjustTime(time.Minute); err != nil {
   104  		t.Fatal(err)
   105  	}
   106  	block2, _ := client.BlockByNumber(context.Background(), nil)
   107  	prevTime := block1.Time()
   108  	newTime := block2.Time()
   109  	if newTime-prevTime != uint64(time.Minute) {
   110  		t.Errorf("adjusted time not equal to 60 seconds. prev: %v, new: %v", prevTime, newTime)
   111  	}
   112  }
   113  
   114  func TestSendTransaction(t *testing.T) {
   115  	sim := simTestBackend(testAddr)
   116  	defer sim.Close()
   117  
   118  	client := sim.Client()
   119  	ctx := context.Background()
   120  
   121  	signedTx, err := newTx(sim, testKey)
   122  	if err != nil {
   123  		t.Errorf("could not create transaction: %v", err)
   124  	}
   125  	// send tx to simulated backend
   126  	err = client.SendTransaction(ctx, signedTx)
   127  	if err != nil {
   128  		t.Errorf("could not add tx to pending block: %v", err)
   129  	}
   130  	sim.Commit()
   131  	block, err := client.BlockByNumber(ctx, big.NewInt(1))
   132  	if err != nil {
   133  		t.Errorf("could not get block at height 1: %v", err)
   134  	}
   135  
   136  	if signedTx.Hash() != block.Transactions()[0].Hash() {
   137  		t.Errorf("did not commit sent transaction. expected hash %v got hash %v", block.Transactions()[0].Hash(), signedTx.Hash())
   138  	}
   139  }
   140  
   141  // TestFork check that the chain length after a reorg is correct.
   142  // Steps:
   143  //  1. Save the current block which will serve as parent for the fork.
   144  //  2. Mine n blocks with n ∈ [0, 20].
   145  //  3. Assert that the chain length is n.
   146  //  4. Fork by using the parent block as ancestor.
   147  //  5. Mine n+1 blocks which should trigger a reorg.
   148  //  6. Assert that the chain length is n+1.
   149  //     Since Commit() was called 2n+1 times in total,
   150  //     having a chain length of just n+1 means that a reorg occurred.
   151  func TestFork(t *testing.T) {
   152  	t.Parallel()
   153  	testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
   154  	sim := simTestBackend(testAddr)
   155  	defer sim.Close()
   156  
   157  	client := sim.Client()
   158  	ctx := context.Background()
   159  
   160  	// 1.
   161  	parent, _ := client.HeaderByNumber(ctx, nil)
   162  
   163  	// 2.
   164  	n := int(rand.Int31n(21))
   165  	for i := 0; i < n; i++ {
   166  		sim.Commit()
   167  	}
   168  
   169  	// 3.
   170  	b, _ := client.BlockNumber(ctx)
   171  	if b != uint64(n) {
   172  		t.Error("wrong chain length")
   173  	}
   174  
   175  	// 4.
   176  	sim.Fork(parent.Hash())
   177  
   178  	// 5.
   179  	for i := 0; i < n+1; i++ {
   180  		sim.Commit()
   181  	}
   182  
   183  	// 6.
   184  	b, _ = client.BlockNumber(ctx)
   185  	if b != uint64(n+1) {
   186  		t.Error("wrong chain length")
   187  	}
   188  }
   189  
   190  // TestForkResendTx checks that re-sending a TX after a fork
   191  // is possible and does not cause a "nonce mismatch" panic.
   192  // Steps:
   193  //  1. Save the current block which will serve as parent for the fork.
   194  //  2. Send a transaction.
   195  //  3. Check that the TX is included in block 1.
   196  //  4. Fork by using the parent block as ancestor.
   197  //  5. Mine a block, Re-send the transaction and mine another one.
   198  //  6. Check that the TX is now included in block 2.
   199  func TestForkResendTx(t *testing.T) {
   200  	t.Parallel()
   201  	testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
   202  	sim := simTestBackend(testAddr)
   203  	defer sim.Close()
   204  
   205  	client := sim.Client()
   206  	ctx := context.Background()
   207  
   208  	// 1.
   209  	parent, _ := client.HeaderByNumber(ctx, nil)
   210  
   211  	// 2.
   212  	tx, err := newTx(sim, testKey)
   213  	if err != nil {
   214  		t.Fatalf("could not create transaction: %v", err)
   215  	}
   216  	client.SendTransaction(ctx, tx)
   217  	sim.Commit()
   218  
   219  	// 3.
   220  	receipt, _ := client.TransactionReceipt(ctx, tx.Hash())
   221  	if h := receipt.BlockNumber.Uint64(); h != 1 {
   222  		t.Errorf("TX included in wrong block: %d", h)
   223  	}
   224  
   225  	// 4.
   226  	if err := sim.Fork(parent.Hash()); err != nil {
   227  		t.Errorf("forking: %v", err)
   228  	}
   229  
   230  	// 5.
   231  	sim.Commit()
   232  	if err := client.SendTransaction(ctx, tx); err != nil {
   233  		t.Fatalf("sending transaction: %v", err)
   234  	}
   235  	sim.Commit()
   236  	receipt, _ = client.TransactionReceipt(ctx, tx.Hash())
   237  	if h := receipt.BlockNumber.Uint64(); h != 2 {
   238  		t.Errorf("TX included in wrong block: %d", h)
   239  	}
   240  }
   241  
   242  func TestCommitReturnValue(t *testing.T) {
   243  	t.Parallel()
   244  	testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
   245  	sim := simTestBackend(testAddr)
   246  	defer sim.Close()
   247  
   248  	client := sim.Client()
   249  	ctx := context.Background()
   250  
   251  	// Test if Commit returns the correct block hash
   252  	h1 := sim.Commit()
   253  	cur, _ := client.HeaderByNumber(ctx, nil)
   254  	if h1 != cur.Hash() {
   255  		t.Error("Commit did not return the hash of the last block.")
   256  	}
   257  
   258  	// Create a block in the original chain (containing a transaction to force different block hashes)
   259  	head, _ := client.HeaderByNumber(ctx, nil) // Should be child's, good enough
   260  	gasPrice := new(big.Int).Add(head.BaseFee, big.NewInt(1))
   261  	_tx := types.NewTransaction(0, testAddr, big.NewInt(1000), params.TxGas, gasPrice, nil)
   262  	tx, _ := types.SignTx(_tx, types.HomesteadSigner{}, testKey)
   263  	client.SendTransaction(ctx, tx)
   264  
   265  	h2 := sim.Commit()
   266  
   267  	// Create another block in the original chain
   268  	sim.Commit()
   269  
   270  	// Fork at the first bock
   271  	if err := sim.Fork(h1); err != nil {
   272  		t.Errorf("forking: %v", err)
   273  	}
   274  
   275  	// Test if Commit returns the correct block hash after the reorg
   276  	h2fork := sim.Commit()
   277  	if h2 == h2fork {
   278  		t.Error("The block in the fork and the original block are the same block!")
   279  	}
   280  	if header, err := client.HeaderByHash(ctx, h2fork); err != nil || header == nil {
   281  		t.Error("Could not retrieve the just created block (side-chain)")
   282  	}
   283  }
   284  
   285  // TestAdjustTimeAfterFork ensures that after a fork, AdjustTime uses the pending fork
   286  // block's parent rather than the canonical head's parent.
   287  func TestAdjustTimeAfterFork(t *testing.T) {
   288  	t.Parallel()
   289  	testAddr := crypto.PubkeyToAddress(testKey.PublicKey)
   290  	sim := simTestBackend(testAddr)
   291  	defer sim.Close()
   292  
   293  	client := sim.Client()
   294  	ctx := context.Background()
   295  
   296  	sim.Commit() // h1
   297  	h1, _ := client.HeaderByNumber(ctx, nil)
   298  
   299  	sim.Commit() // h2
   300  	sim.Fork(h1.Hash())
   301  	sim.AdjustTime(1 * time.Second)
   302  	sim.Commit()
   303  
   304  	head, _ := client.HeaderByNumber(ctx, nil)
   305  	if head.Number.Uint64() == 2 && head.ParentHash != h1.Hash() {
   306  		t.Errorf("failed to build block on fork")
   307  	}
   308  }