nimbus-eth1/nimbus_unified/nimbus_unified.nim

201 lines
6.4 KiB
Nim
Raw Normal View History

# nimbus_unified
# Copyright (c) 2024 Status Research & Development GmbH
# Licensed and distributed under either of
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
# at your option. This file may not be copied, modified, or distributed except according to those terms.
import
2024-10-21 15:45:45 +01:00
std/[atomics, os, exitprocs],
chronicles,
2024-10-21 15:45:45 +01:00
stew/io2,
consensus/consensus_wrapper,
2024-10-21 11:32:29 +01:00
execution/execution_wrapper,
beacon_chain/[conf, conf_common],
beacon_chain/[beacon_chain_db],
beacon_chain/validators/keystore_management
## Constants
2024-10-23 12:10:35 +01:00
## TODO: evaluate the proposed timeouts with team
const cNimbusMaxTasks* = 5
const cNimbusTaskTimeoutMs* = 5000
## Task and associated task information
type NimbusTask* = ref object
name*: string
timeoutMs*: uint32
threadHandler*: Thread[TaskParameters]
## Task manager
type NimbusTasks* = ref object
taskList*: array[cNimbusMaxTasks, NimbusTask]
2024-10-19 02:01:07 +01:00
## log
logScope:
topics = "Task manager"
# ------------------------------------------------------------------------------
# Private and helper functions
# ------------------------------------------------------------------------------
## Execution Layer handler
proc executionLayerHandler(parameters: TaskParameters) {.thread.} =
2024-10-19 02:01:07 +01:00
info "Started task:", task = parameters.name
while true:
executionWrapper(parameters)
if isShutDownRequired.load() == true:
break
2024-10-19 02:01:07 +01:00
info "\tExiting task;", task = parameters.name
## Consensus Layer handler
proc consensusLayerHandler(parameters: TaskParameters) {.thread.} =
2024-10-19 02:01:07 +01:00
info "Started task:", task = parameters.name
consensusWrapper(parameters)
2024-10-19 02:01:07 +01:00
info "\tExiting task:", task = parameters.name
## Waits for tasks to finish (joinThreads)
proc joinTasks(tasks: var NimbusTasks) =
for i in 0 .. cNimbusMaxTasks - 1:
if not tasks.taskList[i].isNil:
joinThread(tasks.taskList[i].threadHandler)
2024-10-19 02:01:07 +01:00
info "\tAll tasks finished"
# var gPidFile: string
# proc createPidFile(filename: string) {.raises: [IOError].} =
# writeFile filename, $os.getCurrentProcessId()
# gPidFile = filename
# addExitProc (
# proc() =
# discard io2.removeFile(filename)
# )
2024-10-21 15:45:45 +01:00
# ----
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
## adds a new task to nimbus Tasks.
## Note that thread handler passed by argument needs to have the signature: proc foobar(NimbusParameters)
proc addNewTask*(
tasks: var NimbusTasks,
timeout: uint32,
taskHandler: proc(config: TaskParameters) {.thread.},
parameters: var TaskParameters,
) =
#search next available worker
var currentIndex = -1
for i in 0 .. cNimbusMaxTasks - 1:
if tasks.taskList[i].isNil:
tasks.taskList[i] = NimbusTask.new
2024-10-21 11:32:29 +01:00
tasks.taskList[i].name = parameters.name
tasks.taskList[i].timeoutMs = timeout
currentIndex = i
2024-10-21 11:32:29 +01:00
parameters.name = parameters.name
break
if currentIndex < 0:
raise newException(NimbusTasksError, "No free slots on Nimbus Tasks")
2024-10-23 12:10:35 +01:00
try:
createThread(tasks.taskList[currentIndex].threadHandler, taskHandler, parameters)
except CatchableError as e:
# TODO: joinThreads
fatal "error creating task (thread)", msg = e.msg
2024-10-23 12:10:35 +01:00
2024-10-19 02:01:07 +01:00
info "Created task:", task = tasks.taskList[currentIndex].name
## Task monitoring
proc monitor*(tasksList: var NimbusTasks, config: NimbusConfig) =
2024-10-19 02:01:07 +01:00
info "monitoring tasks"
while true:
2024-10-19 02:44:53 +01:00
info "checking tasks ... "
2024-10-23 12:10:35 +01:00
# -check tasks flag (to be created when needed) if it's required to shutdown
# this atomic flag solves:
2024-10-21 11:32:29 +01:00
# - non responding thread
# - thread that required shutdown
2024-10-19 02:44:53 +01:00
sleep(cNimbusTaskTimeoutMs)
## create running workers
2024-10-21 11:32:29 +01:00
proc startTasks*(
tasksList: var NimbusTasks, configs: NimbusConfig, beaconConfigs: var BeaconNodeConf
2024-10-21 15:45:45 +01:00
) {.raises: [CatchableError].} =
2024-10-21 11:32:29 +01:00
let
# TODO: extract configs for each task from NimbusConfig
2024-10-23 12:10:35 +01:00
# or extract them somewhere else and passs them here.
# check nimbus_configs annotations.
2024-10-21 11:32:29 +01:00
execName = "Execution Layer"
consName = "Consensus Layer"
var
2024-10-21 11:32:29 +01:00
paramsExecution: TaskParameters = TaskParameters(
name: execName,
configs: "task configs extracted from NimbusConfig go here",
beaconNodeConfigs: beaconConfigs,
)
paramsConsensus: TaskParameters = TaskParameters(
name: execName,
configs: "task configs extracted from NimbusConfig go here",
beaconNodeConfigs: beaconConfigs,
)
tasksList.addNewTask(cNimbusTaskTimeoutMs, executionLayerHandler, paramsExecution)
tasksList.addNewTask(cNimbusTaskTimeoutMs, consensusLayerHandler, paramsConsensus)
2024-10-18 19:14:35 +01:00
2024-10-19 02:44:53 +01:00
# ------
when isMainModule:
2024-10-19 02:01:07 +01:00
info "Starting Nimbus"
2024-10-18 19:14:35 +01:00
## TODO
## - file limits
## - setup logging
2024-10-23 12:10:35 +01:00
## - read configuration (check nimbus_configs file anottations)
2024-10-21 11:32:29 +01:00
## - implement config reader for all components
let nimbusConfigs = NimbusConfig()
var tasksList: NimbusTasks = NimbusTasks.new
2024-10-21 11:32:29 +01:00
##TODO: this is an adapted call os the vars required by makeBannerAndConfig
##these values need to be read from some config file
const SPEC_VERSION = "1.5.0-alpha.8"
const copyrights = "status"
const nimBanner = "nimbus"
const clientId = "nimbus unified"
2024-10-21 11:32:29 +01:00
var beaconNodeConfig = makeBannerAndConfig(
clientId, copyrights, nimBanner, SPEC_VERSION, [], BeaconNodeConf
).valueOr:
stderr.write error
quit QuitFailure
if not (checkAndCreateDataDir(string(beaconNodeConfig.dataDir))):
# We are unable to access/create data folder or data folder's
# permissions are insecure.
quit QuitFailure
2024-10-18 19:14:35 +01:00
# create and start tasks
2024-10-21 11:32:29 +01:00
tasksList.startTasks(nimbusConfigs, beaconNodeConfig)
2024-10-18 19:14:35 +01:00
## Graceful shutdown by handling of Ctrl+C signal
2024-10-23 12:10:35 +01:00
## TODO: we might need to declare it per thread
2024-10-18 19:14:35 +01:00
proc controlCHandler() {.noconv.} =
when defined(windows):
# workaround for https://github.com/nim-lang/Nim/issues/4057
try:
setupForeignThreadGc()
except NimbusTasksError as exc:
raiseAssert exc.msg # shouldn't happen
2024-10-19 02:01:07 +01:00
notice "\nCtrl+C pressed. Shutting down working tasks"
2024-10-18 19:14:35 +01:00
isShutDownRequired.store(true)
tasksList.joinTasks()
2024-10-19 02:01:07 +01:00
notice "Shutting down now"
2024-10-18 19:14:35 +01:00
quit(0)
2024-10-21 11:32:29 +01:00
2024-10-18 19:14:35 +01:00
setControlCHook(controlCHandler)
# createPidFile(beaconNodeConfig.databaseDir.string / "unified.pid")
2024-10-19 02:44:53 +01:00
#start monitoring
tasksList.monitor(nimbusConfigs)