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