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: ¶ms.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 }