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