github.com/ethereum/go-ethereum@v1.14.4-0.20240516095835-473ee8fc07a3/cmd/utils/history_test.go (about) 1 // Copyright 2023 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU 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 // go-ethereum 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 General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package utils 18 19 import ( 20 "bytes" 21 "crypto/sha256" 22 "io" 23 "math/big" 24 "os" 25 "path/filepath" 26 "strings" 27 "testing" 28 29 "github.com/ethereum/go-ethereum/common" 30 "github.com/ethereum/go-ethereum/consensus/ethash" 31 "github.com/ethereum/go-ethereum/core" 32 "github.com/ethereum/go-ethereum/core/rawdb" 33 "github.com/ethereum/go-ethereum/core/types" 34 "github.com/ethereum/go-ethereum/core/vm" 35 "github.com/ethereum/go-ethereum/crypto" 36 "github.com/ethereum/go-ethereum/internal/era" 37 "github.com/ethereum/go-ethereum/params" 38 "github.com/ethereum/go-ethereum/trie" 39 "github.com/ethereum/go-ethereum/triedb" 40 ) 41 42 var ( 43 count uint64 = 128 44 step uint64 = 16 45 ) 46 47 func TestHistoryImportAndExport(t *testing.T) { 48 var ( 49 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 50 address = crypto.PubkeyToAddress(key.PublicKey) 51 genesis = &core.Genesis{ 52 Config: params.TestChainConfig, 53 Alloc: types.GenesisAlloc{address: {Balance: big.NewInt(1000000000000000000)}}, 54 } 55 signer = types.LatestSigner(genesis.Config) 56 ) 57 58 // Generate chain. 59 db, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), int(count), func(i int, g *core.BlockGen) { 60 if i == 0 { 61 return 62 } 63 tx, err := types.SignNewTx(key, signer, &types.DynamicFeeTx{ 64 ChainID: genesis.Config.ChainID, 65 Nonce: uint64(i - 1), 66 GasTipCap: common.Big0, 67 GasFeeCap: g.PrevBlock(0).BaseFee(), 68 Gas: 50000, 69 To: &common.Address{0xaa}, 70 Value: big.NewInt(int64(i)), 71 Data: nil, 72 AccessList: nil, 73 }) 74 if err != nil { 75 t.Fatalf("error creating tx: %v", err) 76 } 77 g.AddTx(tx) 78 }) 79 80 // Initialize BlockChain. 81 chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) 82 if err != nil { 83 t.Fatalf("unable to initialize chain: %v", err) 84 } 85 if _, err := chain.InsertChain(blocks); err != nil { 86 t.Fatalf("error inserting chain: %v", err) 87 } 88 89 // Make temp directory for era files. 90 dir, err := os.MkdirTemp("", "history-export-test") 91 if err != nil { 92 t.Fatalf("error creating temp test directory: %v", err) 93 } 94 defer os.RemoveAll(dir) 95 96 // Export history to temp directory. 97 if err := ExportHistory(chain, dir, 0, count, step); err != nil { 98 t.Fatalf("error exporting history: %v", err) 99 } 100 101 // Read checksums. 102 b, err := os.ReadFile(filepath.Join(dir, "checksums.txt")) 103 if err != nil { 104 t.Fatalf("failed to read checksums: %v", err) 105 } 106 checksums := strings.Split(string(b), "\n") 107 108 // Verify each Era. 109 entries, _ := era.ReadDir(dir, "mainnet") 110 for i, filename := range entries { 111 func() { 112 f, err := os.Open(filepath.Join(dir, filename)) 113 if err != nil { 114 t.Fatalf("error opening era file: %v", err) 115 } 116 var ( 117 h = sha256.New() 118 buf = bytes.NewBuffer(nil) 119 ) 120 if _, err := io.Copy(h, f); err != nil { 121 t.Fatalf("unable to recalculate checksum: %v", err) 122 } 123 if got, want := common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex(), checksums[i]; got != want { 124 t.Fatalf("checksum %d does not match: got %s, want %s", i, got, want) 125 } 126 e, err := era.From(f) 127 if err != nil { 128 t.Fatalf("error opening era: %v", err) 129 } 130 defer e.Close() 131 it, err := era.NewIterator(e) 132 if err != nil { 133 t.Fatalf("error making era reader: %v", err) 134 } 135 for j := 0; it.Next(); j++ { 136 n := i*int(step) + j 137 if it.Error() != nil { 138 t.Fatalf("error reading block entry %d: %v", n, it.Error()) 139 } 140 block, receipts, err := it.BlockAndReceipts() 141 if err != nil { 142 t.Fatalf("error reading block entry %d: %v", n, err) 143 } 144 want := chain.GetBlockByNumber(uint64(n)) 145 if want, got := uint64(n), block.NumberU64(); want != got { 146 t.Fatalf("blocks out of order: want %d, got %d", want, got) 147 } 148 if want.Hash() != block.Hash() { 149 t.Fatalf("block hash mismatch %d: want %s, got %s", n, want.Hash().Hex(), block.Hash().Hex()) 150 } 151 if got := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); got != want.TxHash() { 152 t.Fatalf("tx hash %d mismatch: want %s, got %s", n, want.TxHash(), got) 153 } 154 if got := types.CalcUncleHash(block.Uncles()); got != want.UncleHash() { 155 t.Fatalf("uncle hash %d mismatch: want %s, got %s", n, want.UncleHash(), got) 156 } 157 if got := types.DeriveSha(receipts, trie.NewStackTrie(nil)); got != want.ReceiptHash() { 158 t.Fatalf("receipt root %d mismatch: want %s, got %s", n, want.ReceiptHash(), got) 159 } 160 } 161 }() 162 } 163 164 // Now import Era. 165 db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false) 166 if err != nil { 167 panic(err) 168 } 169 t.Cleanup(func() { 170 db2.Close() 171 }) 172 173 genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults)) 174 imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil, nil) 175 if err != nil { 176 t.Fatalf("unable to initialize chain: %v", err) 177 } 178 if err := ImportHistory(imported, db2, dir, "mainnet"); err != nil { 179 t.Fatalf("failed to import chain: %v", err) 180 } 181 if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() { 182 t.Fatalf("imported chain does not match expected, have (%d, %s) want (%d, %s)", have.Number, have.Hash(), want.Number, want.Hash()) 183 } 184 }