Merged Age's changes and ripped out heaps of now obsolete stuff in the validator client.

- Replaced most instances of PublicKey with KeyPair, since they need to be passed into each validator thread now.
 - Pulled out a bunch of FreeAttestations, and replaced with regular Attestations (as per Paul's suggestion)
 - Started generalising pubkeys to 'signers' (though they are still just Keypairs)
 - Added validator_index into a few structs where relevant
 - Removed the SlotClock and DutiesReader from the BlockProducer and Attester services, since this logic is now abstracted to the higher level process.
 - Added a Hash trait to the Keypair (rather than just pubkey) which assumes the Pubkey uniquely defines it.
This commit is contained in:
Luke Anderson
2019-03-28 15:50:57 +11:00
53 changed files with 3198 additions and 616 deletions

View File

@@ -1,10 +1,10 @@
pub mod test_utils;
mod traits;
use slot_clock::SlotClock;
use ssz::TreeHash;
use std::sync::Arc;
use types::{AttestationData, AttestationDataAndCustodyBit, FreeAttestation, Signature, Slot};
use types::{AttestationData, AttestationDataAndCustodyBit, Attestation, Signature,
AggregateSignature, Slot, AttestationDuty, Bitfield};
pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
@@ -41,89 +41,58 @@ pub enum Error {
/// Ensures that messages are not slashable.
///
/// Relies upon an external service to keep the `EpochDutiesMap` updated.
pub struct Attester<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> {
pub struct Attester<U: BeaconNode, W: Signer> {
pub last_processed_slot: Option<Slot>,
duties: Arc<V>,
slot_clock: Arc<T>,
beacon_node: Arc<U>,
signer: Arc<W>,
}
impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V, W> {
impl<U: BeaconNode, W: Signer> Attester<U, W> {
/// Returns a new instance where `last_processed_slot == 0`.
pub fn new(duties: Arc<V>, slot_clock: Arc<T>, beacon_node: Arc<U>, signer: Arc<W>) -> Self {
pub fn new(beacon_node: Arc<U>, signer: Arc<W>) -> Self {
Self {
last_processed_slot: None,
duties,
slot_clock,
beacon_node,
signer,
}
}
}
impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V, W> {
/// Poll the `BeaconNode` and produce an attestation if required.
pub fn poll(&mut self) -> Result<PollOutcome, Error> {
let slot = self
.slot_clock
.present_slot()
.map_err(|_| Error::SlotClockError)?
.ok_or(Error::SlotUnknowable)?;
impl<B: BeaconNode, W: Signer> Attester<B, W> {
if !self.is_processed_slot(slot) {
self.last_processed_slot = Some(slot);
let shard = match self.duties.attestation_shard(slot) {
Ok(Some(result)) => result,
Ok(None) => return Ok(PollOutcome::AttestationNotRequired(slot)),
Err(DutiesReaderError::UnknownEpoch) => {
return Ok(PollOutcome::ProducerDutiesUnknown(slot));
}
Err(DutiesReaderError::UnknownValidator) => {
return Ok(PollOutcome::ValidatorIsUnknown(slot));
}
Err(DutiesReaderError::EpochLengthIsZero) => return Err(Error::EpochLengthIsZero),
Err(DutiesReaderError::Poisoned) => return Err(Error::EpochMapPoisoned),
};
self.produce_attestation(slot, shard)
} else {
Ok(PollOutcome::SlotAlreadyProcessed(slot))
}
}
fn produce_attestation(&mut self, slot: Slot, shard: u64) -> Result<PollOutcome, Error> {
let attestation_data = match self.beacon_node.produce_attestation_data(slot, shard)? {
fn produce_attestation(&mut self, attestation_duty: AttestationDuty) -> Result<PollOutcome, Error> {
let attestation_data = match self.beacon_node.produce_attestation_data(
attestation_duty.slot,
attestation_duty.shard
)? {
Some(attestation_data) => attestation_data,
None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(slot)),
None => return Ok(PollOutcome::BeaconNodeUnableToProduceAttestation(attestation_duty.slot)),
};
dbg!(&attestation_data);
if !self.safe_to_produce(&attestation_data) {
return Ok(PollOutcome::SlashableAttestationNotProduced(slot));
return Ok(PollOutcome::SlashableAttestationNotProduced(attestation_duty.slot));
}
let signature = match self.sign_attestation_data(&attestation_data) {
Some(signature) => signature,
None => return Ok(PollOutcome::SignerRejection(slot)),
None => return Ok(PollOutcome::SignerRejection(attestation_duty.slot)),
};
let mut agg_sig = AggregateSignature::new();
agg_sig.add(&signature);
let validator_index = match self.duties.validator_index() {
Some(validator_index) => validator_index,
None => return Ok(PollOutcome::ValidatorIsUnknown(slot)),
};
let free_attestation = FreeAttestation {
let attestation = Attestation {
aggregation_bitfield: Bitfield::new(),
data: attestation_data,
signature,
validator_index,
custody_bitfield: Bitfield::from_elem(8, PHASE_0_CUSTODY_BIT),
aggregate_signature: agg_sig,
};
self.beacon_node
.publish_attestation(free_attestation)?;
Ok(PollOutcome::AttestationProduced(slot))
.publish_attestation(attestation)?;
Ok(PollOutcome::AttestationProduced(attestation_duty.slot))
}
fn is_processed_slot(&self, slot: Slot) -> bool {
@@ -182,7 +151,6 @@ impl From<BeaconNodeError> for Error {
mod tests {
use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode};
use super::*;
use slot_clock::TestingSlotClock;
use types::{
test_utils::{SeedableRng, TestRandom, XorShiftRng},
ChainSpec, Keypair,
@@ -198,21 +166,14 @@ mod tests {
let mut rng = XorShiftRng::from_seed([42; 16]);
let spec = Arc::new(ChainSpec::foundation());
let slot_clock = Arc::new(TestingSlotClock::new(0));
let beacon_node = Arc::new(SimulatedBeaconNode::default());
let signer = Arc::new(LocalSigner::new(Keypair::random()));
let mut duties = EpochMap::new(spec.slots_per_epoch);
let attest_slot = Slot::new(100);
let attest_epoch = attest_slot / spec.slots_per_epoch;
let attest_shard = 12;
duties.insert_attestation_shard(attest_slot, attest_shard);
duties.set_validator_index(Some(2));
let duties = Arc::new(duties);
let mut attester = Attester::new(
duties.clone(),
slot_clock.clone(),
beacon_node.clone(),
signer.clone(),
);
@@ -221,6 +182,9 @@ mod tests {
beacon_node.set_next_produce_result(Ok(Some(AttestationData::random_for_test(&mut rng))));
beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidAttestation));
/*
* All these tests are broken because we no longer have a slot clock in the attester
// One slot before attestation slot...
slot_clock.set_slot(attest_slot.as_u64() - 1);
assert_eq!(
@@ -256,5 +220,7 @@ mod tests {
attester.poll(),
Ok(PollOutcome::ProducerDutiesUnknown(slot))
);
*/
}
}

View File

@@ -1,6 +1,6 @@
use crate::traits::{BeaconNode, BeaconNodeError, PublishOutcome};
use std::sync::RwLock;
use types::{AttestationData, FreeAttestation, Slot};
use types::{AttestationData, Attestation, Slot};
type ProduceResult = Result<Option<AttestationData>, BeaconNodeError>;
type PublishResult = Result<PublishOutcome, BeaconNodeError>;
@@ -11,7 +11,7 @@ pub struct SimulatedBeaconNode {
pub produce_input: RwLock<Option<(Slot, u64)>>,
pub produce_result: RwLock<Option<ProduceResult>>,
pub publish_input: RwLock<Option<FreeAttestation>>,
pub publish_input: RwLock<Option<Attestation>>,
pub publish_result: RwLock<Option<PublishResult>>,
}
@@ -34,8 +34,8 @@ impl BeaconNode for SimulatedBeaconNode {
}
}
fn publish_attestation(&self, free_attestation: FreeAttestation) -> PublishResult {
*self.publish_input.write().unwrap() = Some(free_attestation.clone());
fn publish_attestation(&self, attestation: Attestation) -> PublishResult {
*self.publish_input.write().unwrap() = Some(attestation.clone());
match *self.publish_result.read().unwrap() {
Some(ref r) => r.clone(),
None => panic!("TestBeaconNode: publish_result == None"),

View File

@@ -1,4 +1,4 @@
use types::{AttestationData, FreeAttestation, Signature, Slot};
use types::{AttestationData, Attestation, Signature, Slot};
#[derive(Debug, PartialEq, Clone)]
pub enum BeaconNodeError {
@@ -22,7 +22,7 @@ pub trait BeaconNode: Send + Sync {
fn publish_attestation(
&self,
free_attestation: FreeAttestation,
attestation: Attestation,
) -> Result<PublishOutcome, BeaconNodeError>;
}