Fix all compile errors from new Slot/Epoch types

This commit is contained in:
Paul Hauner 2019-02-07 11:22:48 +11:00
parent 9b1d8cd3c1
commit 85450ec254
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
30 changed files with 177 additions and 135 deletions

View File

@ -230,7 +230,7 @@ where
/// Returns `None` if the `validator_index` is invalid. /// Returns `None` if the `validator_index` is invalid.
/// ///
/// Information is retrieved from the present `beacon_state.validator_registry`. /// Information is retrieved from the present `beacon_state.validator_registry`.
pub fn proposer_slots(&self, validator_index: usize) -> Option<Slot> { pub fn proposer_slots(&self, validator_index: usize) -> Option<u64> {
if let Some(validator) = self.state.read().validator_registry.get(validator_index) { if let Some(validator) = self.state.read().validator_registry.get(validator_index) {
Some(validator.proposer_slots) Some(validator.proposer_slots)
} else { } else {
@ -248,7 +248,7 @@ where
/// `self.state` should undergo per slot processing. /// `self.state` should undergo per slot processing.
pub fn read_slot_clock(&self) -> Option<Slot> { pub fn read_slot_clock(&self) -> Option<Slot> {
match self.slot_clock.present_slot() { match self.slot_clock.present_slot() {
Ok(Some(some_slot)) => Some(Slot::new(some_slot)), Ok(Some(some_slot)) => Some(some_slot),
Ok(None) => None, Ok(None) => None,
_ => None, _ => None,
} }

View File

@ -13,7 +13,7 @@ use std::fs::File;
use std::io::prelude::*; use std::io::prelude::*;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair, Validator}; use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair, Slot, Validator};
/// The beacon chain harness simulates a single beacon node with `validator_count` validators connected /// The beacon chain harness simulates a single beacon node with `validator_count` validators connected
/// to it. Each validator is provided a borrow to the beacon chain, where it may read /// to it. Each validator is provided a borrow to the beacon chain, where it may read
@ -40,7 +40,7 @@ impl BeaconChainHarness {
let block_store = Arc::new(BeaconBlockStore::new(db.clone())); let block_store = Arc::new(BeaconBlockStore::new(db.clone()));
let state_store = Arc::new(BeaconStateStore::new(db.clone())); let state_store = Arc::new(BeaconStateStore::new(db.clone()));
let slot_clock = TestingSlotClock::new(spec.genesis_slot); let slot_clock = TestingSlotClock::new(spec.genesis_slot.as_u64());
// Remove the validators present in the spec (if any). // Remove the validators present in the spec (if any).
spec.initial_validators = Vec::with_capacity(validator_count); spec.initial_validators = Vec::with_capacity(validator_count);
@ -60,7 +60,7 @@ impl BeaconChainHarness {
.par_iter() .par_iter()
.map(|keypair| Validator { .map(|keypair| Validator {
pubkey: keypair.pk.clone(), pubkey: keypair.pk.clone(),
activation_slot: 0, activation_slot: Slot::new(0),
..std::default::Default::default() ..std::default::Default::default()
}) })
.collect(); .collect();
@ -115,12 +115,12 @@ impl BeaconChainHarness {
/// This is the equivalent of advancing a system clock forward one `SLOT_DURATION`. /// This is the equivalent of advancing a system clock forward one `SLOT_DURATION`.
/// ///
/// Returns the new slot. /// Returns the new slot.
pub fn increment_beacon_chain_slot(&mut self) -> u64 { pub fn increment_beacon_chain_slot(&mut self) -> Slot {
let slot = self.beacon_chain.present_slot() + 1; let slot = self.beacon_chain.present_slot() + 1;
debug!("Incrementing BeaconChain slot to {}.", slot); debug!("Incrementing BeaconChain slot to {}.", slot);
self.beacon_chain.slot_clock.set_slot(slot); self.beacon_chain.slot_clock.set_slot(slot.as_u64());
self.beacon_chain.advance_state(slot).unwrap(); self.beacon_chain.advance_state(slot).unwrap();
slot slot
} }

View File

@ -11,7 +11,7 @@ use db::ClientDB;
use parking_lot::RwLock; use parking_lot::RwLock;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{AttestationData, BeaconBlock, FreeAttestation, PublicKey, Signature}; use types::{AttestationData, BeaconBlock, FreeAttestation, PublicKey, Signature, Slot};
// mod attester; // mod attester;
// mod producer; // mod producer;
@ -51,7 +51,7 @@ impl<T: ClientDB, U: SlotClock> DirectBeaconNode<T, U> {
impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for DirectBeaconNode<T, U> { impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for DirectBeaconNode<T, U> {
fn produce_attestation_data( fn produce_attestation_data(
&self, &self,
_slot: u64, _slot: Slot,
shard: u64, shard: u64,
) -> Result<Option<AttestationData>, NodeError> { ) -> Result<Option<AttestationData>, NodeError> {
match self.beacon_chain.produce_attestation_data(shard) { match self.beacon_chain.produce_attestation_data(shard) {
@ -87,7 +87,7 @@ impl<T: ClientDB, U: SlotClock> BeaconBlockNode for DirectBeaconNode<T, U> {
/// Requests a new `BeaconBlock from the `BeaconChain`. /// Requests a new `BeaconBlock from the `BeaconChain`.
fn produce_beacon_block( fn produce_beacon_block(
&self, &self,
slot: u64, slot: Slot,
randao_reveal: &Signature, randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconBlockNodeError> { ) -> Result<Option<BeaconBlock>, BeaconBlockNodeError> {
let (block, _state) = self let (block, _state) = self

View File

@ -8,7 +8,7 @@ use block_producer::{
use db::ClientDB; use db::ClientDB;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::PublicKey; use types::{PublicKey, Slot};
/// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from /// Connects directly to a borrowed `BeaconChain` and reads attester/proposer duties directly from
/// it. /// it.
@ -27,7 +27,7 @@ impl<T: ClientDB, U: SlotClock> DirectDuties<T, U> {
} }
impl<T: ClientDB, U: SlotClock> ProducerDutiesReader for DirectDuties<T, U> { impl<T: ClientDB, U: SlotClock> ProducerDutiesReader for DirectDuties<T, U> {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, ProducerDutiesReaderError> { fn is_block_production_slot(&self, slot: Slot) -> Result<bool, ProducerDutiesReaderError> {
let validator_index = self let validator_index = self
.beacon_chain .beacon_chain
.validator_index(&self.pubkey) .validator_index(&self.pubkey)
@ -49,7 +49,7 @@ impl<T: ClientDB, U: SlotClock> AttesterDutiesReader for DirectDuties<T, U> {
} }
} }
fn attestation_shard(&self, slot: u64) -> Result<Option<u64>, AttesterDutiesReaderError> { fn attestation_shard(&self, slot: Slot) -> Result<Option<u64>, AttesterDutiesReaderError> {
if let Some(validator_index) = self.validator_index() { if let Some(validator_index) = self.validator_index() {
match self match self
.beacon_chain .beacon_chain

View File

@ -9,7 +9,7 @@ use block_producer::{BlockProducer, Error as BlockPollError};
use db::MemoryDB; use db::MemoryDB;
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair}; use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair, Slot};
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum BlockProduceError { pub enum BlockProduceError {
@ -59,7 +59,7 @@ impl ValidatorHarness {
beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock>>, beacon_chain: Arc<BeaconChain<MemoryDB, TestingSlotClock>>,
spec: Arc<ChainSpec>, spec: Arc<ChainSpec>,
) -> Self { ) -> Self {
let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot)); let slot_clock = Arc::new(TestingSlotClock::new(spec.genesis_slot.as_u64()));
let signer = Arc::new(LocalSigner::new(keypair.clone())); let signer = Arc::new(LocalSigner::new(keypair.clone()));
let beacon_node = Arc::new(DirectBeaconNode::new(beacon_chain.clone())); let beacon_node = Arc::new(DirectBeaconNode::new(beacon_chain.clone()));
let epoch_map = Arc::new(DirectDuties::new(keypair.pk.clone(), beacon_chain.clone())); let epoch_map = Arc::new(DirectDuties::new(keypair.pk.clone(), beacon_chain.clone()));
@ -127,7 +127,7 @@ impl ValidatorHarness {
/// Set the validators slot clock to the specified slot. /// Set the validators slot clock to the specified slot.
/// ///
/// The validators slot clock will always read this value until it is set to something else. /// The validators slot clock will always read this value until it is set to something else.
pub fn set_slot(&mut self, slot: u64) { pub fn set_slot(&mut self, slot: Slot) {
self.slot_clock.set_slot(slot) self.slot_clock.set_slot(slot.as_u64())
} }
} }

View File

@ -1,13 +1,13 @@
use env_logger::{Builder, Env}; use env_logger::{Builder, Env};
use log::debug; use log::debug;
use test_harness::BeaconChainHarness; use test_harness::BeaconChainHarness;
use types::ChainSpec; use types::{ChainSpec, Slot};
#[test] #[test]
#[ignore] #[ignore]
fn it_can_build_on_genesis_block() { fn it_can_build_on_genesis_block() {
let mut spec = ChainSpec::foundation(); let mut spec = ChainSpec::foundation();
spec.genesis_slot = spec.epoch_length * 8; spec.genesis_slot = Slot::new(spec.epoch_length * 8);
/* /*
spec.shard_count = spec.shard_count / 8; spec.shard_count = spec.shard_count / 8;

View File

@ -3,7 +3,7 @@ mod traits;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{AttestationData, FreeAttestation, Signature}; use types::{AttestationData, FreeAttestation, Signature, Slot};
pub use self::traits::{ pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
@ -13,14 +13,14 @@ const PHASE_0_CUSTODY_BIT: bool = false;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum PollOutcome { pub enum PollOutcome {
AttestationProduced(u64), AttestationProduced(Slot),
AttestationNotRequired(u64), AttestationNotRequired(Slot),
SlashableAttestationNotProduced(u64), SlashableAttestationNotProduced(Slot),
BeaconNodeUnableToProduceAttestation(u64), BeaconNodeUnableToProduceAttestation(Slot),
ProducerDutiesUnknown(u64), ProducerDutiesUnknown(Slot),
SlotAlreadyProcessed(u64), SlotAlreadyProcessed(Slot),
SignerRejection(u64), SignerRejection(Slot),
ValidatorIsUnknown(u64), ValidatorIsUnknown(Slot),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -40,7 +40,7 @@ pub enum Error {
/// ///
/// Relies upon an external service to keep the `EpochDutiesMap` updated. /// Relies upon an external service to keep the `EpochDutiesMap` updated.
pub struct Attester<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> { pub struct Attester<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> {
pub last_processed_slot: Option<u64>, pub last_processed_slot: Option<Slot>,
duties: Arc<V>, duties: Arc<V>,
slot_clock: Arc<T>, slot_clock: Arc<T>,
beacon_node: Arc<U>, beacon_node: Arc<U>,
@ -91,7 +91,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V,
} }
} }
fn produce_attestation(&mut self, slot: u64, shard: u64) -> Result<PollOutcome, Error> { fn produce_attestation(&mut self, slot: Slot, shard: u64) -> Result<PollOutcome, Error> {
let attestation_data = match self.beacon_node.produce_attestation_data(slot, shard)? { let attestation_data = match self.beacon_node.produce_attestation_data(slot, shard)? {
Some(attestation_data) => attestation_data, Some(attestation_data) => attestation_data,
None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)), None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)),
@ -122,7 +122,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V,
Ok(PollOutcome::AttestationProduced(slot)) Ok(PollOutcome::AttestationProduced(slot))
} }
fn is_processed_slot(&self, slot: u64) -> bool { fn is_processed_slot(&self, slot: Slot) -> bool {
match self.last_processed_slot { match self.last_processed_slot {
Some(processed_slot) if slot <= processed_slot => true, Some(processed_slot) if slot <= processed_slot => true,
_ => false, _ => false,
@ -193,7 +193,7 @@ mod tests {
let signer = Arc::new(LocalSigner::new(Keypair::random())); let signer = Arc::new(LocalSigner::new(Keypair::random()));
let mut duties = EpochMap::new(spec.epoch_length); let mut duties = EpochMap::new(spec.epoch_length);
let attest_slot = 100; let attest_slot = Slot::new(100);
let attest_epoch = attest_slot / spec.epoch_length; let attest_epoch = attest_slot / spec.epoch_length;
let attest_shard = 12; let attest_shard = 12;
duties.insert_attestation_shard(attest_slot, attest_shard); duties.insert_attestation_shard(attest_slot, attest_shard);
@ -212,28 +212,28 @@ mod tests {
beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidAttestation)); beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidAttestation));
// One slot before attestation slot... // One slot before attestation slot...
slot_clock.set_slot(attest_slot - 1); slot_clock.set_slot(attest_slot.as_u64() - 1);
assert_eq!( assert_eq!(
attester.poll(), attester.poll(),
Ok(PollOutcome::AttestationNotRequired(attest_slot - 1)) Ok(PollOutcome::AttestationNotRequired(attest_slot - 1))
); );
// On the attest slot... // On the attest slot...
slot_clock.set_slot(attest_slot); slot_clock.set_slot(attest_slot.as_u64());
assert_eq!( assert_eq!(
attester.poll(), attester.poll(),
Ok(PollOutcome::AttestationProduced(attest_slot)) Ok(PollOutcome::AttestationProduced(attest_slot))
); );
// Trying the same attest slot again... // Trying the same attest slot again...
slot_clock.set_slot(attest_slot); slot_clock.set_slot(attest_slot.as_u64());
assert_eq!( assert_eq!(
attester.poll(), attester.poll(),
Ok(PollOutcome::SlotAlreadyProcessed(attest_slot)) Ok(PollOutcome::SlotAlreadyProcessed(attest_slot))
); );
// One slot after the attest slot... // One slot after the attest slot...
slot_clock.set_slot(attest_slot + 1); slot_clock.set_slot(attest_slot.as_u64() + 1);
assert_eq!( assert_eq!(
attester.poll(), attester.poll(),
Ok(PollOutcome::AttestationNotRequired(attest_slot + 1)) Ok(PollOutcome::AttestationNotRequired(attest_slot + 1))
@ -241,7 +241,7 @@ mod tests {
// In an epoch without known duties... // In an epoch without known duties...
let slot = (attest_epoch + 1) * spec.epoch_length; let slot = (attest_epoch + 1) * spec.epoch_length;
slot_clock.set_slot(slot); slot_clock.set_slot(slot.into());
assert_eq!( assert_eq!(
attester.poll(), attester.poll(),
Ok(PollOutcome::ProducerDutiesUnknown(slot)) Ok(PollOutcome::ProducerDutiesUnknown(slot))

View File

@ -1,10 +1,11 @@
use crate::{DutiesReader, DutiesReaderError}; use crate::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use types::{Epoch, Slot};
pub struct EpochMap { pub struct EpochMap {
epoch_length: u64, epoch_length: u64,
validator_index: Option<u64>, validator_index: Option<u64>,
map: HashMap<u64, (u64, u64)>, map: HashMap<Epoch, (Slot, u64)>,
} }
impl EpochMap { impl EpochMap {
@ -16,9 +17,8 @@ impl EpochMap {
} }
} }
pub fn insert_attestation_shard(&mut self, slot: u64, shard: u64) { pub fn insert_attestation_shard(&mut self, slot: Slot, shard: u64) {
let epoch = slot / self.epoch_length; let epoch = slot.epoch(self.epoch_length);
self.map.insert(epoch, (slot, shard)); self.map.insert(epoch, (slot, shard));
} }
@ -28,8 +28,8 @@ impl EpochMap {
} }
impl DutiesReader for EpochMap { impl DutiesReader for EpochMap {
fn attestation_shard(&self, slot: u64) -> Result<Option<u64>, DutiesReaderError> { fn attestation_shard(&self, slot: Slot) -> Result<Option<u64>, DutiesReaderError> {
let epoch = slot / self.epoch_length; let epoch = slot.epoch(self.epoch_length);
match self.map.get(&epoch) { match self.map.get(&epoch) {
Some((attest_slot, attest_shard)) if *attest_slot == slot => Ok(Some(*attest_shard)), Some((attest_slot, attest_shard)) if *attest_slot == slot => Ok(Some(*attest_shard)),

View File

@ -1,6 +1,6 @@
use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome}; use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome};
use std::sync::RwLock; use std::sync::RwLock;
use types::{AttestationData, FreeAttestation}; use types::{AttestationData, FreeAttestation, Slot};
type ProduceResult = Result<Option<AttestationData>, BeaconNodeError>; type ProduceResult = Result<Option<AttestationData>, BeaconNodeError>;
type PublishResult = Result<PublishOutcome, BeaconNodeError>; type PublishResult = Result<PublishOutcome, BeaconNodeError>;
@ -8,7 +8,7 @@ type PublishResult = Result<PublishOutcome, BeaconNodeError>;
/// A test-only struct used to simulate a Beacon Node. /// A test-only struct used to simulate a Beacon Node.
#[derive(Default)] #[derive(Default)]
pub struct SimulatedBeaconNode { pub struct SimulatedBeaconNode {
pub produce_input: RwLock<Option<(u64, u64)>>, pub produce_input: RwLock<Option<(Slot, u64)>>,
pub produce_result: RwLock<Option<ProduceResult>>, pub produce_result: RwLock<Option<ProduceResult>>,
pub publish_input: RwLock<Option<FreeAttestation>>, pub publish_input: RwLock<Option<FreeAttestation>>,
@ -26,7 +26,7 @@ impl SimulatedBeaconNode {
} }
impl BeaconNode for SimulatedBeaconNode { impl BeaconNode for SimulatedBeaconNode {
fn produce_attestation_data(&self, slot: u64, shard: u64) -> ProduceResult { fn produce_attestation_data(&self, slot: Slot, shard: u64) -> ProduceResult {
*self.produce_input.write().unwrap() = Some((slot, shard)); *self.produce_input.write().unwrap() = Some((slot, shard));
match *self.produce_result.read().unwrap() { match *self.produce_result.read().unwrap() {
Some(ref r) => r.clone(), Some(ref r) => r.clone(),

View File

@ -1,4 +1,4 @@
use types::{AttestationData, FreeAttestation, Signature}; use types::{AttestationData, FreeAttestation, Signature, Slot};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum BeaconNodeError { pub enum BeaconNodeError {
@ -16,7 +16,7 @@ pub enum PublishOutcome {
pub trait BeaconNode: Send + Sync { pub trait BeaconNode: Send + Sync {
fn produce_attestation_data( fn produce_attestation_data(
&self, &self,
slot: u64, slot: Slot,
shard: u64, shard: u64,
) -> Result<Option<AttestationData>, BeaconNodeError>; ) -> Result<Option<AttestationData>, BeaconNodeError>;
@ -37,7 +37,7 @@ pub enum DutiesReaderError {
/// Informs a validator of their duties (e.g., block production). /// Informs a validator of their duties (e.g., block production).
pub trait DutiesReader: Send + Sync { pub trait DutiesReader: Send + Sync {
/// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.` /// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.`
fn attestation_shard(&self, slot: u64) -> Result<Option<u64>, DutiesReaderError>; fn attestation_shard(&self, slot: Slot) -> Result<Option<u64>, DutiesReaderError>;
/// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.` /// Returns `Some(shard)` if this slot is an attestation slot. Otherwise, returns `None.`
fn validator_index(&self) -> Option<u64>; fn validator_index(&self) -> Option<u64>;

View File

@ -4,7 +4,7 @@ mod traits;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use ssz::ssz_encode; use ssz::ssz_encode;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, PublicKey}; use types::{BeaconBlock, ChainSpec, PublicKey, Slot};
pub use self::traits::{ pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
@ -13,21 +13,21 @@ pub use self::traits::{
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum PollOutcome { pub enum PollOutcome {
/// A new block was produced. /// A new block was produced.
BlockProduced(u64), BlockProduced(Slot),
/// A block was not produced as it would have been slashable. /// A block was not produced as it would have been slashable.
SlashableBlockNotProduced(u64), SlashableBlockNotProduced(Slot),
/// The validator duties did not require a block to be produced. /// The validator duties did not require a block to be produced.
BlockProductionNotRequired(u64), BlockProductionNotRequired(Slot),
/// The duties for the present epoch were not found. /// The duties for the present epoch were not found.
ProducerDutiesUnknown(u64), ProducerDutiesUnknown(Slot),
/// The slot has already been processed, execution was skipped. /// The slot has already been processed, execution was skipped.
SlotAlreadyProcessed(u64), SlotAlreadyProcessed(Slot),
/// The Beacon Node was unable to produce a block at that slot. /// The Beacon Node was unable to produce a block at that slot.
BeaconNodeUnableToProduceBlock(u64), BeaconNodeUnableToProduceBlock(Slot),
/// The signer failed to sign the message. /// The signer failed to sign the message.
SignerRejection(u64), SignerRejection(Slot),
/// The public key for this validator is not an active validator. /// The public key for this validator is not an active validator.
ValidatorIsUnknown(u64), ValidatorIsUnknown(Slot),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -47,7 +47,7 @@ pub enum Error {
/// ///
/// Relies upon an external service to keep the `EpochDutiesMap` updated. /// Relies upon an external service to keep the `EpochDutiesMap` updated.
pub struct BlockProducer<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> { pub struct BlockProducer<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> {
pub last_processed_slot: Option<u64>, pub last_processed_slot: Option<Slot>,
pubkey: PublicKey, pubkey: PublicKey,
spec: Arc<ChainSpec>, spec: Arc<ChainSpec>,
epoch_map: Arc<V>, epoch_map: Arc<V>,
@ -115,7 +115,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
} }
} }
fn is_processed_slot(&self, slot: u64) -> bool { fn is_processed_slot(&self, slot: Slot) -> bool {
match self.last_processed_slot { match self.last_processed_slot {
Some(processed_slot) if processed_slot >= slot => true, Some(processed_slot) if processed_slot >= slot => true,
_ => false, _ => false,
@ -132,7 +132,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
/// ///
/// The slash-protection code is not yet implemented. There is zero protection against /// The slash-protection code is not yet implemented. There is zero protection against
/// slashing. /// slashing.
fn produce_block(&mut self, slot: u64) -> Result<PollOutcome, Error> { fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
let randao_reveal = { let randao_reveal = {
let producer_nonce = self.beacon_node.proposer_nonce(&self.pubkey)?; let producer_nonce = self.beacon_node.proposer_nonce(&self.pubkey)?;
@ -236,8 +236,8 @@ mod tests {
let signer = Arc::new(LocalSigner::new(Keypair::random())); let signer = Arc::new(LocalSigner::new(Keypair::random()));
let mut epoch_map = EpochMap::new(spec.epoch_length); let mut epoch_map = EpochMap::new(spec.epoch_length);
let produce_slot = 100; let produce_slot = Slot::new(100);
let produce_epoch = produce_slot / spec.epoch_length; let produce_epoch = produce_slot.epoch(spec.epoch_length);
epoch_map.map.insert(produce_epoch, produce_slot); epoch_map.map.insert(produce_epoch, produce_slot);
let epoch_map = Arc::new(epoch_map); let epoch_map = Arc::new(epoch_map);
let keypair = Keypair::random(); let keypair = Keypair::random();
@ -257,39 +257,39 @@ mod tests {
beacon_node.set_next_nonce_result(Ok(0)); beacon_node.set_next_nonce_result(Ok(0));
// One slot before production slot... // One slot before production slot...
slot_clock.set_slot(produce_slot - 1); slot_clock.set_slot(produce_slot.as_u64() - 1);
assert_eq!( assert_eq!(
block_producer.poll(), block_producer.poll(),
Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1))
); );
// On the produce slot... // On the produce slot...
slot_clock.set_slot(produce_slot); slot_clock.set_slot(produce_slot.as_u64());
assert_eq!( assert_eq!(
block_producer.poll(), block_producer.poll(),
Ok(PollOutcome::BlockProduced(produce_slot)) Ok(PollOutcome::BlockProduced(produce_slot.into()))
); );
// Trying the same produce slot again... // Trying the same produce slot again...
slot_clock.set_slot(produce_slot); slot_clock.set_slot(produce_slot.as_u64());
assert_eq!( assert_eq!(
block_producer.poll(), block_producer.poll(),
Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) Ok(PollOutcome::SlotAlreadyProcessed(produce_slot))
); );
// One slot after the produce slot... // One slot after the produce slot...
slot_clock.set_slot(produce_slot + 1); slot_clock.set_slot(produce_slot.as_u64() + 1);
assert_eq!( assert_eq!(
block_producer.poll(), block_producer.poll(),
Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1))
); );
// In an epoch without known duties... // In an epoch without known duties...
let slot = (produce_epoch + 1) * spec.epoch_length; let slot = (produce_epoch.as_u64() + 1) * spec.epoch_length;
slot_clock.set_slot(slot); slot_clock.set_slot(slot);
assert_eq!( assert_eq!(
block_producer.poll(), block_producer.poll(),
Ok(PollOutcome::ProducerDutiesUnknown(slot)) Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot)))
); );
} }
} }

View File

@ -1,9 +1,10 @@
use crate::{DutiesReader, DutiesReaderError}; use crate::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use types::{Epoch, Slot};
pub struct EpochMap { pub struct EpochMap {
epoch_length: u64, epoch_length: u64,
pub map: HashMap<u64, u64>, pub map: HashMap<Epoch, Slot>,
} }
impl EpochMap { impl EpochMap {
@ -16,8 +17,8 @@ impl EpochMap {
} }
impl DutiesReader for EpochMap { impl DutiesReader for EpochMap {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, DutiesReaderError> { fn is_block_production_slot(&self, slot: Slot) -> Result<bool, DutiesReaderError> {
let epoch = slot / self.epoch_length; let epoch = slot.epoch(self.epoch_length);
match self.map.get(&epoch) { match self.map.get(&epoch) {
Some(s) if *s == slot => Ok(true), Some(s) if *s == slot => Ok(true),
Some(s) if *s != slot => Ok(false), Some(s) if *s != slot => Ok(false),

View File

@ -1,6 +1,6 @@
use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome}; use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome};
use std::sync::RwLock; use std::sync::RwLock;
use types::{BeaconBlock, PublicKey, Signature}; use types::{BeaconBlock, PublicKey, Signature, Slot};
type NonceResult = Result<u64, BeaconNodeError>; type NonceResult = Result<u64, BeaconNodeError>;
type ProduceResult = Result<Option<BeaconBlock>, BeaconNodeError>; type ProduceResult = Result<Option<BeaconBlock>, BeaconNodeError>;
@ -12,7 +12,7 @@ pub struct SimulatedBeaconNode {
pub nonce_input: RwLock<Option<PublicKey>>, pub nonce_input: RwLock<Option<PublicKey>>,
pub nonce_result: RwLock<Option<NonceResult>>, pub nonce_result: RwLock<Option<NonceResult>>,
pub produce_input: RwLock<Option<(u64, Signature)>>, pub produce_input: RwLock<Option<(Slot, Signature)>>,
pub produce_result: RwLock<Option<ProduceResult>>, pub produce_result: RwLock<Option<ProduceResult>>,
pub publish_input: RwLock<Option<BeaconBlock>>, pub publish_input: RwLock<Option<BeaconBlock>>,
@ -46,7 +46,7 @@ impl BeaconNode for SimulatedBeaconNode {
} }
/// Returns the value specified by the `set_next_produce_result`. /// Returns the value specified by the `set_next_produce_result`.
fn produce_beacon_block(&self, slot: u64, randao_reveal: &Signature) -> ProduceResult { fn produce_beacon_block(&self, slot: Slot, randao_reveal: &Signature) -> ProduceResult {
*self.produce_input.write().unwrap() = Some((slot, randao_reveal.clone())); *self.produce_input.write().unwrap() = Some((slot, randao_reveal.clone()));
match *self.produce_result.read().unwrap() { match *self.produce_result.read().unwrap() {
Some(ref r) => r.clone(), Some(ref r) => r.clone(),

View File

@ -1,4 +1,4 @@
use types::{BeaconBlock, PublicKey, Signature}; use types::{BeaconBlock, PublicKey, Signature, Slot};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum BeaconNodeError { pub enum BeaconNodeError {
@ -22,7 +22,7 @@ pub trait BeaconNode: Send + Sync {
/// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot.
fn produce_beacon_block( fn produce_beacon_block(
&self, &self,
slot: u64, slot: Slot,
randao_reveal: &Signature, randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconNodeError>; ) -> Result<Option<BeaconBlock>, BeaconNodeError>;
@ -42,7 +42,7 @@ pub enum DutiesReaderError {
/// Informs a validator of their duties (e.g., block production). /// Informs a validator of their duties (e.g., block production).
pub trait DutiesReader: Send + Sync { pub trait DutiesReader: Send + Sync {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, DutiesReaderError>; fn is_block_production_slot(&self, slot: Slot) -> Result<bool, DutiesReaderError>;
} }
/// Signs message using an internally-maintained private key. /// Signs message using an internally-maintained private key.

View File

@ -6,7 +6,7 @@ use db::stores::BeaconBlockStore;
use db::{ClientDB, DBError}; use db::{ClientDB, DBError};
use ssz::{Decodable, DecodeError}; use ssz::{Decodable, DecodeError};
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, Hash256}; use types::{BeaconBlock, Hash256, Slot};
pub enum ForkChoiceError { pub enum ForkChoiceError {
BadSszInDatabase, BadSszInDatabase,
@ -37,7 +37,7 @@ where
/* /*
* Loop through all the head blocks and find the highest slot. * Loop through all the head blocks and find the highest slot.
*/ */
let highest_slot: Option<u64> = None; let highest_slot: Option<Slot> = None;
for (_, block) in &head_blocks { for (_, block) in &head_blocks {
let slot = block.slot; let slot = block.slot;

View File

@ -17,5 +17,6 @@ rand = "0.5.5"
serde = "1.0" serde = "1.0"
serde_derive = "1.0" serde_derive = "1.0"
serde_json = "1.0" serde_json = "1.0"
slog = "^2.2.3"
ssz = { path = "../utils/ssz" } ssz = { path = "../utils/ssz" }
vec_shuffle = { path = "../utils/vec_shuffle" } vec_shuffle = { path = "../utils/vec_shuffle" }

View File

@ -12,6 +12,7 @@
use crate::test_utils::TestRandom; use crate::test_utils::TestRandom;
use rand::RngCore; use rand::RngCore;
use serde_derive::Serialize; use serde_derive::Serialize;
use slog;
use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash}; use ssz::{hash, Decodable, DecodeError, Encodable, SszStream, TreeHash};
use std::cmp::{Ord, Ordering}; use std::cmp::{Ord, Ordering};
use std::fmt; use std::fmt;
@ -162,6 +163,15 @@ macro_rules! impl_math {
*self - other.into() *self - other.into()
} }
pub fn checked_div<T: Into<$type>>(&self, rhs: T) -> Option<$type> {
let rhs: $type = rhs.into();
if rhs == 0 {
None
} else {
Some(*self / rhs)
}
}
pub fn is_power_of_two(&self) -> bool { pub fn is_power_of_two(&self) -> bool {
self.0.is_power_of_two() self.0.is_power_of_two()
} }
@ -183,6 +193,17 @@ macro_rules! impl_display {
write!(f, "{}", self.0) write!(f, "{}", self.0)
} }
} }
impl slog::Value for $type {
fn serialize(
&self,
record: &slog::Record,
key: slog::Key,
serializer: &mut slog::Serializer,
) -> slog::Result {
self.0.serialize(record, key, serializer)
}
}
}; };
} }

View File

@ -109,7 +109,7 @@ fn initial_validators_for_testing() -> Vec<Validator> {
let validator = Validator { let validator = Validator {
pubkey: keypair.pk.clone(), pubkey: keypair.pk.clone(),
withdrawal_credentials: Hash256::zero(), withdrawal_credentials: Hash256::zero(),
proposer_slots: Slot::from(0_u64), proposer_slots: 0,
activation_slot: Slot::max_value(), activation_slot: Slot::max_value(),
exit_slot: Slot::max_value(), exit_slot: Slot::max_value(),
withdrawal_slot: Slot::max_value(), withdrawal_slot: Slot::max_value(),

View File

@ -46,7 +46,7 @@ fn status_flag_from_byte(flag: u8) -> Result<Option<StatusFlags>, StatusFlagsDec
pub struct Validator { pub struct Validator {
pub pubkey: PublicKey, pub pubkey: PublicKey,
pub withdrawal_credentials: Hash256, pub withdrawal_credentials: Hash256,
pub proposer_slots: Slot, pub proposer_slots: u64,
pub activation_slot: Slot, pub activation_slot: Slot,
pub exit_slot: Slot, pub exit_slot: Slot,
pub withdrawal_slot: Slot, pub withdrawal_slot: Slot,
@ -70,7 +70,7 @@ impl Default for Validator {
Self { Self {
pubkey: PublicKey::default(), pubkey: PublicKey::default(),
withdrawal_credentials: Hash256::default(), withdrawal_credentials: Hash256::default(),
proposer_slots: Slot::from(0_u64), proposer_slots: 0,
activation_slot: Slot::from(std::u64::MAX), activation_slot: Slot::from(std::u64::MAX),
exit_slot: Slot::from(std::u64::MAX), exit_slot: Slot::from(std::u64::MAX),
withdrawal_slot: Slot::from(std::u64::MAX), withdrawal_slot: Slot::from(std::u64::MAX),

View File

@ -5,3 +5,4 @@ authors = ["Paul Hauner <paul@paulhauner.com>"]
edition = "2018" edition = "2018"
[dependencies] [dependencies]
types = { path = "../../types" }

View File

@ -3,9 +3,10 @@ mod testing_slot_clock;
pub use crate::system_time_slot_clock::{Error as SystemTimeSlotClockError, SystemTimeSlotClock}; pub use crate::system_time_slot_clock::{Error as SystemTimeSlotClockError, SystemTimeSlotClock};
pub use crate::testing_slot_clock::{Error as TestingSlotClockError, TestingSlotClock}; pub use crate::testing_slot_clock::{Error as TestingSlotClockError, TestingSlotClock};
pub use types::Slot;
pub trait SlotClock: Send + Sync { pub trait SlotClock: Send + Sync {
type Error; type Error;
fn present_slot(&self) -> Result<Option<u64>, Self::Error>; fn present_slot(&self) -> Result<Option<Slot>, Self::Error>;
} }

View File

@ -1,5 +1,6 @@
use super::SlotClock; use super::SlotClock;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use types::Slot;
pub use std::time::SystemTimeError; pub use std::time::SystemTimeError;
@ -38,7 +39,7 @@ impl SystemTimeSlotClock {
impl SlotClock for SystemTimeSlotClock { impl SlotClock for SystemTimeSlotClock {
type Error = Error; type Error = Error;
fn present_slot(&self) -> Result<Option<u64>, Error> { fn present_slot(&self) -> Result<Option<Slot>, Error> {
let syslot_time = SystemTime::now(); let syslot_time = SystemTime::now();
let duration_since_epoch = syslot_time.duration_since(SystemTime::UNIX_EPOCH)?; let duration_since_epoch = syslot_time.duration_since(SystemTime::UNIX_EPOCH)?;
let duration_since_genesis = let duration_since_genesis =
@ -56,8 +57,10 @@ impl From<SystemTimeError> for Error {
} }
} }
fn slot_from_duration(slot_duration_seconds: u64, duration: Duration) -> Option<u64> { fn slot_from_duration(slot_duration_seconds: u64, duration: Duration) -> Option<Slot> {
duration.as_secs().checked_div(slot_duration_seconds) Some(Slot::new(
duration.as_secs().checked_div(slot_duration_seconds)?,
))
} }
#[cfg(test)] #[cfg(test)]
@ -81,19 +84,19 @@ mod tests {
genesis_seconds: genesis, genesis_seconds: genesis,
slot_duration_seconds: slot_time, slot_duration_seconds: slot_time,
}; };
assert_eq!(clock.present_slot().unwrap(), Some(89)); assert_eq!(clock.present_slot().unwrap(), Some(Slot::new(89)));
let clock = SystemTimeSlotClock { let clock = SystemTimeSlotClock {
genesis_seconds: since_epoch.as_secs(), genesis_seconds: since_epoch.as_secs(),
slot_duration_seconds: slot_time, slot_duration_seconds: slot_time,
}; };
assert_eq!(clock.present_slot().unwrap(), Some(0)); assert_eq!(clock.present_slot().unwrap(), Some(Slot::new(0)));
let clock = SystemTimeSlotClock { let clock = SystemTimeSlotClock {
genesis_seconds: since_epoch.as_secs() - slot_time * 42 - 5, genesis_seconds: since_epoch.as_secs() - slot_time * 42 - 5,
slot_duration_seconds: slot_time, slot_duration_seconds: slot_time,
}; };
assert_eq!(clock.present_slot().unwrap(), Some(42)); assert_eq!(clock.present_slot().unwrap(), Some(Slot::new(42)));
} }
#[test] #[test]
@ -102,23 +105,23 @@ mod tests {
assert_eq!( assert_eq!(
slot_from_duration(slot_time, Duration::from_secs(0)), slot_from_duration(slot_time, Duration::from_secs(0)),
Some(0) Some(Slot::new(0))
); );
assert_eq!( assert_eq!(
slot_from_duration(slot_time, Duration::from_secs(10)), slot_from_duration(slot_time, Duration::from_secs(10)),
Some(0) Some(Slot::new(0))
); );
assert_eq!( assert_eq!(
slot_from_duration(slot_time, Duration::from_secs(100)), slot_from_duration(slot_time, Duration::from_secs(100)),
Some(1) Some(Slot::new(1))
); );
assert_eq!( assert_eq!(
slot_from_duration(slot_time, Duration::from_secs(101)), slot_from_duration(slot_time, Duration::from_secs(101)),
Some(1) Some(Slot::new(1))
); );
assert_eq!( assert_eq!(
slot_from_duration(slot_time, Duration::from_secs(1000)), slot_from_duration(slot_time, Duration::from_secs(1000)),
Some(10) Some(Slot::new(10))
); );
} }

View File

@ -1,5 +1,6 @@
use super::SlotClock; use super::SlotClock;
use std::sync::RwLock; use std::sync::RwLock;
use types::Slot;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error {} pub enum Error {}
@ -27,9 +28,9 @@ impl TestingSlotClock {
impl SlotClock for TestingSlotClock { impl SlotClock for TestingSlotClock {
type Error = Error; type Error = Error;
fn present_slot(&self) -> Result<Option<u64>, Error> { fn present_slot(&self) -> Result<Option<Slot>, Error> {
let slot = *self.slot.read().expect("TestingSlotClock poisoned."); let slot = *self.slot.read().expect("TestingSlotClock poisoned.");
Ok(Some(slot)) Ok(Some(Slot::new(slot)))
} }
} }
@ -40,8 +41,8 @@ mod tests {
#[test] #[test]
fn test_slot_now() { fn test_slot_now() {
let clock = TestingSlotClock::new(10); let clock = TestingSlotClock::new(10);
assert_eq!(clock.present_slot(), Ok(Some(10))); assert_eq!(clock.present_slot(), Ok(Some(Slot::new(10))));
clock.set_slot(123); clock.set_slot(123);
assert_eq!(clock.present_slot(), Ok(Some(123))); assert_eq!(clock.present_slot(), Ok(Some(Slot::new(123))));
} }
} }

View File

@ -41,7 +41,7 @@ pub fn process_deposit(
let validator = Validator { let validator = Validator {
pubkey: deposit_input.pubkey.clone(), pubkey: deposit_input.pubkey.clone(),
withdrawal_credentials: deposit_input.withdrawal_credentials, withdrawal_credentials: deposit_input.withdrawal_credentials,
proposer_slots: Slot::new(0), proposer_slots: 0,
activation_slot: spec.far_future_slot, activation_slot: spec.far_future_slot,
exit_slot: spec.far_future_slot, exit_slot: spec.far_future_slot,
withdrawal_slot: spec.far_future_slot, withdrawal_slot: spec.far_future_slot,

View File

@ -5,7 +5,7 @@ use protos::services::{
use protos::services_grpc::BeaconBlockServiceClient; use protos::services_grpc::BeaconBlockServiceClient;
use ssz::{ssz_encode, Decodable}; use ssz::{ssz_encode, Decodable};
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, PublicKey, Signature}; use types::{BeaconBlock, BeaconBlockBody, Eth1Data, Hash256, PublicKey, Signature, Slot};
/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be /// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be
/// implemented upon it. /// implemented upon it.
@ -32,11 +32,11 @@ impl BeaconNode for BeaconBlockGrpcClient {
/// BN is unable to find a parent block. /// BN is unable to find a parent block.
fn produce_beacon_block( fn produce_beacon_block(
&self, &self,
slot: u64, slot: Slot,
randao_reveal: &Signature, randao_reveal: &Signature,
) -> Result<Option<BeaconBlock>, BeaconNodeError> { ) -> Result<Option<BeaconBlock>, BeaconNodeError> {
let mut req = ProduceBeaconBlockRequest::new(); let mut req = ProduceBeaconBlockRequest::new();
req.set_slot(slot); req.set_slot(slot.as_u64());
let reply = self let reply = self
.client .client
@ -54,7 +54,7 @@ impl BeaconNode for BeaconBlockGrpcClient {
// TODO: this conversion is incomplete; fix it. // TODO: this conversion is incomplete; fix it.
Ok(Some(BeaconBlock { Ok(Some(BeaconBlock {
slot: block.get_slot(), slot: Slot::new(block.get_slot()),
parent_root: Hash256::zero(), parent_root: Hash256::zero(),
state_root: Hash256::zero(), state_root: Hash256::zero(),
randao_reveal, randao_reveal,
@ -88,7 +88,7 @@ impl BeaconNode for BeaconBlockGrpcClient {
// TODO: this conversion is incomplete; fix it. // TODO: this conversion is incomplete; fix it.
let mut grpc_block = GrpcBeaconBlock::new(); let mut grpc_block = GrpcBeaconBlock::new();
grpc_block.set_slot(block.slot); grpc_block.set_slot(block.slot.as_u64());
grpc_block.set_block_root(vec![0]); grpc_block.set_block_root(vec![0]);
grpc_block.set_randao_reveal(ssz_encode(&block.randao_reveal)); grpc_block.set_randao_reveal(ssz_encode(&block.randao_reveal));
grpc_block.set_signature(ssz_encode(&block.signature)); grpc_block.set_signature(ssz_encode(&block.signature));

View File

@ -1,6 +1,7 @@
use block_producer::{DutiesReader, DutiesReaderError}; use block_producer::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::RwLock; use std::sync::RwLock;
use types::{Epoch, 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.
/// ///
@ -10,14 +11,14 @@ use std::sync::RwLock;
#[derive(Debug, PartialEq, Clone, Copy, Default)] #[derive(Debug, PartialEq, Clone, Copy, Default)]
pub struct EpochDuties { pub struct EpochDuties {
pub validator_index: u64, pub validator_index: u64,
pub block_production_slot: Option<u64>, pub block_production_slot: Option<Slot>,
// Future shard info // Future shard info
} }
impl EpochDuties { impl EpochDuties {
/// Returns `true` if the supplied `slot` is a slot in which the validator should produce a /// Returns `true` if the supplied `slot` is a slot in which the validator should produce a
/// block. /// block.
pub fn is_block_production_slot(&self, slot: u64) -> bool { pub fn is_block_production_slot(&self, slot: Slot) -> bool {
match self.block_production_slot { match self.block_production_slot {
Some(s) if s == slot => true, Some(s) if s == slot => true,
_ => false, _ => false,
@ -32,7 +33,7 @@ pub enum EpochDutiesMapError {
/// Maps an `epoch` to some `EpochDuties` for a single validator. /// Maps an `epoch` to some `EpochDuties` for a single validator.
pub struct EpochDutiesMap { pub struct EpochDutiesMap {
pub epoch_length: u64, pub epoch_length: u64,
pub map: RwLock<HashMap<u64, EpochDuties>>, pub map: RwLock<HashMap<Epoch, EpochDuties>>,
} }
impl EpochDutiesMap { impl EpochDutiesMap {
@ -43,7 +44,7 @@ impl EpochDutiesMap {
} }
} }
pub fn get(&self, epoch: u64) -> Result<Option<EpochDuties>, EpochDutiesMapError> { pub fn get(&self, epoch: Epoch) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let map = self.map.read().map_err(|_| EpochDutiesMapError::Poisoned)?; let map = self.map.read().map_err(|_| EpochDutiesMapError::Poisoned)?;
match map.get(&epoch) { match map.get(&epoch) {
Some(duties) => Ok(Some(duties.clone())), Some(duties) => Ok(Some(duties.clone())),
@ -53,7 +54,7 @@ impl EpochDutiesMap {
pub fn insert( pub fn insert(
&self, &self,
epoch: u64, epoch: Epoch,
epoch_duties: EpochDuties, epoch_duties: EpochDuties,
) -> Result<Option<EpochDuties>, EpochDutiesMapError> { ) -> Result<Option<EpochDuties>, EpochDutiesMapError> {
let mut map = self let mut map = self
@ -65,10 +66,8 @@ impl EpochDutiesMap {
} }
impl DutiesReader for EpochDutiesMap { impl DutiesReader for EpochDutiesMap {
fn is_block_production_slot(&self, slot: u64) -> Result<bool, DutiesReaderError> { fn is_block_production_slot(&self, slot: Slot) -> Result<bool, DutiesReaderError> {
let epoch = slot let epoch = slot.epoch(self.epoch_length);
.checked_div(self.epoch_length)
.ok_or_else(|| DutiesReaderError::EpochLengthIsZero)?;
let map = self.map.read().map_err(|_| DutiesReaderError::Poisoned)?; let map = self.map.read().map_err(|_| DutiesReaderError::Poisoned)?;
let duties = map let duties = map

View File

@ -3,7 +3,7 @@ use super::EpochDuties;
use protos::services::{ProposeBlockSlotRequest, PublicKey as IndexRequest}; use protos::services::{ProposeBlockSlotRequest, PublicKey as IndexRequest};
use protos::services_grpc::ValidatorServiceClient; use protos::services_grpc::ValidatorServiceClient;
use ssz::ssz_encode; use ssz::ssz_encode;
use types::PublicKey; use types::{Epoch, PublicKey, Slot};
impl BeaconNode for ValidatorServiceClient { impl BeaconNode for ValidatorServiceClient {
/// Request the shuffling from the Beacon Node (BN). /// Request the shuffling from the Beacon Node (BN).
@ -14,7 +14,7 @@ impl BeaconNode for ValidatorServiceClient {
/// Note: presently only block production information is returned. /// Note: presently only block production information is returned.
fn request_shuffling( fn request_shuffling(
&self, &self,
epoch: u64, epoch: Epoch,
public_key: &PublicKey, public_key: &PublicKey,
) -> Result<Option<EpochDuties>, BeaconNodeError> { ) -> Result<Option<EpochDuties>, BeaconNodeError> {
// Lookup the validator index for the supplied public key. // Lookup the validator index for the supplied public key.
@ -29,7 +29,7 @@ impl BeaconNode for ValidatorServiceClient {
let mut req = ProposeBlockSlotRequest::new(); let mut req = ProposeBlockSlotRequest::new();
req.set_validator_index(validator_index); req.set_validator_index(validator_index);
req.set_epoch(epoch); req.set_epoch(epoch.as_u64());
let reply = self let reply = self
.propose_block_slot(&req) .propose_block_slot(&req)
@ -41,6 +41,11 @@ impl BeaconNode for ValidatorServiceClient {
None None
}; };
let block_production_slot = match block_production_slot {
Some(slot) => Some(Slot::new(slot)),
None => None,
};
Ok(Some(EpochDuties { Ok(Some(EpochDuties {
validator_index, validator_index,
block_production_slot, block_production_slot,

View File

@ -12,20 +12,20 @@ use self::traits::{BeaconNode, BeaconNodeError};
use bls::PublicKey; use bls::PublicKey;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::ChainSpec; use types::{ChainSpec, Epoch, Slot};
#[derive(Debug, PartialEq, Clone, Copy)] #[derive(Debug, PartialEq, Clone, Copy)]
pub enum PollOutcome { pub enum PollOutcome {
/// The `EpochDuties` were not updated during this poll. /// The `EpochDuties` were not updated during this poll.
NoChange(u64), NoChange(Epoch),
/// The `EpochDuties` for the `epoch` were previously unknown, but obtained in the poll. /// The `EpochDuties` for the `epoch` were previously unknown, but obtained in the poll.
NewDuties(u64, EpochDuties), NewDuties(Epoch, EpochDuties),
/// New `EpochDuties` were obtained, different to those which were previously known. This is /// New `EpochDuties` were obtained, different to those which were previously known. This is
/// likely to be the result of chain re-organisation. /// likely to be the result of chain re-organisation.
DutiesChanged(u64, EpochDuties), DutiesChanged(Epoch, EpochDuties),
/// The Beacon Node was unable to return the duties as the validator is unknown, or the /// The Beacon Node was unable to return the duties as the validator is unknown, or the
/// shuffling for the epoch is unknown. /// shuffling for the epoch is unknown.
UnknownValidatorOrEpoch(u64), UnknownValidatorOrEpoch(Epoch),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -62,9 +62,7 @@ impl<T: SlotClock, U: BeaconNode> DutiesManager<T, U> {
.map_err(|_| Error::SlotClockError)? .map_err(|_| Error::SlotClockError)?
.ok_or(Error::SlotUnknowable)?; .ok_or(Error::SlotUnknowable)?;
let epoch = slot let epoch = slot.epoch(self.spec.epoch_length);
.checked_div(self.spec.epoch_length)
.ok_or(Error::EpochLengthIsZero)?;
if let Some(duties) = self.beacon_node.request_shuffling(epoch, &self.pubkey)? { if let Some(duties) = self.beacon_node.request_shuffling(epoch, &self.pubkey)? {
// If these duties were known, check to see if they're updates or identical. // If these duties were known, check to see if they're updates or identical.
@ -130,25 +128,34 @@ mod tests {
// Configure response from the BeaconNode. // Configure response from the BeaconNode.
let duties = EpochDuties { let duties = EpochDuties {
validator_index: 0, validator_index: 0,
block_production_slot: Some(10), block_production_slot: Some(Slot::new(10)),
}; };
beacon_node.set_next_shuffling_result(Ok(Some(duties))); beacon_node.set_next_shuffling_result(Ok(Some(duties)));
// Get the duties for the first time... // Get the duties for the first time...
assert_eq!(manager.poll(), Ok(PollOutcome::NewDuties(0, duties))); assert_eq!(
manager.poll(),
Ok(PollOutcome::NewDuties(Epoch::new(0), duties))
);
// Get the same duties again... // Get the same duties again...
assert_eq!(manager.poll(), Ok(PollOutcome::NoChange(0))); assert_eq!(manager.poll(), Ok(PollOutcome::NoChange(Epoch::new(0))));
// Return new duties. // Return new duties.
let duties = EpochDuties { let duties = EpochDuties {
validator_index: 0, validator_index: 0,
block_production_slot: Some(11), block_production_slot: Some(Slot::new(11)),
}; };
beacon_node.set_next_shuffling_result(Ok(Some(duties))); beacon_node.set_next_shuffling_result(Ok(Some(duties)));
assert_eq!(manager.poll(), Ok(PollOutcome::DutiesChanged(0, duties))); assert_eq!(
manager.poll(),
Ok(PollOutcome::DutiesChanged(Epoch::new(0), duties))
);
// Return no duties. // Return no duties.
beacon_node.set_next_shuffling_result(Ok(None)); beacon_node.set_next_shuffling_result(Ok(None));
assert_eq!(manager.poll(), Ok(PollOutcome::UnknownValidatorOrEpoch(0))); assert_eq!(
manager.poll(),
Ok(PollOutcome::UnknownValidatorOrEpoch(Epoch::new(0)))
);
} }
} }

View File

@ -2,13 +2,14 @@ use super::traits::{BeaconNode, BeaconNodeError};
use super::EpochDuties; use super::EpochDuties;
use bls::PublicKey; use bls::PublicKey;
use std::sync::RwLock; use std::sync::RwLock;
use types::Epoch;
type ShufflingResult = Result<Option<EpochDuties>, BeaconNodeError>; type ShufflingResult = Result<Option<EpochDuties>, BeaconNodeError>;
/// A test-only struct used to simulate a Beacon Node. /// A test-only struct used to simulate a Beacon Node.
#[derive(Default)] #[derive(Default)]
pub struct TestBeaconNode { pub struct TestBeaconNode {
pub request_shuffling_input: RwLock<Option<(u64, PublicKey)>>, pub request_shuffling_input: RwLock<Option<(Epoch, PublicKey)>>,
pub request_shuffling_result: RwLock<Option<ShufflingResult>>, pub request_shuffling_result: RwLock<Option<ShufflingResult>>,
} }
@ -21,7 +22,7 @@ impl TestBeaconNode {
impl BeaconNode for TestBeaconNode { impl BeaconNode for TestBeaconNode {
/// Returns the value specified by the `set_next_shuffling_result`. /// Returns the value specified by the `set_next_shuffling_result`.
fn request_shuffling(&self, epoch: u64, public_key: &PublicKey) -> ShufflingResult { fn request_shuffling(&self, epoch: Epoch, public_key: &PublicKey) -> ShufflingResult {
*self.request_shuffling_input.write().unwrap() = Some((epoch, public_key.clone())); *self.request_shuffling_input.write().unwrap() = Some((epoch, public_key.clone()));
match *self.request_shuffling_result.read().unwrap() { match *self.request_shuffling_result.read().unwrap() {
Some(ref r) => r.clone(), Some(ref r) => r.clone(),

View File

@ -1,5 +1,6 @@
use super::EpochDuties; use super::EpochDuties;
use bls::PublicKey; use bls::PublicKey;
use types::Epoch;
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum BeaconNodeError { pub enum BeaconNodeError {
@ -13,7 +14,7 @@ pub trait BeaconNode: Send + Sync {
/// Returns Ok(None) if the public key is unknown, or the shuffling for that epoch is unknown. /// Returns Ok(None) if the public key is unknown, or the shuffling for that epoch is unknown.
fn request_shuffling( fn request_shuffling(
&self, &self,
epoch: u64, epoch: Epoch,
public_key: &PublicKey, public_key: &PublicKey,
) -> Result<Option<EpochDuties>, BeaconNodeError>; ) -> Result<Option<EpochDuties>, BeaconNodeError>;
} }