@ -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
}
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
return nil , common . Hash { } , nil , errGenesisNoConfig
}
}
}
// 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 genesis . Config , block . Hash ( ) , 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 ) {
return nil , common . Hash { } , nil , err
}
return chainCfg , block . Hash ( ) , nil , nil
}
// 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 . Confi g, block . Hash ( ) , nil
return chainCf g, 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 {