2019-03-27 10:32:53 +00:00
|
|
|
use crate::beacon_chain::BeaconChain;
|
2019-02-14 01:09:18 +00:00
|
|
|
use bls::PublicKey;
|
|
|
|
use futures::Future;
|
|
|
|
use grpcio::{RpcContext, RpcStatus, RpcStatusCode, UnarySink};
|
2019-03-27 10:32:53 +00:00
|
|
|
use protos::services::{ActiveValidator, GetDutiesRequest, GetDutiesResponse, ValidatorDuty};
|
2019-02-14 01:09:18 +00:00
|
|
|
use protos::services_grpc::ValidatorService;
|
2019-03-30 13:08:55 +00:00
|
|
|
use slog::{trace, warn};
|
2019-05-13 05:12:19 +00:00
|
|
|
use ssz::Decode;
|
2019-03-27 10:08:28 +00:00
|
|
|
use std::sync::Arc;
|
2019-05-10 04:47:09 +00:00
|
|
|
use types::{Epoch, EthSpec, RelativeEpoch};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
2019-05-13 04:44:43 +00:00
|
|
|
pub struct ValidatorServiceInstance<E: EthSpec> {
|
|
|
|
pub chain: Arc<BeaconChain<E>>,
|
2019-03-30 13:08:55 +00:00
|
|
|
pub log: slog::Logger,
|
2019-02-14 01:09:18 +00:00
|
|
|
}
|
2019-03-27 10:08:28 +00:00
|
|
|
//TODO: Refactor Errors
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-05-13 04:44:43 +00:00
|
|
|
impl<E: EthSpec> ValidatorService for ValidatorServiceInstance<E> {
|
2019-03-27 10:08:28 +00:00
|
|
|
/// 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.
|
2019-03-27 10:32:53 +00:00
|
|
|
fn get_validator_duties(
|
2019-02-14 01:09:18 +00:00
|
|
|
&mut self,
|
|
|
|
ctx: RpcContext,
|
2019-03-27 10:08:28 +00:00
|
|
|
req: GetDutiesRequest,
|
|
|
|
sink: UnarySink<GetDutiesResponse>,
|
2019-02-14 01:09:18 +00:00
|
|
|
) {
|
2019-03-27 10:08:28 +00:00
|
|
|
let validators = req.get_validators();
|
2019-03-30 13:08:55 +00:00
|
|
|
trace!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch());
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-30 13:08:55 +00:00
|
|
|
let spec = self.chain.get_spec();
|
2019-03-31 03:26:58 +00:00
|
|
|
let state = self.chain.get_state();
|
2019-03-28 02:14:41 +00:00
|
|
|
let epoch = Epoch::from(req.get_epoch());
|
2019-03-27 10:08:28 +00:00
|
|
|
let mut resp = GetDutiesResponse::new();
|
2019-03-27 10:32:53 +00:00
|
|
|
let resp_validators = resp.mut_active_validators();
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-28 02:14:41 +00:00
|
|
|
let relative_epoch =
|
|
|
|
match RelativeEpoch::from_epoch(state.slot.epoch(spec.slots_per_epoch), epoch) {
|
|
|
|
Ok(v) => v,
|
|
|
|
Err(e) => {
|
|
|
|
// incorrect epoch
|
|
|
|
let log_clone = self.log.clone();
|
|
|
|
let f = sink
|
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::FailedPrecondition,
|
|
|
|
Some(format!("Invalid epoch: {:?}", e)),
|
|
|
|
))
|
|
|
|
.map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e));
|
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-28 02:14:41 +00:00
|
|
|
let validator_proposers: Result<Vec<usize>, _> = epoch
|
|
|
|
.slot_iter(spec.slots_per_epoch)
|
|
|
|
.map(|slot| state.get_beacon_proposer_index(slot, relative_epoch, &spec))
|
|
|
|
.collect();
|
|
|
|
let validator_proposers = match validator_proposers {
|
|
|
|
Ok(v) => v,
|
2019-03-28 03:32:02 +00:00
|
|
|
Err(e) => {
|
2019-03-28 02:14:41 +00:00
|
|
|
// could not get the validator proposer index
|
|
|
|
let log_clone = self.log.clone();
|
|
|
|
let f = sink
|
|
|
|
.fail(RpcStatus::new(
|
2019-03-28 03:32:02 +00:00
|
|
|
RpcStatusCode::FailedPrecondition,
|
|
|
|
Some(format!("Could not find beacon proposers: {:?}", e)),
|
2019-03-28 02:14:41 +00:00
|
|
|
))
|
|
|
|
.map_err(move |e| warn!(log_clone, "failed to reply {:?} : {:?}", req, e));
|
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
2019-03-27 10:08:28 +00:00
|
|
|
|
|
|
|
// get the duties for each validator
|
2019-03-27 10:32:53 +00:00
|
|
|
for validator_pk in validators.get_public_keys() {
|
|
|
|
let mut active_validator = ActiveValidator::new();
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-05-13 02:07:32 +00:00
|
|
|
let public_key = match PublicKey::from_ssz_bytes(validator_pk) {
|
2019-03-29 00:47:22 +00:00
|
|
|
Ok(v) => v,
|
2019-03-27 10:32:53 +00:00
|
|
|
Err(_) => {
|
2019-03-28 02:14:41 +00:00
|
|
|
let log_clone = self.log.clone();
|
2019-03-27 10:32:53 +00:00
|
|
|
let f = sink
|
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::InvalidArgument,
|
2019-03-28 06:16:43 +00:00
|
|
|
Some("Invalid public_key".to_string()),
|
2019-03-27 10:32:53 +00:00
|
|
|
))
|
2019-04-01 01:14:23 +00:00
|
|
|
.map_err(move |_| warn!(log_clone, "failed to reply {:?}", req));
|
2019-03-27 10:32:53 +00:00
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
2019-03-27 10:08:28 +00:00
|
|
|
};
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-28 02:14:41 +00:00
|
|
|
// get the validator index
|
2019-03-27 10:08:28 +00:00
|
|
|
let val_index = match state.get_validator_index(&public_key) {
|
2019-03-28 02:14:41 +00:00
|
|
|
Ok(Some(index)) => index,
|
|
|
|
Ok(None) => {
|
|
|
|
// index not present in registry, set the duties for this key to None
|
|
|
|
warn!(
|
|
|
|
self.log,
|
|
|
|
"RPC requested a public key that is not in the registry: {:?}", public_key
|
|
|
|
);
|
2019-03-27 10:32:53 +00:00
|
|
|
active_validator.set_none(false);
|
|
|
|
resp_validators.push(active_validator);
|
2019-03-28 06:22:09 +00:00
|
|
|
continue;
|
2019-03-27 10:32:53 +00:00
|
|
|
}
|
2019-03-27 10:08:28 +00:00
|
|
|
// the cache is not built, throw an error
|
2019-03-28 02:14:41 +00:00
|
|
|
Err(e) => {
|
|
|
|
let log_clone = self.log.clone();
|
2019-03-27 10:08:28 +00:00
|
|
|
let f = sink
|
2019-03-27 10:32:53 +00:00
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::FailedPrecondition,
|
2019-03-28 02:14:41 +00:00
|
|
|
Some(format!("Beacon state error {:?}", e)),
|
2019-03-27 10:32:53 +00:00
|
|
|
))
|
2019-03-28 02:14:41 +00:00
|
|
|
.map_err(move |e| warn!(log_clone, "Failed to reply {:?}: {:?}", req, e));
|
2019-03-27 10:08:28 +00:00
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-28 02:14:41 +00:00
|
|
|
// get attestation duties and check if validator is active
|
2019-03-27 10:08:28 +00:00
|
|
|
let attestation_duties = match state.get_attestation_duties(val_index, &spec) {
|
2019-03-27 10:32:53 +00:00
|
|
|
Ok(Some(v)) => v,
|
2019-03-28 02:14:41 +00:00
|
|
|
Ok(_) => {
|
|
|
|
// validator is inactive, go to the next validator
|
|
|
|
warn!(
|
|
|
|
self.log,
|
|
|
|
"RPC requested an inactive validator key: {:?}", public_key
|
|
|
|
);
|
|
|
|
active_validator.set_none(false);
|
|
|
|
resp_validators.push(active_validator);
|
2019-03-28 06:22:09 +00:00
|
|
|
continue;
|
2019-03-28 02:14:41 +00:00
|
|
|
}
|
2019-03-27 10:08:28 +00:00
|
|
|
// the cache is not built, throw an error
|
2019-03-28 02:14:41 +00:00
|
|
|
Err(e) => {
|
|
|
|
let log_clone = self.log.clone();
|
2019-03-27 10:08:28 +00:00
|
|
|
let f = sink
|
2019-03-27 10:32:53 +00:00
|
|
|
.fail(RpcStatus::new(
|
|
|
|
RpcStatusCode::FailedPrecondition,
|
2019-03-28 02:14:41 +00:00
|
|
|
Some(format!("Beacon state error {:?}", e)),
|
2019-03-27 10:32:53 +00:00
|
|
|
))
|
2019-03-28 02:14:41 +00:00
|
|
|
.map_err(move |e| warn!(log_clone, "Failed to reply {:?}: {:?}", req, e));
|
2019-03-27 10:08:28 +00:00
|
|
|
return ctx.spawn(f);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2019-03-28 02:14:41 +00:00
|
|
|
// we have an active validator, set its duties
|
|
|
|
let mut duty = ValidatorDuty::new();
|
|
|
|
|
|
|
|
// check if the validator needs to propose a block
|
|
|
|
if let Some(slot) = validator_proposers.iter().position(|&v| val_index == v) {
|
|
|
|
duty.set_block_production_slot(
|
|
|
|
epoch.start_slot(spec.slots_per_epoch).as_u64() + slot as u64,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// no blocks to propose this epoch
|
|
|
|
duty.set_none(false)
|
|
|
|
}
|
|
|
|
|
2019-03-27 10:32:53 +00:00
|
|
|
duty.set_committee_index(attestation_duties.committee_index as u64);
|
|
|
|
duty.set_attestation_slot(attestation_duties.slot.as_u64());
|
2019-03-27 10:08:28 +00:00
|
|
|
duty.set_attestation_shard(attestation_duties.shard);
|
2019-03-30 13:34:35 +00:00
|
|
|
duty.set_committee_len(attestation_duties.committee_len as u64);
|
2019-02-14 01:09:18 +00:00
|
|
|
|
2019-03-27 10:08:28 +00:00
|
|
|
active_validator.set_duty(duty);
|
2019-03-27 10:32:53 +00:00
|
|
|
resp_validators.push(active_validator);
|
|
|
|
}
|
2019-02-14 01:09:18 +00:00
|
|
|
|
|
|
|
let f = sink
|
|
|
|
.success(resp)
|
|
|
|
.map_err(move |e| println!("failed to reply {:?}: {:?}", req, e));
|
|
|
|
ctx.spawn(f)
|
|
|
|
}
|
|
|
|
}
|