Ctrl+C now stops the BN when waiting for genesis (#1761)

* Ctrl+C now stops the BN when waiting for genesis

* proper shutdown when waiting for genesis if Ctrl+C is used
This commit is contained in:
Viktor Kirilov 2020-09-28 18:19:57 +03:00 committed by GitHub
parent a2270a5f27
commit 2e6fd8976a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 52 additions and 23 deletions

View File

@ -26,7 +26,7 @@ import
spec/state_transition,
conf, time, beacon_chain_db, validator_pool, extras,
attestation_pool, exit_pool, eth2_network, eth2_discovery,
beacon_node_common, beacon_node_types,
beacon_node_common, beacon_node_types, beacon_node_status,
block_pools/[spec_cache, chain_dag, quarantine, clearance, block_pools_types],
nimbus_binary_common, network_metadata,
mainchain_monitor, version, ssz/[merkleization], merkle_minimal,
@ -42,13 +42,6 @@ const
type
RpcServer* = RpcHttpServer
# "state" is already taken by BeaconState
BeaconNodeStatus* = enum
Starting, Running, Stopping
# this needs to be global, so it can be set in the Ctrl+C signal handler
var status = BeaconNodeStatus.Starting
template init(T: type RpcHttpServer, ip: ValidIpAddress, port: Port): T =
newRpcHttpServer([initTAddress(ip, port)])
@ -190,6 +183,8 @@ proc init*(T: type BeaconNode,
mainchainMonitor.start()
genesisState = await mainchainMonitor.waitGenesis()
if bnStatus == BeaconNodeStatus.Stopping:
return nil
info "Eth2 genesis state detected",
genesisTime = genesisState.genesisTime,
@ -849,7 +844,7 @@ proc installMessageValidators(node: BeaconNode) =
node.processor[].voluntaryExitValidator(signedVoluntaryExit))
proc stop*(node: BeaconNode) =
status = BeaconNodeStatus.Stopping
bnStatus = BeaconNodeStatus.Stopping
info "Graceful shutdown"
if not node.config.inProcessValidators:
node.vcProcess.close()
@ -858,9 +853,9 @@ proc stop*(node: BeaconNode) =
info "Database closed"
proc run*(node: BeaconNode) =
if status == BeaconNodeStatus.Starting:
if bnStatus == BeaconNodeStatus.Starting:
# it might have been set to "Stopping" with Ctrl+C
status = BeaconNodeStatus.Running
bnStatus = BeaconNodeStatus.Running
if node.rpcServer != nil:
node.rpcServer.installRpcHandlers(node)
@ -888,7 +883,7 @@ proc run*(node: BeaconNode) =
node.startSyncManager()
# main event loop
while status == BeaconNodeStatus.Running:
while bnStatus == BeaconNodeStatus.Running:
try:
poll()
except CatchableError as e:
@ -1208,7 +1203,7 @@ programMain:
# workaround for https://github.com/nim-lang/Nim/issues/4057
setupForeignThreadGc()
info "Shutting down after having received SIGINT"
status = BeaconNodeStatus.Stopping
bnStatus = BeaconNodeStatus.Stopping
setControlCHook(controlCHandler)
when useInsecureFeatures:
@ -1219,6 +1214,8 @@ programMain:
metrics.startHttpServer($metricsAddress, config.metricsPort)
var node = waitFor BeaconNode.init(rng, config, stateSnapshotContents)
if bnStatus == BeaconNodeStatus.Stopping:
return
when hasPrompt:
initPrompt(node)

View File

@ -0,0 +1,16 @@
# beacon_chain
# Copyright (c) 2018-2020 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.
type
# "state" is already taken by BeaconState
BeaconNodeStatus* = enum
Starting
Running
Stopping
# this needs to be global, so it can be set in the Ctrl+C signal handler
var bnStatus* = BeaconNodeStatus.Starting

View File

@ -3,7 +3,8 @@ import
chronos, web3, web3/ethtypes as web3Types, json, chronicles,
eth/common/eth_types, eth/async_utils,
spec/[datatypes, digest, crypto, beaconstate, helpers, validator],
network_metadata, merkle_minimal
network_metadata, merkle_minimal,
beacon_node_status
from times import epochTime
@ -564,8 +565,27 @@ proc findGenesisBlockInRange(m: MainchainMonitor,
return endBlock
proc safeCancel(fut: var Future[void]) =
if not fut.isNil and not fut.finished:
fut.cancel()
fut = nil
proc stop*(m: MainchainMonitor) =
safeCancel m.runFut
safeCancel m.genesisMonitoringFut
template checkIfShouldStopMainchainMonitor(m: MainchainMonitor) =
if bnStatus == BeaconNodeStatus.Stopping:
if not m.genesisStateFut.isNil:
m.genesisStateFut.complete()
m.genesisStateFut = nil
m.stop
return
proc checkForGenesisLoop(m: MainchainMonitor) {.async.} =
while true:
m.checkIfShouldStopMainchainMonitor()
if not m.genesisState.isNil:
return
@ -636,6 +656,9 @@ proc waitGenesis*(m: MainchainMonitor): Future[BeaconStateRef] {.async.} =
await m.genesisStateFut
m.genesisStateFut = nil
if bnStatus == BeaconNodeStatus.Stopping:
return new BeaconStateRef # cannot return nil...
if m.genesisState != nil:
return m.genesisState
else:
@ -677,6 +700,8 @@ proc processDeposits(m: MainchainMonitor,
# it could easily re-order the steps due to the intruptable
# interleaved execution of async code.
while true:
m.checkIfShouldStopMainchainMonitor()
let blk = await m.depositQueue.popFirst()
m.eth1Chain.trimHeight(Eth1BlockNumber(blk.number) - 1)
@ -776,15 +801,6 @@ proc run(m: MainchainMonitor, delayBeforeStart: Duration) {.async.} =
finally:
await close(dataProvider)
proc safeCancel(fut: var Future[void]) =
if not fut.isNil and not fut.finished:
fut.cancel()
fut = nil
proc stop*(m: MainchainMonitor) =
safeCancel m.runFut
safeCancel m.genesisMonitoringFut
proc start(m: MainchainMonitor, delayBeforeStart: Duration) =
if m.runFut.isNil:
let runFut = m.run(delayBeforeStart)