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

Require properly configured Engine API connection after the merge #4006

Merged
merged 1 commit into from
Aug 22, 2022
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
5 changes: 5 additions & 0 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,11 @@ type
desc: "Force the use of polling when determining the head block of Eth1"
name: "web3-force-polling" .}: bool

requireEngineAPI* {.
defaultValue: true
desc: "Require Nimbus to be configured with an Engine API end-point after the Bellatrix fork epoch"
name: "require-engine-api-in-bellatrix" .}: bool

nonInteractive* {.
desc: "Do not display interative prompts. Quit on missing configuration"
name: "non-interactive" .}: bool
Expand Down
88 changes: 60 additions & 28 deletions beacon_chain/eth1/eth1_monitor.nim
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ type
stopFut: Future[void]
getBeaconTime: GetBeaconTimeFn

requireEngineAPI: bool

when hasGenesisDetection:
genesisValidators: seq[ImmutableValidatorData]
genesisValidatorKeyToIndex: Table[ValidatorPubKey, ValidatorIndex]
Expand Down Expand Up @@ -548,53 +550,67 @@ proc forkchoiceUpdated*(p: Eth1Monitor,
# TODO can't be defined within exchangeTransitionConfiguration
proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.}

proc exchangeTransitionConfiguration*(p: Eth1Monitor): Future[void] {.async.} =
type
EtcStatus {.pure.} = enum
exchangeError
mismatch
localConfigurationUpdated
match

proc exchangeTransitionConfiguration*(p: Eth1Monitor): Future[EtcStatus] {.async.} =
# Eth1 monitor can recycle connections without (external) warning; at least,
# don't crash.
if p.isNil:
debug "exchangeTransitionConfiguration: nil Eth1Monitor"

if p.isNil or p.dataProvider.isNil:
return
return EtcStatus.exchangeError

let ccTransitionConfiguration = TransitionConfigurationV1(
let consensusCfg = TransitionConfigurationV1(
terminalTotalDifficulty: p.depositsChain.cfg.TERMINAL_TOTAL_DIFFICULTY,
terminalBlockHash:
if p.terminalBlockHash.isSome:
p.terminalBlockHash.get
else:
# https://github.com/nim-lang/Nim/issues/19802
(static(default(BlockHash))),
(static default BlockHash),
terminalBlockNumber:
if p.terminalBlockNumber.isSome:
p.terminalBlockNumber.get
else:
# https://github.com/nim-lang/Nim/issues/19802
(static(default(Quantity))))
let ecTransitionConfiguration =
(static default Quantity))
let executionCfg =
try:
awaitWithRetries(
p.dataProvider.web3.provider.engine_exchangeTransitionConfigurationV1(
ccTransitionConfiguration),
consensusCfg),
timeout = 1.seconds)
except CatchableError as err:
debug "Failed to exchange transition configuration", err = err.msg
return

if ccTransitionConfiguration != ecTransitionConfiguration:
warn "exchangeTransitionConfiguration: Configuration mismatch detected",
consensusTerminalTotalDifficulty =
$ccTransitionConfiguration.terminalTotalDifficulty,
consensusTerminalBlockHash =
ccTransitionConfiguration.terminalBlockHash,
consensusTerminalBlockNumber =
ccTransitionConfiguration.terminalBlockNumber.uint64,
executionTerminalTotalDifficulty =
$ecTransitionConfiguration.terminalTotalDifficulty,
executionTerminalBlockHash =
ecTransitionConfiguration.terminalBlockHash,
executionTerminalBlockNumber =
ecTransitionConfiguration.terminalBlockNumber.uint64
error "Failed to exchange transition configuration", err = err.msg
return EtcStatus.exchangeError

if consensusCfg.terminalTotalDifficulty != executionCfg.terminalTotalDifficulty:
warn "Engine API configured with different terminal total difficulty",
engineAPI_value = executionCfg.terminalTotalDifficulty,
localValue = consensusCfg.terminalTotalDifficulty
return EtcStatus.mismatch

if p.terminalBlockNumber.isSome and p.terminalBlockHash.isSome:
var res = EtcStatus.match
if consensusCfg.terminalBlockNumber != executionCfg.terminalBlockNumber:
warn "Engine API reporting different terminal block number",
engineAPI_value = executionCfg.terminalBlockNumber.uint64,
localValue = consensusCfg.terminalBlockNumber.uint64
res = EtcStatus.mismatch
if consensusCfg.terminalBlockHash != executionCfg.terminalBlockHash:
warn "Engine API reporting different terminal block hash",
engineAPI_value = executionCfg.terminalBlockHash,
localValue = consensusCfg.terminalBlockHash
res = EtcStatus.mismatch
return res
else:
p.terminalBlockNumber = some executionCfg.terminalBlockNumber
p.terminalBlockHash = some executionCfg.terminalBlockHash
return EtcStatus.localConfigurationUpdated

template readJsonField(j: JsonNode, fieldName: string, ValueType: type): untyped =
var res: ValueType
Expand Down Expand Up @@ -1037,7 +1053,8 @@ proc init*(T: type Eth1Monitor,
depositContractSnapshot: Option[DepositContractSnapshot],
eth1Network: Option[Eth1Network],
forcePolling: bool,
jwtSecret: Option[seq[byte]]): T =
jwtSecret: Option[seq[byte]],
requireEngineAPI: bool): T =
doAssert web3Urls.len > 0
var web3Urls = web3Urls
for url in mitems(web3Urls):
Expand All @@ -1055,7 +1072,8 @@ proc init*(T: type Eth1Monitor,
eth1Progress: newAsyncEvent(),
forcePolling: forcePolling,
jwtSecret: jwtSecret,
blocksPerLogsRequest: targetBlocksPerLogsRequest)
blocksPerLogsRequest: targetBlocksPerLogsRequest,
requireEngineAPI: requireEngineAPI)

proc safeCancel(fut: var Future[void]) =
if not fut.isNil and not fut.finished:
Expand Down Expand Up @@ -1340,6 +1358,20 @@ proc startEth1Syncing(m: Eth1Monitor, delayBeforeStart: Duration) {.async.} =

await m.ensureDataProvider()

if m.currentEpoch >= m.cfg.BELLATRIX_FORK_EPOCH:
let status = await m.exchangeTransitionConfiguration()
if status == EtcStatus.localConfigurationUpdated:
info "Obtained terminal block from Engine API",
terminalBlockNumber = m.terminalBlockNumber.get.uint64,
terminalBlockHash = m.terminalBlockHash.get
elif status != EtcStatus.match and isFirstRun and m.requireEngineAPI:
fatal "The Bellatrix hard fork requires the beacon node to be connected to a properly configured Engine API end-point. " &
"See https://nimbus.guide/merge.html for more details. " &
"If you want to temporarily continue operating Nimbus without configuring an Engine API end-point, " &
"please specify the command-line option --require-engine-api-in-bellatrix=no when launching it. " &
"Please note that you MUST complete the migration before the network TTD is reached (estimated to happen near 13th of September)"
quit 1

# We might need to reset the chain if the new provider disagrees
# with the previous one regarding the history of the chain or if
# we have detected a conensus violation - our view disagreeing with
Expand Down
6 changes: 4 additions & 2 deletions beacon_chain/nimbus_beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,8 @@ proc init*(T: type BeaconNode,
getDepositContractSnapshot(),
eth1Network,
config.web3ForcePolling,
optJwtSecret)
optJwtSecret,
config.requireEngineAPI)

eth1Monitor.loadPersistedDeposits()

Expand Down Expand Up @@ -639,7 +640,8 @@ proc init*(T: type BeaconNode,
getDepositContractSnapshot(),
eth1Network,
config.web3ForcePolling,
optJwtSecret)
optJwtSecret,
config.requireEngineAPI)

if config.rpcEnabled:
warn "Nimbus's JSON-RPC server has been removed. This includes the --rpc, --rpc-port, and --rpc-address configuration options. https://nimbus.guide/rest-api.html shows how to enable and configure the REST Beacon API server which replaces it."
Expand Down
3 changes: 2 additions & 1 deletion beacon_chain/nimbus_light_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,8 @@ programMain:
cfg, db = nil, getBeaconTime, config.web3Urls,
none(DepositContractSnapshot), metadata.eth1Network,
forcePolling = false,
rng[].loadJwtSecret(config, allowCreate = false))
rng[].loadJwtSecret(config, allowCreate = false),
true)
waitFor res.ensureDataProvider()
res
else:
Expand Down
2 changes: 2 additions & 0 deletions docs/the_nimbus_book/src/merge.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ As a node operator, you will need to run both an execution client and a consensu

If you were running an execution client before, make sure to update its configuration to include an option for [JWT secrets](./eth1.md#3-pass-the-jwt-secret-to-nimbus) and engine API.

Please note that once the Bellatrix fork epoch is reached on 6th of September 2022, Nimbus will refuse to start unless connected to a properly configured execution client. If you need more time to complete the transition, you can temporarily run the beacon node with the command-line option `--require-engine-api-in-bellatrix=no`, but please note that such a setup will stop working once the network TTD is reached (currently estimated to happen on 13th of September, see https://wenmerge.com/ for more up-to-date information).
Copy link
Contributor

@tersec tersec Aug 22, 2022

Choose a reason for hiding this comment

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

https://bordel.wtf/ currently states

Total Terminal Difficulty of 58750000000000000000000 is expected around Thu Sep 15 02:29 2022 UTC, i.e. between Thu Sep 15 01:00 2022 UTC and Thu Sep 15 03:59 2022 UTC

But probably better here to go with the earlier of the plausible estimates (so the wenmerge one is probably better)


### Prepare a suggested fee recipient

After the merge, validators that propose blocks are eligible to recieve transaction fees - read more about fee recipients [here](https://launchpad.ethereum.org/en/merge-readiness#fee-recipient).
Expand Down
2 changes: 1 addition & 1 deletion scripts/test_merge_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ proc run() {.async.} =
eth1Monitor = Eth1Monitor.init(
defaultRuntimeConfig, db = nil, nil, @[paramStr(1)],
none(DepositContractSnapshot), none(Eth1Network), false,
some readJwtSecret(paramStr(2)).get)
some readJwtSecret(paramStr(2)).get, true)

await eth1Monitor.ensureDataProvider()
try:
Expand Down
3 changes: 2 additions & 1 deletion scripts/test_merge_vectors.nim
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ proc run() {.async.} =
jwtSecret = some readJwtSecret("jwt.hex").get
eth1Monitor = Eth1Monitor.init(
defaultRuntimeConfig, db = nil, nil, @[web3Url],
none(DepositContractSnapshot), none(Eth1Network), false, jwtSecret)
none(DepositContractSnapshot), none(Eth1Network),
false, jwtSecret, true)
web3Provider = (await Web3DataProvider.new(
default(Eth1Address), web3Url, jwtSecret)).get

Expand Down