From bc8ec51fe5235da040f4dbf608b152b776331abd Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 27 Mar 2019 15:41:51 +1100 Subject: [PATCH] Update EpochDuty RPC and core functionality --- protos/src/services.proto | 50 +++++-------- validator_client/src/duties/epoch_duties.rs | 30 +++++--- validator_client/src/duties/grpc.rs | 78 ++++++++++----------- validator_client/src/duties/traits.rs | 9 +-- 4 files changed, 79 insertions(+), 88 deletions(-) diff --git a/protos/src/services.proto b/protos/src/services.proto index bcfd353c7..dea9b7a37 100644 --- a/protos/src/services.proto +++ b/protos/src/services.proto @@ -26,10 +26,9 @@ service BeaconBlockService { /// Service that provides the validator client with requisite knowledge about //its public keys service ValidatorService { - rpc ProposeBlockSlot(ProposeBlockSlotRequest) returns (ProposeBlockSlotResponse); - /// Given a set of public keys, returns their respective indicies - rpc ValidatorIndex(PublicKeys) returns (Indicies); - // rpc ValidatorAssignment(ValidatorAssignmentRequest) returns (ValidatorAssignmentResponse); + // Gets the block proposer slot and comittee slot that a validator needs to + // perform work on. + rpc GetValidatorDuties(GetDutiesRequest) returns (GetDutiesResponse); } /// Service that handles validator attestations @@ -93,58 +92,41 @@ message BeaconBlock { /* * Validator Service Messages */ -/* -message ValidatorAssignmentRequest { - uint64 epoch = 1; - bytes validator_index = 2; -} - -// A validators duties for some epoch. -// TODO: add shard duties. -message ValidatorAssignment { - oneof block_production_slot_oneof { - bool block_production_slot_none = 1; - uint64 block_production_slot = 2; - } -} -*/ // Validator Assignment -message PublicKeys { +// the public keys of the validators +message Validators { repeated bytes public_key = 1; } -message Indicies { - repeated uint64 index = 1; -} - - // Propose slot - -message ProposeBlockSlotRequest { +message GetDutiesRequest { uint64 epoch = 1; - repeated uint64 validator_index = 2; + Validators validators = 2; } message GetDutiesResponse { - repeated oneof slot_oneof { + repeated ActiveValidator active_validator = 1; +} + +message ActiveValidator { + oneof slot_oneof { bool none = 1; ValidatorDuty duty = 2; } } -ValidatorDuty { +message ValidatorDuty { oneof block_oneof { bool none = 1; uint64 block_produce_slot = 2; } - uint64 committee_slot = 1; - uint64 committee_shard = 2; - uint64 committee_index = 3; + uint64 committee_slot = 3; + uint64 committee_shard = 4; + uint64 committee_index = 5; } - /* * Attestation Service Messages */ diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index 71f5f26ab..41d3a24c2 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -1,30 +1,40 @@ use block_proposer::{DutiesReader, DutiesReaderError}; use std::collections::HashMap; use std::sync::RwLock; -use types::{Epoch, Fork, Slot}; +use types::{Epoch, Fork, PublicKey, Slot}; /// The information required for a validator to propose and attest during some epoch. /// /// Generally obtained from a Beacon Node, this information contains the validators canonical index -/// (thier sequence in the global validator induction process) and the "shuffling" for that index +/// (their sequence in the global validator induction process) and the "shuffling" for that index /// for some epoch. #[derive(Debug, PartialEq, Clone, Copy, Default)] -pub struct EpochDuties { - pub validator_index: u64, +pub struct EpochDuty { pub block_production_slot: Option, - // Future shard info + pub committee_slot: Slot, + pub committee_shard: u64, + pub committee_index: u64, } -impl EpochDuties { - /// Returns `true` if the supplied `slot` is a slot in which the validator should produce a - /// block. - pub fn is_block_production_slot(&self, slot: Slot) -> bool { +impl EpochDuty { + /// Returns `true` if work needs to be done in the supplied `slot` + pub fn is_work_slot(&self, slot: Slot) -> bool { + // if validator is required to produce a slot return true match self.block_production_slot { - Some(s) if s == slot => true, + Some(s) if s == slot => return true, _ => false, } + + if self.committee_slot == slot { + return true; + } + return false; } } +/// Maps a list of public keys (many validators) to an EpochDuty. +pub struct EpochDuties { + inner: HashMap>, +} pub enum EpochDutiesMapError { Poisoned, diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index 1f7297f0e..91da512e3 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -1,56 +1,54 @@ +use super::epoch_duties::{EpochDuties, EpochDuty}; use super::traits::{BeaconNode, BeaconNodeError}; -use super::EpochDuties; -use protos::services::{ProposeBlockSlotRequest, PublicKeys as IndexRequest}; +use protos::services::{ + ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty, Validators, +}; use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; +use std::collections::HashMap; use types::{Epoch, PublicKey, Slot}; impl BeaconNode for ValidatorServiceClient { - /// Request the shuffling from the Beacon Node (BN). - /// - /// As this function takes a `PublicKey`, it will first attempt to resolve the public key into - /// a validator index, then call the BN for production/attestation duties. - /// - /// Note: presently only block production information is returned. - fn request_shuffling( + /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). + fn request_duties( &self, epoch: Epoch, pubkeys: &[PublicKey], - ) -> Result, BeaconNodeError> { - // Lookup the validator indexes for all the supplied public keys. - let validator_indices = { - let mut req = IndexRequest::new(); - for public_key in pubkeys { - req.mut_public_key().push(ssz_encode(public_key)); - } - let resp = self - .validator_index(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - resp.get_index() - }; - - let mut req = ProposeBlockSlotRequest::new(); - req.set_validator_index(validator_index); + ) -> Result { + // Get the required duties from all validators + // build the request + let mut req = GetDutiesRequest::new(); req.set_epoch(epoch.as_u64()); + let validators = Validators::new().mut_public_key(); + for pubkey in pubkeys { + validators.push(pubkey); + } + req.set_validators(validators); + // send the request, get the duties reply let reply = self - .propose_block_slot(&req) + .get_validator_duties(&req) .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - let block_production_slot = if reply.has_slot() { - Some(reply.get_slot()) - } else { - None - }; - - let block_production_slot = match block_production_slot { - Some(slot) => Some(Slot::new(slot)), - None => None, - }; - - Ok(Some(EpochDuties { - validator_index, - block_production_slot, - })) + let mut epoch_duties: HashMap> = HashMap::new(); + for (index, validator_duty) in reply.get_active_validator().enumerate() { + if let Some(duty) = validator_duty.has_slot() { + // the validator is active + //build the EpochDuty + let active_duty = duty.get_duty(); + let block_produce_slot = active_duty.get_block_produce_slot(); + let epoch_duty = EpochDuty { + block_produce_slot, + committee_slot: active_duty.get_committee_slot(), + committee_shard: active_duty.get_committee_shard(), + committee_index: active_duty.get_committee_index(), + }; + epoch_duties.insert(pubkeys[index], Some(epoch_duty)); + } else { + // validator is not active and has no duties + epoch_duties.insert(pubkeys[index], None); + } + } + Ok(epoch_duties) } } diff --git a/validator_client/src/duties/traits.rs b/validator_client/src/duties/traits.rs index a3dcade4b..3aa8fbab2 100644 --- a/validator_client/src/duties/traits.rs +++ b/validator_client/src/duties/traits.rs @@ -8,12 +8,13 @@ pub enum BeaconNodeError { /// Defines the methods required to obtain a validators shuffling from a Beacon Node. pub trait BeaconNode: Send + Sync { - /// Get the shuffling for the given epoch and public key. + /// Gets the duties for all validators. /// - /// Returns Ok(None) if the public key is unknown, or the shuffling for that epoch is unknown. - fn request_shuffling( + /// Returns a vector of EpochDuties for each validator public key. The entry will be None for + /// validators that are not activated. + fn request_duties( &self, epoch: Epoch, pubkeys: &[PublicKey], - ) -> Result, BeaconNodeError>; + ) -> Result>, BeaconNodeError>; }