Skip to content

Commit def221d

Browse files
authored
nimbus startup cleanups (#3806)
* shutdown both threads in case of init failure on one * rename trusted-setup-file option to match eth2, make sure trusted setup is loaded in main thread
1 parent e2cbfe8 commit def221d

File tree

9 files changed

+137
-139
lines changed

9 files changed

+137
-139
lines changed

execution_chain/conf.nim

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,10 +116,11 @@ type
116116
name: "import-key" .}: InputFile
117117

118118
trustedSetupFile* {.
119-
desc: "Load EIP-4844 trusted setup file"
119+
hidden
120+
desc: "Alternative EIP-4844 trusted setup file"
120121
defaultValue: none(string)
121122
defaultValueDesc: "Baked in trusted setup"
122-
name: "trusted-setup-file" .}: Option[string]
123+
name: "debug-trusted-setup-file" .}: Option[string]
123124

124125
extraData* {.
125126
separator: "\pPAYLOAD BUILDING OPTIONS:"

execution_chain/nimbus.nim

Lines changed: 117 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,13 @@ type
147147
defaultValue: false
148148
name: "engine-api" .}: bool
149149

150+
trustedSetupFile* {.
151+
hidden
152+
desc: "Alternative EIP-4844 trusted setup file"
153+
defaultValue: none(string)
154+
defaultValueDesc: "Baked in trusted setup"
155+
name: "debug-trusted-setup-file" .}: Option[string]
156+
150157
case cmd* {.command, defaultValue: NStartUpCmd.nimbus.}: NStartUpCmd
151158
of nimbus:
152159
discard
@@ -201,8 +208,6 @@ proc runBeaconNode(p: BeaconThreadConfig) {.thread.} =
201208
stderr.writeLine error # Logging not yet set up
202209
quit QuitFailure
203210

204-
let rng = HmacDrbgContext.new()
205-
206211
let engineUrl = EngineApiUrl.init(
207212
&"http://127.0.0.1:{defaultEngineApiPort}/", Opt.some(@(distinctBase(jwtKey)))
208213
)
@@ -218,45 +223,22 @@ proc runBeaconNode(p: BeaconThreadConfig) {.thread.} =
218223
config.tcpPort = p.tcpPort
219224
config.udpPort = p.udpPort
220225

221-
# TODO https://github.com/status-im/nim-taskpools/issues/6
222-
# share taskpool between bn and ec
223-
let taskpool = setupTaskpool(config.numThreads)
224-
225226
info "Launching beacon node",
226227
version = fullVersionStr,
227228
bls_backend = $BLS_BACKEND,
228229
const_preset,
229230
cmdParams = commandLineParams(),
230-
config,
231-
numThreads = taskpool.numThreads
232-
233-
config.createDumpDirs()
234-
235-
let metadata = config.loadEth2Network()
231+
config
236232

237-
# Updating the config based on the metadata certainly is not beautiful but it
238-
# works
239-
for node in metadata.bootstrapNodes:
240-
config.bootstrapNodes.add node
241-
242-
if config.syncHorizon.isNone:
243-
config.syncHorizon = some(metadata.cfg.timeParams.defaultSyncHorizon)
244-
245-
block:
246-
let res =
247-
if config.trustedSetupFile.isNone:
248-
bnconf.loadKzgTrustedSetup()
249-
else:
250-
bnconf.loadKzgTrustedSetup(config.trustedSetupFile.get)
251-
if res.isErr():
252-
raiseAssert res.error()
253-
254-
let stopper = p.tsp.justWait()
255-
256-
if stopper.finished():
257-
return
258-
259-
let node = waitFor BeaconNode.init(rng, config, metadata, taskpool)
233+
let
234+
# TODO https://github.com/status-im/nim-taskpools/issues/6
235+
# share taskpool between bn and ec
236+
taskpool = setupTaskpool(config.numThreads)
237+
stopper = p.tsp.justWait()
238+
rng = HmacDrbgContext.new()
239+
node = (waitFor BeaconNode.init(rng, config, taskpool)).valueOr:
240+
waitFor p.tsp.fire() # Stop the other thread as well..
241+
return
260242

261243
if stopper.finished():
262244
return
@@ -271,6 +253,9 @@ proc runBeaconNode(p: BeaconThreadConfig) {.thread.} =
271253
else:
272254
node.run(stopper)
273255

256+
# Stop the other thread as well, in case we're stopping early
257+
waitFor p.tsp.fire()
258+
274259
proc runExecutionClient(p: ExecutionThreadConfig) {.thread.} =
275260
var config = makeConfig(ignoreUnknown = true)
276261
config.metricsEnabled = false
@@ -285,15 +270,106 @@ proc runExecutionClient(p: ExecutionThreadConfig) {.thread.} =
285270

286271
info "Launching execution client", version = FullVersionStr, config
287272

288-
# TODO https://github.com/status-im/nim-taskpools/issues/6
289-
# share taskpool between bn and ec
290273
let
274+
# TODO https://github.com/status-im/nim-taskpools/issues/6
275+
# share taskpool between bn and ec
291276
taskpool = setupTaskpool(int config.numThreads)
292277
com = setupCommonRef(config, taskpool)
293278

294-
{.gcsafe.}:
295-
dynamicLogScope(comp = "ec"):
296-
nimbus_execution_client.runExeClient(config, com, p.tsp.justWait())
279+
dynamicLogScope(comp = "ec"):
280+
nimbus_execution_client.runExeClient(config, com, p.tsp.justWait())
281+
282+
# Stop the other thread as well, in case `runExeClient` stopped early
283+
waitFor p.tsp.fire()
284+
285+
proc runCombinedClient() =
286+
# Make it harder to connect to the (internal) engine - this will of course
287+
# go away
288+
discard randomBytes(distinctBase(jwtKey))
289+
290+
const banner = "Nimbus v0.0.1"
291+
292+
var config = NimbusConf.loadWithBanners(banner, copyright, [specBanner], true).valueOr:
293+
writePanicLine error # Logging not yet set up
294+
quit QuitFailure
295+
296+
setupLogging(config.logLevel, config.logStdout, none OutFile)
297+
setupFileLimits()
298+
299+
ProcessState.setupStopHandlers()
300+
301+
if not checkAndCreateDataDir(config.dataDir):
302+
# We are unable to access/create data folder or data folder's
303+
# permissions are insecure.
304+
quit QuitFailure
305+
306+
let metricsServer = (waitFor config.initMetricsServer()).valueOr:
307+
quit 1
308+
309+
# Nim GC metrics (for the main thread) will be collected in onSecond(), but
310+
# we disable piggy-backing on other metrics here.
311+
setSystemMetricsAutomaticUpdate(false)
312+
313+
if config.engineApiEnabled:
314+
warn "Engine API is not available when running internal beacon node"
315+
316+
# Trusted setup is shared between threads, so it needs to be initalized
317+
# from the main thread before anything else runs
318+
if config.trustedSetupFile.isSome:
319+
kzg.loadTrustedSetup(config.trustedSetupFile.get(), 0).isOkOr:
320+
fatal "Cannot load Kzg trusted setup from file", msg = error
321+
quit(QuitFailure)
322+
else:
323+
# Load eagerly to avoid race conditions - lazy kzg loading is not thread safe
324+
loadTrustedSetupFromString(kzg.trustedSetup, 0).expect(
325+
"Baked-in KZG setup is correct"
326+
)
327+
328+
var bnThread: Thread[BeaconThreadConfig]
329+
let bnStop = ThreadSignalPtr.new().expect("working ThreadSignalPtr")
330+
createThread(
331+
bnThread,
332+
runBeaconNode,
333+
BeaconThreadConfig(
334+
tsp: bnStop,
335+
tcpPort: config.beaconTcpPort.get(config.tcpPort.get(Port defaultEth2TcpPort)),
336+
udpPort: config.beaconUdpPort.get(config.udpPort.get(Port defaultEth2TcpPort)),
337+
elSync: config.elSync,
338+
),
339+
)
340+
341+
var ecThread: Thread[ExecutionThreadConfig]
342+
let ecStop = ThreadSignalPtr.new().expect("working ThreadSignalPtr")
343+
createThread(
344+
ecThread,
345+
runExecutionClient,
346+
ExecutionThreadConfig(
347+
tsp: ecStop,
348+
tcpPort:
349+
# -1/+1 to make sure global default is respected but +1 is applied to --tcp-port
350+
config.executionTcpPort.get(
351+
Port(uint16(config.tcpPort.get(Port(defaultExecutionPort - 1))) + 1)
352+
),
353+
udpPort:
354+
if config.executionUdpPort.isSome:
355+
config.executionUdpPort
356+
elif config.udpPort.isSome:
357+
some(Port(uint16(config.udpPort.get()) + 1))
358+
else:
359+
none(Port),
360+
),
361+
)
362+
363+
while not ProcessState.stopIt(notice("Shutting down", reason = it)):
364+
os.sleep(100)
365+
366+
waitFor bnStop.fire()
367+
waitFor ecStop.fire()
368+
369+
joinThread(bnThread)
370+
joinThread(ecThread)
371+
372+
waitFor metricsServer.stopMetricsServer()
297373

298374
# noinline to keep it in stack traces
299375
proc main() {.noinline, raises: [CatchableError].} =
@@ -337,82 +413,7 @@ proc main() {.noinline, raises: [CatchableError].} =
337413
elif isEC:
338414
nimbus_execution_client.main()
339415
else:
340-
# Make sure the default nim handlers don't run in any thread
341-
ProcessState.setupStopHandlers()
342-
343-
# Make it harder to connect to the (internal) engine - this will of course
344-
# go away
345-
discard randomBytes(distinctBase(jwtKey))
346-
347-
const banner = "Nimbus v0.0.1"
348-
349-
var config = NimbusConf.loadWithBanners(banner, copyright, [specBanner], true).valueOr:
350-
writePanicLine error # Logging not yet set up
351-
quit QuitFailure
352-
353-
setupLogging(config.logLevel, config.logStdout, none OutFile)
354-
setupFileLimits()
355-
356-
if not (checkAndCreateDataDir(config.dataDir)):
357-
# We are unable to access/create data folder or data folder's
358-
# permissions are insecure.
359-
quit QuitFailure
360-
361-
let metricsServer = (waitFor config.initMetricsServer()).valueOr:
362-
quit 1
363-
364-
# Nim GC metrics (for the main thread) will be collected in onSecond(), but
365-
# we disable piggy-backing on other metrics here.
366-
setSystemMetricsAutomaticUpdate(false)
367-
368-
if config.engineApiEnabled:
369-
warn "Engine API is not available when running internal beacon node"
370-
371-
var bnThread: Thread[BeaconThreadConfig]
372-
let bnStop = ThreadSignalPtr.new().expect("working ThreadSignalPtr")
373-
createThread(
374-
bnThread,
375-
runBeaconNode,
376-
BeaconThreadConfig(
377-
tsp: bnStop,
378-
tcpPort: config.beaconTcpPort.get(config.tcpPort.get(Port defaultEth2TcpPort)),
379-
udpPort: config.beaconUdpPort.get(config.udpPort.get(Port defaultEth2TcpPort)),
380-
elSync: config.elSync,
381-
),
382-
)
383-
384-
var ecThread: Thread[ExecutionThreadConfig]
385-
let ecStop = ThreadSignalPtr.new().expect("working ThreadSignalPtr")
386-
createThread(
387-
ecThread,
388-
runExecutionClient,
389-
ExecutionThreadConfig(
390-
tsp: ecStop,
391-
tcpPort:
392-
# -1/+1 to make sure global default is respected but +1 is applied to --tcp-port
393-
config.executionTcpPort.get(
394-
Port(uint16(config.tcpPort.get(Port(defaultExecutionPort - 1))) + 1)
395-
),
396-
udpPort:
397-
if config.executionUdpPort.isSome:
398-
config.executionUdpPort
399-
elif config.udpPort.isSome:
400-
some(Port(uint16(config.udpPort.get()) + 1))
401-
else:
402-
none(Port),
403-
),
404-
)
405-
406-
while not ProcessState.stopIt(notice("Shutting down", reason = it)):
407-
os.sleep(100)
408-
409-
waitFor bnStop.fire()
410-
waitFor ecStop.fire()
411-
412-
joinThread(bnThread)
413-
joinThread(ecThread)
414-
415-
waitFor metricsServer.stopMetricsServer()
416+
runCombinedClient()
416417

417418
when isMainModule:
418419
main()

execution_chain/nimbus_execution_client.nim

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -223,16 +223,6 @@ proc preventLoadingDataDirForTheWrongNetwork(db: CoreDbRef; config: ExecutionCli
223223
quit(QuitFailure)
224224

225225
proc setupCommonRef*(config: ExecutionClientConf, taskpool: Taskpool): CommonRef =
226-
# Trusted setup is needed for processing Cancun+ blocks
227-
# If user not specify the trusted setup, baked in
228-
# trusted setup will be loaded, lazily.
229-
if config.trustedSetupFile.isSome:
230-
let fileName = config.trustedSetupFile.get()
231-
let res = kzg.loadTrustedSetup(fileName, 0)
232-
if res.isErr:
233-
fatal "Cannot load Kzg trusted setup from file", msg=res.error
234-
quit(QuitFailure)
235-
236226
let coreDB = AristoDbRocks.newCoreDbRef(
237227
config.dataDir,
238228
config.dbOptions(noKeyCache = config.cmd == NimbusCmd.`import`))
@@ -264,9 +254,6 @@ proc setupCommonRef*(config: ExecutionClientConf, taskpool: Taskpool): CommonRef
264254

265255
com
266256

267-
template displayLaunchingInfo(config: ExecutionClientConf) =
268-
info "Launching execution client", version = FullVersionStr, config
269-
270257
# ------------------------------------------------------------------------------
271258
# Public functions, `main()` API
272259
# ------------------------------------------------------------------------------
@@ -320,11 +307,10 @@ proc runExeClient*(
320307
proc main*(config = makeConfig(), nimbus = NimbusNode(nil)) {.noinline.} =
321308
# Set up logging before everything else
322309
setupLogging(config.logLevel, config.logStdout)
310+
setupFileLimits()
323311

324312
info "Launching execution client", version = FullVersionStr, config
325313

326-
setupFileLimits()
327-
328314
ProcessState.setupStopHandlers()
329315

330316
# TODO provide option for fixing / ignoring permission errors
@@ -333,6 +319,14 @@ proc main*(config = makeConfig(), nimbus = NimbusNode(nil)) {.noinline.} =
333319
# permissions are insecure.
334320
quit QuitFailure
335321

322+
# Trusted setup is needed for Cancun+ blocks and is shared between threads,
323+
# so it needs to be initalized from the main thread before anything else tries
324+
# to use it
325+
if config.trustedSetupFile.isSome:
326+
kzg.loadTrustedSetup(config.trustedSetupFile.get(), 0).isOkOr:
327+
fatal "Cannot load KZG trusted setup from file", msg = error
328+
quit(QuitFailure)
329+
336330
# Metrics are useful not just when running node but also during import
337331
let metricsServer =
338332
try:

nimbus_verified_proxy/nimbus_verified_proxy.nim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,9 @@ proc run*(
160160

161161
network = createEth2Node(
162162
rng, lcConfig, netKeys, cfg, forkDigests, getBeaconTime, genesis_validators_root
163-
)
163+
).valueOr:
164+
fatal "Failed to initialize node", err = error
165+
quit QuitFailure
164166

165167
# light client is set to optimistic finalization mode
166168
lightClient = createLightClient(

portal/bridge/beacon/portal_beacon_bridge.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,7 @@ proc runBeacon*(config: PortalBridgeConf) {.raises: [CatchableError].} =
395395
# is something that works.
396396

397397
# Or basically `lightClientOptimisticUpdateSlotOffset`
398-
await sleepAsync((SECONDS_PER_SLOT div INTERVALS_PER_SLOT).int.seconds)
398+
await sleepAsync(cfg.timeParams.SLOT_DURATION div INTERVALS_PER_SLOT)
399399

400400
lastOptimisticUpdateSlot = (
401401
await gossipLCOptimisticUpdate(restClient, portalRpcClient, cfg, forkDigests)

tests/config_file/basic.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ era1-dir = "basic/era1/dir"
33
era-dir = "basic/era/dir"
44
key-store = "basic/keystore"
55
import-key = "basic_import_key"
6-
trusted-setup-file = "basic_trusted_setup_file"
6+
debug-trusted-setup-file = "basic_trusted_setup_file"
77
extra-data = "basic_extra_data"
88
gas-limit = 5678
99

vendor/nim-http-utils

vendor/nimbus-build-system

vendor/nimbus-eth2

Submodule nimbus-eth2 updated 48 files

0 commit comments

Comments
 (0)