Introduce Fork struct to block_producer

It's a pretty crappy solution, IMO. It shouldn't really belong in
"duties" but this gets the job done for now.
This commit is contained in:
Paul Hauner 2019-03-07 13:54:56 +11:00
parent 20ac1bf1f0
commit db3b6cba6d
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
6 changed files with 54 additions and 18 deletions

View File

@ -9,7 +9,7 @@ use db::ClientDB;
use fork_choice::ForkChoice; use fork_choice::ForkChoice;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{PublicKey, Slot}; use types::{Fork, 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.
@ -40,6 +40,10 @@ impl<T: ClientDB, U: SlotClock, F: ForkChoice> ProducerDutiesReader for DirectDu
Err(_) => Err(ProducerDutiesReaderError::UnknownEpoch), Err(_) => Err(ProducerDutiesReaderError::UnknownEpoch),
} }
} }
fn fork(&self) -> Result<Fork, ProducerDutiesReaderError> {
Ok(self.beacon_chain.state.read().fork.clone())
}
} }
impl<T: ClientDB, U: SlotClock, F: ForkChoice> AttesterDutiesReader for DirectDuties<T, U, F> { impl<T: ClientDB, U: SlotClock, F: ForkChoice> AttesterDutiesReader for DirectDuties<T, U, F> {

View File

@ -1,19 +1,15 @@
pub mod test_utils; pub mod test_utils;
mod traits; mod traits;
use int_to_bytes::int_to_bytes32;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use ssz::SignedRoot; use ssz::{SignedRoot, TreeHash};
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Hash256, Proposal, Slot}; use types::{BeaconBlock, ChainSpec, Domain, Hash256, Proposal, Slot};
pub use self::traits::{ pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
}; };
//TODO: obtain the correct domain using a `Fork`.
pub const TEMPORARY_DOMAIN_VALUE: u64 = 0;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum PollOutcome { pub enum PollOutcome {
/// A new block was produced. /// A new block was produced.
@ -32,6 +28,8 @@ pub enum PollOutcome {
SignerRejection(Slot), 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(Slot), ValidatorIsUnknown(Slot),
/// Unable to determine a `Fork` for signature domain generation.
UnableToGetFork(Slot),
} }
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -134,14 +132,20 @@ 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: Slot) -> Result<PollOutcome, Error> { fn produce_block(&mut self, slot: Slot) -> Result<PollOutcome, Error> {
let fork = match self.epoch_map.fork() {
Ok(fork) => fork,
Err(_) => return Ok(PollOutcome::UnableToGetFork(slot)),
};
let randao_reveal = { let randao_reveal = {
// TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`. // TODO: add domain, etc to this message. Also ensure result matches `into_to_bytes32`.
let message = int_to_bytes32(slot.epoch(self.spec.slots_per_epoch).as_u64()); let message = slot.epoch(self.spec.slots_per_epoch).hash_tree_root();
match self match self.signer.sign_randao_reveal(
.signer &message,
.sign_randao_reveal(&message, TEMPORARY_DOMAIN_VALUE) self.spec
{ .get_domain(slot.epoch(self.spec.slots_per_epoch), Domain::Randao, &fork),
) {
None => return Ok(PollOutcome::SignerRejection(slot)), None => return Ok(PollOutcome::SignerRejection(slot)),
Some(signature) => signature, Some(signature) => signature,
} }
@ -152,7 +156,12 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
.produce_beacon_block(slot, &randao_reveal)? .produce_beacon_block(slot, &randao_reveal)?
{ {
if self.safe_to_produce(&block) { if self.safe_to_produce(&block) {
if let Some(block) = self.sign_block(block) { let domain = self.spec.get_domain(
slot.epoch(self.spec.slots_per_epoch),
Domain::Proposal,
&fork,
);
if let Some(block) = self.sign_block(block, domain) {
self.beacon_node.publish_beacon_block(block)?; self.beacon_node.publish_beacon_block(block)?;
Ok(PollOutcome::BlockProduced(slot)) Ok(PollOutcome::BlockProduced(slot))
} else { } else {
@ -170,7 +179,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
/// ///
/// Important: this function will not check to ensure the block is not slashable. This must be /// Important: this function will not check to ensure the block is not slashable. This must be
/// done upstream. /// done upstream.
fn sign_block(&mut self, mut block: BeaconBlock) -> Option<BeaconBlock> { fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option<BeaconBlock> {
self.store_produce(&block); self.store_produce(&block);
let proposal = Proposal { let proposal = Proposal {
@ -182,7 +191,7 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducer<T, U
match self match self
.signer .signer
.sign_block_proposal(&proposal.signed_root()[..], TEMPORARY_DOMAIN_VALUE) .sign_block_proposal(&proposal.signed_root()[..], domain)
{ {
None => None, None => None,
Some(signature) => { Some(signature) => {

View File

@ -1,6 +1,6 @@
use crate::{DutiesReader, DutiesReaderError}; use crate::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use types::{Epoch, Slot}; use types::{Epoch, Fork, Slot};
pub struct EpochMap { pub struct EpochMap {
slots_per_epoch: u64, slots_per_epoch: u64,
@ -25,4 +25,12 @@ impl DutiesReader for EpochMap {
_ => Err(DutiesReaderError::UnknownEpoch), _ => Err(DutiesReaderError::UnknownEpoch),
} }
} }
fn fork(&self) -> Result<Fork, DutiesReaderError> {
Ok(Fork {
previous_version: 0,
current_version: 0,
epoch: Epoch::new(0),
})
}
} }

View File

@ -1,4 +1,4 @@
use types::{BeaconBlock, Signature, Slot}; use types::{BeaconBlock, Fork, Signature, Slot};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub enum BeaconNodeError { pub enum BeaconNodeError {
@ -40,6 +40,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: Slot) -> Result<bool, DutiesReaderError>; fn is_block_production_slot(&self, slot: Slot) -> Result<bool, DutiesReaderError>;
fn fork(&self) -> Result<Fork, DutiesReaderError>;
} }
/// Signs message using an internally-maintained private key. /// Signs message using an internally-maintained private key.

View File

@ -50,6 +50,9 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> BlockProducerServi
Ok(BlockProducerPollOutcome::ValidatorIsUnknown(slot)) => { Ok(BlockProducerPollOutcome::ValidatorIsUnknown(slot)) => {
error!(self.log, "The Beacon Node does not recognise the validator"; "slot" => slot) error!(self.log, "The Beacon Node does not recognise the validator"; "slot" => slot)
} }
Ok(BlockProducerPollOutcome::UnableToGetFork(slot)) => {
error!(self.log, "Unable to get a `Fork` struct to generate signature domains"; "slot" => slot)
}
}; };
std::thread::sleep(Duration::from_millis(self.poll_interval_millis)); std::thread::sleep(Duration::from_millis(self.poll_interval_millis));

View File

@ -1,7 +1,7 @@
use block_proposer::{DutiesReader, DutiesReaderError}; use block_proposer::{DutiesReader, DutiesReaderError};
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::RwLock; use std::sync::RwLock;
use types::{Epoch, Slot}; use types::{Epoch, Fork, 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.
/// ///
@ -75,6 +75,17 @@ impl DutiesReader for EpochDutiesMap {
.ok_or_else(|| DutiesReaderError::UnknownEpoch)?; .ok_or_else(|| DutiesReaderError::UnknownEpoch)?;
Ok(duties.is_block_production_slot(slot)) Ok(duties.is_block_production_slot(slot))
} }
fn fork(&self) -> Result<Fork, DutiesReaderError> {
// TODO: this is garbage data.
//
// It will almost certainly cause signatures to fail verification.
Ok(Fork {
previous_version: 0,
current_version: 0,
epoch: Epoch::new(0),
})
}
} }
// TODO: add tests. // TODO: add tests.