2024-02-07 10:18:27 -06:00
|
|
|
// Copyright 2023 The go-ethereum Authors
|
|
|
|
// This file is part of go-ethereum.
|
|
|
|
//
|
|
|
|
// go-ethereum is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
|
|
// (at your option) any later version.
|
|
|
|
//
|
|
|
|
// go-ethereum is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License for more details.
|
|
|
|
//
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
|
|
package utils
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/sha256"
|
|
|
|
"io"
|
|
|
|
"math/big"
|
|
|
|
"os"
|
2024-03-12 04:00:34 -05:00
|
|
|
"path/filepath"
|
2024-02-07 10:18:27 -06:00
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
|
|
|
"github.com/ethereum/go-ethereum/consensus/ethash"
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
|
|
|
"github.com/ethereum/go-ethereum/core/types"
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
|
|
|
"github.com/ethereum/go-ethereum/crypto"
|
|
|
|
"github.com/ethereum/go-ethereum/internal/era"
|
|
|
|
"github.com/ethereum/go-ethereum/params"
|
|
|
|
"github.com/ethereum/go-ethereum/trie"
|
2024-02-14 02:26:53 -06:00
|
|
|
"github.com/ethereum/go-ethereum/triedb"
|
2024-02-07 10:18:27 -06:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
count uint64 = 128
|
|
|
|
step uint64 = 16
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestHistoryImportAndExport(t *testing.T) {
|
|
|
|
var (
|
|
|
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
|
|
|
address = crypto.PubkeyToAddress(key.PublicKey)
|
|
|
|
genesis = &core.Genesis{
|
|
|
|
Config: params.TestChainConfig,
|
2024-02-16 12:05:33 -06:00
|
|
|
Alloc: types.GenesisAlloc{address: {Balance: big.NewInt(1000000000000000000)}},
|
2024-02-07 10:18:27 -06:00
|
|
|
}
|
|
|
|
signer = types.LatestSigner(genesis.Config)
|
|
|
|
)
|
|
|
|
|
|
|
|
// Generate chain.
|
|
|
|
db, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), int(count), func(i int, g *core.BlockGen) {
|
|
|
|
if i == 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
tx, err := types.SignNewTx(key, signer, &types.DynamicFeeTx{
|
|
|
|
ChainID: genesis.Config.ChainID,
|
|
|
|
Nonce: uint64(i - 1),
|
|
|
|
GasTipCap: common.Big0,
|
|
|
|
GasFeeCap: g.PrevBlock(0).BaseFee(),
|
|
|
|
Gas: 50000,
|
|
|
|
To: &common.Address{0xaa},
|
|
|
|
Value: big.NewInt(int64(i)),
|
|
|
|
Data: nil,
|
|
|
|
AccessList: nil,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating tx: %v", err)
|
|
|
|
}
|
|
|
|
g.AddTx(tx)
|
|
|
|
})
|
|
|
|
|
|
|
|
// Initialize BlockChain.
|
2024-09-04 08:03:06 -05:00
|
|
|
chain, err := core.NewBlockChain(db, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
|
2024-02-07 10:18:27 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to initialize chain: %v", err)
|
|
|
|
}
|
|
|
|
if _, err := chain.InsertChain(blocks); err != nil {
|
2024-04-15 01:40:42 -05:00
|
|
|
t.Fatalf("error inserting chain: %v", err)
|
2024-02-07 10:18:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Make temp directory for era files.
|
|
|
|
dir, err := os.MkdirTemp("", "history-export-test")
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error creating temp test directory: %v", err)
|
|
|
|
}
|
|
|
|
defer os.RemoveAll(dir)
|
|
|
|
|
|
|
|
// Export history to temp directory.
|
|
|
|
if err := ExportHistory(chain, dir, 0, count, step); err != nil {
|
|
|
|
t.Fatalf("error exporting history: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read checksums.
|
2024-03-12 04:00:34 -05:00
|
|
|
b, err := os.ReadFile(filepath.Join(dir, "checksums.txt"))
|
2024-02-07 10:18:27 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("failed to read checksums: %v", err)
|
|
|
|
}
|
|
|
|
checksums := strings.Split(string(b), "\n")
|
|
|
|
|
|
|
|
// Verify each Era.
|
|
|
|
entries, _ := era.ReadDir(dir, "mainnet")
|
|
|
|
for i, filename := range entries {
|
|
|
|
func() {
|
2024-03-12 04:00:34 -05:00
|
|
|
f, err := os.Open(filepath.Join(dir, filename))
|
2024-02-07 10:18:27 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error opening era file: %v", err)
|
|
|
|
}
|
|
|
|
var (
|
|
|
|
h = sha256.New()
|
|
|
|
buf = bytes.NewBuffer(nil)
|
|
|
|
)
|
|
|
|
if _, err := io.Copy(h, f); err != nil {
|
|
|
|
t.Fatalf("unable to recalculate checksum: %v", err)
|
|
|
|
}
|
|
|
|
if got, want := common.BytesToHash(h.Sum(buf.Bytes()[:])).Hex(), checksums[i]; got != want {
|
|
|
|
t.Fatalf("checksum %d does not match: got %s, want %s", i, got, want)
|
|
|
|
}
|
|
|
|
e, err := era.From(f)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error opening era: %v", err)
|
|
|
|
}
|
|
|
|
defer e.Close()
|
|
|
|
it, err := era.NewIterator(e)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error making era reader: %v", err)
|
|
|
|
}
|
|
|
|
for j := 0; it.Next(); j++ {
|
|
|
|
n := i*int(step) + j
|
|
|
|
if it.Error() != nil {
|
2024-02-09 00:42:50 -06:00
|
|
|
t.Fatalf("error reading block entry %d: %v", n, it.Error())
|
2024-02-07 10:18:27 -06:00
|
|
|
}
|
|
|
|
block, receipts, err := it.BlockAndReceipts()
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error reading block entry %d: %v", n, err)
|
|
|
|
}
|
|
|
|
want := chain.GetBlockByNumber(uint64(n))
|
|
|
|
if want, got := uint64(n), block.NumberU64(); want != got {
|
|
|
|
t.Fatalf("blocks out of order: want %d, got %d", want, got)
|
|
|
|
}
|
|
|
|
if want.Hash() != block.Hash() {
|
|
|
|
t.Fatalf("block hash mismatch %d: want %s, got %s", n, want.Hash().Hex(), block.Hash().Hex())
|
|
|
|
}
|
|
|
|
if got := types.DeriveSha(block.Transactions(), trie.NewStackTrie(nil)); got != want.TxHash() {
|
|
|
|
t.Fatalf("tx hash %d mismatch: want %s, got %s", n, want.TxHash(), got)
|
|
|
|
}
|
|
|
|
if got := types.CalcUncleHash(block.Uncles()); got != want.UncleHash() {
|
|
|
|
t.Fatalf("uncle hash %d mismatch: want %s, got %s", n, want.UncleHash(), got)
|
|
|
|
}
|
|
|
|
if got := types.DeriveSha(receipts, trie.NewStackTrie(nil)); got != want.ReceiptHash() {
|
|
|
|
t.Fatalf("receipt root %d mismatch: want %s, got %s", n, want.ReceiptHash(), got)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now import Era.
|
2024-05-08 01:43:33 -05:00
|
|
|
db2, err := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), "", "", false)
|
2024-02-07 10:18:27 -06:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
t.Cleanup(func() {
|
|
|
|
db2.Close()
|
|
|
|
})
|
|
|
|
|
cmd, core, miner: rework genesis setup (#30907)
This pull request refactors the genesis setup function, the major
changes are highlighted here:
**(a) Triedb is opened in verkle mode if `EnableVerkleAtGenesis` is
configured in chainConfig or the database has been initialized previously with
`EnableVerkleAtGenesis` configured**.
A new config field `EnableVerkleAtGenesis` has been added in the
chainConfig. This field must be configured with True if Geth wants to initialize
the genesis in Verkle mode.
In the verkle devnet-7, the verkle transition is activated at genesis.
Therefore, the verkle rules should be used since the genesis. In production
networks (mainnet and public testnets), verkle activation always occurs after
the genesis block. Therefore, this flag is only made for devnet and should be
deprecated later. Besides, verkle transition at non-genesis block hasn't been
implemented yet, it should be done in the following PRs.
**(b) The genesis initialization condition has been simplified**
There is a special mode supported by the Geth is that: Geth can be
initialized with an existing chain segment, which can fasten the node sync
process by retaining the chain freezer folder.
Originally, if the triedb is regarded as uninitialized and the genesis block can
be found in the chain freezer, the genesis block along with genesis state will be
committed. This condition has been simplified to checking the presence of chain
config in key-value store. The existence of chain config can represent the genesis
has been committed.
2025-01-14 04:49:30 -06:00
|
|
|
genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults))
|
2024-09-04 08:03:06 -05:00
|
|
|
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
|
2024-02-07 10:18:27 -06:00
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("unable to initialize chain: %v", err)
|
|
|
|
}
|
|
|
|
if err := ImportHistory(imported, db2, dir, "mainnet"); err != nil {
|
|
|
|
t.Fatalf("failed to import chain: %v", err)
|
|
|
|
}
|
|
|
|
if have, want := imported.CurrentHeader(), chain.CurrentHeader(); have.Hash() != want.Hash() {
|
|
|
|
t.Fatalf("imported chain does not match expected, have (%d, %s) want (%d, %s)", have.Number, have.Hash(), want.Number, want.Hash())
|
|
|
|
}
|
|
|
|
}
|