From 85f2bebfd122f8b7ec27e51d98389acb0597ae51 Mon Sep 17 00:00:00 2001 From: Daniel Liu <139250065@qq.com> Date: Tue, 10 Feb 2026 19:26:34 +0800 Subject: [PATCH] refactor(all): move genesis initialization to blockchain #25523 (#2018) --- accounts/abi/bind/backends/simulated.go | 4 +- cmd/XDC/dao_test.go | 8 +++- cmd/utils/flags.go | 13 ++++--- core/bench_test.go | 9 ++++- core/block_validator_test.go | 2 +- core/blockchain.go | 27 +++++++++++-- core/blockchain_test.go | 50 +++++++++++++------------ core/chain_makers_test.go | 2 +- core/dao_test.go | 36 +++++++++++------- core/genesis.go | 42 ++++++++++++++++++++- core/genesis_test.go | 2 +- core/state_processor_test.go | 6 +-- eth/backend.go | 37 ++++++++---------- eth/filters/filter_system_test.go | 2 +- eth/filters/filter_test.go | 4 +- eth/gasprice/gasprice_test.go | 2 +- eth/handler_test.go | 20 ++++++---- eth/helper_test.go | 2 +- eth/tracers/api_test.go | 2 +- params/config.go | 2 +- tests/block_test_util.go | 2 +- 21 files changed, 178 insertions(+), 96 deletions(-) diff --git a/accounts/abi/bind/backends/simulated.go b/accounts/abi/bind/backends/simulated.go index 728ea28b84..fe920e9d73 100644 --- a/accounts/abi/bind/backends/simulated.go +++ b/accounts/abi/bind/backends/simulated.go @@ -143,7 +143,7 @@ func NewXDCSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64, chainConf TrieTimeLimit: 5 * time.Minute, Preimages: true, } - blockchain, _ := core.NewBlockChain(database, cacheConfig, genesis.Config, consensus, vm.Config{}) + blockchain, _ := core.NewBlockChain(database, cacheConfig, &genesis, consensus, vm.Config{}) backend := &SimulatedBackend{ database: database, @@ -171,7 +171,7 @@ func NewSimulatedBackend(alloc types.GenesisAlloc, gasLimit uint64) *SimulatedBa database := rawdb.NewMemoryDatabase() genesis := core.Genesis{Config: params.AllEthashProtocolChanges, GasLimit: gasLimit, Alloc: alloc} genesis.MustCommit(database) - blockchain, _ := core.NewBlockChain(database, nil, genesis.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := core.NewBlockChain(database, nil, &genesis, ethash.NewFaker(), vm.Config{}) backend := &SimulatedBackend{ database: database, diff --git a/cmd/XDC/dao_test.go b/cmd/XDC/dao_test.go index daa46994da..e46398b640 100644 --- a/cmd/XDC/dao_test.go +++ b/cmd/XDC/dao_test.go @@ -128,8 +128,12 @@ func testDAOForkBlockNewChain(t *testing.T, test int, genesis string, expectBloc } config, err := rawdb.ReadChainConfig(db, genesisHash) if err != nil { - t.Errorf("test %d: failed to retrieve chain config: %v", test, err) - return // we want to return here, the other checks can't make it past this point (nil panic). + t.Errorf("test %d: failed to read chain config: %v", test, err) + return + } + if config == nil { + t.Errorf("test %d: failed to retrieve chain config", test) + return } // Validate the DAO hard-fork block number against the expected value if config.DAOForkBlock == nil { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 9f5241a354..86ac478f16 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -1762,11 +1762,12 @@ func MakeGenesis(ctx *cli.Context) *core.Genesis { } // MakeChain creates a chain manager from set command line flags. -func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (chain *core.BlockChain, chainDb ethdb.Database) { - var err error - chainDb = MakeChainDatabase(ctx, stack, readonly) - - config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) +func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockChain, ethdb.Database) { + var ( + gspec = MakeGenesis(ctx) + chainDb = MakeChainDatabase(ctx, stack, readonly) + ) + config, _, err := core.LoadChainConfig(chainDb, gspec) if err != nil { Fatalf("%v", err) } @@ -1809,7 +1810,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (chain *core.B } } // Disable transaction indexing/unindexing by default. - chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg) + chain, err := core.NewBlockChain(chainDb, cache, gspec, engine, vmcfg) if err != nil { Fatalf("Can't create BlockChain: %v", err) } diff --git a/core/bench_test.go b/core/bench_test.go index 484937b38e..b5892eb480 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -170,7 +170,7 @@ func benchInsertChain(b *testing.B, disk bool, gen func(int, *BlockGen)) { // Time the insertion of the new chain. // State and blocks are stored in the same DB. - chainman, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + chainman, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer chainman.Stop() b.ReportAllocs() b.ResetTimer() @@ -236,6 +236,11 @@ func makeChainForBench(db ethdb.Database, full bool, count uint64) { rawdb.WriteCanonicalHash(db, hash, n) rawdb.WriteTd(db, hash, n, big.NewInt(int64(n+1))) + if n == 0 { + rawdb.WriteChainConfig(db, hash, params.TestChainConfig) + } + rawdb.WriteHeadHeaderHash(db, hash) + if full || n == 0 { block := types.NewBlockWithHeader(header) rawdb.WriteBody(db, hash, n, block.Body()) @@ -273,7 +278,7 @@ func benchReadChain(b *testing.B, full bool, count uint64) { if err != nil { b.Fatalf("error opening database at %v: %v", dir, err) } - chain, err := NewBlockChain(db, nil, params.TestChainConfig, ethash.NewFaker(), vm.Config{}) + chain, err := NewBlockChain(db, nil, nil, ethash.NewFaker(), vm.Config{}) if err != nil { b.Fatalf("error creating chain: %v", err) } diff --git a/core/block_validator_test.go b/core/block_validator_test.go index 34e493cca3..d3f498826d 100644 --- a/core/block_validator_test.go +++ b/core/block_validator_test.go @@ -41,7 +41,7 @@ func TestHeaderVerification(t *testing.T) { headers[i] = block.Header() } // Run the header checker for blocks one-by-one, checking for both valid and invalid nonces - chain, err := NewBlockChain(testdb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + chain, err := NewBlockChain(testdb, nil, gspec, ethash.NewFaker(), vm.Config{}) defer chain.Stop() if err != nil { t.Fatal(err) diff --git a/core/blockchain.go b/core/blockchain.go index 328d284d41..02ed51959e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -22,6 +22,7 @@ import ( "fmt" "io" "math/big" + "strings" "sync" "sync/atomic" "time" @@ -230,7 +231,7 @@ type BlockChain struct { // NewBlockChain returns a fully initialised block chain using information // available in the database. It initialises the default Ethereum Validator and // Processor. -func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { +func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { if cacheConfig == nil { cacheConfig = &CacheConfig{ TrieCleanLimit: 256, @@ -239,6 +240,19 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } } + // Setup the genesis block, commit the provided genesis specification + // to database if the genesis block is not present yet, or load the + // stored one from database. + chainConfig, genesisHash, genesisErr := SetupGenesisBlock(db, genesis) + if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { + return nil, genesisErr + } + log.Info(strings.Repeat("-", 153)) + for line := range strings.SplitSeq(chainConfig.Description(), "\n") { + log.Info(line) + } + log.Info(strings.Repeat("-", 153)) + // Open trie database with provided config triedb := trie.NewDatabaseWithConfig(db, &trie.Config{ Cache: cacheConfig.TrieCleanLimit, @@ -334,6 +348,13 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } } + // Rewind the chain in case of an incompatible config upgrade. + if compat, ok := genesisErr.(*params.ConfigCompatError); ok { + log.Warn("Rewinding chain to upgrade configuration", "err", compat) + bc.SetHead(compat.RewindTo) + rawdb.WriteChainConfig(db, genesisHash, chainConfig) + } + // Start future block processor. bc.wg.Go(bc.futureBlocksLoop) @@ -341,8 +362,8 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par } // NewBlockChainEx extend old blockchain, add order state db -func NewBlockChainEx(db ethdb.Database, XDCxDb ethdb.XDCxDatabase, cacheConfig *CacheConfig, chainConfig *params.ChainConfig, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { - blockchain, err := NewBlockChain(db, cacheConfig, chainConfig, engine, vmConfig) +func NewBlockChainEx(db ethdb.Database, XDCxDb ethdb.XDCxDatabase, cacheConfig *CacheConfig, genesis *Genesis, engine consensus.Engine, vmConfig vm.Config) (*BlockChain, error) { + blockchain, err := NewBlockChain(db, cacheConfig, genesis, engine, vmConfig) if err != nil { return nil, err } diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 85a8b06d68..b10921adff 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -44,16 +44,16 @@ import ( // are also returned in case more test blocks are needed later. func newCanonical(engine consensus.Engine, n int, full bool) (ethdb.Database, *BlockChain, error) { var ( + db = rawdb.NewMemoryDatabase() gspec = &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: params.AllEthashProtocolChanges, } + genesis = gspec.MustCommit(db) ) - db := rawdb.NewMemoryDatabase() - genesis := gspec.MustCommit(db) // Initialize a fresh chain with only a genesis block - blockchain, _ := NewBlockChain(db, nil, params.AllEthashProtocolChanges, engine, vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, engine, vm.Config{}) // Create and inject the requested chain if n == 0 { @@ -517,7 +517,11 @@ func testReorgBadHashes(t *testing.T, full bool) { blockchain.Stop() // Create a new BlockChain and check that it rolled back the state. - ncm, err := NewBlockChain(blockchain.db, nil, blockchain.chainConfig, ethash.NewFaker(), vm.Config{}) + gspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: params.AllEthashProtocolChanges, + } + ncm, err := NewBlockChain(blockchain.db, nil, gspec, ethash.NewFaker(), vm.Config{}) if err != nil { t.Fatalf("failed to create new chain manager: %v", err) } @@ -620,7 +624,7 @@ func TestFastVsFullChains(t *testing.T) { // Import the chain as an archive node for the comparison baseline archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec, ethash.NewFaker(), vm.Config{}) defer archive.Stop() if n, err := archive.InsertChain(blocks); err != nil { @@ -629,7 +633,7 @@ func TestFastVsFullChains(t *testing.T) { // Fast import the chain as a non-archive node to test fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec, ethash.NewFaker(), vm.Config{}) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -711,7 +715,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { archiveDb := rawdb.NewMemoryDatabase() gspec.MustCommit(archiveDb) - archive, _ := NewBlockChain(archiveDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + archive, _ := NewBlockChain(archiveDb, nil, gspec, ethash.NewFaker(), vm.Config{}) if n, err := archive.InsertChain(blocks); err != nil { t.Fatalf("failed to process block %d: %v", n, err) } @@ -724,7 +728,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { // Import the chain as a non-archive node and ensure all pointers are updated fastDb := rawdb.NewMemoryDatabase() gspec.MustCommit(fastDb) - fast, _ := NewBlockChain(fastDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + fast, _ := NewBlockChain(fastDb, nil, gspec, ethash.NewFaker(), vm.Config{}) defer fast.Stop() headers := make([]*types.Header, len(blocks)) @@ -745,7 +749,7 @@ func TestLightVsFastVsFullChainHeads(t *testing.T) { lightDb := rawdb.NewMemoryDatabase() gspec.MustCommit(lightDb) - light, _ := NewBlockChain(lightDb, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + light, _ := NewBlockChain(lightDb, nil, gspec, ethash.NewFaker(), vm.Config{}) if n, err := light.InsertHeaderChain(headers, 1); err != nil { t.Fatalf("failed to insert header %d: %v", n, err) } @@ -814,7 +818,7 @@ func TestChainTxReorgs(t *testing.T) { } }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) if i, err := blockchain.InsertChain(chain); err != nil { t.Fatalf("failed to insert original chain[%d]: %v", i, err) } @@ -887,7 +891,7 @@ func TestLogReorgs(t *testing.T) { signer = types.LatestSigner(gspec.Config) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() rmLogsCh := make(chan RemovedLogsEvent) @@ -1066,7 +1070,7 @@ func TestEIP155Transition(t *testing.T) { genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 4, func(i int, block *BlockGen) { @@ -1173,7 +1177,7 @@ func TestEIP161AccountRemoval(t *testing.T) { } genesis = gspec.MustCommit(db) ) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() blocks, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 3, func(i int, block *BlockGen) { @@ -1252,7 +1256,7 @@ func TestBlockchainHeaderchainReorgConsistency(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1300,7 +1304,7 @@ func TestTrieForkGC(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1327,12 +1331,12 @@ func TestTrieForkGC(t *testing.T) { func TestLargeReorgTrieGC(t *testing.T) { // Generate the original common chain segment and the two competing forks engine := ethash.NewFaker() + + db := rawdb.NewMemoryDatabase() gspec := &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: params.TestChainConfig, } - - db := rawdb.NewMemoryDatabase() genesis := gspec.MustCommit(db) shared, _ := GenerateChain(gspec.Config, genesis, engine, db, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) @@ -1343,7 +1347,7 @@ func TestLargeReorgTrieGC(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1425,7 +1429,7 @@ func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks in diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { b.Fatalf("failed to create tester chain: %v", err) } @@ -1652,7 +1656,7 @@ func TestEIP2718Transition(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1747,7 +1751,7 @@ func TestTransientStorageReset(t *testing.T) { gspec.MustCommit(diskdb) // Initialize the blockchain with 1153 enabled. - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vmConfig) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vmConfig) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1842,7 +1846,7 @@ func TestEIP3651(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } @@ -1945,7 +1949,7 @@ func TestDeleteCreateRevert(t *testing.T) { diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/core/chain_makers_test.go b/core/chain_makers_test.go index 7e62bd9ff4..dc5bf6428c 100644 --- a/core/chain_makers_test.go +++ b/core/chain_makers_test.go @@ -78,7 +78,7 @@ func ExampleGenerateChain() { }) // Import the chain. This runs all block validation rules. - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() if i, err := blockchain.InsertChain(chain); err != nil { diff --git a/core/dao_test.go b/core/dao_test.go index 3885f5cfb7..7498fb635e 100644 --- a/core/dao_test.go +++ b/core/dao_test.go @@ -32,29 +32,39 @@ func TestDAOForkRangeExtradata(t *testing.T) { forkBlock := big.NewInt(32) // Generate a common prefix for both pro-forkers and non-forkers + db := rawdb.NewMemoryDatabase() gspec := &Genesis{ BaseFee: big.NewInt(params.InitialBaseFee), Config: params.TestChainConfig, } - db := rawdb.NewMemoryDatabase() genesis := gspec.MustCommit(db) prefix, _ := GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, int(forkBlock.Int64()-1), func(i int, gen *BlockGen) {}) // Create the concurrent, conflicting two nodes proDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(proDb) proConf := *params.TestChainConfig proConf.DAOForkBlock = forkBlock proConf.DAOForkSupport = true - proBc, _ := NewBlockChain(proDb, nil, &proConf, ethash.NewFaker(), vm.Config{}) + progspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &proConf, + } + gspec.MustCommit(proDb) + + proBc, _ := NewBlockChain(proDb, nil, progspec, ethash.NewFaker(), vm.Config{}) defer proBc.Stop() conDb := rawdb.NewMemoryDatabase() - gspec.MustCommit(conDb) conConf := *params.TestChainConfig conConf.DAOForkBlock = forkBlock conConf.DAOForkSupport = false - conBc, _ := NewBlockChain(conDb, nil, &conConf, ethash.NewFaker(), vm.Config{}) + congspec := &Genesis{ + BaseFee: big.NewInt(params.InitialBaseFee), + Config: &conConf, + } + gspec.MustCommit(conDb) + + conBc, _ := NewBlockChain(conDb, nil, congspec, ethash.NewFaker(), vm.Config{}) defer conBc.Stop() if _, err := proBc.InsertChain(prefix); err != nil { @@ -67,8 +77,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { for i := int64(0); i < params.DAOForkExtraRange.Int64(); i++ { // Create a pro-fork block, and try to feed into the no-fork chain db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) + congspec.MustCommit(db) + bc, _ := NewBlockChain(db, nil, congspec, ethash.NewFaker(), vm.Config{}) blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -92,8 +102,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Create a no-fork block, and try to feed into the pro-fork chain db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) + progspec.MustCommit(db) + bc, _ = NewBlockChain(db, nil, progspec, ethash.NewFaker(), vm.Config{}) blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) for j := 0; j < len(blocks)/2; j++ { @@ -118,8 +128,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Verify that contra-forkers accept pro-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ := NewBlockChain(db, nil, &conConf, ethash.NewFaker(), vm.Config{}) + congspec.MustCommit(db) + bc, _ := NewBlockChain(db, nil, congspec, ethash.NewFaker(), vm.Config{}) defer bc.Stop() blocks := conBc.GetBlocksFromHash(conBc.CurrentBlock().Hash(), int(conBc.CurrentBlock().Number.Uint64())) @@ -138,8 +148,8 @@ func TestDAOForkRangeExtradata(t *testing.T) { } // Verify that pro-forkers accept contra-fork extra-datas after forking finishes db = rawdb.NewMemoryDatabase() - gspec.MustCommit(db) - bc, _ = NewBlockChain(db, nil, &proConf, ethash.NewFaker(), vm.Config{}) + progspec.MustCommit(db) + bc, _ = NewBlockChain(db, nil, progspec, ethash.NewFaker(), vm.Config{}) defer bc.Stop() blocks = proBc.GetBlocksFromHash(proBc.CurrentBlock().Hash(), int(proBc.CurrentBlock().Number.Uint64())) diff --git a/core/genesis.go b/core/genesis.go index d30326a74b..5a729a8652 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -246,7 +246,10 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig // Get the existing chain configuration. newcfg := genesis.configOrDefault(stored) - storedcfg, _ := rawdb.ReadChainConfig(db, stored) + storedcfg, err := rawdb.ReadChainConfig(db, stored) + if err != nil { + return nil, common.Hash{}, err + } if storedcfg == nil { log.Warn("Found genesis block without chain config") rawdb.WriteChainConfig(db, stored, newcfg) @@ -285,6 +288,43 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig return newcfg, stored, nil } +// LoadChainConfig loads the stored chain config if it is already present in +// database, otherwise, return the config in the provided genesis specification. +func LoadChainConfig(db ethdb.Database, genesis *Genesis) (cfg *params.ChainConfig, ghash common.Hash, err error) { + // Load the stored chain config from the database. It can be nil + // in case the database is empty. Notably, we only care about the + // chain config corresponds to the canonical chain. + stored := rawdb.ReadCanonicalHash(db, 0) + if stored != (common.Hash{}) { + storedcfg, err := rawdb.ReadChainConfig(db, stored) + if err != nil { + return nil, common.Hash{}, err + } + if storedcfg != nil { + return storedcfg, stored, nil + } + } + // Load the config from the provided genesis specification + if genesis != nil { + // Reject invalid genesis spec without valid chain config + if genesis.Config == nil { + return nil, common.Hash{}, errGenesisNoConfig + } + // If the canonical genesis header is present, but the chain + // config is missing(initialize the empty leveldb with an + // external ancient chain segment), ensure the provided genesis + // is matched. + ghash := genesis.ToBlock().Hash() + if stored != (common.Hash{}) && ghash != stored { + return nil, ghash, &GenesisMismatchError{stored, ghash} + } + return genesis.Config, ghash, nil + } + // There is no stored chain config and no new config provided, + // In this case the default chain config(mainnet) will be used + return params.XDCMainnetChainConfig, params.MainnetGenesisHash, nil +} + func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig { switch { case g != nil: diff --git a/core/genesis_test.go b/core/genesis_test.go index 66f8f2e9ba..c8a37e3ff4 100644 --- a/core/genesis_test.go +++ b/core/genesis_test.go @@ -167,7 +167,7 @@ func TestSetupGenesis(t *testing.T) { // Advance to block #4, past the homestead transition block of customg. genesis := oldcustomg.MustCommit(db) - bc, _ := NewBlockChain(db, nil, oldcustomg.Config, ethash.NewFullFaker(), vm.Config{}) + bc, _ := NewBlockChain(db, nil, &oldcustomg, ethash.NewFullFaker(), vm.Config{}) defer bc.Stop() blocks, _ := GenerateChain(oldcustomg.Config, genesis, ethash.NewFaker(), db, 4, nil) diff --git a/core/state_processor_test.go b/core/state_processor_test.go index 7d183d6e6a..6eeb234737 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -123,7 +123,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ = NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) tooBigInitCode = [params.MaxInitCodeSize + 1]byte{} ) @@ -284,7 +284,7 @@ func TestStateProcessorErrors(t *testing.T) { }, } genesis = gspec.MustCommit(db) - blockchain, _ = NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ = NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) ) defer blockchain.Stop() for i, tt := range []struct { @@ -415,7 +415,7 @@ func TestApplyTransactionWithEVMTracer(t *testing.T) { }, } genesis := gspec.MustCommit(db) - blockchain, _ := NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + blockchain, _ := NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) defer blockchain.Stop() // Create state database diff --git a/eth/backend.go b/eth/backend.go index fe6cb386e7..eaed1b7250 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -23,7 +23,6 @@ import ( "fmt" "math/big" "runtime" - "strings" "sync" "sync/atomic" @@ -109,6 +108,7 @@ type Ethereum struct { // New creates a new Ethereum object (including the // initialisation of the common Ethereum object) func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendingServ *XDCxlending.Lending) (*Ethereum, error) { + // Ensure configuration values are compatible and sane if config.SyncMode == downloader.LightSync { return nil, errors.New("can't run eth.Ethereum in light sync mode, light mode has been deprecated") } @@ -116,28 +116,25 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin return nil, fmt.Errorf("invalid sync mode %d", config.SyncMode) } - // Assemble the Ethereum object chainDb, err := stack.OpenDatabase("chaindata", config.DatabaseCache, config.DatabaseHandles, "eth/db/chaindata/", false) if err != nil { return nil, err } - chainConfig, genesisHash, genesisErr := core.SetupGenesisBlock(chainDb, config.Genesis) - if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok { - return nil, genesisErr + // Here we determine genesis hash and active ChainConfig. + // We need these to figure out the consensus parameters and to set up history pruning. + chainConfig, _, err := core.LoadChainConfig(chainDb, config.Genesis) + if err != nil { + return nil, err } + // Set networkID to chainID by default. networkID := config.NetworkId if networkID == 0 { networkID = chainConfig.ChainID.Uint64() } common.CopyConstants(networkID) - log.Info(strings.Repeat("-", 153)) - for line := range strings.SplitSeq(chainConfig.Description(), "\n") { - log.Info(line) - } - log.Info(strings.Repeat("-", 153)) - + // Assemble the Ethereum object. eth := &Ethereum{ config: config, chainDb: chainDb, @@ -168,6 +165,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin } log.Info("Initialising Ethereum protocol", "versions", ProtocolVersions, "network", networkID, "dbversion", dbVer) + // Create BlockChain object. if !config.SkipBcVersionCheck { if bcVersion != nil && *bcVersion > core.BlockChainVersion { return nil, fmt.Errorf("database version is v%d, XDC %s only supports v%d", *bcVersion, version.WithMeta, core.BlockChainVersion) @@ -224,7 +222,7 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin return eth.Lending } } - eth.blockchain, err = core.NewBlockChainEx(chainDb, XDCXServ.GetLevelDB(), cacheConfig, eth.chainConfig, eth.engine, vmConfig) + eth.blockchain, err = core.NewBlockChainEx(chainDb, XDCXServ.GetLevelDB(), cacheConfig, config.Genesis, eth.engine, vmConfig) if err != nil { return nil, err } @@ -256,14 +254,9 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin } } - // Rewind the chain in case of an incompatible config upgrade. - if compat, ok := genesisErr.(*params.ConfigCompatError); ok { - log.Warn("Rewinding chain to upgrade configuration", "err", compat) - eth.blockchain.SetHead(compat.RewindTo) - rawdb.WriteChainConfig(chainDb, genesisHash, chainConfig) - } eth.bloomIndexer.Start(eth.blockchain) + // TxPool if config.TxPool.Journal != "" { config.TxPool.Journal = stack.ResolvePath(config.TxPool.Journal) } @@ -274,13 +267,13 @@ func New(stack *node.Node, config *ethconfig.Config, XDCXServ *XDCx.XDCX, lendin return nil, err } - eth.orderPool = legacypool.NewOrderPool(eth.chainConfig, eth.blockchain) - eth.lendingPool = legacypool.NewLendingPool(eth.chainConfig, eth.blockchain) + eth.orderPool = legacypool.NewOrderPool(eth.blockchain.Config(), eth.blockchain) + eth.lendingPool = legacypool.NewLendingPool(eth.blockchain.Config(), eth.blockchain) - if eth.protocolManager, err = NewProtocolManagerEx(eth.chainConfig, config.SyncMode, networkID, eth.eventMux, eth.txPool, eth.orderPool, eth.lendingPool, eth.engine, eth.blockchain, chainDb); err != nil { + if eth.protocolManager, err = NewProtocolManagerEx(eth.blockchain.Config(), config.SyncMode, networkID, eth.eventMux, eth.txPool, eth.orderPool, eth.lendingPool, eth.engine, eth.blockchain, chainDb); err != nil { return nil, err } - eth.miner = miner.New(eth, eth.chainConfig, eth.EventMux(), eth.engine, stack.Config().AnnounceTxs) + eth.miner = miner.New(eth, eth.blockchain.Config(), eth.EventMux(), eth.engine, stack.Config().AnnounceTxs) eth.miner.SetExtra(makeExtraData(config.ExtraData)) var xdPoS *XDPoS.XDPoS = nil diff --git a/eth/filters/filter_system_test.go b/eth/filters/filter_system_test.go index 74ef8b7598..374fd9efbc 100644 --- a/eth/filters/filter_system_test.go +++ b/eth/filters/filter_system_test.go @@ -382,7 +382,7 @@ func TestInvalidGetLogsRequest(t *testing.T) { ) // Insert the blocks into the chain so filter can look them up - blockchain, err := core.NewBlockChain(db, nil, genesis.Config, ethash.NewFaker(), vm.Config{}) + blockchain, err := core.NewBlockChain(db, nil, genesis, ethash.NewFaker(), vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/eth/filters/filter_test.go b/eth/filters/filter_test.go index 64f248f04a..bf296de8ba 100644 --- a/eth/filters/filter_test.go +++ b/eth/filters/filter_test.go @@ -246,7 +246,7 @@ func TestFilters(t *testing.T) { } }) - bc, err := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + bc, err := core.NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) if err != nil { t.Fatal(err) } @@ -372,7 +372,7 @@ func TestRangeLimit(t *testing.T) { } genesis := gspec.MustCommit(db) chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, 10, func(i int, gen *core.BlockGen) {}) - bc, err := core.NewBlockChain(db, nil, gspec.Config, ethash.NewFaker(), vm.Config{}) + bc, err := core.NewBlockChain(db, nil, gspec, ethash.NewFaker(), vm.Config{}) if err != nil { t.Fatal(err) } diff --git a/eth/gasprice/gasprice_test.go b/eth/gasprice/gasprice_test.go index 7fe557d6be..3f4d2213e6 100644 --- a/eth/gasprice/gasprice_test.go +++ b/eth/gasprice/gasprice_test.go @@ -154,7 +154,7 @@ func newTestBackend(t *testing.T, eip1559Block *big.Int, pending bool) *testBack // Construct testing chain diskdb := rawdb.NewMemoryDatabase() gspec.MustCommit(diskdb) - chain, err := core.NewBlockChain(diskdb, nil, gspec.Config, engine, vm.Config{}) + chain, err := core.NewBlockChain(diskdb, nil, gspec, engine, vm.Config{}) if err != nil { t.Fatalf("Failed to create local chain, %v", err) } diff --git a/eth/handler_test.go b/eth/handler_test.go index 3e74b6ad1e..7a7f3be83a 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -469,15 +469,19 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool } // Create a DAO aware protocol manager var ( - evmux = new(event.TypeMux) - pow = ethash.NewFaker() - db = rawdb.NewMemoryDatabase() - config = ¶ms.ChainConfig{DAOForkBlock: big.NewInt(1), DAOForkSupport: localForked} - gspec = &core.Genesis{Config: config} + evmux = new(event.TypeMux) + pow = ethash.NewFaker() + db = rawdb.NewMemoryDatabase() + gspec = &core.Genesis{ + Config: ¶ms.ChainConfig{ + DAOForkBlock: big.NewInt(1), + DAOForkSupport: localForked, + }, + } genesis = gspec.MustCommit(db) - blockchain, _ = core.NewBlockChain(db, nil, config, pow, vm.Config{}) + blockchain, _ = core.NewBlockChain(db, nil, gspec, pow, vm.Config{}) ) - pm, err := NewProtocolManager(config, downloader.FullSync, ethconfig.Defaults.NetworkId, evmux, new(testTxPool), pow, blockchain, db) + pm, err := NewProtocolManager(gspec.Config, downloader.FullSync, ethconfig.Defaults.NetworkId, evmux, new(testTxPool), pow, blockchain, db) if err != nil { t.Fatalf("failed to start test protocol manager: %v", err) } @@ -489,7 +493,7 @@ func testDAOChallenge(t *testing.T, localForked, remoteForked bool, timeout bool defer peer.close() challenge := &getBlockHeadersData{ - Origin: hashOrNumber{Number: config.DAOForkBlock.Uint64()}, + Origin: hashOrNumber{Number: gspec.Config.DAOForkBlock.Uint64()}, Amount: 1, Skip: 0, Reverse: false, diff --git a/eth/helper_test.go b/eth/helper_test.go index 191d32deeb..6aa5d7e559 100644 --- a/eth/helper_test.go +++ b/eth/helper_test.go @@ -62,7 +62,7 @@ func newTestProtocolManager(mode downloader.SyncMode, blocks int, generator func Config: params.TestChainConfig, } genesis = gspec.MustCommit(db) - blockchain, _ = core.NewBlockChain(db, nil, gspec.Config, engine, vm.Config{}) + blockchain, _ = core.NewBlockChain(db, nil, gspec, engine, vm.Config{}) ) chain, _ := core.GenerateChain(gspec.Config, genesis, ethash.NewFaker(), db, blocks, generator) if _, err := blockchain.InsertChain(chain); err != nil { diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 6935448fae..3b9a9d19d2 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -81,7 +81,7 @@ func newTestBackend(t *testing.T, n int, gspec *core.Genesis, generator func(i i TrieTimeLimit: 5 * time.Minute, TrieDirtyDisabled: true, // Archive mode } - chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, backend.chainConfig, backend.engine, vm.Config{}) + chain, err := core.NewBlockChain(backend.chaindb, cacheConfig, gspec, backend.engine, vm.Config{}) if err != nil { t.Fatalf("failed to create tester chain: %v", err) } diff --git a/params/config.go b/params/config.go index 838fbbe72e..0f46093259 100644 --- a/params/config.go +++ b/params/config.go @@ -249,7 +249,7 @@ var ( }, } - // MainnetChainConfig is the chain parameters to run a node on the main network. + // MainnetChainConfig is the chain parameters to run a node on the ethereum main network. MainnetChainConfig = &ChainConfig{ ChainID: big.NewInt(1), HomesteadBlock: big.NewInt(1150000), diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 9ea91611f8..bba978aac4 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -112,7 +112,7 @@ func (t *BlockTest) Run() error { return fmt.Errorf("genesis block state root does not match test: computed=%x, test=%x", gblock.Root().Bytes(), t.json.Genesis.StateRoot) } - chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, config, ethash.NewFaker(), vm.Config{}) + chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieCleanLimit: 0}, gspec, ethash.NewFaker(), vm.Config{}) if err != nil { return err }