cmd, core, eth, les, params: add merge-passed chain config (#24538)

* cmd, core, eth, les, params: add merge-passed chain config

* eth/catalyst, params: add various warning on malfunctioning beacons

* eth/catalyst: fix warning for beacons without transition exchanges
This commit is contained in:
Péter Szilágyi 2022-08-01 15:13:25 +03:00 committed by GitHub
parent 49aa8a633b
commit 6fd06ab075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 332 additions and 160 deletions

@ -20,7 +20,6 @@ import (
"bufio"
"errors"
"fmt"
"math/big"
"os"
"reflect"
"unicode"
@ -157,12 +156,13 @@ func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
// makeFullNode loads geth configuration and creates the Ethereum backend.
func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
stack, cfg := makeConfigNode(ctx)
if ctx.IsSet(utils.OverrideGrayGlacierFlag.Name) {
cfg.Eth.OverrideGrayGlacier = new(big.Int).SetUint64(ctx.Uint64(utils.OverrideGrayGlacierFlag.Name))
}
if ctx.IsSet(utils.OverrideTerminalTotalDifficulty.Name) {
cfg.Eth.OverrideTerminalTotalDifficulty = flags.GlobalBig(ctx, utils.OverrideTerminalTotalDifficulty.Name)
}
if ctx.IsSet(utils.OverrideTerminalTotalDifficultyPassed.Name) {
override := ctx.Bool(utils.OverrideTerminalTotalDifficultyPassed.Name)
cfg.Eth.OverrideTerminalTotalDifficultyPassed = &override
}
backend, eth := utils.RegisterEthService(stack, &cfg.Eth)
// Warn users to migrate if they have a legacy freezer format.
if eth != nil && !ctx.IsSet(utils.IgnoreLegacyReceiptsFlag.Name) {
@ -181,7 +181,6 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
utils.Fatalf("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.")
}
}
// Configure GraphQL if requested
if ctx.IsSet(utils.GraphQLEnabledFlag.Name) {
utils.RegisterGraphQLService(stack, backend, cfg.Node)

@ -69,8 +69,8 @@ var (
utils.NoUSBFlag,
utils.USBFlag,
utils.SmartCardDaemonPathFlag,
utils.OverrideGrayGlacierFlag,
utils.OverrideTerminalTotalDifficulty,
utils.OverrideTerminalTotalDifficultyPassed,
utils.EthashCacheDirFlag,
utils.EthashCachesInMemoryFlag,
utils.EthashCachesOnDiskFlag,

@ -262,17 +262,16 @@ var (
Value: 2048,
Category: flags.EthCategory,
}
OverrideGrayGlacierFlag = &cli.Uint64Flag{
Name: "override.grayglacier",
Usage: "Manually specify Gray Glacier fork-block, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideTerminalTotalDifficulty = &flags.BigFlag{
Name: "override.terminaltotaldifficulty",
Usage: "Manually specify TerminalTotalDifficulty, overriding the bundled setting",
Category: flags.EthCategory,
}
OverrideTerminalTotalDifficultyPassed = &cli.BoolFlag{
Name: "override.terminaltotaldifficultypassed",
Usage: "Manually specify TerminalTotalDifficultyPassed, overriding the bundled setting",
Category: flags.EthCategory,
}
// Light server and client settings
LightServeFlag = &cli.IntFlag{
Name: "light.serve",

@ -233,7 +233,7 @@ func SetupGenesisBlock(db ethdb.Database, genesis *Genesis) (*params.ChainConfig
return SetupGenesisBlockWithOverride(db, genesis, nil, nil)
}
func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideGrayGlacier, overrideTerminalTotalDifficulty *big.Int) (*params.ChainConfig, common.Hash, error) {
func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, overrideTerminalTotalDifficulty *big.Int, overrideTerminalTotalDifficultyPassed *bool) (*params.ChainConfig, common.Hash, error) {
if genesis != nil && genesis.Config == nil {
return params.AllEthashProtocolChanges, common.Hash{}, errGenesisNoConfig
}
@ -243,8 +243,8 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, genesis *Genesis, override
if overrideTerminalTotalDifficulty != nil {
config.TerminalTotalDifficulty = overrideTerminalTotalDifficulty
}
if overrideGrayGlacier != nil {
config.GrayGlacierBlock = overrideGrayGlacier
if overrideTerminalTotalDifficultyPassed != nil {
config.TerminalTotalDifficultyPassed = *overrideTerminalTotalDifficultyPassed
}
}
}

@ -241,7 +241,7 @@ func (f *chainFreezer) freeze(db ethdb.KeyValueStore) {
if n := len(ancients); n > 0 {
context = append(context, []interface{}{"hash", ancients[n-1]}...)
}
log.Info("Deep froze chain segment", context...)
log.Debug("Deep froze chain segment", context...)
// Avoid database thrashing with tiny writes
if frozen-first < freezerBatchLimit {

@ -137,7 +137,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
if err != nil {
return nil, err
}
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty)
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed)
if _, ok := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !ok {
return nil, genesisErr
}

@ -22,6 +22,7 @@ import (
"encoding/binary"
"errors"
"fmt"
"math/big"
"sync"
"time"
@ -59,6 +60,11 @@ const (
// invalidTipsetsCap is the max number of recent block hashes tracked that
// have lead to some bad ancestor block. It's just an OOM protection.
invalidTipsetsCap = 512
// beaconUpdateTimeout is the max time allowed for a beacon client to signal
// use (from the last heartbeat) before it's consifered offline and the user
// is warned.
beaconUpdateTimeout = 30 * time.Second
)
type ConsensusAPI struct {
@ -90,7 +96,17 @@ type ConsensusAPI struct {
invalidTipsets map[common.Hash]*types.Header // Ephemeral cache to track invalid tipsets and their bad ancestor
invalidLock sync.Mutex // Protects the invalid maps from concurrent access
forkChoiceLock sync.Mutex // Lock for the forkChoiceUpdated method
// Geth can appear to be stuck or do strange things if the beacon client is
// offline or is sending us strange data. Stash some update stats away so
// that we can warn the user and not have them open issues on our tracker.
lastTransitionUpdate time.Time
lastTransitionLock sync.Mutex
lastForkchoiceUpdate time.Time
lastForkchoiceLock sync.Mutex
lastNewPayloadUpdate time.Time
lastNewPayloadLock sync.Mutex
forkchoiceLock sync.Mutex // Lock for the forkChoiceUpdated method
}
// NewConsensusAPI creates a new consensus api for the given backend.
@ -107,6 +123,7 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI {
invalidTipsets: make(map[common.Hash]*types.Header),
}
eth.Downloader().SetBadBlockCallback(api.setInvalidAncestor)
go api.heartbeat()
return api
}
@ -122,14 +139,18 @@ func NewConsensusAPI(eth *eth.Ethereum) *ConsensusAPI {
// If there are payloadAttributes:
// we try to assemble a block with the payloadAttributes and return its payloadID
func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, payloadAttributes *beacon.PayloadAttributesV1) (beacon.ForkChoiceResponse, error) {
api.forkChoiceLock.Lock()
defer api.forkChoiceLock.Unlock()
api.forkchoiceLock.Lock()
defer api.forkchoiceLock.Unlock()
log.Trace("Engine API request received", "method", "ForkchoiceUpdated", "head", update.HeadBlockHash, "finalized", update.FinalizedBlockHash, "safe", update.SafeBlockHash)
if update.HeadBlockHash == (common.Hash{}) {
log.Warn("Forkchoice requested update to zero hash")
return beacon.STATUS_INVALID, nil // TODO(karalabe): Why does someone send us this?
}
// Stash away the last update to warn the user if the beacon client goes offline
api.lastForkchoiceLock.Lock()
api.lastForkchoiceUpdate = time.Now()
api.lastForkchoiceLock.Unlock()
// Check whether we have the block yet in our database or not. If not, we'll
// need to either trigger a sync, or to reject this forkchoice update for a
@ -265,15 +286,20 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV1(update beacon.ForkchoiceStateV1, pa
// ExchangeTransitionConfigurationV1 checks the given configuration against
// the configuration of the node.
func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config beacon.TransitionConfigurationV1) (*beacon.TransitionConfigurationV1, error) {
log.Trace("Engine API request received", "method", "ExchangeTransitionConfiguration", "ttd", config.TerminalTotalDifficulty)
if config.TerminalTotalDifficulty == nil {
return nil, errors.New("invalid terminal total difficulty")
}
// Stash away the last update to warn the user if the beacon client goes offline
api.lastTransitionLock.Lock()
api.lastTransitionUpdate = time.Now()
api.lastTransitionLock.Unlock()
ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty
if ttd == nil || ttd.Cmp(config.TerminalTotalDifficulty.ToInt()) != 0 {
log.Warn("Invalid TTD configured", "geth", ttd, "beacon", config.TerminalTotalDifficulty)
return nil, fmt.Errorf("invalid ttd: execution %v consensus %v", ttd, config.TerminalTotalDifficulty)
}
if config.TerminalBlockHash != (common.Hash{}) {
if hash := api.eth.BlockChain().GetCanonicalHash(uint64(config.TerminalBlockNumber)); hash == config.TerminalBlockHash {
return &beacon.TransitionConfigurationV1{
@ -305,6 +331,11 @@ func (api *ConsensusAPI) NewPayloadV1(params beacon.ExecutableDataV1) (beacon.Pa
log.Debug("Invalid NewPayload params", "params", params, "error", err)
return beacon.PayloadStatusV1{Status: beacon.INVALIDBLOCKHASH}, nil
}
// Stash away the last update to warn the user if the beacon client goes offline
api.lastNewPayloadLock.Lock()
api.lastNewPayloadUpdate = time.Now()
api.lastNewPayloadLock.Unlock()
// If we already have the block locally, ignore the entire execution and just
// return a fake success.
if block := api.eth.BlockChain().GetBlockByHash(params.BlockHash); block != nil {
@ -507,3 +538,123 @@ func (api *ConsensusAPI) invalid(err error, latestValid *types.Header) beacon.Pa
errorMsg := err.Error()
return beacon.PayloadStatusV1{Status: beacon.INVALID, LatestValidHash: &currentHash, ValidationError: &errorMsg}
}
// heatbeat loops indefinitely, and checks if there have been beacon client updates
// received in the last while. If not - or if they but strange ones - it warns the
// user that something might be off with their consensus node.
//
// TODO(karalabe): Spin this goroutine down somehow
func (api *ConsensusAPI) heartbeat() {
// Sleep a bit more on startup since there's obviously no beacon client yet
// attached, so no need to print scary warnings to the user.
time.Sleep(beaconUpdateTimeout)
var (
offlineLogged time.Time
)
for {
// Sleep a bit and retrieve the last known consensus updates
time.Sleep(5 * time.Second)
// If the network is not yet merged/merging, don't bother scaring the user
ttd := api.eth.BlockChain().Config().TerminalTotalDifficulty
if ttd == nil {
continue
}
api.lastTransitionLock.Lock()
lastTransitionUpdate := api.lastTransitionUpdate
api.lastTransitionLock.Unlock()
api.lastForkchoiceLock.Lock()
lastForkchoiceUpdate := api.lastForkchoiceUpdate
api.lastForkchoiceLock.Unlock()
api.lastNewPayloadLock.Lock()
lastNewPayloadUpdate := api.lastNewPayloadUpdate
api.lastNewPayloadLock.Unlock()
// If there have been no updates for the past while, warn the user
// that the beacon client is probably offline
if api.eth.BlockChain().Config().TerminalTotalDifficultyPassed || api.eth.Merger().TDDReached() {
if time.Since(lastForkchoiceUpdate) > beaconUpdateTimeout && time.Since(lastNewPayloadUpdate) > beaconUpdateTimeout {
if time.Since(lastTransitionUpdate) > beaconUpdateTimeout {
if time.Since(offlineLogged) > beaconUpdateTimeout {
if lastTransitionUpdate.IsZero() {
log.Warn("Post-merge network, but no beacon client seen. Please launch one to follow the chain!")
} else {
log.Warn("Previously seen beacon client is offline. Please ensure it is operational to follow the chain!")
}
offlineLogged = time.Now()
}
continue
}
if time.Since(offlineLogged) > beaconUpdateTimeout {
if lastForkchoiceUpdate.IsZero() && lastNewPayloadUpdate.IsZero() {
log.Warn("Beacon client online, but never received consensus updates. Please ensure your beacon client is operational to follow the chain!")
} else {
log.Warn("Beacon client online, but no consensus updates received in a while. Please fix your beacon client to follow the chain!")
}
offlineLogged = time.Now()
}
continue
}
} else {
if time.Since(lastTransitionUpdate) > beaconUpdateTimeout {
if time.Since(offlineLogged) > beaconUpdateTimeout {
// Retrieve the last few blocks and make a rough estimate as
// to when the merge transition should happen
var (
chain = api.eth.BlockChain()
head = chain.CurrentBlock()
htd = chain.GetTd(head.Hash(), head.NumberU64())
eta time.Duration
)
if head.NumberU64() > 0 && htd.Cmp(ttd) < 0 {
// Accumulate the last 64 difficulties to estimate the growth
var diff float64
block := head
for i := 0; i < 64; i++ {
diff += float64(block.Difficulty().Uint64())
if parent := chain.GetBlock(block.ParentHash(), block.NumberU64()-1); parent == nil {
break
} else {
block = parent
}
}
// Estimate an ETA based on the block times and the difficulty growth
growth := diff / float64(head.Time()-block.Time()+1) // +1 to avoid div by zero
if growth > 0 {
if left := new(big.Int).Sub(ttd, htd); left.IsUint64() {
eta = time.Duration(float64(left.Uint64())/growth) * time.Second
} else {
eta = time.Duration(new(big.Int).Div(left, big.NewInt(int64(growth))).Uint64()) * time.Second
}
}
}
var message string
if htd.Cmp(ttd) > 0 {
if lastTransitionUpdate.IsZero() {
message = "Merge already reached, but no beacon client seen. Please launch one to follow the chain!"
} else {
message = "Merge already reached, but previously seen beacon client is offline. Please ensure it is operational to follow the chain!"
}
} else {
if lastTransitionUpdate.IsZero() {
message = "Merge is configured, but no beacon client seen. Please ensure you have one available before the transision arrives!"
} else {
message = "Merge is configured, but previously seen beacon client is offline. Please ensure it is operational before the transision arrives!"
}
}
if eta == 0 {
log.Warn(message)
} else {
log.Warn(message, "eta", common.PrettyAge(time.Now().Add(-eta))) // weird hack, but duration formatted doens't handle days
}
offlineLogged = time.Now()
}
continue
}
}
}
}

@ -205,11 +205,11 @@ type Config struct {
// CheckpointOracle is the configuration for checkpoint oracle.
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
// Gray Glacier block override (TODO: remove after the fork)
OverrideGrayGlacier *big.Int `toml:",omitempty"`
// OverrideTerminalTotalDifficulty (TODO: remove after the fork)
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`
// OverrideTerminalTotalDifficultyPassed (TODO: remove after the fork)
OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"`
}
// CreateConsensusEngine creates a consensus engine for the given chain configuration.

@ -18,49 +18,49 @@ import (
// MarshalTOML marshals as TOML.
func (c Config) MarshalTOML() (interface{}, error) {
type Config struct {
Genesis *core.Genesis `toml:",omitempty"`
NetworkId uint64
SyncMode downloader.SyncMode
EthDiscoveryURLs []string
SnapDiscoveryURLs []string
NoPruning bool
NoPrefetch bool
TxLookupLimit uint64 `toml:",omitempty"`
RequiredBlocks map[uint64]common.Hash `toml:"-"`
LightServ int `toml:",omitempty"`
LightIngress int `toml:",omitempty"`
LightEgress int `toml:",omitempty"`
LightPeers int `toml:",omitempty"`
LightNoPrune bool `toml:",omitempty"`
LightNoSyncServe bool `toml:",omitempty"`
SyncFromCheckpoint bool `toml:",omitempty"`
UltraLightServers []string `toml:",omitempty"`
UltraLightFraction int `toml:",omitempty"`
UltraLightOnlyAnnounce bool `toml:",omitempty"`
SkipBcVersionCheck bool `toml:"-"`
DatabaseHandles int `toml:"-"`
DatabaseCache int
DatabaseFreezer string
TrieCleanCache int
TrieCleanCacheJournal string `toml:",omitempty"`
TrieCleanCacheRejournal time.Duration `toml:",omitempty"`
TrieDirtyCache int
TrieTimeout time.Duration
SnapshotCache int
Preimages bool
Miner miner.Config
Ethash ethash.Config
TxPool core.TxPoolConfig
GPO gasprice.Config
EnablePreimageRecording bool
DocRoot string `toml:"-"`
RPCGasCap uint64
RPCEVMTimeout time.Duration
RPCTxFeeCap float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideGrayGlacier *big.Int `toml:",omitempty"`
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`
Genesis *core.Genesis `toml:",omitempty"`
NetworkId uint64
SyncMode downloader.SyncMode
EthDiscoveryURLs []string
SnapDiscoveryURLs []string
NoPruning bool
NoPrefetch bool
TxLookupLimit uint64 `toml:",omitempty"`
RequiredBlocks map[uint64]common.Hash `toml:"-"`
LightServ int `toml:",omitempty"`
LightIngress int `toml:",omitempty"`
LightEgress int `toml:",omitempty"`
LightPeers int `toml:",omitempty"`
LightNoPrune bool `toml:",omitempty"`
LightNoSyncServe bool `toml:",omitempty"`
SyncFromCheckpoint bool `toml:",omitempty"`
UltraLightServers []string `toml:",omitempty"`
UltraLightFraction int `toml:",omitempty"`
UltraLightOnlyAnnounce bool `toml:",omitempty"`
SkipBcVersionCheck bool `toml:"-"`
DatabaseHandles int `toml:"-"`
DatabaseCache int
DatabaseFreezer string
TrieCleanCache int
TrieCleanCacheJournal string `toml:",omitempty"`
TrieCleanCacheRejournal time.Duration `toml:",omitempty"`
TrieDirtyCache int
TrieTimeout time.Duration
SnapshotCache int
Preimages bool
Miner miner.Config
Ethash ethash.Config
TxPool core.TxPoolConfig
GPO gasprice.Config
EnablePreimageRecording bool
DocRoot string `toml:"-"`
RPCGasCap uint64
RPCEVMTimeout time.Duration
RPCTxFeeCap float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`
OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"`
}
var enc Config
enc.Genesis = c.Genesis
@ -104,57 +104,57 @@ func (c Config) MarshalTOML() (interface{}, error) {
enc.RPCTxFeeCap = c.RPCTxFeeCap
enc.Checkpoint = c.Checkpoint
enc.CheckpointOracle = c.CheckpointOracle
enc.OverrideGrayGlacier = c.OverrideGrayGlacier
enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty
enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed
return &enc, nil
}
// UnmarshalTOML unmarshals from TOML.
func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
type Config struct {
Genesis *core.Genesis `toml:",omitempty"`
NetworkId *uint64
SyncMode *downloader.SyncMode
EthDiscoveryURLs []string
SnapDiscoveryURLs []string
NoPruning *bool
NoPrefetch *bool
TxLookupLimit *uint64 `toml:",omitempty"`
RequiredBlocks map[uint64]common.Hash `toml:"-"`
LightServ *int `toml:",omitempty"`
LightIngress *int `toml:",omitempty"`
LightEgress *int `toml:",omitempty"`
LightPeers *int `toml:",omitempty"`
LightNoPrune *bool `toml:",omitempty"`
LightNoSyncServe *bool `toml:",omitempty"`
SyncFromCheckpoint *bool `toml:",omitempty"`
UltraLightServers []string `toml:",omitempty"`
UltraLightFraction *int `toml:",omitempty"`
UltraLightOnlyAnnounce *bool `toml:",omitempty"`
SkipBcVersionCheck *bool `toml:"-"`
DatabaseHandles *int `toml:"-"`
DatabaseCache *int
DatabaseFreezer *string
TrieCleanCache *int
TrieCleanCacheJournal *string `toml:",omitempty"`
TrieCleanCacheRejournal *time.Duration `toml:",omitempty"`
TrieDirtyCache *int
TrieTimeout *time.Duration
SnapshotCache *int
Preimages *bool
Miner *miner.Config
Ethash *ethash.Config
TxPool *core.TxPoolConfig
GPO *gasprice.Config
EnablePreimageRecording *bool
DocRoot *string `toml:"-"`
RPCGasCap *uint64
RPCEVMTimeout *time.Duration
RPCTxFeeCap *float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideGrayGlacier *big.Int `toml:",omitempty"`
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`
Genesis *core.Genesis `toml:",omitempty"`
NetworkId *uint64
SyncMode *downloader.SyncMode
EthDiscoveryURLs []string
SnapDiscoveryURLs []string
NoPruning *bool
NoPrefetch *bool
TxLookupLimit *uint64 `toml:",omitempty"`
RequiredBlocks map[uint64]common.Hash `toml:"-"`
LightServ *int `toml:",omitempty"`
LightIngress *int `toml:",omitempty"`
LightEgress *int `toml:",omitempty"`
LightPeers *int `toml:",omitempty"`
LightNoPrune *bool `toml:",omitempty"`
LightNoSyncServe *bool `toml:",omitempty"`
SyncFromCheckpoint *bool `toml:",omitempty"`
UltraLightServers []string `toml:",omitempty"`
UltraLightFraction *int `toml:",omitempty"`
UltraLightOnlyAnnounce *bool `toml:",omitempty"`
SkipBcVersionCheck *bool `toml:"-"`
DatabaseHandles *int `toml:"-"`
DatabaseCache *int
DatabaseFreezer *string
TrieCleanCache *int
TrieCleanCacheJournal *string `toml:",omitempty"`
TrieCleanCacheRejournal *time.Duration `toml:",omitempty"`
TrieDirtyCache *int
TrieTimeout *time.Duration
SnapshotCache *int
Preimages *bool
Miner *miner.Config
Ethash *ethash.Config
TxPool *core.TxPoolConfig
GPO *gasprice.Config
EnablePreimageRecording *bool
DocRoot *string `toml:"-"`
RPCGasCap *uint64
RPCEVMTimeout *time.Duration
RPCTxFeeCap *float64
Checkpoint *params.TrustedCheckpoint `toml:",omitempty"`
CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"`
OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"`
OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"`
}
var dec Config
if err := unmarshal(&dec); err != nil {
@ -283,11 +283,11 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
if dec.CheckpointOracle != nil {
c.CheckpointOracle = dec.CheckpointOracle
}
if dec.OverrideGrayGlacier != nil {
c.OverrideGrayGlacier = dec.OverrideGrayGlacier
}
if dec.OverrideTerminalTotalDifficulty != nil {
c.OverrideTerminalTotalDifficulty = dec.OverrideTerminalTotalDifficulty
}
if dec.OverrideTerminalTotalDifficultyPassed != nil {
c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed
}
return nil
}

@ -191,11 +191,22 @@ func newHandler(config *handlerConfig) (*handler, error) {
}
}
}
// Construct the downloader (long sync) and its backing state bloom if snap
// sync is requested. The downloader is responsible for deallocating the state
// bloom when it's done.
// Construct the downloader (long sync)
h.downloader = downloader.New(h.checkpointNumber, config.Database, h.eventMux, h.chain, nil, h.removePeer, success)
if ttd := h.chain.Config().TerminalTotalDifficulty; ttd != nil {
if h.chain.Config().TerminalTotalDifficultyPassed {
log.Info("Chain post-merge, sync via beacon client")
} else {
head := h.chain.CurrentBlock()
if td := h.chain.GetTd(head.Hash(), head.NumberU64()); td.Cmp(ttd) >= 0 {
log.Info("Chain post-TTD, sync via beacon client")
} else {
log.Warn("Chain pre-merge, sync via PoW (ensure beacon client is ready)")
}
}
} else if h.chain.Config().TerminalTotalDifficultyPassed {
log.Error("Chain configured post-merge, but without TTD. Are you debugging sync?")
}
// Construct the fetcher (short sync)
validator := func(header *types.Header) error {
// All the block fetcher activities should be disabled

@ -163,7 +163,7 @@ func (cs *chainSyncer) nextSyncOp() *chainSyncOp {
// An alternative would be to check the local chain for exceeding the TTD and
// avoid triggering a sync in that case, but that could also miss sibling or
// other family TTD block being accepted.
if cs.handler.merger.TDDReached() {
if cs.handler.chain.Config().TerminalTotalDifficultyPassed || cs.handler.merger.TDDReached() {
return nil
}
// Ensure we're at minimum peer count.

@ -93,7 +93,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*LightEthereum, error) {
if err != nil {
return nil, err
}
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideGrayGlacier, config.OverrideTerminalTotalDifficulty)
chainConfig, genesisHash, genesisErr := core.SetupGenesisBlockWithOverride(chainDb, config.Genesis, config.OverrideTerminalTotalDifficulty, config.OverrideTerminalTotalDifficultyPassed)
if _, isCompat := genesisErr.(*params.ConfigCompatError); genesisErr != nil && !isCompat {
return nil, genesisErr
}

@ -100,23 +100,24 @@ var (
// RopstenChainConfig contains the chain parameters to run a node on the Ropsten test network.
RopstenChainConfig = &ChainConfig{
ChainID: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
ByzantiumBlock: big.NewInt(1_700_000),
ConstantinopleBlock: big.NewInt(4_230_000),
PetersburgBlock: big.NewInt(4_939_394),
IstanbulBlock: big.NewInt(6_485_846),
MuirGlacierBlock: big.NewInt(7_117_117),
BerlinBlock: big.NewInt(9_812_189),
LondonBlock: big.NewInt(10_499_401),
TerminalTotalDifficulty: new(big.Int).SetUint64(50000000000000000),
Ethash: new(EthashConfig),
ChainID: big.NewInt(3),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP150Hash: common.HexToHash("0x41941023680923e0fe4d74a34bdac8141f2540e3ae90623718e47d66d1ca4a2d"),
EIP155Block: big.NewInt(10),
EIP158Block: big.NewInt(10),
ByzantiumBlock: big.NewInt(1_700_000),
ConstantinopleBlock: big.NewInt(4_230_000),
PetersburgBlock: big.NewInt(4_939_394),
IstanbulBlock: big.NewInt(6_485_846),
MuirGlacierBlock: big.NewInt(7_117_117),
BerlinBlock: big.NewInt(9_812_189),
LondonBlock: big.NewInt(10_499_401),
TerminalTotalDifficulty: new(big.Int).SetUint64(50_000_000_000_000_000),
TerminalTotalDifficultyPassed: true,
Ethash: new(EthashConfig),
}
// RopstenTrustedCheckpoint contains the light client trusted checkpoint for the Ropsten test network.
@ -142,23 +143,24 @@ var (
// SepoliaChainConfig contains the chain parameters to run a node on the Sepolia test network.
SepoliaChainConfig = &ChainConfig{
ChainID: big.NewInt(11155111),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000),
MergeNetsplitBlock: big.NewInt(1735371),
Ethash: new(EthashConfig),
ChainID: big.NewInt(11155111),
HomesteadBlock: big.NewInt(0),
DAOForkBlock: nil,
DAOForkSupport: true,
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
TerminalTotalDifficulty: big.NewInt(17_000_000_000_000_000),
TerminalTotalDifficultyPassed: true,
MergeNetsplitBlock: big.NewInt(1735371),
Ethash: new(EthashConfig),
}
// SepoliaTrustedCheckpoint contains the light client trusted checkpoint for the Sepolia test network.
@ -263,16 +265,16 @@ var (
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil}
AllEthashProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil}
// AllCliqueProtocolChanges contains every protocol change (EIPs) introduced
// and accepted by the Ethereum core developers into the Clique consensus.
//
// This configuration is intentionally not using keyed fields to force anyone
// adding flags to the config to also have to set these fields.
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, new(EthashConfig), nil}
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil}
TestRules = TestChainConfig.Rules(new(big.Int), false)
)
@ -370,6 +372,11 @@ type ChainConfig struct {
// the network that triggers the consensus upgrade.
TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"`
// TerminalTotalDifficultyPassed is a flag specifying that the network already
// passed the terminal total difficulty. Its purpose is to disable legacy sync
// even without having seen the TTD locally (safer long term).
TerminalTotalDifficultyPassed bool `json:"terminalTotalDifficultyPassed,omitempty"`
// Various consensus engines
Ethash *EthashConfig `json:"ethash,omitempty"`
Clique *CliqueConfig `json:"clique,omitempty"`
@ -408,12 +415,16 @@ func (c *ChainConfig) String() string {
case c.Ethash != nil:
if c.TerminalTotalDifficulty == nil {
banner += "Consensus: Ethash (proof-of-work)\n"
} else if !c.TerminalTotalDifficultyPassed {
banner += "Consensus: Beacon (proof-of-stake), merging from Ethash (proof-of-work)\n"
} else {
banner += "Consensus: Beacon (proof-of-stake), merged from Ethash (proof-of-work)\n"
}
case c.Clique != nil:
if c.TerminalTotalDifficulty == nil {
banner += "Consensus: Clique (proof-of-authority)\n"
} else if !c.TerminalTotalDifficultyPassed {
banner += "Consensus: Beacon (proof-of-stake), merging from Clique (proof-of-authority)\n"
} else {
banner += "Consensus: Beacon (proof-of-stake), merged from Clique (proof-of-authority)\n"
}
@ -462,9 +473,10 @@ func (c *ChainConfig) String() string {
banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)"
} else {
banner += "Merge configured:\n"
banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n"
banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty)
banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock)
banner += " - Hard-fork specification: https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/paris.md)\n"
banner += fmt.Sprintf(" - Network known to be merged: %v\n", c.TerminalTotalDifficultyPassed)
banner += fmt.Sprintf(" - Total terminal difficulty: %v\n", c.TerminalTotalDifficulty)
banner += fmt.Sprintf(" - Merge netsplit block: %-8v", c.MergeNetsplitBlock)
}
return banner
}