2018-11-23 23:58:49 +00:00
|
|
|
import
|
2020-09-12 05:35:58 +00:00
|
|
|
tables, json, streams,
|
2019-04-06 07:46:07 +00:00
|
|
|
chronos, chronicles,
|
2020-06-16 05:45:04 +00:00
|
|
|
spec/[datatypes, crypto, digest, signatures, helpers],
|
2020-09-01 13:44:40 +00:00
|
|
|
beacon_node_types,
|
2020-09-16 11:30:03 +00:00
|
|
|
json_serialization/std/[sets, net],
|
|
|
|
validator_slashing_protection,
|
|
|
|
eth/db/[kvstore, kvstore_sqlite3]
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2020-09-16 11:30:03 +00:00
|
|
|
func init*(T: type ValidatorPool,
|
|
|
|
slashingProtectionDB: SlashingProtectionDB): T =
|
|
|
|
## Initialize the validator pool and the slashing protection service
|
|
|
|
## `genesis_validator_root` is used as an unique ID for the
|
|
|
|
## blockchain
|
|
|
|
## `backend` is the KeyValue Store backend
|
2018-11-29 01:08:34 +00:00
|
|
|
result.validators = initTable[ValidatorPubKey, AttachedValidator]()
|
2020-09-16 11:30:03 +00:00
|
|
|
result.slashingProtection = slashingProtectionDB
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2018-12-19 12:58:53 +00:00
|
|
|
template count*(pool: ValidatorPool): int =
|
|
|
|
pool.validators.len
|
|
|
|
|
2018-11-23 23:58:49 +00:00
|
|
|
proc addLocalValidator*(pool: var ValidatorPool,
|
2018-11-29 01:08:34 +00:00
|
|
|
pubKey: ValidatorPubKey,
|
2019-02-14 21:41:04 +00:00
|
|
|
privKey: ValidatorPrivKey) =
|
2019-11-25 12:47:29 +00:00
|
|
|
let v = AttachedValidator(pubKey: pubKey,
|
2018-12-08 14:17:47 +00:00
|
|
|
kind: inProcess,
|
2019-02-14 21:41:04 +00:00
|
|
|
privKey: privKey)
|
2018-12-08 14:17:47 +00:00
|
|
|
pool.validators[pubKey] = v
|
2020-10-01 18:56:42 +00:00
|
|
|
notice "Local validator attached", pubKey, validator = shortLog(v)
|
2019-04-06 07:46:07 +00:00
|
|
|
|
2020-09-01 13:44:40 +00:00
|
|
|
proc addRemoteValidator*(pool: var ValidatorPool,
|
|
|
|
pubKey: ValidatorPubKey,
|
|
|
|
v: AttachedValidator) =
|
|
|
|
pool.validators[pubKey] = v
|
2020-10-01 18:56:42 +00:00
|
|
|
notice "Remote validator attached", pubKey, validator = shortLog(v)
|
2020-09-01 13:44:40 +00:00
|
|
|
|
2020-08-10 13:21:31 +00:00
|
|
|
proc getValidator*(pool: ValidatorPool,
|
2018-11-29 01:08:34 +00:00
|
|
|
validatorKey: ValidatorPubKey): AttachedValidator =
|
2020-08-10 13:21:31 +00:00
|
|
|
pool.validators.getOrDefault(validatorKey.initPubKey)
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2020-09-01 13:44:40 +00:00
|
|
|
proc signWithRemoteValidator(v: AttachedValidator, data: Eth2Digest):
|
|
|
|
Future[ValidatorSig] {.async.} =
|
|
|
|
v.connection.inStream.writeLine(v.connection.pubKeyStr, " ", $data)
|
|
|
|
v.connection.inStream.flush()
|
|
|
|
var line = newStringOfCap(120).TaintedString
|
|
|
|
discard v.connection.outStream.readLine(line)
|
|
|
|
result = ValidatorSig.fromHex(line).get()
|
|
|
|
# TODO this is an ugly hack to fake a delay and subsequent async reordering
|
|
|
|
# for the purpose of testing the external validator delay - to be
|
|
|
|
# replaced by something more sensible
|
|
|
|
await sleepAsync(chronos.milliseconds(1))
|
|
|
|
|
2020-11-09 14:18:55 +00:00
|
|
|
# TODO: Honest validator - https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md
|
2020-03-30 11:31:44 +00:00
|
|
|
proc signBlockProposal*(v: AttachedValidator, fork: Fork,
|
|
|
|
genesis_validators_root: Eth2Digest, slot: Slot,
|
2019-04-06 07:46:07 +00:00
|
|
|
blockRoot: Eth2Digest): Future[ValidatorSig] {.async.} =
|
2018-11-29 01:08:34 +00:00
|
|
|
if v.kind == inProcess:
|
2020-03-30 11:31:44 +00:00
|
|
|
result = get_block_signature(
|
|
|
|
fork, genesis_validators_root, slot, blockRoot, v.privKey)
|
2018-11-23 23:58:49 +00:00
|
|
|
else:
|
2020-09-01 13:44:40 +00:00
|
|
|
let root = compute_block_root(fork, genesis_validators_root, slot, blockRoot)
|
|
|
|
result = await signWithRemoteValidator(v, root)
|
2018-11-23 23:58:49 +00:00
|
|
|
|
|
|
|
proc signAttestation*(v: AttachedValidator,
|
2019-09-08 18:09:01 +00:00
|
|
|
attestation: AttestationData,
|
2020-03-30 11:31:44 +00:00
|
|
|
fork: Fork, genesis_validators_root: Eth2Digest):
|
|
|
|
Future[ValidatorSig] {.async.} =
|
2018-11-29 01:08:34 +00:00
|
|
|
if v.kind == inProcess:
|
2020-03-30 11:31:44 +00:00
|
|
|
result = get_attestation_signature(
|
|
|
|
fork, genesis_validators_root, attestation, v.privKey)
|
2018-11-23 23:58:49 +00:00
|
|
|
else:
|
2020-09-01 13:44:40 +00:00
|
|
|
let root = compute_attestation_root(fork, genesis_validators_root, attestation)
|
|
|
|
result = await signWithRemoteValidator(v, root)
|
2018-11-23 23:58:49 +00:00
|
|
|
|
2020-06-05 09:57:40 +00:00
|
|
|
proc produceAndSignAttestation*(validator: AttachedValidator,
|
|
|
|
attestationData: AttestationData,
|
2020-11-16 16:10:51 +00:00
|
|
|
committeeLen: int, indexInCommittee: Natural,
|
2020-06-05 09:57:40 +00:00
|
|
|
fork: Fork, genesis_validators_root: Eth2Digest):
|
|
|
|
Future[Attestation] {.async.} =
|
|
|
|
let validatorSignature = await validator.signAttestation(attestationData,
|
|
|
|
fork, genesis_validators_root)
|
|
|
|
|
|
|
|
var aggregationBits = CommitteeValidatorsBits.init(committeeLen)
|
|
|
|
aggregationBits.setBit indexInCommittee
|
|
|
|
|
|
|
|
return Attestation(data: attestationData, signature: validatorSignature, aggregation_bits: aggregationBits)
|
|
|
|
|
2020-04-15 02:41:22 +00:00
|
|
|
proc signAggregateAndProof*(v: AttachedValidator,
|
|
|
|
aggregate_and_proof: AggregateAndProof,
|
2020-09-01 13:44:40 +00:00
|
|
|
fork: Fork, genesis_validators_root: Eth2Digest):
|
|
|
|
Future[ValidatorSig] {.async.} =
|
2020-04-15 02:41:22 +00:00
|
|
|
if v.kind == inProcess:
|
|
|
|
result = get_aggregate_and_proof_signature(
|
|
|
|
fork, genesis_validators_root, aggregate_and_proof, v.privKey)
|
|
|
|
else:
|
2020-09-01 13:44:40 +00:00
|
|
|
let root = compute_aggregate_and_proof_root(
|
|
|
|
fork, genesis_validators_root, aggregate_and_proof)
|
|
|
|
result = await signWithRemoteValidator(v, root)
|
2020-04-15 02:41:22 +00:00
|
|
|
|
2020-11-09 14:18:55 +00:00
|
|
|
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0/specs/phase0/validator.md#randao-reveal
|
2020-03-30 11:31:44 +00:00
|
|
|
func genRandaoReveal*(k: ValidatorPrivKey, fork: Fork,
|
|
|
|
genesis_validators_root: Eth2Digest, slot: Slot): ValidatorSig =
|
2020-06-16 05:45:04 +00:00
|
|
|
get_epoch_signature(
|
|
|
|
fork, genesis_validators_root, slot.compute_epoch_at_slot, k)
|
2019-02-07 20:13:10 +00:00
|
|
|
|
2020-09-01 13:44:40 +00:00
|
|
|
proc genRandaoReveal*(v: AttachedValidator, fork: Fork,
|
|
|
|
genesis_validators_root: Eth2Digest, slot: Slot):
|
|
|
|
Future[ValidatorSig] {.async.} =
|
|
|
|
if v.kind == inProcess:
|
|
|
|
return genRandaoReveal(v.privKey, fork, genesis_validators_root, slot)
|
|
|
|
else:
|
|
|
|
let root = compute_epoch_root(
|
|
|
|
fork, genesis_validators_root, slot.compute_epoch_at_slot)
|
|
|
|
result = await signWithRemoteValidator(v, root)
|
|
|
|
|
|
|
|
proc getSlotSig*(v: AttachedValidator, fork: Fork,
|
|
|
|
genesis_validators_root: Eth2Digest, slot: Slot
|
|
|
|
): Future[ValidatorSig] {.async.} =
|
|
|
|
if v.kind == inProcess:
|
|
|
|
result = get_slot_signature(
|
|
|
|
fork, genesis_validators_root, slot, v.privKey)
|
|
|
|
else:
|
|
|
|
let root = compute_slot_root(fork, genesis_validators_root, slot)
|
|
|
|
result = await signWithRemoteValidator(v, root)
|