Skip to content

Commit

Permalink
Validator key management API (#2755)
Browse files Browse the repository at this point in the history
  • Loading branch information
cheatfate authored Oct 4, 2021
1 parent 05eb884 commit 65257b8
Show file tree
Hide file tree
Showing 14 changed files with 719 additions and 125 deletions.
24 changes: 15 additions & 9 deletions beacon_chain/beacon_node_types.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,15 @@
{.push raises: [Defect].}

import
std/[deques, intsets, streams, tables, hashes],
std/[deques, intsets, streams, tables, hashes, options],
stew/endians2,
./spec/datatypes/[phase0, altair],
./spec/keystore,
./consensus_object_pools/block_pools_types,
./fork_choice/fork_choice_types,
./validators/slashing_protection

export deques, tables, hashes, block_pools_types
export deques, tables, hashes, options, block_pools_types

const
ATTESTATION_LOOKBACK* =
Expand Down Expand Up @@ -146,22 +147,27 @@ type
# Validator Pool
#
# #############################################
ValidatorKind* = enum
inProcess
remote
ValidatorKind* {.pure.} = enum
Local, Remote

ValidatorConnection* = object
inStream*: Stream
outStream*: Stream
pubKeyStr*: string

ValidatorPrivateItem* = object
privateKey*: ValidatorPrivKey
description*: Option[string]
path*: Option[KeyPath]
uuid*: Option[string]
version*: Option[uint64]

AttachedValidator* = ref object
pubKey*: ValidatorPubKey

case kind*: ValidatorKind
of inProcess:
privKey*: ValidatorPrivKey
else:
of ValidatorKind.Local:
data*: ValidatorPrivateItem
of ValidatorKind.Remote:
connection*: ValidatorConnection

# The index at which this validator has been observed in the chain -
Expand Down
12 changes: 12 additions & 0 deletions beacon_chain/conf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,12 @@ type
defaultValueDesc: "127.0.0.1"
name: "rest-address" }: ValidIpAddress

validatorApiEnabled* {.
desc: "Enable the REST (BETA version) validator keystore management " &
"API",
defaultValue: false,
name: "validator-api"}: bool

inProcessValidators* {.
desc: "Disable the push model (the beacon node tells a signing process with the private keys of the validators what to sign and when) and load the validators in the beacon node itself"
defaultValue: true # the use of the nimbus_signing_process binary by default will be delayed until async I/O over stdin/stdout is developed for the child process.
Expand Down Expand Up @@ -546,6 +552,12 @@ type
desc: "A directory containing validator keystore passwords"
name: "secrets-dir" }: Option[InputDir]

validatorApiEnabled* {.
desc: "Enable the REST (BETA version) validator keystore management " &
"API",
defaultValue: false,
name: "validator-api"}: bool

case cmd* {.
command
defaultValue: VCNoCommand }: VCStartUpCmd
Expand Down
13 changes: 9 additions & 4 deletions beacon_chain/nimbus_beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,8 @@ proc installRestHandlers(restServer: RestServerRef, node: BeaconNode) =
restServer.router.installNimbusApiHandlers(node)
restServer.router.installNodeApiHandlers(node)
restServer.router.installValidatorApiHandlers(node)
if node.config.validatorApiEnabled:
restServer.router.installValidatorManagementHandlers(node)

proc installMessageValidators(node: BeaconNode) =
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/p2p-interface.md#attestations-and-aggregation
Expand Down Expand Up @@ -1641,13 +1643,13 @@ proc handleValidatorExitCommand(config: BeaconNodeConf) {.async.} =
"key '" & validatorKeyAsStr & "'."
quit 1

let signingKey = loadKeystore(
let signingItem = loadKeystore(
validatorsDir,
config.secretsDir,
validatorKeyAsStr,
config.nonInteractive)

if signingKey.isNone:
if signingItem.isNone:
fatal "Unable to continue without decrypted signing key"
quit 1

Expand All @@ -1669,8 +1671,11 @@ proc handleValidatorExitCommand(config: BeaconNodeConf) {.async.} =
epoch: exitAtEpoch,
validator_index: validatorIdx))

signedExit.signature = get_voluntary_exit_signature(
fork, genesisValidatorsRoot, signedExit.message, signingKey.get).toValidatorSig()
signedExit.signature =
block:
let key = signingItem.get().privateKey
get_voluntary_exit_signature(fork, genesisValidatorsRoot,
signedExit.message, key).toValidatorSig()

template ask(prompt: string): string =
try:
Expand Down
22 changes: 10 additions & 12 deletions beacon_chain/nimbus_signing_process.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,28 @@

{.push raises: [Defect].}

import
# Standard library
std/[os, strutils, tables],

# Local modules
./spec/[digest, crypto],
./validators/keystore_management
import std/[os, strutils, tables]
import "."/spec/[digest, crypto],
"."/validators/keystore_management,
"."/beacon_node_types

{.pop.} # TODO moduletests exceptions

programMain:
var validators: Table[ValidatorPubKey, ValidatorPrivKey]
var validators: Table[ValidatorPubKey, ValidatorPrivateItem]
# load and send all public keys so the BN knows for which ones to ping us
doAssert paramCount() == 2
for curr in validatorKeysFromDirs(paramStr(1), paramStr(2)):
validators[curr.toPubKey.toPubKey()] = curr
echo curr.toPubKey
validators[curr.privateKey.toPubKey().toPubKey()] = curr
echo curr.privateKey.toPubKey
echo "end"

# simple format: `<pubkey> <eth2digest_to_sign>` => `<signature>`
while true:
let args = stdin.readLine.split(" ")
doAssert args.len == 2

let privKey = validators[ValidatorPubKey.fromHex(args[0]).get()]
let item = validators[ValidatorPubKey.fromHex(args[0]).get()]

echo blsSign(privKey, Eth2Digest.fromHex(args[1]).data).toValidatorSig()
echo blsSign(item.privateKey,
Eth2Digest.fromHex(args[1]).data).toValidatorSig()
6 changes: 3 additions & 3 deletions beacon_chain/nimbus_validator_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -76,14 +76,14 @@ proc initGenesis*(vc: ValidatorClientRef): Future[RestGenesis] {.async.} =
proc initValidators*(vc: ValidatorClientRef): Future[bool] {.async.} =
info "Initializaing validators", path = vc.config.validatorsDir()
var duplicates: seq[ValidatorPubKey]
for key in vc.config.validatorKeys():
let pubkey = key.toPubKey().toPubKey()
for item in vc.config.validatorItems():
let pubkey = item.privateKey.toPubKey().toPubKey()
if pubkey in duplicates:
error "Duplicate validator's key found", validator_pubkey = pubkey
return false
else:
duplicates.add(pubkey)
vc.attachedValidators.addLocalValidator(key)
vc.attachedValidators.addLocalValidator(item)
return true

proc initClock*(vc: ValidatorClientRef): Future[BeaconClock] {.async.} =
Expand Down
4 changes: 2 additions & 2 deletions beacon_chain/rpc/rest_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ import
"."/[
rest_utils,
rest_beacon_api, rest_config_api, rest_debug_api, rest_event_api,
rest_nimbus_api, rest_node_api, rest_validator_api]
rest_nimbus_api, rest_node_api, rest_validator_api, rest_key_management_api]

export
rest_utils,
rest_beacon_api, rest_config_api, rest_debug_api, rest_event_api,
rest_nimbus_api, rest_node_api, rest_validator_api
rest_nimbus_api, rest_node_api, rest_validator_api, rest_key_management_api
Loading

0 comments on commit 65257b8

Please sign in to comment.