Implements RPC Server side of epoch duties
This commit is contained in:
parent
cde049df1f
commit
1f437a3e7b
@ -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)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user