Update EpochDuty RPC and core functionality

This commit is contained in:
Age Manning 2019-03-27 15:41:51 +11:00
parent 96ccd58414
commit bc8ec51fe5
No known key found for this signature in database
GPG Key ID: 05EED64B79E06A93
4 changed files with 79 additions and 88 deletions

View File

@ -26,10 +26,9 @@ service BeaconBlockService {
/// Service that provides the validator client with requisite knowledge about /// Service that provides the validator client with requisite knowledge about
//its public keys //its public keys
service ValidatorService { service ValidatorService {
rpc ProposeBlockSlot(ProposeBlockSlotRequest) returns (ProposeBlockSlotResponse); // Gets the block proposer slot and comittee slot that a validator needs to
/// Given a set of public keys, returns their respective indicies // perform work on.
rpc ValidatorIndex(PublicKeys) returns (Indicies); rpc GetValidatorDuties(GetDutiesRequest) returns (GetDutiesResponse);
// rpc ValidatorAssignment(ValidatorAssignmentRequest) returns (ValidatorAssignmentResponse);
} }
/// Service that handles validator attestations /// Service that handles validator attestations
@ -93,58 +92,41 @@ message BeaconBlock {
/* /*
* Validator Service Messages * 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 // Validator Assignment
message PublicKeys { // the public keys of the validators
message Validators {
repeated bytes public_key = 1; repeated bytes public_key = 1;
} }
message Indicies {
repeated uint64 index = 1;
}
// Propose slot // Propose slot
message GetDutiesRequest {
message ProposeBlockSlotRequest {
uint64 epoch = 1; uint64 epoch = 1;
repeated uint64 validator_index = 2; Validators validators = 2;
} }
message GetDutiesResponse { message GetDutiesResponse {
repeated oneof slot_oneof { repeated ActiveValidator active_validator = 1;
}
message ActiveValidator {
oneof slot_oneof {
bool none = 1; bool none = 1;
ValidatorDuty duty = 2; ValidatorDuty duty = 2;
} }
} }
ValidatorDuty { message ValidatorDuty {
oneof block_oneof { oneof block_oneof {
bool none = 1; bool none = 1;
uint64 block_produce_slot = 2; uint64 block_produce_slot = 2;
} }
uint64 committee_slot = 1; uint64 committee_slot = 3;
uint64 committee_shard = 2; uint64 committee_shard = 4;
uint64 committee_index = 3; uint64 committee_index = 5;
} }
/* /*
* Attestation Service Messages * Attestation Service Messages
*/ */

View File

@ -1,30 +1,40 @@
use block_proposer::{DutiesReader, DutiesReaderError}; use block_proposer::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::RwLock; 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. /// 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 /// 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. /// for some epoch.
#[derive(Debug, PartialEq, Clone, Copy, Default)] #[derive(Debug, PartialEq, Clone, Copy, Default)]
pub struct EpochDuties { pub struct EpochDuty {
pub validator_index: u64,
pub block_production_slot: Option<Slot>, pub block_production_slot: Option<Slot>,
// Future shard info pub committee_slot: Slot,
pub committee_shard: u64,
pub committee_index: u64,
} }
impl EpochDuties { impl EpochDuty {
/// Returns `true` if the supplied `slot` is a slot in which the validator should produce a /// Returns `true` if work needs to be done in the supplied `slot`
/// block. pub fn is_work_slot(&self, slot: Slot) -> bool {
pub fn is_block_production_slot(&self, slot: Slot) -> bool { // if validator is required to produce a slot return true
match self.block_production_slot { match self.block_production_slot {
Some(s) if s == slot => true, Some(s) if s == slot => return true,
_ => false, _ => 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<PublicKey, Option<EpochDuty>>,
}
pub enum EpochDutiesMapError { pub enum EpochDutiesMapError {
Poisoned, Poisoned,

View File

@ -1,56 +1,54 @@
use super::epoch_duties::{EpochDuties, EpochDuty};
use super::traits::{BeaconNode, BeaconNodeError}; use super::traits::{BeaconNode, BeaconNodeError};
use super::EpochDuties; use protos::services::{
use protos::services::{ProposeBlockSlotRequest, PublicKeys as IndexRequest}; ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty, Validators,
};
use protos::services_grpc::ValidatorServiceClient; use protos::services_grpc::ValidatorServiceClient;
use ssz::ssz_encode; use ssz::ssz_encode;
use std::collections::HashMap;
use types::{Epoch, PublicKey, Slot}; use types::{Epoch, PublicKey, Slot};
impl BeaconNode for ValidatorServiceClient { impl BeaconNode for ValidatorServiceClient {
/// Request the shuffling from the Beacon Node (BN). /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN).
/// fn request_duties(
/// 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(
&self, &self,
epoch: Epoch, epoch: Epoch,
pubkeys: &[PublicKey], pubkeys: &[PublicKey],
) -> Result<Option<EpochDuties>, BeaconNodeError> { ) -> Result<EpochDuties, BeaconNodeError> {
// Lookup the validator indexes for all the supplied public keys. // Get the required duties from all validators
let validator_indices = { // build the request
let mut req = IndexRequest::new(); let mut req = GetDutiesRequest::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);
req.set_epoch(epoch.as_u64()); 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 let reply = self
.propose_block_slot(&req) .get_validator_duties(&req)
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
let block_production_slot = if reply.has_slot() { let mut epoch_duties: HashMap<PublicKey, Option<EpochDuties>> = HashMap::new();
Some(reply.get_slot()) for (index, validator_duty) in reply.get_active_validator().enumerate() {
} else { if let Some(duty) = validator_duty.has_slot() {
None // the validator is active
}; //build the EpochDuty
let active_duty = duty.get_duty();
let block_production_slot = match block_production_slot { let block_produce_slot = active_duty.get_block_produce_slot();
Some(slot) => Some(Slot::new(slot)), let epoch_duty = EpochDuty {
None => None, block_produce_slot,
}; committee_slot: active_duty.get_committee_slot(),
committee_shard: active_duty.get_committee_shard(),
Ok(Some(EpochDuties { committee_index: active_duty.get_committee_index(),
validator_index, };
block_production_slot, 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)
} }
} }

View File

@ -8,12 +8,13 @@ pub enum BeaconNodeError {
/// Defines the methods required to obtain a validators shuffling from a Beacon Node. /// Defines the methods required to obtain a validators shuffling from a Beacon Node.
pub trait BeaconNode: Send + Sync { 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. /// Returns a vector of EpochDuties for each validator public key. The entry will be None for
fn request_shuffling( /// validators that are not activated.
fn request_duties(
&self, &self,
epoch: Epoch, epoch: Epoch,
pubkeys: &[PublicKey], pubkeys: &[PublicKey],
) -> Result<Option<EpochDuties>, BeaconNodeError>; ) -> Result<Vec<Option<EpochDuties>>, BeaconNodeError>;
} }