Skip to content

Commit 4e41ed1

Browse files
authored
Require properly configured Engine API connection after the merge (#4006)
1 parent f1ddcff commit 4e41ed1

File tree

7 files changed

+76
-33
lines changed

7 files changed

+76
-33
lines changed

beacon_chain/conf.nim

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,11 @@ type
172172
desc: "Force the use of polling when determining the head block of Eth1"
173173
name: "web3-force-polling" .}: bool
174174

175+
requireEngineAPI* {.
176+
defaultValue: true
177+
desc: "Require Nimbus to be configured with an Engine API end-point after the Bellatrix fork epoch"
178+
name: "require-engine-api-in-bellatrix" .}: bool
179+
175180
nonInteractive* {.
176181
desc: "Do not display interative prompts. Quit on missing configuration"
177182
name: "non-interactive" .}: bool

beacon_chain/eth1/eth1_monitor.nim

Lines changed: 60 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ type
141141
stopFut: Future[void]
142142
getBeaconTime: GetBeaconTimeFn
143143

144+
requireEngineAPI: bool
145+
144146
when hasGenesisDetection:
145147
genesisValidators: seq[ImmutableValidatorData]
146148
genesisValidatorKeyToIndex: Table[ValidatorPubKey, ValidatorIndex]
@@ -548,53 +550,67 @@ proc forkchoiceUpdated*(p: Eth1Monitor,
548550
# TODO can't be defined within exchangeTransitionConfiguration
549551
proc `==`(x, y: Quantity): bool {.borrow, noSideEffect.}
550552

551-
proc exchangeTransitionConfiguration*(p: Eth1Monitor): Future[void] {.async.} =
553+
type
554+
EtcStatus {.pure.} = enum
555+
exchangeError
556+
mismatch
557+
localConfigurationUpdated
558+
match
559+
560+
proc exchangeTransitionConfiguration*(p: Eth1Monitor): Future[EtcStatus] {.async.} =
552561
# Eth1 monitor can recycle connections without (external) warning; at least,
553562
# don't crash.
554563
if p.isNil:
555564
debug "exchangeTransitionConfiguration: nil Eth1Monitor"
556565

557566
if p.isNil or p.dataProvider.isNil:
558-
return
567+
return EtcStatus.exchangeError
559568

560-
let ccTransitionConfiguration = TransitionConfigurationV1(
569+
let consensusCfg = TransitionConfigurationV1(
561570
terminalTotalDifficulty: p.depositsChain.cfg.TERMINAL_TOTAL_DIFFICULTY,
562571
terminalBlockHash:
563572
if p.terminalBlockHash.isSome:
564573
p.terminalBlockHash.get
565574
else:
566-
# https://github.com/nim-lang/Nim/issues/19802
567-
(static(default(BlockHash))),
575+
(static default BlockHash),
568576
terminalBlockNumber:
569577
if p.terminalBlockNumber.isSome:
570578
p.terminalBlockNumber.get
571579
else:
572-
# https://github.com/nim-lang/Nim/issues/19802
573-
(static(default(Quantity))))
574-
let ecTransitionConfiguration =
580+
(static default Quantity))
581+
let executionCfg =
575582
try:
576583
awaitWithRetries(
577584
p.dataProvider.web3.provider.engine_exchangeTransitionConfigurationV1(
578-
ccTransitionConfiguration),
585+
consensusCfg),
579586
timeout = 1.seconds)
580587
except CatchableError as err:
581-
debug "Failed to exchange transition configuration", err = err.msg
582-
return
583-
584-
if ccTransitionConfiguration != ecTransitionConfiguration:
585-
warn "exchangeTransitionConfiguration: Configuration mismatch detected",
586-
consensusTerminalTotalDifficulty =
587-
$ccTransitionConfiguration.terminalTotalDifficulty,
588-
consensusTerminalBlockHash =
589-
ccTransitionConfiguration.terminalBlockHash,
590-
consensusTerminalBlockNumber =
591-
ccTransitionConfiguration.terminalBlockNumber.uint64,
592-
executionTerminalTotalDifficulty =
593-
$ecTransitionConfiguration.terminalTotalDifficulty,
594-
executionTerminalBlockHash =
595-
ecTransitionConfiguration.terminalBlockHash,
596-
executionTerminalBlockNumber =
597-
ecTransitionConfiguration.terminalBlockNumber.uint64
588+
error "Failed to exchange transition configuration", err = err.msg
589+
return EtcStatus.exchangeError
590+
591+
if consensusCfg.terminalTotalDifficulty != executionCfg.terminalTotalDifficulty:
592+
warn "Engine API configured with different terminal total difficulty",
593+
engineAPI_value = executionCfg.terminalTotalDifficulty,
594+
localValue = consensusCfg.terminalTotalDifficulty
595+
return EtcStatus.mismatch
596+
597+
if p.terminalBlockNumber.isSome and p.terminalBlockHash.isSome:
598+
var res = EtcStatus.match
599+
if consensusCfg.terminalBlockNumber != executionCfg.terminalBlockNumber:
600+
warn "Engine API reporting different terminal block number",
601+
engineAPI_value = executionCfg.terminalBlockNumber.uint64,
602+
localValue = consensusCfg.terminalBlockNumber.uint64
603+
res = EtcStatus.mismatch
604+
if consensusCfg.terminalBlockHash != executionCfg.terminalBlockHash:
605+
warn "Engine API reporting different terminal block hash",
606+
engineAPI_value = executionCfg.terminalBlockHash,
607+
localValue = consensusCfg.terminalBlockHash
608+
res = EtcStatus.mismatch
609+
return res
610+
else:
611+
p.terminalBlockNumber = some executionCfg.terminalBlockNumber
612+
p.terminalBlockHash = some executionCfg.terminalBlockHash
613+
return EtcStatus.localConfigurationUpdated
598614

599615
template readJsonField(j: JsonNode, fieldName: string, ValueType: type): untyped =
600616
var res: ValueType
@@ -1037,7 +1053,8 @@ proc init*(T: type Eth1Monitor,
10371053
depositContractSnapshot: Option[DepositContractSnapshot],
10381054
eth1Network: Option[Eth1Network],
10391055
forcePolling: bool,
1040-
jwtSecret: Option[seq[byte]]): T =
1056+
jwtSecret: Option[seq[byte]],
1057+
requireEngineAPI: bool): T =
10411058
doAssert web3Urls.len > 0
10421059
var web3Urls = web3Urls
10431060
for url in mitems(web3Urls):
@@ -1055,7 +1072,8 @@ proc init*(T: type Eth1Monitor,
10551072
eth1Progress: newAsyncEvent(),
10561073
forcePolling: forcePolling,
10571074
jwtSecret: jwtSecret,
1058-
blocksPerLogsRequest: targetBlocksPerLogsRequest)
1075+
blocksPerLogsRequest: targetBlocksPerLogsRequest,
1076+
requireEngineAPI: requireEngineAPI)
10591077

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

13411359
await m.ensureDataProvider()
13421360

1361+
if m.currentEpoch >= m.cfg.BELLATRIX_FORK_EPOCH:
1362+
let status = await m.exchangeTransitionConfiguration()
1363+
if status == EtcStatus.localConfigurationUpdated:
1364+
info "Obtained terminal block from Engine API",
1365+
terminalBlockNumber = m.terminalBlockNumber.get.uint64,
1366+
terminalBlockHash = m.terminalBlockHash.get
1367+
elif status != EtcStatus.match and isFirstRun and m.requireEngineAPI:
1368+
fatal "The Bellatrix hard fork requires the beacon node to be connected to a properly configured Engine API end-point. " &
1369+
"See https://nimbus.guide/merge.html for more details. " &
1370+
"If you want to temporarily continue operating Nimbus without configuring an Engine API end-point, " &
1371+
"please specify the command-line option --require-engine-api-in-bellatrix=no when launching it. " &
1372+
"Please note that you MUST complete the migration before the network TTD is reached (estimated to happen near 13th of September)"
1373+
quit 1
1374+
13431375
# We might need to reset the chain if the new provider disagrees
13441376
# with the previous one regarding the history of the chain or if
13451377
# we have detected a conensus violation - our view disagreeing with

beacon_chain/nimbus_beacon_node.nim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -538,7 +538,8 @@ proc init*(T: type BeaconNode,
538538
getDepositContractSnapshot(),
539539
eth1Network,
540540
config.web3ForcePolling,
541-
optJwtSecret)
541+
optJwtSecret,
542+
config.requireEngineAPI)
542543

543544
eth1Monitor.loadPersistedDeposits()
544545

@@ -639,7 +640,8 @@ proc init*(T: type BeaconNode,
639640
getDepositContractSnapshot(),
640641
eth1Network,
641642
config.web3ForcePolling,
642-
optJwtSecret)
643+
optJwtSecret,
644+
config.requireEngineAPI)
643645

644646
if config.rpcEnabled:
645647
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."

beacon_chain/nimbus_light_client.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ programMain:
6161
cfg, db = nil, getBeaconTime, config.web3Urls,
6262
none(DepositContractSnapshot), metadata.eth1Network,
6363
forcePolling = false,
64-
rng[].loadJwtSecret(config, allowCreate = false))
64+
rng[].loadJwtSecret(config, allowCreate = false),
65+
true)
6566
waitFor res.ensureDataProvider()
6667
res
6768
else:

docs/the_nimbus_book/src/merge.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ As a node operator, you will need to run both an execution client and a consensu
2222

2323
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.
2424

25+
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).
26+
2527
### Prepare a suggested fee recipient
2628

2729
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).

scripts/test_merge_node.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ proc run() {.async.} =
5959
eth1Monitor = Eth1Monitor.init(
6060
defaultRuntimeConfig, db = nil, nil, @[paramStr(1)],
6161
none(DepositContractSnapshot), none(Eth1Network), false,
62-
some readJwtSecret(paramStr(2)).get)
62+
some readJwtSecret(paramStr(2)).get, true)
6363

6464
await eth1Monitor.ensureDataProvider()
6565
try:

scripts/test_merge_vectors.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,8 @@ proc run() {.async.} =
6060
jwtSecret = some readJwtSecret("jwt.hex").get
6161
eth1Monitor = Eth1Monitor.init(
6262
defaultRuntimeConfig, db = nil, nil, @[web3Url],
63-
none(DepositContractSnapshot), none(Eth1Network), false, jwtSecret)
63+
none(DepositContractSnapshot), none(Eth1Network),
64+
false, jwtSecret, true)
6465
web3Provider = (await Web3DataProvider.new(
6566
default(Eth1Address), web3Url, jwtSecret)).get
6667

0 commit comments

Comments
 (0)