Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/utils: if dev-mode is enabled and db is pre-existing, validate that genesis configuration is compatible #28468

Merged
merged 6 commits into from
Nov 22, 2023
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: 15 additions & 0 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,21 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
chaindb := tryMakeReadOnlyDatabase(ctx, stack)
if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) {
cfg.Genesis = nil // fallback to db content

//validate genesis has PoS enabled in block 0
genesis, err := core.ReadGenesis(chaindb)
if err != nil {
Fatalf("Could not read genesis from database: %v", err)
}
if !genesis.Config.TerminalTotalDifficultyPassed {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is not enough. The setting TerminalTotalDifficultyPassed configures some aspects of the client to assume the merge has happened, but the actual trigger for the merge is whether the total difficulty is higher than TTD. So you need to add a check here that expects TerminalTotalDifficulty to be set, and Difficulty of the genesis block to be higher than TerminalTotalDifficulty.

Copy link
Contributor Author

@jwasinger jwasinger Nov 13, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's interesting is that the default dev mode configuration sets the total difficulty to 0, ttd to 0, and terminalTotalDifficultyPassed to true (so the conf is invalid and/or the merge should happen on block 1). But the simulated beacon initially sets the genesis as the finalized block and we accept it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just a weird edge-case that we don't validate in forkchoiceUpdated because it would never have occured on mainnet. we just blindly accept going firmly into proof-of-stake if the beacon client indicates a finalized block.

Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficultyPassed must be true in developer mode")
}
if genesis.Config.TerminalTotalDifficulty == nil {
Fatalf("Bad developer-mode genesis configuration: terminalTotalDifficulty must be specified.")
}
if genesis.Difficulty.Cmp(genesis.Config.TerminalTotalDifficulty) != 1 {
Fatalf("Bad developer-mode genesis configuration: genesis block difficulty must be > terminalTotalDifficulty")
}
jwasinger marked this conversation as resolved.
Show resolved Hide resolved
}
chaindb.Close()
}
Expand Down
2 changes: 1 addition & 1 deletion core/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -572,7 +572,7 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet common.Address) *Genesis {
Config: &config,
GasLimit: gasLimit,
BaseFee: big.NewInt(params.InitialBaseFee),
Difficulty: big.NewInt(0),
Difficulty: big.NewInt(1),
Alloc: map[common.Address]GenesisAccount{
common.BytesToAddress([]byte{1}): {Balance: big.NewInt(1)}, // ECRecover
common.BytesToAddress([]byte{2}): {Balance: big.NewInt(1)}, // SHA256
Expand Down
4 changes: 0 additions & 4 deletions eth/catalyst/simulated_beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@ type SimulatedBeacon struct {
}

func NewSimulatedBeacon(period uint64, eth *eth.Ethereum) (*SimulatedBeacon, error) {
chainConfig := eth.APIBackend.ChainConfig()
if !chainConfig.IsDevMode {
return nil, errors.New("incompatible pre-existing chain configuration")
}
block := eth.BlockChain().CurrentBlock()
current := engine.ForkchoiceStateV1{
HeadBlockHash: block.Hash(),
Expand Down
6 changes: 2 additions & 4 deletions params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ var (
ShanghaiTime: newUint64(0),
TerminalTotalDifficulty: big.NewInt(0),
TerminalTotalDifficultyPassed: true,
IsDevMode: true,
}

// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
Expand Down Expand Up @@ -329,9 +328,8 @@ type ChainConfig struct {
TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"`

// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
IsDevMode bool `json:"isDev,omitempty"`
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
}

// EthashConfig is the consensus engine configs for proof-of-work based sealing.
Expand Down