Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -2097,7 +2097,18 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
gspec = MakeGenesis(ctx)
chainDb = MakeChainDatabase(ctx, stack, readonly)
)
config, err := core.LoadChainConfig(chainDb, gspec)

var overrides core.ChainOverrides
if ctx.IsSet(OverrideCancun.Name) {
v := ctx.Uint64(OverrideCancun.Name)
overrides.OverrideCancun = &v
}
if ctx.IsSet(OverrideVerkle.Name) {
v := ctx.Uint64(OverrideVerkle.Name)
overrides.OverrideVerkle = &v
}

config, err := core.LoadChainConfigWithOverride(chainDb, gspec, &overrides)
if err != nil {
Fatalf("%v", err)
}
Expand Down Expand Up @@ -2144,7 +2155,7 @@ func MakeChain(ctx *cli.Context, stack *node.Node, readonly bool) (*core.BlockCh
vmcfg := vm.Config{EnablePreimageRecording: ctx.Bool(VMEnableDebugFlag.Name)}

// Disable transaction indexing/unindexing by default.
chain, err := core.NewBlockChain(chainDb, cache, gspec, nil, engine, vmcfg, nil, nil)
chain, err := core.NewBlockChain(chainDb, cache, gspec, &overrides, engine, vmcfg, nil, nil)
if err != nil {
Fatalf("Can't create BlockChain: %v", err)
}
Expand Down
167 changes: 111 additions & 56 deletions core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,39 @@ type ChainOverrides struct {
OverrideVerkle *uint64
}

func applyOverrides(config *params.ChainConfig, overrides *ChainOverrides) {
if config == nil {
return
}
if overrides != nil && overrides.OverrideCancun != nil {
config.CancunTime = overrides.OverrideCancun
}
if overrides != nil && overrides.OverrideVerkle != nil {
config.VerkleTime = overrides.OverrideVerkle
}
}

func validateAnzeonGenesisConfig(config *params.ChainConfig) error {
if config != nil && config.AnzeonEnabled() {
if err := config.Anzeon.CheckValidity(); err != nil {
return fmt.Errorf("Invalid genesis config: %v", err)
}
}
return nil
}

func initializeAnzeonGenesis(genesis *Genesis) error {
if genesis == nil || genesis.Config == nil || !genesis.Config.AnzeonEnabled() {
return nil
}
extraData, err := wbft.CreateInitialExtraData(genesis.Config.Anzeon)
if err != nil {
return err
}
genesis.ExtraData = extraData
return InjectContracts(genesis, genesis.Config)
}

// SetupGenesisBlock writes or updates the genesis block in db.
// The block that will be used is:
//
Expand All @@ -237,16 +270,6 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
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
}
}
}
// Just commit the new block if there is no stored genesis block.
stored := rawdb.ReadCanonicalHash(db, 0)
if (stored == common.Hash{}) {
Expand All @@ -256,22 +279,13 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
} else {
log.Info("Writing custom genesis block")
}
applyOverrides(genesis.Config)

if genesis.Config.AnzeonEnabled() {
if err := genesis.Config.Anzeon.CheckValidity(); err != nil {
return nil, common.Hash{}, fmt.Errorf("Invalid genesis config: %v", err)
}
applyOverrides(genesis.Config, overrides)

var err error
genesis.ExtraData, err = wbft.CreateInitialExtraData(genesis.Config.Anzeon)
if err != nil {
return genesis.Config, common.Hash{}, err
}
err = InjectContracts(genesis, genesis.Config)
if err != nil {
return genesis.Config, common.Hash{}, err
}
if err := validateAnzeonGenesisConfig(genesis.Config); err != nil {
return nil, common.Hash{}, err
}
if err := initializeAnzeonGenesis(genesis); err != nil {
return genesis.Config, common.Hash{}, err
}
block, err := genesis.Commit(db, triedb)
if err != nil {
Expand All @@ -288,21 +302,13 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
if genesis == nil {
genesis = DefaultStableNetMainnetGenesisBlock()
}
applyOverrides(genesis.Config)
applyOverrides(genesis.Config, overrides)

if genesis.Config.AnzeonEnabled() {
if err := genesis.Config.Anzeon.CheckValidity(); err != nil {
return nil, common.Hash{}, fmt.Errorf("Invalid genesis config: %v", err)
}
var err error
genesis.ExtraData, err = wbft.CreateInitialExtraData(genesis.Config.Anzeon)
if err != nil {
return genesis.Config, stored, err
}
err = InjectContracts(genesis, genesis.Config)
if err != nil {
return genesis.Config, stored, err
}
if err := validateAnzeonGenesisConfig(genesis.Config); err != nil {
return nil, common.Hash{}, err
}
if err := initializeAnzeonGenesis(genesis); err != nil {
return genesis.Config, stored, err
}

// Ensure the stored genesis matches with the given one.
Expand All @@ -318,21 +324,12 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
}
// Check whether the genesis block is already written.
if genesis != nil {
applyOverrides(genesis.Config)
if genesis.Config.AnzeonEnabled() {
if err := genesis.Config.Anzeon.CheckValidity(); err != nil {
return nil, common.Hash{}, fmt.Errorf("Invalid genesis config: %v", err)
}

var err error
genesis.ExtraData, err = wbft.CreateInitialExtraData(genesis.Config.Anzeon)
if err != nil {
return genesis.Config, common.Hash{}, err
}
err = InjectContracts(genesis, genesis.Config)
if err != nil {
return genesis.Config, common.Hash{}, err
}
applyOverrides(genesis.Config, overrides)
if err := validateAnzeonGenesisConfig(genesis.Config); err != nil {
return nil, common.Hash{}, err
}
if err := initializeAnzeonGenesis(genesis); err != nil {
return genesis.Config, common.Hash{}, err
}
hash := genesis.ToBlock().Hash()
if hash != stored {
Expand All @@ -341,7 +338,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
}
// Get the existing chain configuration.
newcfg := genesis.configOrDefault(stored)
applyOverrides(newcfg)
applyOverrides(newcfg, overrides)
if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, common.Hash{}, err
}
Expand All @@ -359,7 +356,7 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
// apply the overrides.
if genesis == nil && stored != params.MainnetGenesisHash && stored != params.StableNetMainnetGenesisHash {
newcfg = storedcfg
applyOverrides(newcfg)
applyOverrides(newcfg, overrides)
}
// Check config compatibility and write the config. Compatibility errors
// are returned to the caller unless we're already at block zero.
Expand All @@ -378,6 +375,64 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
return newcfg, stored, nil
}

// LoadChainConfigWithOverride loads the chain configuration from the database if present,
// otherwise returns the config from the provided genesis specification, with overrides applied.
func LoadChainConfigWithOverride(db ethdb.Database, genesis *Genesis, overrides *ChainOverrides) (*params.ChainConfig, error) {
if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, errGenesisNoConfig
}

stored := rawdb.ReadCanonicalHash(db, 0)
// If no genesis block is stored, use the provided genesis or default
if (stored == common.Hash{}) {
if genesis == nil {
genesis = DefaultStableNetMainnetGenesisBlock()
}
if genesis.Config == nil {
return params.AllEthashProtocolChanges, errGenesisNoConfig
}
applyOverrides(genesis.Config, overrides)
return genesis.Config, nil
}

// If a canonical genesis already exists and a genesis is provided, ensure
// the provided genesis does not point to a different chain.
if genesis != nil {
applyOverrides(genesis.Config, overrides)
if err := validateAnzeonGenesisConfig(genesis.Config); err != nil {
return nil, err
}
if err := initializeAnzeonGenesis(genesis); err != nil {
return genesis.Config, err
}
hash := genesis.ToBlock().Hash()
if hash != stored {
return genesis.Config, &GenesisMismatchError{Stored: stored, New: hash}
}
}

// Genesis exists, get the config
newcfg := genesis.configOrDefault(stored)
applyOverrides(newcfg, overrides)

// Validate fork order
if err := newcfg.CheckConfigForkOrder(); err != nil {
return newcfg, err
}

// Check if there's a stored config in the database
storedcfg := rawdb.ReadChainConfig(db, stored)
if storedcfg != nil {
// Special case: private network - use stored config with overrides
if genesis == nil && stored != params.MainnetGenesisHash && stored != params.StableNetMainnetGenesisHash {
newcfg = storedcfg
applyOverrides(newcfg, overrides)
}
}

return newcfg, 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) (*params.ChainConfig, error) {
Expand Down
111 changes: 111 additions & 0 deletions core/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,117 @@ func TestSetupGenesis(t *testing.T) {
testSetupGenesis(t, rawdb.PathScheme)
}

func TestLoadChainConfigWithOverride(t *testing.T) {
t.Run("no block in DB, genesis with overrides", func(t *testing.T) {
db := rawdb.NewMemoryDatabase()
cancunTime := uint64(1234)

config := *params.TestChainConfig
genesis := &Genesis{
Config: &config,
GasLimit: 4712388,
Difficulty: big.NewInt(1),
Alloc: types.GenesisAlloc{
{1}: {Balance: big.NewInt(1)},
},
}
got, err := LoadChainConfigWithOverride(db, genesis, &ChainOverrides{OverrideCancun: &cancunTime})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got.CancunTime == nil || *got.CancunTime != cancunTime {
t.Fatalf("override not applied, got=%v want=%d", got.CancunTime, cancunTime)
}
})

t.Run("private network in DB, genesis nil uses stored config with overrides", func(t *testing.T) {
db := rawdb.NewMemoryDatabase()
verkleTime := uint64(5678)

config := *params.TestChainConfig
config.ChainID = big.NewInt(1337)
genesis := &Genesis{
Config: &config,
GasLimit: 4712388,
Difficulty: big.NewInt(1),
Alloc: types.GenesisAlloc{
{1}: {Balance: big.NewInt(1)},
},
}
block := genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))

got, err := LoadChainConfigWithOverride(db, nil, &ChainOverrides{OverrideVerkle: &verkleTime})
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
if got.ChainID.Cmp(config.ChainID) != 0 {
t.Fatalf("unexpected chain id, got=%v want=%v", got.ChainID, config.ChainID)
}
if got.VerkleTime == nil || *got.VerkleTime != verkleTime {
t.Fatalf("override not applied, got=%v want=%d", got.VerkleTime, verkleTime)
}
storedcfg := rawdb.ReadChainConfig(db, block.Hash())
if storedcfg == nil {
t.Fatalf("stored chain config missing")
}
if storedcfg.ChainID.Cmp(got.ChainID) != 0 {
t.Fatalf("unexpected stored chain id, got=%v want=%v", storedcfg.ChainID, got.ChainID)
}
})

t.Run("stored genesis with mismatching provided genesis returns mismatch error", func(t *testing.T) {
db := rawdb.NewMemoryDatabase()

config := *params.TestChainConfig
config.ChainID = big.NewInt(9999)
storedGenesis := &Genesis{
Config: &config,
GasLimit: 4712388,
Difficulty: big.NewInt(1),
Alloc: types.GenesisAlloc{
{1}: {Balance: big.NewInt(1)},
},
}
block := storedGenesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults))

mismatchGenesis := &Genesis{
Config: &config,
GasLimit: 4712388,
Difficulty: big.NewInt(1),
Nonce: 1, // force different genesis hash
Alloc: types.GenesisAlloc{
{1}: {Balance: big.NewInt(1)},
},
}

_, err := LoadChainConfigWithOverride(db, mismatchGenesis, nil)
if err == nil {
t.Fatalf("expected mismatch error")
}
mismatchErr, ok := err.(*GenesisMismatchError)
if !ok {
t.Fatalf("unexpected error type: %T", err)
}
if mismatchErr.Stored != block.Hash() {
t.Fatalf("unexpected stored hash, got=%s want=%s", mismatchErr.Stored, block.Hash())
}
if mismatchErr.New != mismatchGenesis.ToBlock().Hash() {
t.Fatalf("unexpected new hash, got=%s want=%s", mismatchErr.New, mismatchGenesis.ToBlock().Hash())
}
})

t.Run("genesis without config returns errGenesisNoConfig", func(t *testing.T) {
db := rawdb.NewMemoryDatabase()
got, err := LoadChainConfigWithOverride(db, new(Genesis), nil)
if err != errGenesisNoConfig {
t.Fatalf("unexpected error, got=%v want=%v", err, errGenesisNoConfig)
}
if got != params.AllEthashProtocolChanges {
t.Fatalf("unexpected config return for error path")
}
})
}

func testSetupGenesis(t *testing.T, scheme string) {
var (
customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50")
Expand Down
Loading