diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 710e71836607c..2562de8ae9ea8 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -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) diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 964332078730d..dcf74ecedd4b0 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -69,8 +69,8 @@ var ( utils.NoUSBFlag, utils.USBFlag, utils.SmartCardDaemonPathFlag, - utils.OverrideGrayGlacierFlag, utils.OverrideTerminalTotalDifficulty, + utils.OverrideTerminalTotalDifficultyPassed, utils.EthashCacheDirFlag, utils.EthashCachesInMemoryFlag, utils.EthashCachesOnDiskFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 8380c3f2b572e..f27a882b503c3 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -269,17 +269,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", diff --git a/core/genesis.go b/core/genesis.go index 747422361a9cd..4c5a9e8ae749c 100644 --- a/core/genesis.go +++ b/core/genesis.go @@ -238,7 +238,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 } @@ -248,8 +248,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 } } } diff --git a/core/rawdb/chain_freezer.go b/core/rawdb/chain_freezer.go index 4c49db2748b22..ec39b7b59cd2f 100644 --- a/core/rawdb/chain_freezer.go +++ b/core/rawdb/chain_freezer.go @@ -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 { diff --git a/eth/backend.go b/eth/backend.go index d8a8e3fe94e9f..57269f5f1c77a 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -154,7 +154,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 } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index c5f2313cabbcc..93b78a3867f5a 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -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: ¤tHash, 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 + } + } + } +} diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 0d423ba6c8f75..b22553f6fff82 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -208,11 +208,12 @@ type Config struct { // SYSCOIN NEVMPubEP string `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. diff --git a/eth/ethconfig/gen_config.go b/eth/ethconfig/gen_config.go index 2d8455a42ce9c..722b912919478 100644 --- a/eth/ethconfig/gen_config.go +++ b/eth/ethconfig/gen_config.go @@ -61,8 +61,8 @@ func (c Config) MarshalTOML() (interface{}, error) { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` // SYSCOIN NEVMPubEP string `toml:",omitempty"` - OverrideGrayGlacier *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` } var enc Config enc.Genesis = c.Genesis @@ -107,8 +107,8 @@ func (c Config) MarshalTOML() (interface{}, error) { enc.Checkpoint = c.Checkpoint enc.CheckpointOracle = c.CheckpointOracle enc.NEVMPubEP = c.NEVMPubEP - enc.OverrideGrayGlacier = c.OverrideGrayGlacier enc.OverrideTerminalTotalDifficulty = c.OverrideTerminalTotalDifficulty + enc.OverrideTerminalTotalDifficultyPassed = c.OverrideTerminalTotalDifficultyPassed return &enc, nil } @@ -158,8 +158,8 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error { CheckpointOracle *params.CheckpointOracleConfig `toml:",omitempty"` // SYSCOIN NEVMPubEP *string `toml:",omitempty"` - OverrideGrayGlacier *big.Int `toml:",omitempty"` - OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficulty *big.Int `toml:",omitempty"` + OverrideTerminalTotalDifficultyPassed *bool `toml:",omitempty"` } var dec Config if err := unmarshal(&dec); err != nil { @@ -288,14 +288,14 @@ 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.NEVMPubEP != nil { c.NEVMPubEP = *dec.NEVMPubEP } + if dec.OverrideTerminalTotalDifficultyPassed != nil { + c.OverrideTerminalTotalDifficultyPassed = dec.OverrideTerminalTotalDifficultyPassed + } return nil } diff --git a/eth/handler.go b/eth/handler.go index 31775e73c3007..301ff9d15f056 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -197,11 +197,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 diff --git a/eth/sync.go b/eth/sync.go index d67d2311d0d98..8fd86b578cf62 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -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. diff --git a/les/client.go b/les/client.go index e98d4e241dde1..49d9a1d9319ad 100644 --- a/les/client.go +++ b/les/client.go @@ -112,7 +112,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 } diff --git a/params/config.go b/params/config.go index fb0a6e8aca2d9..df093610701d9 100644 --- a/params/config.go +++ b/params/config.go @@ -146,23 +146,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. @@ -307,16 +308,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), nil, 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), nil, 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), nil, 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), nil, 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), nil, 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), nil, big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(EthashConfig), nil} TestRules = TestChainConfig.Rules(new(big.Int), false) ) @@ -417,6 +418,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"` @@ -456,12 +462,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" }