Add FreeAttesation type

This commit is contained in:
Paul Hauner 2019-01-28 16:21:33 +11:00
parent 5bbffcb053
commit be7e326c33
No known key found for this signature in database
GPG Key ID: D362883A9218FCC6
11 changed files with 92 additions and 66 deletions

View File

@ -1,6 +1,7 @@
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use types::{ use types::{
AggregateSignature, Attestation, AttestationData, BeaconState, Bitfield, ChainSpec, Signature, AggregateSignature, Attestation, AttestationData, BeaconState, Bitfield, ChainSpec,
FreeAttestation, Signature,
}; };
const PHASE_0_CUSTODY_BIT: bool = false; const PHASE_0_CUSTODY_BIT: bool = false;
@ -32,27 +33,30 @@ impl AttestationAggregator {
pub fn process_free_attestation( pub fn process_free_attestation(
&mut self, &mut self,
state: &BeaconState, state: &BeaconState,
attestation_data: &AttestationData, free_attestation: &FreeAttestation,
signature: &Signature,
validator_index: u64,
) -> Result<ProcessOutcome, ProcessError> { ) -> Result<ProcessOutcome, ProcessError> {
let validator_index = validator_index as usize; let validator_index = free_attestation.validator_index as usize;
let signable_message = attestation_data.signable_message(PHASE_0_CUSTODY_BIT); let signable_message = free_attestation.data.signable_message(PHASE_0_CUSTODY_BIT);
let validator_pubkey = &state let validator_pubkey = &state
.validator_registry .validator_registry
.get(validator_index) .get(validator_index)
.ok_or_else(|| ProcessError::BadValidatorIndex)? .ok_or_else(|| ProcessError::BadValidatorIndex)?
.pubkey; .pubkey;
if !signature.verify(&signable_message, &validator_pubkey) { if !free_attestation
.signature
.verify(&signable_message, &validator_pubkey)
{
return Err(ProcessError::BadSignature); return Err(ProcessError::BadSignature);
} }
if let Some(existing_attestation) = self.store.get(&signable_message) { if let Some(existing_attestation) = self.store.get(&signable_message) {
if let Some(updated_attestation) = if let Some(updated_attestation) = aggregate_attestation(
aggregate_attestation(existing_attestation, signature, validator_index) existing_attestation,
{ &free_attestation.signature,
validator_index,
) {
self.store.insert(signable_message, updated_attestation); self.store.insert(signable_message, updated_attestation);
Ok(ProcessOutcome::Aggregated) Ok(ProcessOutcome::Aggregated)
} else { } else {
@ -60,11 +64,11 @@ impl AttestationAggregator {
} }
} else { } else {
let mut aggregate_signature = AggregateSignature::new(); let mut aggregate_signature = AggregateSignature::new();
aggregate_signature.add(signature); aggregate_signature.add(&free_attestation.signature);
let mut aggregation_bitfield = Bitfield::new(); let mut aggregation_bitfield = Bitfield::new();
aggregation_bitfield.set(validator_index, true); aggregation_bitfield.set(validator_index, true);
let new_attestation = Attestation { let new_attestation = Attestation {
data: attestation_data.clone(), data: free_attestation.data.clone(),
aggregation_bitfield, aggregation_bitfield,
custody_bitfield: Bitfield::new(), custody_bitfield: Bitfield::new(),
aggregate_signature, aggregate_signature,

View File

@ -1,7 +1,7 @@
use super::{BeaconChain, ClientDB, SlotClock}; use super::{BeaconChain, ClientDB, SlotClock};
pub use crate::attestation_aggregator::{ProcessError as AggregatorError, ProcessOutcome}; pub use crate::attestation_aggregator::{ProcessError as AggregatorError, ProcessOutcome};
use crate::canonical_head::Error as HeadError; use crate::canonical_head::Error as HeadError;
use types::{AttestationData, Signature}; use types::FreeAttestation;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Error { pub enum Error {
@ -17,9 +17,7 @@ where
{ {
pub fn process_free_attestation( pub fn process_free_attestation(
&self, &self,
attestation_data: &AttestationData, free_attestation: FreeAttestation,
signature: &Signature,
validator_index: u64,
) -> Result<ProcessOutcome, Error> { ) -> Result<ProcessOutcome, Error> {
let present_slot = self let present_slot = self
.present_slot() .present_slot()
@ -29,7 +27,7 @@ where
self.attestation_aggregator self.attestation_aggregator
.write() .write()
.expect("Aggregator unlock failed.") .expect("Aggregator unlock failed.")
.process_free_attestation(&state, attestation_data, signature, validator_index) .process_free_attestation(&state, &free_attestation)
.map_err(|e| e.into()) .map_err(|e| e.into())
} }
} }

View File

@ -4,7 +4,7 @@ use beacon_chain::block_processing::Error as ProcessingError;
use beacon_chain::block_production::Error as BlockProductionError; use beacon_chain::block_production::Error as BlockProductionError;
use db::ClientDB; use db::ClientDB;
use slot_clock::SlotClock; use slot_clock::SlotClock;
use types::{AttestationData, Signature}; use types::{AttestationData, FreeAttestation};
impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for BenchingBeaconNode<T, U> impl<T: ClientDB, U: SlotClock> AttesterBeaconNode for BenchingBeaconNode<T, U>
where where
@ -24,15 +24,9 @@ where
fn publish_attestation_data( fn publish_attestation_data(
&self, &self,
attestation_data: AttestationData, free_attestation: FreeAttestation,
signature: Signature,
validator_index: u64,
) -> Result<PublishOutcome, NodeError> { ) -> Result<PublishOutcome, NodeError> {
match self.beacon_chain.process_free_attestation( match self.beacon_chain.process_free_attestation(free_attestation) {
&attestation_data,
&signature,
validator_index,
) {
Ok(_) => Ok(PublishOutcome::ValidAttestation), Ok(_) => Ok(PublishOutcome::ValidAttestation),
Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))), Err(e) => Err(NodeError::RemoteFailure(format!("{:?}", e))),
} }

View File

@ -3,16 +3,11 @@ 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, Signature}; use types::{BeaconBlock, FreeAttestation};
mod attester; mod attester;
mod producer; mod producer;
/// An attestation that hasn't been aggregated into an `Attestation`.
///
/// (attestation_data, signature, validator_index)
pub type FreeAttestation = (AttestationData, Signature, u64);
pub struct BenchingBeaconNode<T: ClientDB, U: SlotClock> { pub struct BenchingBeaconNode<T: ClientDB, U: SlotClock> {
beacon_chain: Arc<BeaconChain<T, U>>, beacon_chain: Arc<BeaconChain<T, U>>,
published_blocks: RwLock<Vec<BeaconBlock>>, published_blocks: RwLock<Vec<BeaconBlock>>,
@ -31,4 +26,8 @@ impl<T: ClientDB, U: SlotClock> BenchingBeaconNode<T, U> {
pub fn last_published_block(&self) -> Option<BeaconBlock> { pub fn last_published_block(&self) -> Option<BeaconBlock> {
Some(self.published_blocks.read().last()?.clone()) Some(self.published_blocks.read().last()?.clone())
} }
pub fn last_published_free_attestation(&self) -> Option<FreeAttestation> {
Some(self.published_attestations.read().last()?.clone())
}
} }

View File

@ -1,24 +1,30 @@
use attester::Attester; use attester::{Attester, Error as AttestationPollError};
use beacon_chain::BeaconChain; use beacon_chain::BeaconChain;
use block_producer::{BlockProducer, Error as PollError}; use block_producer::{BlockProducer, Error as BlockPollError};
use db::MemoryDB; use db::MemoryDB;
use signer::TestSigner; use signer::TestSigner;
use slot_clock::TestingSlotClock; use slot_clock::TestingSlotClock;
use std::sync::Arc; use std::sync::Arc;
use types::{BeaconBlock, ChainSpec, Keypair}; use types::{BeaconBlock, ChainSpec, FreeAttestation, Keypair};
mod beacon_node; mod beacon_node;
mod direct_duties; mod direct_duties;
mod signer; mod signer;
pub use self::beacon_node::BenchingBeaconNode; pub use self::beacon_node::BenchingBeaconNode;
pub use self::direct_duties::DirectDuties; pub use self::direct_duties::DirectDuties;
pub use block_producer::PollOutcome; pub use attester::PollOutcome as AttestationPollOutcome;
pub use block_producer::PollOutcome as BlockPollOutcome;
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum ProduceError { pub enum BlockProduceError {
DidNotProduce(PollOutcome), DidNotProduce(BlockPollOutcome),
PollError(PollError), PollError(BlockPollError),
}
#[derive(Debug, PartialEq)]
pub enum AttestationProduceError {
DidNotProduce(AttestationPollOutcome),
PollError(AttestationPollError),
} }
pub struct TestValidator { pub struct TestValidator {
@ -81,13 +87,13 @@ impl TestValidator {
} }
} }
pub fn produce_block(&mut self) -> Result<BeaconBlock, ProduceError> { pub fn produce_block(&mut self) -> Result<BeaconBlock, BlockProduceError> {
// Using `BenchingBeaconNode`, the validator will always return sucessufully if it tries to // Using `BenchingBeaconNode`, the validator will always return sucessufully if it tries to
// publish a block. // publish a block.
match self.block_producer.poll() { match self.block_producer.poll() {
Ok(PollOutcome::BlockProduced(_)) => {} Ok(BlockPollOutcome::BlockProduced(_)) => {}
Ok(outcome) => return Err(ProduceError::DidNotProduce(outcome)), Ok(outcome) => return Err(BlockProduceError::DidNotProduce(outcome)),
Err(error) => return Err(ProduceError::PollError(error)), Err(error) => return Err(BlockProduceError::PollError(error)),
}; };
Ok(self Ok(self
.beacon_node .beacon_node
@ -95,6 +101,18 @@ impl TestValidator {
.expect("Unable to obtain produced block.")) .expect("Unable to obtain produced block."))
} }
pub fn produce_free_attestation(&mut self) -> Result<FreeAttestation, AttestationProduceError> {
match self.attester.poll() {
Ok(AttestationPollOutcome::AttestationProduced(_)) => {}
Ok(outcome) => return Err(AttestationProduceError::DidNotProduce(outcome)),
Err(error) => return Err(AttestationProduceError::PollError(error)),
};
Ok(self
.beacon_node
.last_published_free_attestation()
.expect("Unable to obtain produced attestation."))
}
pub fn set_slot(&mut self, slot: u64) { pub fn set_slot(&mut self, slot: u64) {
self.slot_clock.set_slot(slot) self.slot_clock.set_slot(slot)
} }

View File

@ -4,25 +4,25 @@ use types::ChainSpec;
#[test] #[test]
fn it_can_build_on_genesis_block() { fn it_can_build_on_genesis_block() {
let validator_count = 2; let validator_count = 2;
let mut rig = BeaconChainHarness::new(ChainSpec::foundation(), validator_count); let mut harness = BeaconChainHarness::new(ChainSpec::foundation(), validator_count);
rig.advance_chain_with_block(); harness.advance_chain_with_block();
} }
#[test] #[test]
#[ignore] #[ignore]
fn it_can_produce_past_first_epoch_boundary() { fn it_can_produce_past_first_epoch_boundary() {
let validator_count = 2; let validator_count = 2;
let mut rig = BeaconChainHarness::new(ChainSpec::foundation(), validator_count); let mut harness = BeaconChainHarness::new(ChainSpec::foundation(), validator_count);
let blocks = rig.spec.epoch_length + 1; let blocks = harness.spec.epoch_length + 1;
for _ in 0..blocks { for _ in 0..blocks {
rig.advance_chain_with_block(); harness.advance_chain_with_block();
} }
let dump = rig.chain_dump().expect("Chain dump failed."); let dump = harness.chain_dump().expect("Chain dump failed.");
assert_eq!(dump.len() as u64, blocks + 1); // + 1 for genesis block. assert_eq!(dump.len() as u64, blocks + 1); // + 1 for genesis block.
rig.dump_to_file("/tmp/chaindump.json".to_string(), &dump); harness.dump_to_file("/tmp/chaindump.json".to_string(), &dump);
} }

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, Signature}; use types::{AttestationData, FreeAttestation, Signature};
pub use self::traits::{ pub use self::traits::{
BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer, BeaconNode, BeaconNodeError, DutiesReader, DutiesReaderError, PublishOutcome, Signer,
@ -111,8 +111,14 @@ impl<T: SlotClock, U: BeaconNode, V: DutiesReader, W: Signer> Attester<T, U, V,
None => return Ok(PollOutcome::ValidatorIsUnknown(slot)), None => return Ok(PollOutcome::ValidatorIsUnknown(slot)),
}; };
let free_attestation = FreeAttestation {
data: attestation_data,
signature,
validator_index,
};
self.beacon_node self.beacon_node
.publish_attestation_data(attestation_data, signature, validator_index)?; .publish_attestation_data(free_attestation)?;
Ok(PollOutcome::AttestationProduced(slot)) Ok(PollOutcome::AttestationProduced(slot))
} }

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, Signature}; use types::{AttestationData, FreeAttestation};
type ProduceResult = Result<Option<AttestationData>, BeaconNodeError>; type ProduceResult = Result<Option<AttestationData>, BeaconNodeError>;
type PublishResult = Result<PublishOutcome, BeaconNodeError>; type PublishResult = Result<PublishOutcome, BeaconNodeError>;
@ -11,7 +11,7 @@ pub struct TestBeaconNode {
pub produce_input: RwLock<Option<(u64, u64)>>, pub produce_input: RwLock<Option<(u64, u64)>>,
pub produce_result: RwLock<Option<ProduceResult>>, pub produce_result: RwLock<Option<ProduceResult>>,
pub publish_input: RwLock<Option<(AttestationData, Signature, u64)>>, pub publish_input: RwLock<Option<FreeAttestation>>,
pub publish_result: RwLock<Option<PublishResult>>, pub publish_result: RwLock<Option<PublishResult>>,
} }
@ -34,13 +34,8 @@ impl BeaconNode for TestBeaconNode {
} }
} }
fn publish_attestation_data( fn publish_attestation_data(&self, free_attestation: FreeAttestation) -> PublishResult {
&self, *self.publish_input.write().unwrap() = Some(free_attestation.clone());
attestation_data: AttestationData,
signature: Signature,
validator_index: u64,
) -> PublishResult {
*self.publish_input.write().unwrap() = Some((attestation_data, signature, validator_index));
match *self.publish_result.read().unwrap() { match *self.publish_result.read().unwrap() {
Some(ref r) => r.clone(), Some(ref r) => r.clone(),
None => panic!("TestBeaconNode: publish_result == None"), None => panic!("TestBeaconNode: publish_result == None"),

View File

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

View File

@ -0,0 +1,12 @@
/// Note: this object does not actually exist in the spec.
///
/// We use it for managing attestations that have not been aggregated.
use super::{AttestationData, Signature};
use serde_derive::Serialize;
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct FreeAttestation {
pub data: AttestationData,
pub signature: Signature,
pub validator_index: u64,
}

View File

@ -15,6 +15,7 @@ pub mod eth1_data;
pub mod eth1_data_vote; pub mod eth1_data_vote;
pub mod exit; pub mod exit;
pub mod fork; pub mod fork;
pub mod free_attestation;
pub mod pending_attestation; pub mod pending_attestation;
pub mod proposal_signed_data; pub mod proposal_signed_data;
pub mod proposer_slashing; pub mod proposer_slashing;
@ -47,6 +48,7 @@ pub use crate::eth1_data::Eth1Data;
pub use crate::eth1_data_vote::Eth1DataVote; pub use crate::eth1_data_vote::Eth1DataVote;
pub use crate::exit::Exit; pub use crate::exit::Exit;
pub use crate::fork::Fork; pub use crate::fork::Fork;
pub use crate::free_attestation::FreeAttestation;
pub use crate::pending_attestation::PendingAttestation; pub use crate::pending_attestation::PendingAttestation;
pub use crate::proposal_signed_data::ProposalSignedData; pub use crate::proposal_signed_data::ProposalSignedData;
pub use crate::proposer_slashing::ProposerSlashing; pub use crate::proposer_slashing::ProposerSlashing;