Implements RPC Server side of epoch duties

This commit is contained in:
Age Manning 2019-03-27 21:08:28 +11:00
parent cde049df1f
commit 1f437a3e7b
No known key found for this signature in database
GPG Key ID: 05EED64B79E06A93
3 changed files with 108 additions and 32 deletions

View File

@ -49,7 +49,10 @@ pub fn start_server(
create_beacon_block_service(instance) create_beacon_block_service(instance)
}; };
let validator_service = { let validator_service = {
let instance = ValidatorServiceInstance { log: log.clone() }; let instance = ValidatorServiceInstance {
chain: beacon_chain.clone(),
log: log.clone(),
};
create_validator_service(instance) create_validator_service(instance)
}; };

View File

@ -2,59 +2,132 @@ use bls::PublicKey;
use futures::Future; use futures::Future;
use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink}; use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink};
use protos::services::{ use protos::services::{
IndexResponse, ProposeBlockSlotRequest, ProposeBlockSlotResponse, PublicKey as PublicKeyRequest, GetDutiesRequest, GetDutiesResponse, Validators};
};
use protos::services_grpc::ValidatorService; use protos::services_grpc::ValidatorService;
use slog::{debug, Logger}; use slog::{debug, Logger};
use ssz::Decodable; use ssz::Decodable;
use std::sync::Arc;
use crate::beacon_chain::BeaconChain;
#[derive(Clone)] #[derive(Clone)]
pub struct ValidatorServiceInstance { pub struct ValidatorServiceInstance {
pub chain: Arc<BeaconChain>,
pub log: Logger, pub log: Logger,
} }
//TODO: Refactor Errors
impl ValidatorService for ValidatorServiceInstance { impl ValidatorService for ValidatorServiceInstance {
fn validator_index(
/// For a list of validator public keys, this function returns the slot at which each
/// validator must propose a block, attest to a shard, their shard committee and the shard they
/// need to attest to.
fn get_validator_duties (
&mut self, &mut self,
ctx: RpcContext, ctx: RpcContext,
req: PublicKeyRequest, req: GetDutiesRequest,
sink: UnarySink<IndexResponse>, sink: UnarySink<GetDutiesResponse>,
) { ) {
if let Ok((public_key, _)) = PublicKey::ssz_decode(req.get_public_key(), 0) { let validators = req.get_validators();
debug!(self.log, "RPC request"; "endpoint" => "ValidatorIndex", "public_key" => public_key.concatenated_hex_id()); debug!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch());
let mut resp = IndexResponse::new(); let epoch = req.get_epoch();
let mut resp = GetDutiesResponse::new();
// TODO: return a legit value. let spec = self.chain.spec;
resp.set_index(1); let state = self.chain.state.read();
let f = sink //TODO: Decide whether to rebuild the cache
.success(resp) //TODO: Get the active validator indicies
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); //let active_validator_indices = self.chain.state.read().get_cached_active_validator_indices(
ctx.spawn(f) let active_validator_indices = &[1,2,3,4,5,6,7,8];
} else { // TODO: Is this the most efficient? Perhaps we cache this data structure.
let f = sink
// this is an array of validators who are to propose this epoch
// TODO: RelativeEpoch?
let validator_proposers = 0..spec.slots_per_epoch.to_iter().map(|slot| state.get_beacon_proposer_index(slot, epoch, &spec)).collect();
// get the duties for each validator
for validator in validators {
let active_validator = ActiveValidator::new();
let public_key = match PublicKey::ssz_decode(validator, 0) {
Ok((v_) => v,
Err(_) => {
let f = sink
.fail(RpcStatus::new( .fail(RpcStatus::new(
RpcStatusCode::InvalidArgument, RpcStatusCode::InvalidArgument,
Some("Invalid public_key".to_string()), Some("Invalid public_key".to_string()),
)) ))
//TODO: Handle error correctly
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e)); .map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
ctx.spawn(f) return ctx.spawn(f);
} }
} };
fn propose_block_slot( // is the validator active
&mut self, let val_index = match state.get_validator_index(&public_key) {
ctx: RpcContext, Ok(index) => {
req: ProposeBlockSlotRequest, if active_validator_indices.contains(index) {
sink: UnarySink<ProposeBlockSlotResponse>, // validator is active, return the index
) { index
debug!(self.log, "RPC request"; "endpoint" => "ProposeBlockSlot", "epoch" => req.get_epoch(), "validator_index" => req.get_validator_index()); }
else {
// validator is inactive, go to the next validator
active_validator.set_none();
resp.push(active_validator);
break;
}
},
// the cache is not built, throw an error
Err(_) =>{
let f = sink
.fail(RpcStatus::new(
RpcStatusCode::FailedPreCondition,
Some("Beacon state cache is not built".to_string()),
))
//TODO: Handle error correctly
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
return ctx.spawn(f);
}
};
let mut resp = ProposeBlockSlotResponse::new(); // we have an active validator, set its duties
let duty = ValidatorDuty::new();
// check if it needs to propose a block
let Some(slot) = validator_proposers.iter().position(|&v| val_index ==v) {
duty.set_block_production_slot(slot);
}
else {
// no blocks to propose this epoch
duty.set_none()
}
// get attestation duties
let attestation_duties = match state.get_attestation_duties(val_index, &spec) {
Ok(v) => v,
// the cache is not built, throw an error
Err(_) =>{
let f = sink
.fail(RpcStatus::new(
RpcStatusCode::FailedPreCondition,
Some("Beacon state cache is not built".to_string()),
))
//TODO: Handle error correctly
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
return ctx.spawn(f);
}
};
duty.set_committee_index(attestation_duties.committee_index);
duty.set_attestation_slot(attestation_duties.slot);
duty.set_attestation_shard(attestation_duties.shard);
active_validator.set_duty(duty);
resp.push(active_validator);
}
// TODO: return a legit value.
resp.set_slot(1);
let f = sink let f = sink
.success(resp) .success(resp)

View File

@ -122,8 +122,8 @@ message ValidatorDuty {
bool none = 1; bool none = 1;
uint64 block_production_slot = 2; uint64 block_production_slot = 2;
} }
uint64 committee_slot = 3; uint64 attestation_slot = 3;
uint64 committee_shard = 4; uint64 attestation_shard = 4;
uint64 committee_index = 5; uint64 committee_index = 5;
} }