diff --git a/validator_client/src/attester_service/beacon_node_attestation.rs b/validator_client/src/attester_service/beacon_node_attestation.rs index fa8d540319..b5ff777de8 100644 --- a/validator_client/src/attester_service/beacon_node_attestation.rs +++ b/validator_client/src/attester_service/beacon_node_attestation.rs @@ -1,5 +1,6 @@ //TODO: generalise these enums to the crate -use super::block_producer::{BeaconNodeError, PublishOutcome}; +use crate::block_producer::{BeaconNodeError, PublishOutcome}; +use types::{Attestation, AttestationData, Slot}; /// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the /// actual beacon node. diff --git a/validator_client/src/attester_service/mod.rs b/validator_client/src/attester_service/mod.rs index 20488b1c19..7b2174b0cd 100644 --- a/validator_client/src/attester_service/mod.rs +++ b/validator_client/src/attester_service/mod.rs @@ -1,22 +1,38 @@ -mod grpc; mod beacon_node_attestation; +mod grpc; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; -use super::block_proposer::beacon_node_block::BeaconNodeError; +//TODO: Move these higher up in the crate +use super::block_producer::{BeaconNodeError, ValidatorEvent}; +use crate::signer::Signer; +use beacon_node_attestation::BeaconNodeAttestation; +use slog::{error, info, warn}; +use ssz::TreeHash; +use types::{ + AggregateSignature, Attestation, AttestationData, AttestationDataAndCustodyBit, + AttestationDuty, Bitfield, +}; +//TODO: Group these errors at a crate level #[derive(Debug, PartialEq)] pub enum Error { BeaconNodeError(BeaconNodeError), } +impl From for Error { + fn from(e: BeaconNodeError) -> Error { + Error::BeaconNodeError(e) + } +} + /// This struct contains the logic for requesting and signing beacon attestations for a validator. The /// validator can abstractly sign via the Signer trait object. pub struct AttestationProducer<'a, B: BeaconNodeAttestation, S: Signer> { /// The current fork. pub fork: Fork, - /// The current slot to produce an attestation for. - pub slot: Slot, + /// The attestation duty to perform. + pub duty: AttestationDuty, /// The current epoch. pub spec: Arc, /// The beacon node to connect to. @@ -42,6 +58,9 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(_slot)) => { error!(log, "Attestation production error"; "Error" => format!("Beacon node was unable to produce an attestation")) } + Ok(v) => { + warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) + } } } @@ -56,25 +75,23 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// The slash-protection code is not yet implemented. There is zero protection against /// slashing. pub fn produce_attestation(&mut self) -> Result { - let epoch = self.slot.epoch(self.spec.slots_per_epoch); + let epoch = self.duty.slot.epoch(self.spec.slots_per_epoch); - if let Some(attestation) = self + let attestation = self .beacon_node - .produce_attestation_data(self.slot, self.shard)? - { - if self.safe_to_produce(&attestation) { - let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); - if let Some(attestation) = self.sign_attestation(attestation, domain) { - self.beacon_node.publish_attestation(attestation)?; - Ok(ValidatorEvent::AttestationProduced(self.slot)) - } else { - Ok(ValidatorEvent::SignerRejection(self.slot)) - } + .produce_attestation_data(self.duty.slot, self.duty.shard)?; + if self.safe_to_produce(&attestation) { + let domain = self.spec.get_domain(epoch, Domain::Attestation, &self.fork); + if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { + self.beacon_node.publish_attestation(attestation)?; + Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) } else { - Ok(ValidatorEvent::SlashableAttestationNotProduced(self.slot)) + Ok(ValidatorEvent::SignerRejection(self.duty.slot)) } } else { - Ok(ValidatorEvent::BeaconNodeUnableToProduceAttestation(self.slot)) + Ok(ValidatorEvent::SlashableAttestationNotProduced( + self.duty.slot, + )) } } @@ -82,33 +99,39 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// /// Important: this function will not check to ensure the attestation is not slashable. This must be /// done upstream. - fn sign_attestation(&mut self, mut attestation: Attestation, duties: AttestationDuties, domain: u64) -> Option { + fn sign_attestation( + &mut self, + mut attestation: AttestationData, + duties: AttestationDuty, + domain: u64, + ) -> Option { self.store_produce(&attestation); // build the aggregate signature - let aggregate_sig = { + let aggregate_signature = { let message = AttestationDataAndCustodyBit { - data: attestation.clone(), - custody_bit: false, - }.hash_tree_root(); + data: attestation.clone(), + custody_bit: false, + } + .hash_tree_root(); let sig = self.signer.sign_message(&message, domain)?; let mut agg_sig = AggregateSignature::new(); agg_sig.add(&sig); agg_sig - } + }; - let mut aggregation_bitfield = Bitfield::with_capacity(duties.comitee_size); - let custody_bitfield = Bitfield::with_capacity(duties.committee_size); - aggregation_bitfield.set(duties.committee_index, true); + let mut aggregation_bitfield = Bitfield::with_capacity(duties.committee_len); + let custody_bitfield = Bitfield::with_capacity(duties.committee_len); + aggregation_bitfield.set(duties.committee_index, true); - Attestation { - aggregation_bitfield, - data, - custody_bitfield, - aggregate_signature, - } + Some(Attestation { + aggregation_bitfield, + data: attestation, + custody_bitfield, + aggregate_signature, + }) } /// Returns `true` if signing an attestation is safe (non-slashable). @@ -116,8 +139,8 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// !!! UNSAFE !!! /// /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _block: &Attestation) -> bool { - //TODO: Implement slash protection + fn safe_to_produce(&self, _attestation: &AttestationData) -> bool { + //TODO: Implement slash protection true } @@ -126,7 +149,7 @@ impl<'a, B: BeaconNodeAttestation, S: Signer> AttestationProducer<'a, B, S> { /// !!! UNSAFE !!! /// /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &BeaconBlock) { + fn store_produce(&mut self, _attestation: &AttestationData) { // TODO: Implement slash protection } } diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs index 09ce9bffae..592c0b9192 100644 --- a/validator_client/src/block_producer/mod.rs +++ b/validator_client/src/block_producer/mod.rs @@ -1,10 +1,11 @@ mod beacon_node_block; mod grpc; -use self::beacon_node_block::{BeaconNodeBlock, BeaconNodeError}; +use self::beacon_node_block::BeaconNodeBlock; +pub use self::beacon_node_block::{BeaconNodeError, PublishOutcome}; pub use self::grpc::BeaconBlockGrpcClient; use crate::signer::Signer; -use slog::{error, info}; +use slog::{error, info, warn}; use ssz::{SignedRoot, TreeHash}; use std::sync::Arc; use types::{BeaconBlock, ChainSpec, Domain, Fork, Slot}; @@ -18,10 +19,16 @@ pub enum Error { pub enum ValidatorEvent { /// A new block was produced. BlockProduced(Slot), + /// A new attestation was produced. + AttestationProduced(Slot), /// A block was not produced as it would have been slashable. SlashableBlockNotProduced(Slot), + /// An attestation was not produced as it would have been slashable. + SlashableAttestationNotProduced(Slot), /// The Beacon Node was unable to produce a block at that slot. BeaconNodeUnableToProduceBlock(Slot), + /// The Beacon Node was unable to produce an attestation at that slot. + BeaconNodeUnableToProduceAttestation(Slot), /// The signer failed to sign the message. SignerRejection(Slot), } @@ -58,6 +65,9 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(_slot)) => { error!(log, "Block production error"; "Error" => format!("Beacon node was unable to produce a block")) } + Ok(v) => { + warn!(log, "Unknown result for block production"; "Error" => format!("{:?}",v)) + } } } @@ -76,7 +86,7 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { let randao_reveal = { let message = epoch.hash_tree_root(); - let randao_reveal = match self.signer.sign_randao_reveal( + let randao_reveal = match self.signer.sign_message( &message, self.spec.get_domain(epoch, Domain::Randao, &self.fork), ) { @@ -113,10 +123,7 @@ impl<'a, B: BeaconNodeBlock, S: Signer> BlockProducer<'a, B, S> { fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option { self.store_produce(&block); - match self - .signer - .sign_block_proposal(&block.signed_root()[..], domain) - { + match self.signer.sign_message(&block.signed_root()[..], domain) { None => None, Some(signature) => { block.signature = signature; diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs index d0753a2a6a..692a8d6a62 100644 --- a/validator_client/src/duties/epoch_duties.rs +++ b/validator_client/src/duties/epoch_duties.rs @@ -38,7 +38,7 @@ impl EpochDuty { // if the validator is required to attest to a shard, create the data let mut attestation_duty = None; if self.attestation_duty.slot == slot { - attestation_duty = self.attestation_duty + attestation_duty = Some(self.attestation_duty) } if produce_block | attestation_duty.is_some() { @@ -60,7 +60,7 @@ impl fmt::Display for EpochDuty { write!( f, "produce block slot: {}, attestation slot: {}, attestation shard: {}", - display_block, self.attestation_slot, self.attestation_shard + display_block, self.attestation_duty.slot, self.attestation_duty.shard ) } } diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs index f0d892e98f..ab87b602e0 100644 --- a/validator_client/src/duties/grpc.rs +++ b/validator_client/src/duties/grpc.rs @@ -6,7 +6,7 @@ use protos::services_grpc::ValidatorServiceClient; use ssz::ssz_encode; use std::collections::HashMap; use std::time::Duration; -use types::{Epoch, PublicKey, Slot}; +use types::{AttestationDuty, Epoch, PublicKey, Slot}; impl BeaconNodeDuties for ValidatorServiceClient { /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). @@ -49,11 +49,11 @@ impl BeaconNodeDuties for ValidatorServiceClient { }; let attestation_duty = AttestationDuty { - slot: Slot::from(active_duty.get_attestation_slot()), - shard: active_duty.get_attestation_shard(), - committee_index: active_duty.get_committee_index(), - comittee_size: 10, - } + slot: Slot::from(active_duty.get_attestation_slot()), + shard: active_duty.get_attestation_shard(), + committee_index: active_duty.get_committee_index() as usize, + committee_len: 10, + }; let epoch_duty = EpochDuty { block_production_slot,