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.
This commit is contained in:
rjl493456442 2025-01-14 18:49:30 +08:00 committed by GitHub
parent 864e717b56
commit 37c0e6992e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 191 additions and 150 deletions

View File

@ -230,11 +230,10 @@ func initGenesis(ctx *cli.Context) error {
triedb := utils.MakeTrieDatabase(ctx, chaindb, ctx.Bool(utils.CachePreimagesFlag.Name), false, genesis.IsVerkle())
defer triedb.Close()
_, hash, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
_, hash, _, err := core.SetupGenesisBlockWithOverride(chaindb, triedb, genesis, &overrides)
if err != nil {
utils.Fatalf("Failed to write genesis block: %v", err)
}
log.Info("Successfully wrote genesis state", "database", "chaindata", "hash", hash)
return nil

View File

@ -170,7 +170,7 @@ func TestHistoryImportAndExport(t *testing.T) {
db2.Close()
})
genesis.MustCommit(db2, triedb.NewDatabase(db, triedb.HashDefaults))
genesis.MustCommit(db2, triedb.NewDatabase(db2, triedb.HashDefaults))
imported, err := core.NewBlockChain(db2, nil, genesis, nil, ethash.NewFaker(), vm.Config{}, nil)
if err != nil {
t.Fatalf("unable to initialize chain: %v", err)

View File

@ -269,14 +269,19 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
cacheConfig = defaultCacheConfig
}
// Open trie database with provided config
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(genesis != nil && genesis.IsVerkle()))
enableVerkle, err := EnableVerkleAtGenesis(db, genesis)
if err != nil {
return nil, err
}
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(enableVerkle))
// 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 := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
// Write the supplied genesis to the database if it has not been initialized
// yet. The corresponding chain config will be returned, either from the
// provided genesis or from the locally stored configuration if the genesis
// has already been initialized.
chainConfig, genesisHash, compatErr, err := SetupGenesisBlockWithOverride(db, triedb, genesis, overrides)
if err != nil {
return nil, err
}
log.Info("")
log.Info(strings.Repeat("-", 153))
@ -303,7 +308,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
vmConfig: vmConfig,
logger: vmConfig.Tracer,
}
var err error
bc.hc, err = NewHeaderChain(db, chainConfig, engine, bc.insertStopped)
if err != nil {
return nil, err
@ -453,16 +457,15 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
}
// 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)
if compat.RewindToTime > 0 {
bc.SetHeadWithTimestamp(compat.RewindToTime)
if compatErr != nil {
log.Warn("Rewinding chain to upgrade configuration", "err", compatErr)
if compatErr.RewindToTime > 0 {
bc.SetHeadWithTimestamp(compatErr.RewindToTime)
} else {
bc.SetHead(compat.RewindToBlock)
bc.SetHead(compatErr.RewindToBlock)
}
rawdb.WriteChainConfig(db, genesisHash, chainConfig)
}
// Start tx indexer if it's enabled.
if txLookupLimit != nil {
bc.txIndexer = newTxIndexer(*txLookupLimit, bc)

View File

@ -247,6 +247,24 @@ type ChainOverrides struct {
OverrideVerkle *uint64
}
// apply applies the chain overrides on the supplied chain config.
func (o *ChainOverrides) apply(cfg *params.ChainConfig) (*params.ChainConfig, error) {
if o == nil || cfg == nil {
return cfg, nil
}
cpy := *cfg
if o.OverrideCancun != nil {
cpy.CancunTime = o.OverrideCancun
}
if o.OverrideVerkle != nil {
cpy.VerkleTime = o.OverrideVerkle
}
if err := cpy.CheckConfigForkOrder(); err != nil {
return nil, err
}
return &cpy, nil
}
// SetupGenesisBlock writes or updates the genesis block in db.
// The block that will be used is:
//
@ -258,109 +276,102 @@ type ChainOverrides struct {
// The stored chain configuration will be updated if it is compatible (i.e. does not
// specify a fork block below the local head block). In case of a conflict, the
// error is a *params.ConfigCompatError and the new, unwritten config is returned.
//
// The returned chain configuration is never nil.
func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, error) {
func SetupGenesisBlock(db ethdb.Database, triedb *triedb.Database, genesis *Genesis) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
return SetupGenesisBlockWithOverride(db, triedb, genesis, nil)
}
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, error) {
func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
// Sanitize the supplied genesis, ensuring it has the associated chain
// config attached.
if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
return nil, common.Hash{}, nil, errGenesisNoConfig
}
applyOverrides := func(config *params.ChainConfig) {
if config != nil {
if overrides != nil && overrides.OverrideCancun != nil {
config.CancunTime = overrides.OverrideCancun
}
if overrides != nil && overrides.OverrideVerkle != nil {
config.VerkleTime = overrides.OverrideVerkle
}
}
}
// Just commit the new block if there is no stored genesis block.
stored := rawdb.ReadCanonicalHash(db, 0)
if (stored == common.Hash{}) {
// Commit the genesis if the database is empty
ghash := rawdb.ReadCanonicalHash(db, 0)
if (ghash == common.Hash{}) {
if genesis == nil {
log.Info("Writing default main-net genesis block")
genesis = DefaultGenesisBlock()
} else {
log.Info("Writing custom genesis block")
}
chainCfg, err := overrides.apply(genesis.Config)
if err != nil {
return nil, common.Hash{}, nil, err
}
genesis.Config = chainCfg
applyOverrides(genesis.Config)
block, err := genesis.Commit(db, triedb)
if err != nil {
return genesis.Config, common.Hash{}, err
return nil, common.Hash{}, nil, err
}
return genesis.Config, block.Hash(), nil
return chainCfg, block.Hash(), nil, nil
}
// The genesis block is present(perhaps in ancient database) while the
// state database is not initialized yet. It can happen that the node
// is initialized with an external ancient store. Commit genesis state
// in this case.
header := rawdb.ReadHeader(db, stored, 0)
if header.Root != types.EmptyRootHash && !triedb.Initialized(header.Root) {
// Commit the genesis if the genesis block exists in the ancient database
// but the key-value database is empty without initializing the genesis
// fields. This scenario can occur when the node is created from scratch
// with an existing ancient store.
storedCfg := rawdb.ReadChainConfig(db, ghash)
if storedCfg == nil {
// Ensure the stored genesis block matches with the given genesis. Private
// networks must explicitly specify the genesis in the config file, mainnet
// genesis will be used as default and the initialization will always fail.
if genesis == nil {
log.Info("Writing default main-net genesis block")
genesis = DefaultGenesisBlock()
} else {
log.Info("Writing custom genesis block")
}
applyOverrides(genesis.Config)
// Ensure the stored genesis matches with the given one.
hash := genesis.ToBlock().Hash()
if hash != stored {
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
chainCfg, err := overrides.apply(genesis.Config)
if err != nil {
return nil, common.Hash{}, nil, err
}
genesis.Config = chainCfg
if hash := genesis.ToBlock().Hash(); hash != ghash {
return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash}
}
block, err := genesis.Commit(db, triedb)
if err != nil {
return genesis.Config, hash, err
return nil, common.Hash{}, nil, err
}
return genesis.Config, block.Hash(), nil
return chainCfg, block.Hash(), nil, nil
}
// Check whether the genesis block is already written.
// The genesis block has already been committed previously. Verify that the
// provided genesis with chain overrides matches the existing one, and update
// the stored chain config if necessary.
if genesis != nil {
applyOverrides(genesis.Config)
hash := genesis.ToBlock().Hash()
if hash != stored {
return genesis.Config, hash, &GenesisMismatchError{stored, hash}
chainCfg, err := overrides.apply(genesis.Config)
if err != nil {
return nil, common.Hash{}, nil, err
}
genesis.Config = chainCfg
if hash := genesis.ToBlock().Hash(); hash != ghash {
return nil, common.Hash{}, nil, &GenesisMismatchError{ghash, hash}
}
}
// Get the existing chain configuration.
newcfg := genesis.configOrDefault(stored)
applyOverrides(newcfg)
if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, common.Hash{}, err
}
storedcfg := rawdb.ReadChainConfig(db, stored)
if storedcfg == nil {
log.Warn("Found genesis block without chain config")
rawdb.WriteChainConfig(db, stored, newcfg)
return newcfg, stored, nil
}
storedData, _ := json.Marshal(storedcfg)
// Special case: if a private network is being used (no genesis and also no
// mainnet hash in the database), we must not apply the `configOrDefault`
// chain config as that would be AllProtocolChanges (applying any new fork
// on top of an existing private network genesis block). In that case, only
// apply the overrides.
if genesis == nil && stored != params.MainnetGenesisHash {
newcfg = storedcfg
applyOverrides(newcfg)
}
// Check config compatibility and write the config. Compatibility errors
// are returned to the caller unless we're already at block zero.
head := rawdb.ReadHeadHeader(db)
if head == nil {
return newcfg, stored, errors.New("missing head header")
return nil, common.Hash{}, nil, errors.New("missing head header")
}
compatErr := storedcfg.CheckCompatible(newcfg, head.Number.Uint64(), head.Time)
newCfg := genesis.chainConfigOrDefault(ghash, storedCfg)
// TODO(rjl493456442) better to define the comparator of chain config
// and short circuit if the chain config is not changed.
compatErr := storedCfg.CheckCompatible(newCfg, head.Number.Uint64(), head.Time)
if compatErr != nil && ((head.Number.Uint64() != 0 && compatErr.RewindToBlock != 0) || (head.Time != 0 && compatErr.RewindToTime != 0)) {
return newcfg, stored, compatErr
return newCfg, ghash, compatErr, nil
}
// Don't overwrite if the old is identical to the new
if newData, _ := json.Marshal(newcfg); !bytes.Equal(storedData, newData) {
rawdb.WriteChainConfig(db, stored, newcfg)
// Don't overwrite if the old is identical to the new. It's useful
// for the scenarios that database is opened in the read-only mode.
storedData, _ := json.Marshal(storedCfg)
if newData, _ := json.Marshal(newCfg); !bytes.Equal(storedData, newData) {
rawdb.WriteChainConfig(db, ghash, newCfg)
}
return newcfg, stored, nil
return newCfg, ghash, nil, nil
}
// LoadChainConfig loads the stored chain config if it is already present in
@ -396,7 +407,10 @@ func LoadChainConfig(db ethdb.Database, genesis *Genesis) (*params.ChainConfig,
return params.MainnetChainConfig, nil
}
func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
// chainConfigOrDefault retrieves the attached chain configuration. If the genesis
// object is null, it returns the default chain configuration based on the given
// genesis hash, or the locally stored config if it's not a pre-defined network.
func (g *Genesis) chainConfigOrDefault(ghash common.Hash, stored *params.ChainConfig) *params.ChainConfig {
switch {
case g != nil:
return g.Config
@ -407,14 +421,14 @@ func (g *Genesis) configOrDefault(ghash common.Hash) *params.ChainConfig {
case ghash == params.SepoliaGenesisHash:
return params.SepoliaChainConfig
default:
return params.AllEthashProtocolChanges
return stored
}
}
// IsVerkle indicates whether the state is already stored in a verkle
// tree at genesis time.
func (g *Genesis) IsVerkle() bool {
return g.Config.IsVerkle(new(big.Int).SetUint64(g.Number), g.Timestamp)
return g.Config.IsVerkleGenesis()
}
// ToBlock returns the genesis block according to genesis specification.
@ -494,7 +508,7 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
}
config := g.Config
if config == nil {
config = params.AllEthashProtocolChanges
return nil, errors.New("invalid genesis without chain config")
}
if err := config.CheckConfigForkOrder(); err != nil {
return nil, err
@ -514,16 +528,17 @@ func (g *Genesis) Commit(db ethdb.Database, triedb *triedb.Database) (*types.Blo
if err != nil {
return nil, err
}
rawdb.WriteGenesisStateSpec(db, block.Hash(), blob)
rawdb.WriteTd(db, block.Hash(), block.NumberU64(), block.Difficulty())
rawdb.WriteBlock(db, block)
rawdb.WriteReceipts(db, block.Hash(), block.NumberU64(), nil)
rawdb.WriteCanonicalHash(db, block.Hash(), block.NumberU64())
rawdb.WriteHeadBlockHash(db, block.Hash())
rawdb.WriteHeadFastBlockHash(db, block.Hash())
rawdb.WriteHeadHeaderHash(db, block.Hash())
rawdb.WriteChainConfig(db, block.Hash(), config)
return block, nil
batch := db.NewBatch()
rawdb.WriteGenesisStateSpec(batch, block.Hash(), blob)
rawdb.WriteTd(batch, block.Hash(), block.NumberU64(), block.Difficulty())
rawdb.WriteBlock(batch, block)
rawdb.WriteReceipts(batch, block.Hash(), block.NumberU64(), nil)
rawdb.WriteCanonicalHash(batch, block.Hash(), block.NumberU64())
rawdb.WriteHeadBlockHash(batch, block.Hash())
rawdb.WriteHeadFastBlockHash(batch, block.Hash())
rawdb.WriteHeadHeaderHash(batch, block.Hash())
rawdb.WriteChainConfig(batch, block.Hash(), config)
return block, batch.Write()
}
// MustCommit writes the genesis block and state to db, panicking on error.
@ -536,6 +551,29 @@ func (g *Genesis) MustCommit(db ethdb.Database, triedb *triedb.Database) *types.
return block
}
// EnableVerkleAtGenesis indicates whether the verkle fork should be activated
// at genesis. This is a temporary solution only for verkle devnet testing, where
// verkle fork is activated at genesis, and the configured activation date has
// already passed.
//
// In production networks (mainnet and public testnets), verkle activation always
// occurs after the genesis block, making this function irrelevant in those cases.
func EnableVerkleAtGenesis(db ethdb.Database, genesis *Genesis) (bool, error) {
if genesis != nil {
if genesis.Config == nil {
return false, errGenesisNoConfig
}
return genesis.Config.EnableVerkleAtGenesis, nil
}
if ghash := rawdb.ReadCanonicalHash(db, 0); ghash != (common.Hash{}) {
chainCfg := rawdb.ReadChainConfig(db, ghash)
if chainCfg != nil {
return chainCfg.EnableVerkleAtGenesis, nil
}
}
return false, nil
}
// DefaultGenesisBlock returns the Ethereum main net genesis block.
func DefaultGenesisBlock() *Genesis {
return &Genesis{

View File

@ -54,23 +54,23 @@ func testSetupGenesis(t *testing.T, scheme string) {
oldcustomg.Config = &params.ChainConfig{HomesteadBlock: big.NewInt(2)}
tests := []struct {
name string
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error)
wantConfig *params.ChainConfig
wantHash common.Hash
wantErr error
name string
fn func(ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error)
wantConfig *params.ChainConfig
wantHash common.Hash
wantErr error
wantCompactErr *params.ConfigCompatError
}{
{
name: "genesis without ChainConfig",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis))
},
wantErr: errGenesisNoConfig,
wantConfig: params.AllEthashProtocolChanges,
wantErr: errGenesisNoConfig,
},
{
name: "no block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil)
},
wantHash: params.MainnetGenesisHash,
@ -78,7 +78,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
{
name: "mainnet block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
DefaultGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme)))
return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil)
},
@ -87,7 +87,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
{
name: "custom block in DB, genesis == nil",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, nil)
@ -97,18 +97,16 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
{
name: "custom block in DB, genesis == sepolia",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
customg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock())
},
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
wantHash: params.SepoliaGenesisHash,
wantConfig: params.SepoliaChainConfig,
wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash},
},
{
name: "compatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
oldcustomg.Commit(db, tdb)
return SetupGenesisBlock(db, tdb, &customg)
@ -118,7 +116,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
{
name: "incompatible config in DB",
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) {
fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) {
// Commit the 'old' genesis block with Homestead transition at #2.
// Advance to block #4, past the homestead transition block of customg.
tdb := triedb.NewDatabase(db, newDbConfig(scheme))
@ -135,7 +133,7 @@ func testSetupGenesis(t *testing.T, scheme string) {
},
wantHash: customghash,
wantConfig: customg.Config,
wantErr: &params.ConfigCompatError{
wantCompactErr: &params.ConfigCompatError{
What: "Homestead fork block",
StoredBlock: big.NewInt(2),
NewBlock: big.NewInt(3),
@ -146,12 +144,16 @@ func testSetupGenesis(t *testing.T, scheme string) {
for _, test := range tests {
db := rawdb.NewMemoryDatabase()
config, hash, err := test.fn(db)
config, hash, compatErr, err := test.fn(db)
// Check the return values.
if !reflect.DeepEqual(err, test.wantErr) {
spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr))
}
if !reflect.DeepEqual(compatErr, test.wantCompactErr) {
spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true}
t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(compatErr), spew.NewFormatter(test.wantCompactErr))
}
if !reflect.DeepEqual(config, test.wantConfig) {
t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig)
}
@ -279,6 +281,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
PragueTime: &verkleTime,
VerkleTime: &verkleTime,
TerminalTotalDifficulty: big.NewInt(0),
EnableVerkleAtGenesis: true,
Ethash: nil,
Clique: nil,
}

View File

@ -57,6 +57,7 @@ var (
ShanghaiTime: u64(0),
VerkleTime: u64(0),
TerminalTotalDifficulty: common.Big0,
EnableVerkleAtGenesis: true,
// TODO uncomment when proof generation is merged
// ProofInBlocks: true,
}
@ -77,6 +78,7 @@ var (
ShanghaiTime: u64(0),
VerkleTime: u64(0),
TerminalTotalDifficulty: common.Big0,
EnableVerkleAtGenesis: true,
}
)

View File

@ -145,7 +145,7 @@ func createMiner(t *testing.T) *Miner {
chainDB := rawdb.NewMemoryDatabase()
triedb := triedb.NewDatabase(chainDB, nil)
genesis := minerTestGenesisBlock(15, 11_500_000, common.HexToAddress("12345"))
chainConfig, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis)
chainConfig, _, _, err := core.SetupGenesisBlock(chainDB, triedb, genesis)
if err != nil {
t.Fatalf("can't create new chain config: %v", err)
}

View File

@ -326,6 +326,19 @@ type ChainConfig struct {
DepositContractAddress common.Address `json:"depositContractAddress,omitempty"`
// EnableVerkleAtGenesis is a flag that specifies whether the network uses
// the Verkle tree starting from the genesis block. If set to true, the
// genesis state will be committed using the Verkle tree, eliminating the
// need for any Verkle transition later.
//
// This is a temporary flag only for verkle devnet testing, where verkle is
// activated at genesis, and the configured activation date has already passed.
//
// In production networks (mainnet and public testnets), verkle activation
// always occurs after the genesis block, making this flag irrelevant in
// those cases.
EnableVerkleAtGenesis bool `json:"enableVerkleAtGenesis,omitempty"`
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
@ -525,6 +538,20 @@ func (c *ChainConfig) IsVerkle(num *big.Int, time uint64) bool {
return c.IsLondon(num) && isTimestampForked(c.VerkleTime, time)
}
// IsVerkleGenesis checks whether the verkle fork is activated at the genesis block.
//
// Verkle mode is considered enabled if the verkle fork time is configured,
// regardless of whether the local time has surpassed the fork activation time.
// This is a temporary workaround for verkle devnet testing, where verkle is
// activated at genesis, and the configured activation date has already passed.
//
// In production networks (mainnet and public testnets), verkle activation
// always occurs after the genesis block, making this function irrelevant in
// those cases.
func (c *ChainConfig) IsVerkleGenesis() bool {
return c.EnableVerkleAtGenesis
}
// IsEIP4762 returns whether eip 4762 has been activated at given block.
func (c *ChainConfig) IsEIP4762(num *big.Int, time uint64) bool {
return c.IsVerkle(num, time)

View File

@ -64,10 +64,6 @@ type backend interface {
// state. An error will be returned if the specified state is not available.
StateReader(root common.Hash) (database.StateReader, error)
// Initialized returns an indicator if the state data is already initialized
// according to the state scheme.
Initialized(genesisRoot common.Hash) bool
// Size returns the current storage size of the diff layers on top of the
// disk layer and the storage size of the nodes cached in the disk layer.
//
@ -178,12 +174,6 @@ func (db *Database) Size() (common.StorageSize, common.StorageSize, common.Stora
return diffs, nodes, preimages
}
// Initialized returns an indicator if the state data is already initialized
// according to the state scheme.
func (db *Database) Initialized(genesisRoot common.Hash) bool {
return db.backend.Initialized(genesisRoot)
}
// Scheme returns the node scheme used in the database.
func (db *Database) Scheme() string {
if db.config.PathDB != nil {

View File

@ -532,12 +532,6 @@ func (c *cleaner) Delete(key []byte) error {
panic("not implemented")
}
// Initialized returns an indicator if state data is already initialized
// in hash-based scheme by checking the presence of genesis state.
func (db *Database) Initialized(genesisRoot common.Hash) bool {
return rawdb.HasLegacyTrieNode(db.diskdb, genesisRoot)
}
// Update inserts the dirty nodes in provided nodeset into database and link the
// account trie with multiple storage tries if necessary.
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet) error {

View File

@ -529,21 +529,6 @@ func (db *Database) Size() (diffs common.StorageSize, nodes common.StorageSize)
return diffs, nodes
}
// Initialized returns an indicator if the state data is already
// initialized in path-based scheme.
func (db *Database) Initialized(genesisRoot common.Hash) bool {
var inited bool
db.tree.forEach(func(layer layer) {
if layer.rootHash() != types.EmptyRootHash {
inited = true
}
})
if !inited {
inited = rawdb.ReadSnapSyncStatusFlag(db.diskdb) != rawdb.StateSyncUnknown
}
return inited
}
// modifyAllowed returns the indicator if mutation is allowed. This function
// assumes the db.lock is already held.
func (db *Database) modifyAllowed() error {