github.com/tacshi/go-ethereum@v0.0.0-20230616113857-84a434e20921/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  	"testing"
    23  
    24  	"github.com/tacshi/go-ethereum/common"
    25  	"github.com/tacshi/go-ethereum/consensus/beacon"
    26  	"github.com/tacshi/go-ethereum/consensus/ethash"
    27  	"github.com/tacshi/go-ethereum/core/rawdb"
    28  	"github.com/tacshi/go-ethereum/core/types"
    29  	"github.com/tacshi/go-ethereum/core/vm"
    30  	"github.com/tacshi/go-ethereum/crypto"
    31  	"github.com/tacshi/go-ethereum/params"
    32  )
    33  
    34  func TestGenerateWithdrawalChain(t *testing.T) {
    35  	var (
    36  		keyHex  = "9c647b8b7c4e7c3490668fb6c11473619db80c93704c70893d3813af4090c39c"
    37  		key, _  = crypto.HexToECDSA(keyHex)
    38  		address = crypto.PubkeyToAddress(key.PublicKey) // 658bdf435d810c91414ec09147daa6db62406379
    39  		aa      = common.Address{0xaa}
    40  		bb      = common.Address{0xbb}
    41  		funds   = big.NewInt(0).Mul(big.NewInt(1337), big.NewInt(params.Ether))
    42  		config  = *params.AllEthashProtocolChanges
    43  		gspec   = &Genesis{
    44  			Config:     &config,
    45  			Alloc:      GenesisAlloc{address: {Balance: funds}},
    46  			BaseFee:    big.NewInt(params.InitialBaseFee),
    47  			Difficulty: common.Big1,
    48  			GasLimit:   5_000_000,
    49  		}
    50  		gendb  = rawdb.NewMemoryDatabase()
    51  		signer = types.LatestSigner(gspec.Config)
    52  		db     = rawdb.NewMemoryDatabase()
    53  	)
    54  
    55  	config.TerminalTotalDifficultyPassed = true
    56  	config.TerminalTotalDifficulty = common.Big0
    57  	config.ShanghaiTime = u64(0)
    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] = GenesisAccount{
    66  		Balance: common.Big1,
    67  		Nonce:   1,
    68  		Storage: storage,
    69  		Code:    common.Hex2Bytes("6042"),
    70  	}
    71  	gspec.Alloc[bb] = GenesisAccount{
    72  		Balance: common.Big2,
    73  		Nonce:   1,
    74  		Storage: storage,
    75  		Code:    common.Hex2Bytes("600154600354"),
    76  	}
    77  
    78  	genesis := gspec.MustCommit(gendb)
    79  
    80  	chain, _ := GenerateChain(gspec.Config, genesis, beacon.NewFaker(), gendb, 4, func(i int, gen *BlockGen) {
    81  		tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(address), address, big.NewInt(1000), params.TxGas, new(big.Int).Add(gen.BaseFee(), common.Big1), nil), signer, key)
    82  		gen.AddTx(tx)
    83  		if i == 1 {
    84  			gen.AddWithdrawal(&types.Withdrawal{
    85  				Validator: 42,
    86  				Address:   common.Address{0xee},
    87  				Amount:    1337,
    88  			})
    89  			gen.AddWithdrawal(&types.Withdrawal{
    90  				Validator: 13,
    91  				Address:   common.Address{0xee},
    92  				Amount:    1,
    93  			})
    94  		}
    95  		if i == 3 {
    96  			gen.AddWithdrawal(&types.Withdrawal{
    97  				Validator: 42,
    98  				Address:   common.Address{0xee},
    99  				Amount:    1337,
   100  			})
   101  			gen.AddWithdrawal(&types.Withdrawal{
   102  				Validator: 13,
   103  				Address:   common.Address{0xee},
   104  				Amount:    1,
   105  			})
   106  		}
   107  	})
   108  
   109  	// Import the chain. This runs all block validation rules.
   110  	blockchain, _ := NewBlockChain(db, nil, nil, gspec, nil, beacon.NewFaker(), vm.Config{}, nil, nil)
   111  	defer blockchain.Stop()
   112  
   113  	if i, err := blockchain.InsertChain(chain); err != nil {
   114  		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
   115  		return
   116  	}
   117  
   118  	// enforce that withdrawal indexes are monotonically increasing from 0
   119  	var (
   120  		withdrawalIndex uint64
   121  		head            = blockchain.CurrentBlock().Number.Uint64()
   122  	)
   123  	for i := 0; i < int(head); i++ {
   124  		block := blockchain.GetBlockByNumber(uint64(i))
   125  		if block == nil {
   126  			t.Fatalf("block %d not found", i)
   127  		}
   128  		if len(block.Withdrawals()) == 0 {
   129  			continue
   130  		}
   131  		for j := 0; j < len(block.Withdrawals()); j++ {
   132  			if block.Withdrawals()[j].Index != withdrawalIndex {
   133  				t.Fatalf("withdrawal index %d does not equal expected index %d", block.Withdrawals()[j].Index, withdrawalIndex)
   134  			}
   135  			withdrawalIndex += 1
   136  		}
   137  	}
   138  }
   139  
   140  func ExampleGenerateChain() {
   141  	var (
   142  		key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   143  		key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a")
   144  		key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee")
   145  		addr1   = crypto.PubkeyToAddress(key1.PublicKey)
   146  		addr2   = crypto.PubkeyToAddress(key2.PublicKey)
   147  		addr3   = crypto.PubkeyToAddress(key3.PublicKey)
   148  		db      = rawdb.NewMemoryDatabase()
   149  	)
   150  
   151  	// Ensure that key1 has some funds in the genesis block.
   152  	gspec := &Genesis{
   153  		Config: &params.ChainConfig{HomesteadBlock: new(big.Int)},
   154  		Alloc:  GenesisAlloc{addr1: {Balance: big.NewInt(1000000)}},
   155  	}
   156  	genesis := gspec.MustCommit(db)
   157  
   158  	// This call generates a chain of 5 blocks. The function runs for
   159  	// each block and adds different features to gen based on the
   160  	// block index.
   161  	signer := types.HomesteadSigner{}
   162  	chain, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 5, func(i int, gen *BlockGen) {
   163  		switch i {
   164  		case 0:
   165  			// In block 1, addr1 sends addr2 some ether.
   166  			tx, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(10000), params.TxGas, nil, nil), signer, key1)
   167  			gen.AddTx(tx)
   168  		case 1:
   169  			// In block 2, addr1 sends some more ether to addr2.
   170  			// addr2 passes it on to addr3.
   171  			tx1, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr1), addr2, big.NewInt(1000), params.TxGas, nil, nil), signer, key1)
   172  			tx2, _ := types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr3, big.NewInt(1000), params.TxGas, nil, nil), signer, key2)
   173  			gen.AddTx(tx1)
   174  			gen.AddTx(tx2)
   175  		case 2:
   176  			// Block 3 is empty but was mined by addr3.
   177  			gen.SetCoinbase(addr3)
   178  			gen.SetExtra([]byte("yeehaw"))
   179  		case 3:
   180  			// Block 4 includes blocks 2 and 3 as uncle headers (with modified extra data).
   181  			b2 := gen.PrevBlock(1).Header()
   182  			b2.Extra = []byte("foo")
   183  			gen.AddUncle(b2)
   184  			b3 := gen.PrevBlock(2).Header()
   185  			b3.Extra = []byte("foo")
   186  			gen.AddUncle(b3)
   187  		}
   188  	})
   189  
   190  	// Import the chain. This runs all block validation rules.
   191  	blockchain, _ := NewBlockChain(db, nil, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil, nil)
   192  	defer blockchain.Stop()
   193  
   194  	if i, err := blockchain.InsertChain(chain); err != nil {
   195  		fmt.Printf("insert error (block %d): %v\n", chain[i].NumberU64(), err)
   196  		return
   197  	}
   198  
   199  	state, _ := blockchain.State()
   200  	fmt.Printf("last block: #%d\n", blockchain.CurrentBlock().Number)
   201  	fmt.Println("balance of addr1:", state.GetBalance(addr1))
   202  	fmt.Println("balance of addr2:", state.GetBalance(addr2))
   203  	fmt.Println("balance of addr3:", state.GetBalance(addr3))
   204  	// Output:
   205  	// last block: #5
   206  	// balance of addr1: 989000
   207  	// balance of addr2: 10000
   208  	// balance of addr3: 19687500000000001000
   209  }