Fix compile errors from block_producer upgrades

This commit is contained in:
Paul Hauner
2019-01-25 13:02:59 +11:00
parent f4f5b3a13c
commit 19417efa63
8 changed files with 135 additions and 106 deletions

View File

@@ -1,11 +1,11 @@
use block_producer::{BeaconNode, BeaconNodeError};
use block_producer::{BeaconNode, BeaconNodeError, PublishOutcome};
use protos::services::{
BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest,
};
use protos::services_grpc::BeaconBlockServiceClient;
use ssz::{ssz_encode, Decodable};
use std::sync::Arc;
use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, Signature};
use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, PublicKey, Signature};
/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be
/// implemented upon it.
@@ -20,11 +20,21 @@ impl BeaconBlockGrpcClient {
}
impl BeaconNode for BeaconBlockGrpcClient {
fn proposer_nonce(&self, pubkey: &PublicKey) -> Result<u64, BeaconNodeError> {
// TODO: this might not be required.
//
// See: https://github.com/ethereum/eth2.0-specs/pull/496
panic!("Not implemented.")
}
/// Request a Beacon Node (BN) to produce a new block at the supplied slot.
///
/// Returns `None` if it is not possible to produce at the supplied slot. For example, if the
/// BN is unable to find a parent block.
fn produce_beacon_block(&self, slot: u64) -> Result<Option<BeaconBlock>, BeaconNodeError> {
fn produce_beacon_block(
&self,
slot: u64,
randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconNodeError> {
let mut req = ProduceBeaconBlockRequest::new();
req.set_slot(slot);
@@ -73,7 +83,7 @@ impl BeaconNode for BeaconBlockGrpcClient {
///
/// Generally, this will be called after a `produce_beacon_block` call with a block that has
/// been completed (signed) by the validator client.
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<bool, BeaconNodeError> {
fn publish_beacon_block(&self, block: BeaconBlock) -> Result<PublishOutcome, BeaconNodeError> {
let mut req = PublishBeaconBlockRequest::new();
// TODO: this conversion is incomplete; fix it.
@@ -90,6 +100,11 @@ impl BeaconNode for BeaconBlockGrpcClient {
.publish_beacon_block(&req)
.map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?;
Ok(reply.get_success())
if reply.get_success() {
Ok(PublishOutcome::ValidBlock)
} else {
// TODO: distinguish between different errors
Ok(PublishOutcome::InvalidBlock("Publish failed".to_string()))
}
}
}

View File

@@ -42,6 +42,9 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducerServi
Ok(BlockProducerPollOutcome::SignerRejection(slot)) => {
error!(self.log, "The cryptographic signer refused to sign the block"; "slot" => slot)
}
Ok(BlockProducerPollOutcome::ValidatorIsUnknown(slot)) => {
error!(self.log, "The Beacon Node does not recognise the validator"; "slot" => slot)
}
};
std::thread::sleep(Duration::from_millis(self.poll_interval_millis));

View File

@@ -0,0 +1,81 @@
use block_producer::{DutiesReader, DutiesReaderError};
use std::collections::HashMap;
use std::sync::RwLock;
/// 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
/// for some epoch.
#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub struct EpochDuties {
pub validator_index: u64,
pub block_production_slot: Option<u64>,
// Future shard info
}
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: u64) -> bool {
match self.block_production_slot {
Some(s) if s == slot => true,
_ => false,
}
}
}
pub enum EpochDutiesMapError {
Poisoned,
}
/// Maps an `epoch` to some `EpochDuties` for a single validator.
pub struct EpochDutiesMap {
pub epoch_length: u64,
pub map: RwLock<HashMap<u64, EpochDuties>>,
}
impl EpochDutiesMap {
pub fn new(epoch_length: u64) -> Self {
Self {
epoch_length,
map: RwLock::new(HashMap::new()),
}
}
pub fn get(&self, epoch: u64) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let map = self.map.read().map_err(|_| EpochDutiesMapError::Poisoned)?;
match map.get(&epoch) {
Some(duties) => Ok(Some(duties.clone())),
None => Ok(None),
}
}
pub fn insert(
&self,
epoch: u64,
epoch_duties: EpochDuties,
) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let mut map = self
.map
.write()
.map_err(|_| EpochDutiesMapError::Poisoned)?;
Ok(map.insert(epoch, epoch_duties))
}
}
impl DutiesReader for EpochDutiesMap {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, DutiesReaderError> {
let epoch = slot
.checked_div(self.epoch_length)
.ok_or_else(|| DutiesReaderError::EpochLengthIsZero)?;
let map = self.map.read().map_err(|_| DutiesReaderError::Poisoned)?;
let duties = map
.get(&epoch)
.ok_or_else(|| DutiesReaderError::UnknownEpoch)?;
Ok(duties.is_block_production_slot(slot))
}
}
// TODO: add tests.

View File

@@ -1,88 +1,18 @@
mod duties_map;
mod grpc;
mod service;
#[cfg(test)]
mod test_node;
mod traits;
pub use self::duties_map::EpochDutiesMap;
use self::duties_map::{EpochDuties, EpochDutiesMapError};
pub use self::service::DutiesManagerService;
use self::traits::{BeaconNode, BeaconNodeError};
use block_producer::{DutiesReader, DutiesReaderError};
use bls::PublicKey;
use slot_clock::SlotClock;
use spec::ChainSpec;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
pub use self::service::DutiesManagerService;
/// 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
/// for some epoch.
#[derive(Debug, PartialEq, Clone, Copy, Default)]
pub struct EpochDuties {
pub validator_index: u64,
pub block_production_slot: Option<u64>,
// Future shard info
}
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: u64) -> bool {
match self.block_production_slot {
Some(s) if s == slot => true,
_ => false,
}
}
}
pub enum EpochDutiesMapError {
Poisoned,
}
/// Maps an `epoch` to some `EpochDuties` for a single validator.
pub struct EpochDutiesMap {
pub map: RwLock<HashMap<u64, EpochDuties>>,
}
impl EpochDutiesMap {
pub fn new() -> Self {
Self {
map: RwLock::new(HashMap::new()),
}
}
pub fn get(&self, epoch: u64) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let map = self.map.read().map_err(|_| EpochDutiesMapError::Poisoned)?;
match map.get(&epoch) {
Some(duties) => Ok(Some(duties.clone())),
None => Ok(None),
}
}
pub fn insert(
&self,
epoch: u64,
epoch_duties: EpochDuties,
) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let mut map = self
.map
.write()
.map_err(|_| EpochDutiesMapError::Poisoned)?;
Ok(map.insert(epoch, epoch_duties))
}
}
impl DutiesReader for EpochDutiesMap {
fn is_block_production_slot(&self, epoch: u64, slot: u64) -> Result<bool, DutiesReaderError> {
let map = self.map.read().map_err(|_| DutiesReaderError::Poisoned)?;
let duties = map
.get(&epoch)
.ok_or_else(|| DutiesReaderError::UnknownEpoch)?;
Ok(duties.is_block_production_slot(slot))
}
}
use std::sync::Arc;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PollOutcome {
@@ -117,7 +47,7 @@ pub struct DutiesManager<T: SlotClock, U: BeaconNode> {
/// The validator's public key.
pub pubkey: PublicKey,
pub spec: Arc<ChainSpec>,
pub slot_clock: Arc<RwLock<T>>,
pub slot_clock: Arc<T>,
pub beacon_node: Arc<U>,
}
@@ -129,8 +59,6 @@ impl<T: SlotClock, U: BeaconNode> DutiesManager<T, U> {
pub fn poll(&self) -> Result<PollOutcome, Error> {
let slot = self
.slot_clock
.read()
.map_err(|_| Error::SlotClockPoisoned)?
.present_slot()
.map_err(|_| Error::SlotClockError)?
.ok_or(Error::SlotUnknowable)?;
@@ -187,9 +115,9 @@ mod tests {
#[test]
pub fn polling() {
let spec = Arc::new(ChainSpec::foundation());
let duties_map = Arc::new(EpochDutiesMap::new());
let duties_map = Arc::new(EpochDutiesMap::new(spec.epoch_length));
let keypair = Keypair::random();
let slot_clock = Arc::new(RwLock::new(TestingSlotClock::new(0)));
let slot_clock = Arc::new(TestingSlotClock::new(0));
let beacon_node = Arc::new(TestBeaconNode::default());
let manager = DutiesManager {

View File

@@ -10,7 +10,7 @@ use slog::{error, info, o, Drain};
use slot_clock::SystemTimeSlotClock;
use spec::ChainSpec;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
use std::sync::Arc;
use std::thread;
mod block_producer_service;
@@ -92,7 +92,7 @@ fn main() {
info!(log, "Genesis time"; "unix_epoch_seconds" => spec.genesis_time);
let clock = SystemTimeSlotClock::new(spec.genesis_time, spec.slot_duration)
.expect("Unable to instantiate SystemTimeSlotClock.");
Arc::new(RwLock::new(clock))
Arc::new(clock)
};
let poll_interval_millis = spec.slot_duration * 1000 / 10; // 10% epoch time precision.
@@ -108,7 +108,7 @@ fn main() {
for keypair in keypairs {
info!(log, "Starting validator services"; "validator" => keypair.pk.concatenated_hex_id());
let duties_map = Arc::new(EpochDutiesMap::new());
let duties_map = Arc::new(EpochDutiesMap::new(spec.epoch_length));
// Spawn a new thread to maintain the validator's `EpochDuties`.
let duties_manager_thread = {
@@ -139,6 +139,7 @@ fn main() {
// Spawn a new thread to perform block production for the validator.
let producer_thread = {
let spec = spec.clone();
let pubkey = keypair.pk.clone();
let signer = Arc::new(TestSigner::new(keypair.clone()));
let duties_map = duties_map.clone();
let slot_clock = slot_clock.clone();
@@ -146,7 +147,7 @@ fn main() {
let client = Arc::new(BeaconBlockGrpcClient::new(beacon_block_grpc_client.clone()));
thread::spawn(move || {
let block_producer =
BlockProducer::new(spec, duties_map, slot_clock, client, signer);
BlockProducer::new(spec, pubkey, duties_map, slot_clock, client, signer);
let mut block_producer_service = BlockProducerService {
block_producer,
poll_interval_millis,