github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/core/chain_makers_test.go (about)

     1  // Copyright 2015 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 core
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  	"reflect"
    23  	"testing"
    24  
    25  	"github.com/davecgh/go-spew/spew"
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/consensus/beacon"
    28  	"github.com/ethereum/go-ethereum/consensus/ethash"
    29  	"github.com/ethereum/go-ethereum/core/rawdb"
    30  	"github.com/ethereum/go-ethereum/core/types"
    31  	"github.com/ethereum/go-ethereum/core/vm"
    32  	"github.com/ethereum/go-ethereum/crypto"
    33  	"github.com/ethereum/go-ethereum/params"
    34  	"github.com/ethereum/go-ethereum/triedb"
    35  )
    36  
    37  func TestGeneratePOSChain(t *testing.T) {
    38  	var (
    39  		keyHex  = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
    40  		key, _  = crypto.HexToECDSA(keyHex)
    41  		address = crypto.PubkeyToAddress(key.PublicKey) // 658bdf435d810c91414ec09147daa6db62406379
    42  		aa      = common.Address{0xaa}
    43  		bb      = common.Address{0xbb}
    44  		funds   = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
    45  		config  = *params.AllEthashProtocolChanges
    46  		gspec   = &Genesis{
    47  			Config: &config,
    48  			Alloc: types.GenesisAlloc{
    49  				address:                   {Balance: funds},
    50  				params.BeaconRootsAddress: {Code: params.BeaconRootsCode},
    51  			},
    52  			BaseFee:    big.NewInt(params.InitialBaseFee),
    53  			Difficulty: common.Big1,
    54  			GasLimit:   5_000_000,
    55  		}
    56  		gendb = rawdb.NewMemoryDatabase()
    57  		db    = rawdb.NewMemoryDatabase()
    58  	)
    59  
    60  	config.TerminalTotalDifficultyPassed = true
    61  	config.TerminalTotalDifficulty = common.Big0
    62  	config.ShanghaiTime = u64(0)
    63  	config.CancunTime = u64(0)
    64  
    65  	// init 0xaa with some storage elements
    66  	storage := make(map[common.Hash]common.Hash)
    67  	storage[common.Hash{0x00}] = common.Hash{0x00}
    68  	storage[common.Hash{0x01}] = common.Hash{0x01}
    69  	storage[common.Hash{0x02}] = common.Hash{0x02}
    70  	storage[common.Hash{0x03}] = common.HexToHash("0303")
    71  	gspec.Alloc[aa] = types.Account{
    72  		Balance: common.Big1,
    73  		Nonce:   1,
    74  		Storage: storage,
    75  		Code:    common.Hex2Bytes("6042"),
    76  	}
    77  	gspec.Alloc[bb] = types.Account{
    78  		Balance: common.Big2,
    79  		Nonce:   1,
    80  		Storage: storage,
    81  		Code:    common.Hex2Bytes("600154600354"),
    82  	}
    83  	genesis := gspec.MustCommit(gendb, triedb.NewDatabase(gendb, triedb.HashDefaults))
    84  
    85  	genchain, genreceipts := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
    86  		gen.SetParentBeaconRoot(common.Hash{byte(i + 1)})
    87  
    88  		// Add value transfer tx.
    89  		tx := types.MustSignNewTx(key, gen.Signer(), &types.LegacyTx{
    90  			Nonce:    gen.TxNonce(address),
    91  			To:       &address,
    92  			Value:    big.NewInt(1000),
    93  			Gas:      params.TxGas,
    94  			GasPrice: new(big.Int).Add(gen.BaseFee(), common.Big1),
    95  		})
    96  		gen.AddTx(tx)
    97  
    98  		// Add withdrawals.
    99  		if i == 1 {
   100  			gen.AddWithdrawal(&types.Withdrawal{
   101  				Validator: 42,
   102  				Address:   common.Address{0xee},
   103  				Amount:    1337,
   104  			})
   105  			gen.AddWithdrawal(&types.Withdrawal{
   106  				Validator: 13,
   107  				Address:   common.Address{0xee},
   108  				Amount:    1,
   109  			})
   110  		}
   111  		if i == 3 {
   112  			gen.AddWithdrawal(&types.Withdrawal{
   113  				Validator: 42,
   114  				Address:   common.Address{0xee},
   115  				Amount:    1337,
   116  			})
   117  			gen.AddWithdrawal(&types.Withdrawal{
   118  				Validator: 13,
   119  				Address:   common.Address{0xee},
   120  				Amount:    1,
   121  			})
   122  		}
   123  	})
   124  
   125  	// Import the chain. This runs all block validation rules.
   126  	blockchain, _ := NewBlockChain(db, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil)
   127  	defer blockchain.Stop()
   128  
   129  	if i, err := blockchain.InsertChain(genchain); err != nil {
   130  		t.Fatalf("insert error (block %d): %v\n", genchain[i].NumberU64(), err)
   131  	}
   132  
   133  	// enforce that withdrawal indexes are monotonically increasing from 0
   134  	var (
   135  		withdrawalIndex uint64
   136  	)
   137  	for i := range genchain {
   138  		blocknum := genchain[i].NumberU64()
   139  		block := blockchain.GetBlockByNumber(blocknum)
   140  		if block == nil {
   141  			t.Fatalf("block %d not found", blocknum)
   142  		}
   143  
   144  		// Verify receipts.
   145  		genBlockReceipts := genreceipts[i]
   146  		for _, r := range genBlockReceipts {
   147  			if r.BlockNumber.Cmp(block.Number()) != 0 {
   148  				t.Errorf("receipt has wrong block number %d, want %d", r.BlockNumber, block.Number())
   149  			}
   150  			if r.BlockHash != block.Hash() {
   151  				t.Errorf("receipt has wrong block hash %v, want %v", r.BlockHash, block.Hash())
   152  			}
   153  
   154  			// patch up empty logs list to make DeepEqual below work
   155  			if r.Logs == nil {
   156  				r.Logs = []*types.Log{}
   157  			}
   158  		}
   159  		blockchainReceipts := blockchain.GetReceiptsByHash(block.Hash())
   160  		if !reflect.DeepEqual(genBlockReceipts, blockchainReceipts) {
   161  			t.Fatalf("receipts mismatch\ngenerated: %s\nblockchain: %s", spew.Sdump(genBlockReceipts), spew.Sdump(blockchainReceipts))
   162  		}
   163  
   164  		// Verify withdrawals.
   165  		if len(block.Withdrawals()) == 0 {
   166  			continue
   167  		}
   168  		for j := 0; j < len(block.Withdrawals()); j++ {
   169  			if block.Withdrawals()[j].Index != withdrawalIndex {
   170  				t.Fatalf("withdrawal index %d does not equal expected index %d", block.Withdrawals()[j].Index, withdrawalIndex)
   171  			}
   172  			withdrawalIndex += 1
   173  		}
   174  
   175  		// Verify parent beacon root.
   176  		want := common.Hash{byte(blocknum)}
   177  		if got := block.BeaconRoot(); *got != want {
   178  			t.Fatalf("block %d, wrong parent beacon root: got %s, want %s", i, got, want)
   179  		}
   180  		state, _ := blockchain.State()
   181  		idx := block.Time()%8191 + 8191
   182  		got := state.GetState(params.BeaconRootsAddress, common.BigToHash(new(big.Int).SetUint64(idx)))
   183  		if got != want {
   184  			t.Fatalf("block %d, wrong parent beacon root in state: got %s, want %s", i, got, want)
   185  		}
   186  	}
   187  }
   188  
   189  func ExampleGenerateChain() {
   190  	var (
   191  		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   192  		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   193  		key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   194  		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
   195  		addr2   = crypto.PubkeyToAddress(key2.PublicKey)
   196  		addr3   = crypto.PubkeyToAddress(key3.PublicKey)
   197  		db      = rawdb.NewMemoryDatabase()
   198  		genDb   = rawdb.NewMemoryDatabase()
   199  	)
   200  
   201  	// Ensure that key1 has some funds in the genesis block.
   202  	gspec := &Genesis{
   203  		Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
   204  		Alloc:  types.GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
   205  	}
   206  	genesis := gspec.MustCommit(genDb, triedb.NewDatabase(genDb, triedb.HashDefaults))
   207  
   208  	// This call generates a chain of 5 blocks. The function runs for
   209  	// each block and adds different features to gen based on the
   210  	// block index.
   211  	signer := types.HomesteadSigner{}
   212  	chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), genDb, 5, func(i int, gen *BlockGen) {
   213  		switch i {
   214  		case 0:
   215  			// In block 1, addr1 sends addr2 some ether.
   216  			tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
   217  			gen.AddTx(tx)
   218  		case 1:
   219  			// In block 2, addr1 sends some more ether to addr2.
   220  			// addr2 passes it on to addr3.
   221  			tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
   222  			tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
   223  			gen.AddTx(tx1)
   224  			gen.AddTx(tx2)
   225  		case 2:
   226  			// Block 3 is empty but was mined by addr3.
   227  			gen.SetCoinbase(addr3)
   228  			gen.SetExtra([]byte("yeehaw"))
   229  		case 3:
   230  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   231  			b2 := gen.PrevBlock(1).Header()
   232  			b2.Extra = []byte("foo")
   233  			gen.AddUncle(b2)
   234  			b3 := gen.PrevBlock(2).Header()
   235  			b3.Extra = []byte("foo")
   236  			gen.AddUncle(b3)
   237  		}
   238  	})
   239  
   240  	// Import the chain. This runs all block validation rules.
   241  	blockchain, _ := NewBlockChain(db, DefaultCacheConfigWithScheme(rawdb.HashScheme), gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
   242  	defer blockchain.Stop()
   243  
   244  	if i, err := blockchain.InsertChain(chain); err != nil {
   245  		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
   246  		return
   247  	}
   248  
   249  	state, _ := blockchain.State()
   250  	fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number)
   251  	fmt.Println("balance of addr1:", state.GetBalance(addr1))
   252  	fmt.Println("balance of addr2:", state.GetBalance(addr2))
   253  	fmt.Println("balance of addr3:", state.GetBalance(addr3))
   254  	// Output:
   255  	// last block: #5
   256  	// balance of addr1: 989000
   257  	// balance of addr2: 10000
   258  	// balance of addr3: 19687500000000001000
   259  }