diff --git a/validator_client/src/attestation_producer/beacon_node_attestation.rs b/validator_client/src/attestation_producer/beacon_node_attestation.rs deleted file mode 100644 index d3dfaf3281..0000000000 --- a/validator_client/src/attestation_producer/beacon_node_attestation.rs +++ /dev/null @@ -1,23 +0,0 @@ -//TODO: generalise these enums to the crate -use crate::block_producer::{BeaconNodeError, PublishOutcome}; -use types::{Attestation, AttestationData, CommitteeIndex, EthSpec, Slot}; - -/// Defines the methods required to produce and publish attestations on a Beacon Node. Abstracts the -/// actual beacon node. -pub trait BeaconNodeAttestation: Send + Sync { - /// Request that the node produces the required attestation data. - /// - fn produce_attestation_data( - &self, - slot: Slot, - index: CommitteeIndex, - ) -> Result; - - /// Request that the node publishes a attestation. - /// - /// Returns `true` if the publish was successful. - fn publish_attestation( - &self, - attestation: Attestation, - ) -> Result; -} diff --git a/validator_client/src/attestation_producer/grpc.rs b/validator_client/src/attestation_producer/grpc.rs deleted file mode 100644 index a7f979dc05..0000000000 --- a/validator_client/src/attestation_producer/grpc.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::beacon_node_attestation::BeaconNodeAttestation; -use crate::block_producer::{BeaconNodeError, PublishOutcome}; -use protos::services_grpc::AttestationServiceClient; -use ssz::{Decode, Encode}; - -use protos::services::{ - Attestation as GrpcAttestation, ProduceAttestationDataRequest, PublishAttestationRequest, -}; -use types::{Attestation, AttestationData, CommitteeIndex, EthSpec, Slot}; - -impl BeaconNodeAttestation for AttestationServiceClient { - fn produce_attestation_data( - &self, - slot: Slot, - index: CommitteeIndex, - ) -> Result { - let mut req = ProduceAttestationDataRequest::new(); - req.set_slot(slot.as_u64()); - req.set_shard(index); - - let reply = self - .produce_attestation_data(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - let attestation_data = - AttestationData::from_ssz_bytes(reply.get_attestation_data().get_ssz()) - .map_err(|_| BeaconNodeError::DecodeFailure)?; - Ok(attestation_data) - } - - fn publish_attestation( - &self, - attestation: Attestation, - ) -> Result { - let mut req = PublishAttestationRequest::new(); - - let ssz = attestation.as_ssz_bytes(); - - let mut grpc_attestation = GrpcAttestation::new(); - grpc_attestation.set_ssz(ssz); - - req.set_attestation(grpc_attestation); - - let reply = self - .publish_attestation(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - if reply.get_success() { - Ok(PublishOutcome::Valid) - } else { - // TODO: distinguish between different errors - Ok(PublishOutcome::InvalidAttestation( - "Publish failed".to_string(), - )) - } - } -} diff --git a/validator_client/src/attestation_producer/mod.rs b/validator_client/src/attestation_producer/mod.rs deleted file mode 100644 index cd2ed4a138..0000000000 --- a/validator_client/src/attestation_producer/mod.rs +++ /dev/null @@ -1,166 +0,0 @@ -mod beacon_node_attestation; -mod grpc; - -use std::sync::Arc; -use types::{ChainSpec, Domain, EthSpec, Fork}; -//TODO: Move these higher up in the crate -use super::block_producer::{BeaconNodeError, PublishOutcome, ValidatorEvent}; -use crate::signer::Signer; -use beacon_node_attestation::BeaconNodeAttestation; -use core::marker::PhantomData; -use slog::{error, info, warn}; -use tree_hash::TreeHash; -use types::{AggregateSignature, Attestation, AttestationData, AttestationDuty, BitList}; - -//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, E: EthSpec> { - /// The current fork. - pub fork: Fork, - /// The attestation duty to perform. - pub duty: AttestationDuty, - /// The current epoch. - pub spec: Arc, - /// The beacon node to connect to. - pub beacon_node: Arc, - /// The signer to sign the block. - pub signer: &'a S, - /// Used for calculating epoch. - pub slots_per_epoch: u64, - /// Mere vessel for E. - pub _phantom: PhantomData, -} - -impl<'a, B: BeaconNodeAttestation, S: Signer, E: EthSpec> AttestationProducer<'a, B, S, E> { - /// Handle outputs and results from attestation production. - pub fn handle_produce_attestation(&mut self, log: slog::Logger) { - match self.produce_attestation() { - Ok(ValidatorEvent::AttestationProduced(slot)) => info!( - log, - "Attestation produced"; - "validator" => format!("{}", self.signer), - "slot" => slot, - ), - Err(e) => error!(log, "Attestation production error"; "Error" => format!("{:?}", e)), - Ok(ValidatorEvent::SignerRejection(_slot)) => { - error!(log, "Attestation production error"; "Error" => "Signer could not sign the attestation".to_string()) - } - Ok(ValidatorEvent::IndexedAttestationNotProduced(_slot)) => { - error!(log, "Attestation production error"; "Error" => "Rejected the attestation as it could have been slashed".to_string()) - } - Ok(ValidatorEvent::PublishAttestationFailed) => { - error!(log, "Attestation production error"; "Error" => "Beacon node was unable to publish an attestation".to_string()) - } - Ok(ValidatorEvent::InvalidAttestation) => { - error!(log, "Attestation production error"; "Error" => "The signed attestation was invalid".to_string()) - } - Ok(v) => { - warn!(log, "Unknown result for attestation production"; "Error" => format!("{:?}",v)) - } - } - } - - /// Produce an attestation, sign it and send it back - /// - /// Assumes that an attestation is required at this slot (does not check the duties). - /// - /// Ensures the message is not slashable. - /// - /// !!! UNSAFE !!! - /// - /// The slash-protection code is not yet implemented. There is zero protection against - /// slashing. - pub fn produce_attestation(&mut self) -> Result { - let epoch = self.duty.slot.epoch(self.slots_per_epoch); - - let attestation = self - .beacon_node - .produce_attestation_data(self.duty.slot, self.duty.index)?; - if self.safe_to_produce(&attestation) { - let domain = self - .spec - .get_domain(epoch, Domain::BeaconAttester, &self.fork); - if let Some(attestation) = self.sign_attestation(attestation, self.duty, domain) { - match self.beacon_node.publish_attestation(attestation) { - Ok(PublishOutcome::InvalidAttestation(_string)) => { - Ok(ValidatorEvent::InvalidAttestation) - } - Ok(PublishOutcome::Valid) => { - Ok(ValidatorEvent::AttestationProduced(self.duty.slot)) - } - Err(_) | Ok(_) => Ok(ValidatorEvent::PublishAttestationFailed), - } - } else { - Ok(ValidatorEvent::SignerRejection(self.duty.slot)) - } - } else { - Ok(ValidatorEvent::IndexedAttestationNotProduced( - self.duty.slot, - )) - } - } - - /// Consumes an attestation, returning the attestation signed by the validators private key. - /// - /// Important: this function will not check to ensure the attestation is not slashable. This must be - /// done upstream. - fn sign_attestation( - &mut self, - attestation: AttestationData, - duties: AttestationDuty, - domain: u64, - ) -> Option> { - self.store_produce(&attestation); - - // build the aggregate signature - let aggregate_signature = { - let message = attestation.tree_hash_root(); - - let sig = self.signer.sign_message(&message, domain)?; - - let mut agg_sig = AggregateSignature::new(); - agg_sig.add(&sig); - agg_sig - }; - - let mut aggregation_bits = BitList::with_capacity(duties.committee_len).ok()?; - aggregation_bits.set(duties.committee_position, true).ok()?; - - Some(Attestation { - aggregation_bits, - data: attestation, - signature: aggregate_signature, - }) - } - - /// Returns `true` if signing an attestation is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _attestation: &AttestationData) -> bool { - //TODO: Implement slash protection - true - } - - /// Record that an attestation was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _attestation: &AttestationData) { - // TODO: Implement slash protection - } -} diff --git a/validator_client/src/block_producer/beacon_node_block.rs b/validator_client/src/block_producer/beacon_node_block.rs deleted file mode 100644 index 7e681d44b7..0000000000 --- a/validator_client/src/block_producer/beacon_node_block.rs +++ /dev/null @@ -1,34 +0,0 @@ -use types::{BeaconBlock, EthSpec, Signature, Slot}; -#[derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeError { - RemoteFailure(String), - DecodeFailure, -} - -#[derive(Debug, PartialEq, Clone)] -pub enum PublishOutcome { - Valid, - InvalidBlock(String), - InvalidAttestation(String), -} - -/// Defines the methods required to produce and publish blocks on a Beacon Node. Abstracts the -/// actual beacon node. -pub trait BeaconNodeBlock: Send + Sync { - /// Request that the node produces a block. - /// - /// Returns Ok(None) if the Beacon Node is unable to produce at the given slot. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result>, BeaconNodeError>; - - /// Request that the node publishes a block. - /// - /// Returns `true` if the publish was successful. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result; -} diff --git a/validator_client/src/block_producer/grpc.rs b/validator_client/src/block_producer/grpc.rs deleted file mode 100644 index 7a3e7f2841..0000000000 --- a/validator_client/src/block_producer/grpc.rs +++ /dev/null @@ -1,87 +0,0 @@ -use super::beacon_node_block::*; -use protos::services::{ - BeaconBlock as GrpcBeaconBlock, ProduceBeaconBlockRequest, PublishBeaconBlockRequest, -}; -use protos::services_grpc::BeaconBlockServiceClient; -use ssz::{Decode, Encode}; -use std::sync::Arc; -use types::{BeaconBlock, EthSpec, Signature, Slot}; - -//TODO: Remove this new type. Do not need to wrap -/// A newtype designed to wrap the gRPC-generated service so the `BeaconNode` trait may be -/// implemented upon it. -pub struct BeaconBlockGrpcClient { - client: Arc, -} - -impl BeaconBlockGrpcClient { - pub fn new(client: Arc) -> Self { - Self { client } - } -} - -impl BeaconNodeBlock for BeaconBlockGrpcClient { - /// Request a Beacon Node (BN) to produce a new block at the supplied slot. - /// - /// Returns `None` if it is not possible to produce at the supplied slot. For example, if the - /// BN is unable to find a parent block. - fn produce_beacon_block( - &self, - slot: Slot, - randao_reveal: &Signature, - ) -> Result>, BeaconNodeError> { - // request a beacon block from the node - let mut req = ProduceBeaconBlockRequest::new(); - req.set_slot(slot.as_u64()); - req.set_randao_reveal(randao_reveal.as_ssz_bytes()); - - //TODO: Determine if we want an explicit timeout - let reply = self - .client - .produce_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - // format the reply - if reply.has_block() { - let block = reply.get_block(); - let ssz = block.get_ssz(); - - let block = - BeaconBlock::from_ssz_bytes(&ssz).map_err(|_| BeaconNodeError::DecodeFailure)?; - - Ok(Some(block)) - } else { - Ok(None) - } - } - - /// Request a Beacon Node (BN) to publish a block. - /// - /// Generally, this will be called after a `produce_beacon_block` call with a block that has - /// been completed (signed) by the validator client. - fn publish_beacon_block( - &self, - block: BeaconBlock, - ) -> Result { - let mut req = PublishBeaconBlockRequest::new(); - - let ssz = block.as_ssz_bytes(); - - let mut grpc_block = GrpcBeaconBlock::new(); - grpc_block.set_ssz(ssz); - - req.set_block(grpc_block); - - let reply = self - .client - .publish_beacon_block(&req) - .map_err(|err| BeaconNodeError::RemoteFailure(format!("{:?}", err)))?; - - if reply.get_success() { - Ok(PublishOutcome::Valid) - } else { - // TODO: distinguish between different errors - Ok(PublishOutcome::InvalidBlock("Publish failed".to_string())) - } - } -} diff --git a/validator_client/src/block_producer/mod.rs b/validator_client/src/block_producer/mod.rs deleted file mode 100644 index d88ac15f63..0000000000 --- a/validator_client/src/block_producer/mod.rs +++ /dev/null @@ -1,259 +0,0 @@ -mod beacon_node_block; -mod grpc; - -use self::beacon_node_block::BeaconNodeBlock; -pub use self::beacon_node_block::{BeaconNodeError, PublishOutcome}; -pub use self::grpc::BeaconBlockGrpcClient; -use crate::signer::Signer; -use core::marker::PhantomData; -use slog::{error, info, trace, warn}; -use std::sync::Arc; -use tree_hash::{SignedRoot, TreeHash}; -use types::{BeaconBlock, ChainSpec, Domain, EthSpec, Fork, Slot}; - -#[derive(Debug, PartialEq)] -pub enum Error { - BeaconNodeError(BeaconNodeError), -} - -#[derive(Debug, PartialEq)] -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. - IndexedAttestationNotProduced(Slot), - /// The Beacon Node was unable to produce a block at that slot. - BeaconNodeUnableToProduceBlock(Slot), - /// The signer failed to sign the message. - SignerRejection(Slot), - /// Publishing an attestation failed. - PublishAttestationFailed, - /// Beacon node rejected the attestation. - InvalidAttestation, -} - -/// This struct contains the logic for requesting and signing beacon blocks for a validator. The -/// validator can abstractly sign via the Signer trait object. -pub struct BlockProducer<'a, B: BeaconNodeBlock, S: Signer, E: EthSpec> { - /// The current fork. - pub fork: Fork, - /// The current slot to produce a block for. - pub slot: Slot, - /// The current epoch. - pub spec: Arc, - /// The beacon node to connect to. - pub beacon_node: Arc, - /// The signer to sign the block. - pub signer: &'a S, - /// Used for calculating epoch. - pub slots_per_epoch: u64, - /// Mere vessel for E. - pub _phantom: PhantomData, - /// The logger, for logging - pub log: slog::Logger, -} - -impl<'a, B: BeaconNodeBlock, S: Signer, E: EthSpec> BlockProducer<'a, B, S, E> { - /// Handle outputs and results from block production. - pub fn handle_produce_block(&mut self) { - match self.produce_block() { - Ok(ValidatorEvent::BlockProduced(slot)) => info!( - self.log, - "Block produced"; - "validator" => format!("{}", self.signer), - "slot" => slot, - ), - Err(e) => error!(self.log, "Block production error"; "Error" => format!("{:?}", e)), - Ok(ValidatorEvent::SignerRejection(_slot)) => { - error!(self.log, "Block production error"; "Error" => "Signer Could not sign the block".to_string()) - } - Ok(ValidatorEvent::SlashableBlockNotProduced(_slot)) => { - error!(self.log, "Block production error"; "Error" => "Rejected the block as it could have been slashed".to_string()) - } - Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(_slot)) => { - error!(self.log, "Block production error"; "Error" => "Beacon node was unable to produce a block".to_string()) - } - Ok(v) => { - warn!(self.log, "Unknown result for block production"; "Error" => format!("{:?}",v)) - } - } - } - - /// Produce a block at some slot. - /// - /// Assumes that a block is required at this slot (does not check the duties). - /// - /// Ensures the message is not slashable. - /// - /// !!! UNSAFE !!! - /// - /// The slash-protection code is not yet implemented. There is zero protection against - /// slashing. - pub fn produce_block(&mut self) -> Result { - let epoch = self.slot.epoch(self.slots_per_epoch); - trace!(self.log, "Producing block"; "epoch" => epoch); - - let message = epoch.tree_hash_root(); - let randao_reveal = match self.signer.sign_message( - &message, - self.spec.get_domain(epoch, Domain::Randao, &self.fork), - ) { - None => { - warn!(self.log, "Signing rejected"; "message" => format!("{:?}", message)); - return Ok(ValidatorEvent::SignerRejection(self.slot)); - } - Some(signature) => signature, - }; - - if let Some(block) = self - .beacon_node - .produce_beacon_block(self.slot, &randao_reveal)? - { - if self.safe_to_produce(&block) { - let slot = block.slot; - let domain = self - .spec - .get_domain(epoch, Domain::BeaconProposer, &self.fork); - if let Some(block) = self.sign_block(block, domain) { - self.beacon_node.publish_beacon_block(block)?; - Ok(ValidatorEvent::BlockProduced(slot)) - } else { - Ok(ValidatorEvent::SignerRejection(self.slot)) - } - } else { - Ok(ValidatorEvent::SlashableBlockNotProduced(self.slot)) - } - } else { - Ok(ValidatorEvent::BeaconNodeUnableToProduceBlock(self.slot)) - } - } - - /// Consumes a block, returning that block signed by the validators private key. - /// - /// Important: this function will not check to ensure the block is not slashable. This must be - /// done upstream. - fn sign_block(&mut self, mut block: BeaconBlock, domain: u64) -> Option> { - self.store_produce(&block); - - match self.signer.sign_message(&block.signed_root()[..], domain) { - None => None, - Some(signature) => { - block.signature = signature; - Some(block) - } - } - } - - /// Returns `true` if signing a block is safe (non-slashable). - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn safe_to_produce(&self, _block: &BeaconBlock) -> bool { - // TODO: ensure the producer doesn't produce slashable blocks. - // https://github.com/sigp/lighthouse/issues/160 - true - } - - /// Record that a block was produced so that slashable votes may not be made in the future. - /// - /// !!! UNSAFE !!! - /// - /// Important: this function is presently stubbed-out. It provides ZERO SAFETY. - fn store_produce(&mut self, _block: &BeaconBlock) { - // TODO: record this block production to prevent future slashings. - // https://github.com/sigp/lighthouse/issues/160 - } -} - -impl From for Error { - fn from(e: BeaconNodeError) -> Error { - Error::BeaconNodeError(e) - } -} - -/* Old tests - Re-work for new logic -#[cfg(test)] -mod tests { - use super::test_utils::{EpochMap, LocalSigner, SimulatedBeaconNode}; - use super::*; - use slot_clock::TestingSlotClock; - use types::{ - test_utils::{SeedableRng, TestRandom, XorShiftRng}, - Keypair, - }; - - // TODO: implement more thorough testing. - // https://github.com/sigp/lighthouse/issues/160 - // - // These tests should serve as a good example for future tests. - - #[test] - pub fn polling() { - let mut rng = XorShiftRng::from_seed([42; 16]); - - let spec = Arc::new(ChainSpec::mainnet()); - 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 epoch_map = EpochMap::new(T::slots_per_epoch()); - let produce_slot = Slot::new(100); - let produce_epoch = produce_slot.epoch(T::slots_per_epoch()); - epoch_map.map.insert(produce_epoch, produce_slot); - let epoch_map = Arc::new(epoch_map); - - let mut block_proposer = BlockProducer::new( - spec.clone(), - epoch_map.clone(), - slot_clock.clone(), - beacon_node.clone(), - signer.clone(), - ); - - // Configure responses from the BeaconNode. - beacon_node.set_next_produce_result(Ok(Some(BeaconBlock::random_for_test(&mut rng)))); - beacon_node.set_next_publish_result(Ok(PublishOutcome::ValidBlock)); - - // One slot before production slot... - slot_clock.set_slot(produce_slot.as_u64() - 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot - 1)) - ); - - // On the produce slot... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProduced(produce_slot.into())) - ); - - // Trying the same produce slot again... - slot_clock.set_slot(produce_slot.as_u64()); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::SlotAlreadyProcessed(produce_slot)) - ); - - // One slot after the produce slot... - slot_clock.set_slot(produce_slot.as_u64() + 1); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::BlockProductionNotRequired(produce_slot + 1)) - ); - - // In an epoch without known duties... - let slot = (produce_epoch.as_u64() + 1) * T::slots_per_epoch(); - slot_clock.set_slot(slot); - assert_eq!( - block_proposer.poll(), - Ok(PollOutcome::ProducerDutiesUnknown(Slot::new(slot))) - ); - } -} -*/ diff --git a/validator_client/src/duties/beacon_node_duties.rs b/validator_client/src/duties/beacon_node_duties.rs deleted file mode 100644 index af1fab60bf..0000000000 --- a/validator_client/src/duties/beacon_node_duties.rs +++ /dev/null @@ -1,20 +0,0 @@ -use super::EpochDuties; -use types::{Epoch, PublicKey}; - -#[derive(Debug, PartialEq, Clone)] -pub enum BeaconNodeDutiesError { - RemoteFailure(String), -} - -/// Defines the methods required to obtain a validators shuffling from a Beacon Node. -pub trait BeaconNodeDuties: Send + Sync { - /// Gets the duties for all validators. - /// - /// Returns a vector of EpochDuties for each validator public key. The entry will be None for - /// validators that are not activated. - fn request_duties( - &self, - epoch: Epoch, - pub_keys: &[PublicKey], - ) -> Result; -} diff --git a/validator_client/src/duties/epoch_duties.rs b/validator_client/src/duties/epoch_duties.rs deleted file mode 100644 index 5a22dccb2b..0000000000 --- a/validator_client/src/duties/epoch_duties.rs +++ /dev/null @@ -1,133 +0,0 @@ -use std::collections::HashMap; -use std::fmt; -use std::ops::{Deref, DerefMut}; -use types::{AttestationDuty, Epoch, PublicKey, Slot}; - -/// When work needs to be performed by a validator, this type is given back to the main service -/// which indicates all the information that required to process the work. -/// -/// Note: This is calculated per slot, so a validator knows which slot is related to this struct. -#[derive(Debug, Clone)] -pub struct WorkInfo { - /// Validator needs to produce a block. - pub produce_block: bool, - /// Validator needs to produce an attestation. This supplies the required attestation data. - pub attestation_duty: Option, -} - -/// The information required for a validator to propose and attest during some epoch. -/// -/// Generally obtained from a Beacon Node, this information contains the validators canonical index -/// (their sequence in the global validator induction process) and the "shuffling" for that index -/// for some epoch. -#[derive(Debug, PartialEq, Clone, Copy, Default)] -pub struct EpochDuty { - pub block_production_slot: Option, - pub attestation_duty: AttestationDuty, -} - -impl EpochDuty { - /// Returns `WorkInfo` if work needs to be done in the supplied `slot` - pub fn is_work_slot(&self, slot: Slot) -> Option { - // if validator is required to produce a slot return true - let produce_block = match self.block_production_slot { - Some(s) if s == slot => true, - _ => false, - }; - - // if the validator is required to attest to a index, create the data - let mut attestation_duty = None; - if self.attestation_duty.slot == slot { - attestation_duty = Some(self.attestation_duty) - } - - if produce_block | attestation_duty.is_some() { - return Some(WorkInfo { - produce_block, - attestation_duty, - }); - } - None - } -} - -impl fmt::Display for EpochDuty { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let mut display_block = String::from("None"); - if let Some(block_slot) = self.block_production_slot { - display_block = block_slot.to_string(); - } - write!( - f, - "produce block slot: {}, attestation slot: {}, attestation index: {}", - display_block, self.attestation_duty.slot, self.attestation_duty.index - ) - } -} - -/// Maps a list of keypairs (many validators) to an EpochDuty. -pub type EpochDuties = HashMap>; - -pub enum EpochDutiesMapError { - UnknownEpoch, - UnknownValidator, -} - -/// Maps an `epoch` to some `EpochDuties` for a single validator. -pub struct EpochDutiesMap { - pub slots_per_epoch: u64, - pub map: HashMap, -} - -impl EpochDutiesMap { - pub fn new(slots_per_epoch: u64) -> Self { - Self { - slots_per_epoch, - map: HashMap::new(), - } - } -} - -// Expose the hashmap methods -impl Deref for EpochDutiesMap { - type Target = HashMap; - - fn deref(&self) -> &Self::Target { - &self.map - } -} -impl DerefMut for EpochDutiesMap { - fn deref_mut(&mut self) -> &mut HashMap { - &mut self.map - } -} - -impl EpochDutiesMap { - /// Checks if the validator has work to do. - pub fn is_work_slot( - &self, - slot: Slot, - signer: &PublicKey, - ) -> Result, EpochDutiesMapError> { - let epoch = slot.epoch(self.slots_per_epoch); - - let epoch_duties = self - .map - .get(&epoch) - .ok_or_else(|| EpochDutiesMapError::UnknownEpoch)?; - if let Some(epoch_duty) = epoch_duties.get(signer) { - if let Some(duty) = epoch_duty { - // Retrieves the duty for a validator at a given slot - Ok(duty.is_work_slot(slot)) - } else { - // the validator isn't active - Ok(None) - } - } else { - // validator isn't known - Err(EpochDutiesMapError::UnknownValidator) - } - } -} - -// TODO: add tests. diff --git a/validator_client/src/duties/grpc.rs b/validator_client/src/duties/grpc.rs deleted file mode 100644 index 565672c982..0000000000 --- a/validator_client/src/duties/grpc.rs +++ /dev/null @@ -1,67 +0,0 @@ -use super::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; -use super::epoch_duties::{EpochDuties, EpochDuty}; -// to use if we manually specify a timeout -//use grpcio::CallOption; -use protos::services::{GetDutiesRequest, Validators}; -use protos::services_grpc::ValidatorServiceClient; -use ssz::ssz_encode; -use std::collections::HashMap; -// use std::time::Duration; -use types::{AttestationDuty, Epoch, PublicKey, Slot}; - -impl BeaconNodeDuties for ValidatorServiceClient { - /// Requests all duties (block signing and committee attesting) from the Beacon Node (BN). - fn request_duties( - &self, - epoch: Epoch, - pub_keys: &[PublicKey], - ) -> Result { - // Get the required duties from all validators - // build the request - let mut req = GetDutiesRequest::new(); - req.set_epoch(epoch.as_u64()); - let mut validators = Validators::new(); - validators.set_public_keys(pub_keys.iter().map(|v| ssz_encode(v)).collect()); - req.set_validators(validators); - - // set a timeout for requests - // let call_opt = CallOption::default().timeout(Duration::from_secs(2)); - - // send the request, get the duties reply - let reply = self - .get_validator_duties(&req) - .map_err(|err| BeaconNodeDutiesError::RemoteFailure(format!("{:?}", err)))?; - - let mut epoch_duties: HashMap> = HashMap::new(); - for (index, validator_duty) in reply.get_active_validators().iter().enumerate() { - if !validator_duty.has_duty() { - // validator is inactive - epoch_duties.insert(pub_keys[index].clone(), None); - continue; - } - // active validator - let active_duty = validator_duty.get_duty(); - let block_production_slot = { - if active_duty.has_block_production_slot() { - Some(Slot::from(active_duty.get_block_production_slot())) - } else { - None - } - }; - - let attestation_duty = AttestationDuty { - slot: Slot::from(active_duty.get_attestation_slot()), - index: active_duty.get_attestation_shard(), - committee_position: active_duty.get_committee_index() as usize, - committee_len: active_duty.get_committee_len() as usize, - }; - - let epoch_duty = EpochDuty { - block_production_slot, - attestation_duty, - }; - epoch_duties.insert(pub_keys[index].clone(), Some(epoch_duty)); - } - Ok(epoch_duties) - } -} diff --git a/validator_client/src/duties/mod.rs b/validator_client/src/duties/mod.rs deleted file mode 100644 index bc20b853b9..0000000000 --- a/validator_client/src/duties/mod.rs +++ /dev/null @@ -1,214 +0,0 @@ -mod beacon_node_duties; -mod epoch_duties; -mod grpc; -// TODO: reintroduce tests -//#[cfg(test)] -//mod test_node; - -pub use self::beacon_node_duties::{BeaconNodeDuties, BeaconNodeDutiesError}; -use self::epoch_duties::{EpochDuties, EpochDutiesMapError}; -pub use self::epoch_duties::{EpochDutiesMap, WorkInfo}; -use super::signer::Signer; -use futures::Async; -use parking_lot::RwLock; -use slog::{debug, error, info}; -use std::fmt::Display; -use std::sync::Arc; -use types::{Epoch, PublicKey, Slot}; - -#[derive(Debug, PartialEq, Clone)] -pub enum UpdateOutcome { - /// The `EpochDuties` were not updated during this poll. - NoChange(Epoch), - /// The `EpochDuties` for the `epoch` were previously unknown, but obtained in the poll. - NewDuties(Epoch, EpochDuties), - /// New `EpochDuties` were obtained, different to those which were previously known. This is - /// likely to be the result of chain re-organisation. - DutiesChanged(Epoch, EpochDuties), -} - -#[derive(Debug, PartialEq)] -pub enum Error { - DutiesMapPoisoned, - BeaconNodeDutiesError(BeaconNodeDutiesError), - UnknownEpoch, - UnknownValidator, -} - -/// A polling state machine which ensures the latest `EpochDuties` are obtained from the Beacon -/// Node. -/// -/// This keeps track of all validator keys and required voting slots. -pub struct DutiesManager { - pub duties_map: RwLock, - /// A list of all signer objects known to the validator service. - pub signers: Arc>, - pub beacon_node: Arc, -} - -impl DutiesManager { - /// Check the Beacon Node for `EpochDuties`. - /// - /// be a wall-clock (e.g., system time, remote server time, etc.). - fn update(&self, epoch: Epoch) -> Result { - let public_keys: Vec = self.signers.iter().map(Signer::to_public).collect(); - let duties = self.beacon_node.request_duties(epoch, &public_keys)?; - { - // If these duties were known, check to see if they're updates or identical. - if let Some(known_duties) = self.duties_map.read().get(&epoch) { - if *known_duties == duties { - return Ok(UpdateOutcome::NoChange(epoch)); - } - } - } - if !self.duties_map.read().contains_key(&epoch) { - //TODO: Remove clone by removing duties from outcome - self.duties_map.write().insert(epoch, duties.clone()); - return Ok(UpdateOutcome::NewDuties(epoch, duties)); - } - // duties have changed - //TODO: Duties could be large here. Remove from display and avoid the clone. - self.duties_map.write().insert(epoch, duties.clone()); - Ok(UpdateOutcome::DutiesChanged(epoch, duties)) - } - - /// A future wrapping around `update()`. This will perform logic based upon the update - /// process and complete once the update has completed. - pub fn run_update(&self, epoch: Epoch, log: slog::Logger) -> Result, ()> { - match self.update(epoch) { - Err(error) => error!(log, "Epoch duties poll error"; "error" => format!("{:?}", error)), - Ok(UpdateOutcome::NoChange(epoch)) => { - debug!(log, "No change in duties"; "epoch" => epoch) - } - Ok(UpdateOutcome::DutiesChanged(epoch, duties)) => { - info!(log, "Duties changed (potential re-org)"; "epoch" => epoch, "duties" => format!("{:?}", duties)) - } - Ok(UpdateOutcome::NewDuties(epoch, duties)) => { - info!(log, "New duties obtained"; "epoch" => epoch); - print_duties(&log, duties); - } - }; - Ok(Async::Ready(())) - } - - /// Returns a list of (index, WorkInfo) indicating all the validators that have work to perform - /// this slot. - pub fn get_current_work(&self, slot: Slot) -> Option> { - let mut current_work: Vec<(usize, WorkInfo)> = Vec::new(); - - // if the map is poisoned, return None - let duties = self.duties_map.read(); - - for (index, validator_signer) in self.signers.iter().enumerate() { - match duties.is_work_slot(slot, &validator_signer.to_public()) { - Ok(Some(work_type)) => current_work.push((index, work_type)), - Ok(None) => {} // No work for this validator - //TODO: This should really log an error, as we shouldn't end up with an err here. - Err(_) => {} // Unknown epoch or validator, no work - } - } - if current_work.is_empty() { - return None; - } - Some(current_work) - } -} - -//TODO: Use error_chain to handle errors -impl From for Error { - fn from(e: BeaconNodeDutiesError) -> Error { - Error::BeaconNodeDutiesError(e) - } -} - -//TODO: Use error_chain to handle errors -impl From> for Error { - fn from(_e: std::sync::PoisonError) -> Error { - Error::DutiesMapPoisoned - } -} -impl From for Error { - fn from(e: EpochDutiesMapError) -> Error { - match e { - EpochDutiesMapError::UnknownEpoch => Error::UnknownEpoch, - EpochDutiesMapError::UnknownValidator => Error::UnknownValidator, - } - } -} - -fn print_duties(log: &slog::Logger, duties: EpochDuties) { - for (pk, duty) in duties.iter() { - if let Some(display_duty) = duty { - info!(log, "Validator: {}",pk; "Duty" => format!("{}",display_duty)); - } else { - info!(log, "Validator: {}",pk; "Duty" => "None"); - } - } -} - -/* TODO: Modify tests for new Duties Manager form -#[cfg(test)] -mod tests { - use super::test_node::TestBeaconNode; - use super::*; - use bls::Keypair; - use slot_clock::TestingSlotClock; - use types::Slot; - - // TODO: implement more thorough testing. - // https://github.com/sigp/lighthouse/issues/160 - // - // These tests should serve as a good example for future tests. - - - #[test] - pub fn polling() { - let spec = Arc::new(ChainSpec::mainnet()); - let duties_map = Arc::new(EpochDutiesMap::new(T::slots_per_epoch())); - let keypair = Keypair::random(); - let slot_clock = Arc::new(TestingSlotClock::new(0)); - let beacon_node = Arc::new(TestBeaconNode::default()); - - let manager = DutiesManager { - spec: spec.clone(), - pubkey: keypair.pk.clone(), - duties_map: duties_map.clone(), - slot_clock: slot_clock.clone(), - beacon_node: beacon_node.clone(), - }; - - // Configure response from the BeaconNode. - let duties = EpochDuties { - validator_index: 0, - block_production_slot: Some(Slot::new(10)), - }; - beacon_node.set_next_shuffling_result(Ok(Some(duties))); - - // Get the duties for the first time... - assert_eq!( - manager.poll(), - Ok(PollOutcome::NewDuties(Epoch::new(0), duties)) - ); - // Get the same duties again... - assert_eq!(manager.poll(), Ok(PollOutcome::NoChange(Epoch::new(0)))); - - // Return new duties. - let duties = EpochDuties { - validator_index: 0, - block_production_slot: Some(Slot::new(11)), - }; - beacon_node.set_next_shuffling_result(Ok(Some(duties))); - assert_eq!( - manager.poll(), - Ok(PollOutcome::DutiesChanged(Epoch::new(0), duties)) - ); - - // Return no duties. - beacon_node.set_next_shuffling_result(Ok(None)); - assert_eq!( - manager.poll(), - Ok(PollOutcome::UnknownValidatorOrEpoch(Epoch::new(0))) - ); - } -} -*/ diff --git a/validator_client/src/duties/test_node.rs b/validator_client/src/duties/test_node.rs deleted file mode 100644 index 331b78f3bc..0000000000 --- a/validator_client/src/duties/test_node.rs +++ /dev/null @@ -1,32 +0,0 @@ -use super::traits::{BeaconNode, BeaconNodeError}; -use super::EpochDuties; -use bls::PublicKey; -use std::sync::RwLock; -use types::Epoch; - -type ShufflingResult = Result, BeaconNodeError>; - -/// A test-only struct used to simulate a Beacon Node. -#[derive(Default)] -pub struct TestBeaconNode { - pub request_shuffling_input: RwLock>, - pub request_shuffling_result: RwLock>, -} - -impl TestBeaconNode { - /// Set the result to be returned when `request_shuffling` is called. - pub fn set_next_shuffling_result(&self, result: ShufflingResult) { - *self.request_shuffling_result.write().unwrap() = Some(result); - } -} - -impl BeaconNode for TestBeaconNode { - /// Returns the value specified by the `set_next_shuffling_result`. - fn request_shuffling(&self, epoch: Epoch, public_key: &PublicKey) -> ShufflingResult { - *self.request_shuffling_input.write().unwrap() = Some((epoch, public_key.clone())); - match *self.request_shuffling_result.read().unwrap() { - Some(ref r) => r.clone(), - None => panic!("TestBeaconNode: produce_result == None"), - } - } -} diff --git a/validator_client/src/error.rs b/validator_client/src/error.rs deleted file mode 100644 index e13f7ded51..0000000000 --- a/validator_client/src/error.rs +++ /dev/null @@ -1,12 +0,0 @@ -use error_chain::error_chain; - -error_chain! { - links { } - - errors { - SystemTimeError(t: String ) { - description("Error reading system time"), - display("SystemTimeError: '{}'", t) - } - } -} diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 863436ba3f..6f1c1b3371 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -2,9 +2,7 @@ mod block_service; mod cli; mod config; mod duties_service; -mod error; mod fork_service; -mod signer; mod validator_store; pub mod validator_directory; diff --git a/validator_client/src/service.rs b/validator_client/src/service.rs deleted file mode 100644 index 60d1fad018..0000000000 --- a/validator_client/src/service.rs +++ /dev/null @@ -1,364 +0,0 @@ -/// The Validator Client service. -/// -/// Connects to a beacon node and negotiates the correct chain id. -/// -/// Once connected, the service loads known validators keypairs from disk. Every slot, -/// the service pings the beacon node, asking for new duties for each of the validators. -/// -/// When a validator needs to either produce a block or sign an attestation, it requests the -/// data from the beacon node and performs the signing before publishing the block to the beacon -/// node. -use crate::attestation_producer::AttestationProducer; -use crate::block_producer::{BeaconBlockGrpcClient, BlockProducer}; -use crate::config::Config as ValidatorConfig; -use crate::duties::{BeaconNodeDuties, DutiesManager, EpochDutiesMap}; -use crate::error as error_chain; -use crate::signer::Signer; -use eth2_config::Eth2Config; -use grpcio::{ChannelBuilder, EnvBuilder}; -use parking_lot::RwLock; -use protos::services::Empty; -use protos::services_grpc::{ - AttestationServiceClient, BeaconBlockServiceClient, BeaconNodeServiceClient, - ValidatorServiceClient, -}; -use slog::{crit, error, info, trace, warn}; -use slot_clock::{SlotClock, SystemTimeSlotClock}; -use std::marker::PhantomData; -use std::sync::Arc; -use std::time::Duration; -use types::{ChainSpec, Epoch, EthSpec, Fork, Keypair, Slot}; - -/// The validator service. This is the main thread that executes and maintains validator -/// duties. -//TODO: Generalize the BeaconNode types to use testing -pub struct Service { - /// The node's current fork version we are processing on. - fork: Fork, - /// The slot clock for this service. - pub slot_clock: SystemTimeSlotClock, - /// The slot that is currently, or was previously processed by the service. - current_slot: RwLock>, - slots_per_epoch: u64, - /// The chain specification for this clients instance. - pub spec: Arc, - /// The duties manager which maintains the state of when to perform actions. - duties_manager: Arc>, - // GRPC Clients - /// The beacon block GRPC client. - beacon_block_client: Arc, - /// The attester GRPC client. - attestation_client: Arc, - /// The validator client logger. - log: slog::Logger, - _phantom: PhantomData, -} - -impl Service { - /// Initial connection to the beacon node to determine its properties. - /// - /// This tries to connect to a beacon node. Once connected, it initialised the gRPC clients - /// and returns an instance of the service. - pub fn initialize_service( - client_config: ValidatorConfig, - eth2_config: Eth2Config, - log: slog::Logger, - ) -> error_chain::Result> { - let server_url = format!( - "{}:{}", - client_config.server, client_config.server_grpc_port - ); - - let env = Arc::new(EnvBuilder::new().build()); - // Beacon node gRPC beacon node endpoints. - let beacon_node_client = { - let ch = ChannelBuilder::new(env.clone()).connect(&server_url); - BeaconNodeServiceClient::new(ch) - }; - - // retrieve node information and validate the beacon node - let node_info = loop { - match beacon_node_client.info(&Empty::new()) { - Err(e) => { - let retry_seconds = 5; - warn!( - log, - "Could not connect to beacon node"; - "error" => format!("{:?}", e), - "retry_in" => format!("{} seconds", retry_seconds), - ); - std::thread::sleep(Duration::from_secs(retry_seconds)); - continue; - } - Ok(info) => { - // verify the node's network id - if eth2_config.spec.network_id != info.network_id as u8 { - error!( - log, - "Beacon Node's genesis time is in the future. No work to do.\n Exiting" - ); - return Err(format!("Beacon node has the wrong chain id. Expected chain id: {}, node's chain id: {}", eth2_config.spec.network_id, info.network_id).into()); - } - break info; - } - }; - }; - - // build requisite objects to form Self - let genesis_time = node_info.get_genesis_time(); - let genesis_slot = Slot::from(node_info.get_genesis_slot()); - - info!( - log, - "Beacon node connected"; - "version" => node_info.version.clone(), - "network_id" => node_info.network_id, - "genesis_time" => genesis_time - ); - - let proto_fork = node_info.get_fork(); - let mut previous_version: [u8; 4] = [0; 4]; - let mut current_version: [u8; 4] = [0; 4]; - previous_version.copy_from_slice(&proto_fork.get_previous_version()[..4]); - current_version.copy_from_slice(&proto_fork.get_current_version()[..4]); - let fork = Fork { - previous_version, - current_version, - epoch: Epoch::from(proto_fork.get_epoch()), - }; - - // initialize the RPC clients - - // Beacon node gRPC beacon block endpoints. - let beacon_block_client = { - let ch = ChannelBuilder::new(env.clone()).connect(&server_url); - let beacon_block_service_client = Arc::new(BeaconBlockServiceClient::new(ch)); - // a wrapper around the service client to implement the beacon block node trait - Arc::new(BeaconBlockGrpcClient::new(beacon_block_service_client)) - }; - - // Beacon node gRPC validator endpoints. - let validator_client = { - let ch = ChannelBuilder::new(env.clone()).connect(&server_url); - Arc::new(ValidatorServiceClient::new(ch)) - }; - - //Beacon node gRPC attester endpoints. - let attestation_client = { - let ch = ChannelBuilder::new(env.clone()).connect(&server_url); - Arc::new(AttestationServiceClient::new(ch)) - }; - - // build the validator slot clock - let slot_clock = SystemTimeSlotClock::new( - genesis_slot, - Duration::from_secs(genesis_time), - Duration::from_millis(eth2_config.spec.milliseconds_per_slot), - ); - - /* Generate the duties manager */ - - // Load generated keypairs - let keypairs = Arc::new(client_config.fetch_keys(&log)?); - - info!( - log, - "Keypairs loaded"; - "local_validator_count" => keypairs.len() - ); - - let slots_per_epoch = E::slots_per_epoch(); - - // Builds a mapping of Epoch -> Map(PublicKey, EpochDuty) - // where EpochDuty contains slot numbers and attestation data that each validator needs to - // produce work on. - let duties_map = RwLock::new(EpochDutiesMap::new(slots_per_epoch)); - - // builds a manager which maintains the list of current duties for all known validators - // and can check when a validator needs to perform a task. - let duties_manager = Arc::new(DutiesManager { - duties_map, - // these are abstract objects capable of signing - signers: keypairs, - beacon_node: validator_client, - }); - - let spec = Arc::new(eth2_config.spec); - - Ok(Service { - fork, - slot_clock, - current_slot: RwLock::new(None), - slots_per_epoch, - spec, - duties_manager, - beacon_block_client, - attestation_client, - log, - _phantom: PhantomData, - }) - } -} - -impl Service { - /// The execution logic that runs every slot. - // Errors are logged to output, and core execution continues unless fatal errors occur. - pub fn per_slot_execution(&self) -> error_chain::Result<()> { - /* get the new current slot and epoch */ - self.update_current_slot()?; - - /* check for new duties */ - self.check_for_duties(); - - /* process any required duties for validators */ - self.process_duties(); - - trace!( - self.log, - "Per slot execution finished"; - ); - - Ok(()) - } - - /// Updates the known current slot and epoch. - fn update_current_slot(&self) -> error_chain::Result<()> { - let wall_clock_slot = self - .slot_clock - .now() - .ok_or_else::(|| { - "Genesis is not in the past. Exiting.".into() - })?; - - let wall_clock_epoch = wall_clock_slot.epoch(self.slots_per_epoch); - let mut current_slot = self.current_slot.write(); - - // this is a non-fatal error. If the slot clock repeats, the node could - // have been slow to process the previous slot and is now duplicating tasks. - // We ignore duplicated but raise a critical error. - if let Some(current_slot) = *current_slot { - if wall_clock_slot <= current_slot { - crit!( - self.log, - "The validator tried to duplicate a slot. Likely missed the previous slot" - ); - return Err("Duplicate slot".into()); - } - } - *current_slot = Some(wall_clock_slot); - info!(self.log, "Processing"; "slot" => wall_clock_slot.as_u64(), "epoch" => wall_clock_epoch.as_u64()); - Ok(()) - } - - /// For all known validator keypairs, update any known duties from the beacon node. - fn check_for_duties(&self) { - let cloned_manager = self.duties_manager.clone(); - let cloned_log = self.log.clone(); - let current_epoch = self - .current_slot - .read() - .expect("The current slot must be updated before checking for duties") - .epoch(self.slots_per_epoch); - - trace!( - self.log, - "Checking for duties"; - "epoch" => current_epoch - ); - - // spawn a new thread separate to the runtime - // TODO: Handle thread termination/timeout - // TODO: Add duties thread back in, with channel to process duties in duty change. - // leave sequential for now. - //std::thread::spawn(move || { - // the return value is a future which returns ready. - // built to be compatible with the tokio runtime. - let _empty = cloned_manager.run_update(current_epoch, cloned_log.clone()); - //}); - } - - /// If there are any duties to process, spawn a separate thread and perform required actions. - fn process_duties(&self) { - if let Some(work) = self.duties_manager.get_current_work( - self.current_slot - .read() - .expect("The current slot must be updated before processing duties"), - ) { - trace!( - self.log, - "Processing duties"; - "work_items" => work.len() - ); - - for (signer_index, work_type) in work { - if work_type.produce_block { - // we need to produce a block - // spawns a thread to produce a beacon block - let signers = self.duties_manager.signers.clone(); // this is an arc - let fork = self.fork.clone(); - let slot = self - .current_slot - .read() - .expect("The current slot must be updated before processing duties"); - let spec = self.spec.clone(); - let beacon_node = self.beacon_block_client.clone(); - let log = self.log.clone(); - let slots_per_epoch = self.slots_per_epoch; - std::thread::spawn(move || { - info!( - log, - "Producing a block"; - "validator"=> format!("{}", signers[signer_index]), - "slot"=> slot - ); - let signer = &signers[signer_index]; - let mut block_producer = BlockProducer { - fork, - slot, - spec, - beacon_node, - signer, - slots_per_epoch, - _phantom: PhantomData::, - log, - }; - block_producer.handle_produce_block(); - }); - } - if work_type.attestation_duty.is_some() { - // we need to produce an attestation - // spawns a thread to produce and sign an attestation - let slot = self - .current_slot - .read() - .expect("The current slot must be updated before processing duties"); - let signers = self.duties_manager.signers.clone(); // this is an arc - let fork = self.fork.clone(); - let spec = self.spec.clone(); - let beacon_node = self.attestation_client.clone(); - let log = self.log.clone(); - let slots_per_epoch = self.slots_per_epoch; - std::thread::spawn(move || { - info!( - log, - "Producing an attestation"; - "validator"=> format!("{}", signers[signer_index]), - "slot"=> slot - ); - let signer = &signers[signer_index]; - let mut attestation_producer = AttestationProducer { - fork, - duty: work_type.attestation_duty.expect("Should never be none"), - spec, - beacon_node, - signer, - slots_per_epoch, - _phantom: PhantomData::, - }; - attestation_producer.handle_produce_attestation(log); - }); - } - } - } - } -} diff --git a/validator_client/src/signer.rs b/validator_client/src/signer.rs deleted file mode 100644 index 018142322f..0000000000 --- a/validator_client/src/signer.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::fmt::Display; -use types::{Keypair, PublicKey, Signature}; - -/// Signs message using an internally-maintained private key. -pub trait Signer: Display + Send + Sync + Clone { - fn sign_message(&self, message: &[u8], domain: u64) -> Option; - /// Returns a public key for the signer object. - fn to_public(&self) -> PublicKey; -} - -/* Implements Display and Signer for Keypair */ - -impl Signer for Keypair { - fn to_public(&self) -> PublicKey { - self.pk.clone() - } - - fn sign_message(&self, message: &[u8], domain: u64) -> Option { - Some(Signature::new(message, domain, &self.sk)) - } -}