Skip to content

Commit

Permalink
Add beacon node checking procedures.
Browse files Browse the repository at this point in the history
  • Loading branch information
cheatfate committed Jun 22, 2021
1 parent 71b821f commit 2f2e02c
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 29 deletions.
4 changes: 4 additions & 0 deletions beacon_chain/conf.nim
Expand Up @@ -541,6 +541,10 @@ type
desc: "A directory containing validator keystore passwords"
name: "secrets-dir" }: Option[InputDir]

eth2Network* {.
desc: "The Eth2 network to join [=mainnet]"
name: "network" }: Option[string]

case cmd* {.
command
defaultValue: VCNoCommand }: VCStartUpCmd
Expand Down
139 changes: 118 additions & 21 deletions beacon_chain/nimbus_validator_client.nim
Expand Up @@ -23,7 +23,7 @@ import
# ./spec/eth2_apis/beacon_rpc_client,
./sync/sync_manager,
"."/[conf, beacon_clock, version],
./networking/[eth2_network, eth2_discovery],
./networking/[eth2_network, eth2_discovery, network_metadata],
./beacon_node_types,
./nimbus_binary_common,
./ssz/merkleization,
Expand All @@ -33,32 +33,40 @@ import
./eth/db/[kvstore, kvstore_sqlite3],
./rpc/[beacon_rest_api, node_rest_api, validator_rest_api, rest_utils,
config_rest_api, eth2_json_rest_serialization],
./eth/keys, ./eth/p2p/discoveryv5/random2
./eth/keys

logScope: topics = "vc"

type
BeaconNodeServer = object
BeaconNodeServerRef = ref object
client: RestClientRef
endpoint: string
config: Option[RestConfigTuple]
ident: Option[string]
syncInfo: Option[SyncInfo]
status: BeaconNodeStatus

BeaconNodeStatus* {.pure.} = enum
Uninitalized, Offline, Incompatible, NotSynced, Ready
Uninitalized, Offline, Incompatible, NotSynced, Online

ValidatorClient = ref object
config: ValidatorClientConf
networkMetadata: Eth2NetworkMetadata
graffitiBytes: GraffitiBytes
beaconNodes: seq[BeaconNodeServer]
beaconNodes: seq[BeaconNodeServerRef]
beaconClock: BeaconClock
attachedValidators: ValidatorPool
fork: Fork
proposalsForCurrentEpoch: Table[Slot, ValidatorPubKey]
attestationsForEpoch: Table[Epoch, Table[Slot, seq[AttesterDuties]]]
beaconGenesis: BeaconGenesisTuple

chronicles.formatIt BeaconNodeServer:
it.client.address.hostname & ":" & Base10.toString(it.client.address.port)
chronicles.formatIt BeaconNodeServerRef:
if it.ident.isSome():
it.client.address.hostname & ":" & Base10.toString(it.client.address.port) &
" [" & it.ident.get() & "]"
else:
it.client.address.hostname & ":" & Base10.toString(it.client.address.port)

template client(vc: ValidatorClient): RestClientRef =
vc.beaconNodes[0].client
Expand Down Expand Up @@ -384,22 +392,107 @@ proc initClock*(vc: ValidatorClient): Future[bool] {.async.} =
vc.beaconClock = BeaconClock.init(vc.beaconGenesis.genesis_time)
return true

proc checkCompatible*(node: BeaconNodeServer): Future[BeaconNodeStatus] {.
proc checkCompatible*(node: BeaconNodeServerRef): Future[void] {.
async.} =
debug "Requesting beacon node configuration"
debug "Requesting beacon node network configuration", endpoint = node
let info =
try:
let res = await node.client.getConfig()
res.data.data
except CancelledError as exc:
error "Request was interrupted"
error "Configuration request was interrupted", endpoint = node
node.status = BeaconNodeStatus.Offline
raise exc
except RestError as exc:
error "Unable to obtain beacon node's configuration",
error_name = exc.name, error_message = exc.message
error_name = exc.name, error_message = exc.msg,
endpoint = node
node.status = BeaconNodeStatus.Offline
echo info
node.status
return
except CatchableError as exc:
error "Unexpected exception", error_name = exc.name,
error_message = exc.msg, endpoint = node
node.status = BeaconNodeStatus.Offline
return

if info.MAX_VALIDATORS_PER_COMMITTEE != MAX_VALIDATORS_PER_COMMITTEE or
info.SLOTS_PER_EPOCH != SLOTS_PER_EPOCH or
info.EPOCHS_PER_ETH1_VOTING_PERIOD != EPOCHS_PER_ETH1_VOTING_PERIOD or
info.SLOTS_PER_HISTORICAL_ROOT != SLOTS_PER_HISTORICAL_ROOT or
info.EPOCHS_PER_HISTORICAL_VECTOR != EPOCHS_PER_HISTORICAL_VECTOR or
info.EPOCHS_PER_SLASHINGS_VECTOR != EPOCHS_PER_SLASHINGS_VECTOR or
info.HISTORICAL_ROOTS_LIMIT != HISTORICAL_ROOTS_LIMIT or
info.VALIDATOR_REGISTRY_LIMIT != VALIDATOR_REGISTRY_LIMIT or
info.MAX_PROPOSER_SLASHINGS != MAX_PROPOSER_SLASHINGS or
info.MAX_ATTESTER_SLASHINGS != MAX_ATTESTER_SLASHINGS or
info.MAX_ATTESTATIONS != MAX_ATTESTATIONS or
info.MAX_DEPOSITS != MAX_DEPOSITS or
info.MAX_VOLUNTARY_EXITS != MAX_VOLUNTARY_EXITS:

node.status = BeaconNodeStatus.Incompatible
debug "Received incompatible configuration", endpoint = node
else:
debug "Received compatible configuration", endpoint = node

node.config = some(info)
node.status = BeaconNodeStatus.Online

proc checkSync*(node: BeaconNodeServerRef, clock: BeaconClock): Future[void] {.
async.} =
debug "Requesting beacon node sync status", endpoint = node
let syncInfo =
try:
let res = await node.client.getSyncingStatus()
res.data.data
except CancelledError as exc:
error "Sync status request was interrupted", endpoint = node
node.status = BeaconNodeStatus.Offline
raise exc
except RestError as exc:
error "Unable to obtain beacon node's sync status",
error_name = exc.name, error_message = exc.msg,
endpoint = node
node.status = BeaconNodeStatus.Offline
return
except CatchableError as exc:
error "Unexpected exception", error_name = exc.name,
error_message = exc.msg, endpoint = node
node.status = BeaconNodeStatus.Offline
return
node.syncInfo = some(syncInfo)
node.status = BeaconNodeStatus.Online

proc checkOnline*(node: BeaconNodeServerRef): Future[void] {.
async.} =
debug "Checking beacon node status", endpoint = node
let agent =
try:
let res = await node.client.getVersion()
res.data.data
except CancelledError as exc:
error "Status request was interrupted", endpoint = node
node.status = BeaconNodeStatus.Offline
raise exc
except RestError as exc:
error "Unable to check beacon node's status",
error_name = exc.name, error_message = exc.msg,
endpoint = node
node.status = BeaconNodeStatus.Offline
return
except CatchableError as exc:
error "Unexpected exception", error_name = exc.name,
error_message = exc.msg, endpoint = node
node.status = BeaconNodeStatus.Offline
return
node.ident = some(agent.version)
node.status = BeaconNodeStatus.Online

proc loadEth2Network(config: ValidatorClientConf): Eth2NetworkMetadata {.
raises: [Defect, IOError].} =
if config.eth2Network.isSome():
getMetadataForNetwork(config.eth2Network.get())
else:
mainnetMetadata

proc asyncInit*(vc: ValidatorClient) {.async.} =
if not(await initClock(vc)):
Expand All @@ -408,13 +501,14 @@ proc asyncInit*(vc: ValidatorClient) {.async.} =
if not(await initValidators(vc)):
fatal "Could not initialize local validators"

echo await checkCompatible(vc.client())
await checkOnline(vc.beaconNodes[0])
await checkCompatible(vc.beaconNodes[0])

vc.attachedValidators.slashingProtection =
SlashingProtectionDB.init(
vc.beaconGenesis.genesis_validators_root,
vc.config.validatorsDir(), "slashing_protection"
)
# vc.attachedValidators.slashingProtection =
# SlashingProtectionDB.init(
# vc.beaconGenesis.genesis_validators_root,
# vc.config.validatorsDir(), "slashing_protection"
# )



Expand All @@ -428,18 +522,20 @@ programMain:
setupStdoutLogging(config.logLevel)
setupLogging(config.logLevel, config.logFile)

let metadata = loadEth2Network(config)

case config.cmd
of VCNoCommand:
let beaconNodes =
block:
var servers: seq[BeaconNodeServer]
var servers: seq[BeaconNodeServerRef]
for url in config.beaconNodes:
let res = RestClientRef.new(url)
if res.isErr():
warn "Unable to resolve remote beacon node server's hostname",
url = url
else:
servers.add(BeaconNodeServer(client: res.get()))
servers.add(BeaconNodeServerRef(client: res.get(), endpoint: url))
servers

if len(beaconNodes) == 0:
Expand All @@ -453,6 +549,7 @@ programMain:

var vc = ValidatorClient(
config: config,
networkMetadata: metadata,
beaconNodes: beaconNodes,
graffitiBytes: if config.graffiti.isSome:
config.graffiti.get()
Expand Down
50 changes: 42 additions & 8 deletions beacon_chain/rpc/eth2_json_rest_serialization.nim
@@ -1,6 +1,6 @@
import
std/[typetraits],
stew/[results, base10, byteutils],
stew/[results, base10, byteutils, endians2],
chronicles, presto,
faststreams/[outputs],
serialization, json_serialization,
Expand Down Expand Up @@ -103,13 +103,13 @@ type
MAX_ATTESTATIONS: uint64
MAX_DEPOSITS: uint64
MAX_VOLUNTARY_EXITS: uint64
DOMAIN_BEACON_PROPOSER: array[4, byte]
DOMAIN_BEACON_ATTESTER: array[4, byte]
DOMAIN_RANDAO: array[4, byte]
DOMAIN_DEPOSIT: array[4, byte]
DOMAIN_VOLUNTARY_EXIT: array[4, byte]
DOMAIN_SELECTION_PROOF: array[4, byte]
DOMAIN_AGGREGATE_AND_PROOF: array[4, byte]
DOMAIN_BEACON_PROPOSER: DomainType
DOMAIN_BEACON_ATTESTER: DomainType
DOMAIN_RANDAO: DomainType
DOMAIN_DEPOSIT: DomainType
DOMAIN_VOLUNTARY_EXIT: DomainType
DOMAIN_SELECTION_PROOF: DomainType
DOMAIN_AGGREGATE_AND_PROOF: DomainType

DataEnclosedObject*[T] = object
data*: T
Expand Down Expand Up @@ -216,6 +216,40 @@ proc readValue*(reader: var JsonReader[RestJson], value: var uint64) {.
else:
reader.raiseUnexpectedValue($res.error())

## byte
proc writeValue*(w: var JsonWriter[RestJson], value: byte) =
var data: array[1, byte]
data[0] = value
writeValue(w, hexOriginal(data))

proc readValue*(reader: var JsonReader[RestJson], value: var byte) {.
raises: [IOError, SerializationError, Defect].} =
var data: array[1, byte]
try:
hexToByteArray(reader.readValue(string), data)
value = data[0]
except ValueError:
raiseUnexpectedValue(reader,
"byte value should be a valid hex string")

## DomainType
proc writeValue*(w: var JsonWriter[RestJson], value: DomainType) =
writeValue(w, hexOriginal(uint32(value).toBytesLE()))

proc readValue*(reader: var JsonReader[RestJson], value: var DomainType) {.
raises: [IOError, SerializationError, Defect].} =
var data: array[4, byte]
try:
hexToByteArray(reader.readValue(string), data)
let res = uint32.fromBytesLE(data)
if res >= uint32(low(DomainType)) and res <= uint32(high(DomainType)):
value = cast[DomainType](res)
else:
raiseUnexpectedValue(reader, "Incorrect DomainType value")
except ValueError:
raiseUnexpectedValue(reader,
"DomainType value should be a valid hex string")

## Slot
proc writeValue*(writer: var JsonWriter[RestJson], value: Slot) {.
raises: [IOError, Defect].} =
Expand Down

0 comments on commit 2f2e02c

Please sign in to comment.