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:
parent
864e717b56
commit
37c0e6992e
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
202
core/genesis.go
202
core/genesis.go
|
@ -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{
|
||||
|
|
|
@ -54,23 +54,23 @@ func testSetupGenesis(t *testing.T, scheme string) {
|
|||
oldcustomg.Config = ¶ms.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: ¶ms.ConfigCompatError{
|
||||
wantCompactErr: ¶ms.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,
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
)
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue