Tidy signing, reduce ForkService duplication

This commit is contained in:
Paul Hauner
2019-11-23 17:02:39 +11:00
parent b9967048ea
commit f76f97a3fd
13 changed files with 119 additions and 153 deletions

View File

@@ -12,7 +12,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
.about("Create a new Ethereum 2.0 validator.") .about("Create a new Ethereum 2.0 validator.")
.subcommand( .subcommand(
SubCommand::with_name("insecure") SubCommand::with_name("insecure")
.about("Uses the insecure deterministic keypairs. Do not store value in these.") .about("Produce insecure, ephemeral validators. DO NOT USE TO STORE VALUE.")
.arg( .arg(
Arg::with_name("first") Arg::with_name("first")
.index(1) .index(1)
@@ -32,7 +32,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
) )
.subcommand( .subcommand(
SubCommand::with_name("random") SubCommand::with_name("random")
.about("Uses the Rust rand crate ThreadRandom to generate keys.") .about("Produces public keys using entropy from the Rust 'rand' library.")
.arg( .arg(
Arg::with_name("validator_count") Arg::with_name("validator_count")
.index(1) .index(1)

View File

@@ -2,7 +2,7 @@ use clap::ArgMatches;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
/// Defines the encoding for the API /// Defines the encoding for the API.
#[derive(Clone, Serialize, Deserialize, Copy)] #[derive(Clone, Serialize, Deserialize, Copy)]
pub enum ApiEncodingFormat { pub enum ApiEncodingFormat {
JSON, JSON,

View File

@@ -55,10 +55,7 @@ fn sign_block<T: BeaconChainTypes>(
.block_proposer(block.slot) .block_proposer(block.slot)
.expect("should get proposer index"); .expect("should get proposer index");
let keypair = generate_deterministic_keypair(proposer_index); let keypair = generate_deterministic_keypair(proposer_index);
let epoch = block.slot.epoch(E::slots_per_epoch()); block.sign(&keypair.sk, &fork, spec);
let message = block.signed_root();
let domain = spec.get_domain(epoch, Domain::BeaconProposer, &fork);
block.signature = Signature::new(&message, domain, &keypair.sk);
} }
#[test] #[test]

View File

@@ -1 +0,0 @@
# CI & Testing

View File

@@ -12,10 +12,10 @@ If this doesn't work or is not clear enough, see the [Detailed Instructions](#de
## Detailed Instructions ## Detailed Instructions
1. Install Rust and Cargo with [rustup](https://rustup.rs/). 1. Install Rust and Cargo with [rustup](https://rustup.rs/).
- Use the `stable` toolchain (it's the default). - Use the `stable` toolchain (it's the default).
1. Clone the Lighthouse repository. 1. Clone the Lighthouse repository.
- Run `$ git clone https://github.com/sigp/lighthouse.git` - Run `$ git clone https://github.com/sigp/lighthouse.git`
- Change into the newly created directory with `$ cd lighthouse` - Change into the newly created directory with `$ cd lighthouse`
1. Build Lighthouse with `$ make`. 1. Build Lighthouse with `$ make`.
1. Installation was successful if `$ lighthouse --help` displays the 1. Installation was successful if `$ lighthouse --help` displays the
command-line documentation. command-line documentation.

View File

@@ -15,9 +15,8 @@ don't have `ganache-cli` available on your `PATH`.
## Testing ## Testing
Lighthouse uses `cargo test` for running the test suite. This is the As with most other Rust projects, Lighthouse uses `cargo test` for unit and
recommended work-flow for testing during development. For example, test the integration tests. For example, to test the `ssz` crate run:
`ssz` crate with:
```bash ```bash
cd eth2/utils/ssz cd eth2/utils/ssz
@@ -45,6 +44,6 @@ repository contains a large set of tests that verify Lighthouse behaviour
against the Ethereum Foundation specifications. against the Ethereum Foundation specifications.
These tests are quite large (100's of MB) so they're only downloaded if you run These tests are quite large (100's of MB) so they're only downloaded if you run
the `$ make test-ef` command (or anything that calls it). You may want to avoid `$ make test-ef` (or anything that run it). You may want to avoid
these if you're on a slow or metered Internet connection, CI will downloadingthese tests if you're on a slow or metered Internet connection. CI
require them to pass though. will require them to pass, though.

View File

@@ -100,6 +100,13 @@ impl<T: EthSpec> BeaconBlock<T> {
..self.block_header() ..self.block_header()
} }
} }
/// Signs `self`.
pub fn sign(&mut self, secret_key: &SecretKey, fork: &Fork, spec: &ChainSpec) {
let message = self.signed_root();
let domain = spec.get_domain(self.epoch(), Domain::BeaconProposer, &fork);
self.signature = Signature::new(&message, domain, &secret_key);
}
} }
#[cfg(test)] #[cfg(test)]

View File

@@ -137,12 +137,12 @@ fn run<E: EthSpec>(
account_manager::run(sub_matches, runtime_context); account_manager::run(sub_matches, runtime_context);
// Exit early if the account manager was run. It does not used the tokio executor, so no // Exit early if the account manager was run. It does not use the tokio executor, no need
// need to wait for it to shutdown. // to wait for it to shutdown.
return Ok(()); return Ok(());
} }
let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("Beacon Node") { let beacon_node = if let Some(sub_matches) = matches.subcommand_matches("beacon_node") {
let runtime_context = environment.core_context(); let runtime_context = environment.core_context();
let beacon = environment let beacon = environment

View File

@@ -1,6 +1,4 @@
use crate::{ use crate::{duties_service::DutiesService, validator_store::ValidatorStore};
duties_service::DutiesService, fork_service::ForkService, validator_store::ValidatorStore,
};
use environment::RuntimeContext; use environment::RuntimeContext;
use exit_future::Signal; use exit_future::Signal;
use futures::{Future, Stream}; use futures::{Future, Stream};
@@ -11,16 +9,15 @@ use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use tokio::timer::Interval; use tokio::timer::Interval;
use types::{ChainSpec, CommitteeIndex, EthSpec, Fork, Slot}; use types::{ChainSpec, CommitteeIndex, EthSpec, Slot};
/// Delay this period of time after the slot starts. This allows the node to process the new slot. /// Delay this period of time after the slot starts. This allows the node to process the new slot.
const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100); const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);
#[derive(Clone)] #[derive(Clone)]
pub struct AttestationServiceBuilder<T: Clone, E: EthSpec> { pub struct AttestationServiceBuilder<T: Clone, E: EthSpec> {
fork_service: Option<ForkService<T, E>>,
duties_service: Option<DutiesService<T, E>>, duties_service: Option<DutiesService<T, E>>,
validator_store: Option<ValidatorStore<E>>, validator_store: Option<ValidatorStore<T, E>>,
slot_clock: Option<T>, slot_clock: Option<T>,
beacon_node: Option<RemoteBeaconNode<E>>, beacon_node: Option<RemoteBeaconNode<E>>,
context: Option<RuntimeContext<E>>, context: Option<RuntimeContext<E>>,
@@ -30,7 +27,6 @@ pub struct AttestationServiceBuilder<T: Clone, E: EthSpec> {
impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationServiceBuilder<T, E> { impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationServiceBuilder<T, E> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
fork_service: None,
duties_service: None, duties_service: None,
validator_store: None, validator_store: None,
slot_clock: None, slot_clock: None,
@@ -39,17 +35,12 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationServiceBuilder<T, E>
} }
} }
pub fn fork_service(mut self, service: ForkService<T, E>) -> Self {
self.fork_service = Some(service);
self
}
pub fn duties_service(mut self, service: DutiesService<T, E>) -> Self { pub fn duties_service(mut self, service: DutiesService<T, E>) -> Self {
self.duties_service = Some(service); self.duties_service = Some(service);
self self
} }
pub fn validator_store(mut self, store: ValidatorStore<E>) -> Self { pub fn validator_store(mut self, store: ValidatorStore<T, E>) -> Self {
self.validator_store = Some(store); self.validator_store = Some(store);
self self
} }
@@ -72,9 +63,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationServiceBuilder<T, E>
pub fn build(self) -> Result<AttestationService<T, E>, String> { pub fn build(self) -> Result<AttestationService<T, E>, String> {
Ok(AttestationService { Ok(AttestationService {
inner: Arc::new(Inner { inner: Arc::new(Inner {
fork_service: self
.fork_service
.ok_or_else(|| "Cannot build AttestationService without fork_service")?,
duties_service: self duties_service: self
.duties_service .duties_service
.ok_or_else(|| "Cannot build AttestationService without duties_service")?, .ok_or_else(|| "Cannot build AttestationService without duties_service")?,
@@ -97,8 +85,7 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationServiceBuilder<T, E>
pub struct Inner<T: Clone, E: EthSpec> { pub struct Inner<T: Clone, E: EthSpec> {
duties_service: DutiesService<T, E>, duties_service: DutiesService<T, E>,
fork_service: ForkService<T, E>, validator_store: ValidatorStore<T, E>,
validator_store: ValidatorStore<E>,
slot_clock: T, slot_clock: T,
beacon_node: RemoteBeaconNode<E>, beacon_node: RemoteBeaconNode<E>,
context: RuntimeContext<E>, context: RuntimeContext<E>,
@@ -178,10 +165,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationService<T, E> {
.slot_clock .slot_clock
.now() .now()
.ok_or_else(|| "Failed to read slot clock".to_string())?; .ok_or_else(|| "Failed to read slot clock".to_string())?;
let fork = inner
.fork_service
.fork()
.ok_or_else(|| "Failed to get Fork".to_string())?;
let mut committee_indices: HashMap<CommitteeIndex, Vec<ValidatorDuty>> = HashMap::new(); let mut committee_indices: HashMap<CommitteeIndex, Vec<ValidatorDuty>> = HashMap::new();
@@ -206,7 +189,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationService<T, E> {
slot, slot,
committee_index, committee_index,
validator_duties, validator_duties,
fork.clone(),
)); ));
}); });
@@ -218,7 +200,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationService<T, E> {
slot: Slot, slot: Slot,
committee_index: CommitteeIndex, committee_index: CommitteeIndex,
validator_duties: Vec<ValidatorDuty>, validator_duties: Vec<ValidatorDuty>,
fork: Fork,
) -> impl Future<Item = (), Error = ()> { ) -> impl Future<Item = (), Error = ()> {
let inner_1 = self.inner.clone(); let inner_1 = self.inner.clone();
let inner_2 = self.inner.clone(); let inner_2 = self.inner.clone();
@@ -250,7 +231,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> AttestationService<T, E> {
&duty.validator_pubkey, &duty.validator_pubkey,
validator_committee_position, validator_committee_position,
attestation, attestation,
&fork,
) )
.ok_or_else(|| "Unable to sign attestation".to_string()) .ok_or_else(|| "Unable to sign attestation".to_string())
} else { } else {

View File

@@ -1,6 +1,4 @@
use crate::{ use crate::{duties_service::DutiesService, validator_store::ValidatorStore};
duties_service::DutiesService, fork_service::ForkService, validator_store::ValidatorStore,
};
use environment::RuntimeContext; use environment::RuntimeContext;
use exit_future::Signal; use exit_future::Signal;
use futures::{stream, Future, IntoFuture, Stream}; use futures::{stream, Future, IntoFuture, Stream};
@@ -17,9 +15,8 @@ const TIME_DELAY_FROM_SLOT: Duration = Duration::from_millis(100);
#[derive(Clone)] #[derive(Clone)]
pub struct BlockServiceBuilder<T: Clone, E: EthSpec> { pub struct BlockServiceBuilder<T: Clone, E: EthSpec> {
fork_service: Option<ForkService<T, E>>,
duties_service: Option<DutiesService<T, E>>, duties_service: Option<DutiesService<T, E>>,
validator_store: Option<ValidatorStore<E>>, validator_store: Option<ValidatorStore<T, E>>,
slot_clock: Option<Arc<T>>, slot_clock: Option<Arc<T>>,
beacon_node: Option<RemoteBeaconNode<E>>, beacon_node: Option<RemoteBeaconNode<E>>,
context: Option<RuntimeContext<E>>, context: Option<RuntimeContext<E>>,
@@ -29,7 +26,6 @@ pub struct BlockServiceBuilder<T: Clone, E: EthSpec> {
impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockServiceBuilder<T, E> { impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
fork_service: None,
duties_service: None, duties_service: None,
validator_store: None, validator_store: None,
slot_clock: None, slot_clock: None,
@@ -38,17 +34,12 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
} }
} }
pub fn fork_service(mut self, service: ForkService<T, E>) -> Self {
self.fork_service = Some(service);
self
}
pub fn duties_service(mut self, service: DutiesService<T, E>) -> Self { pub fn duties_service(mut self, service: DutiesService<T, E>) -> Self {
self.duties_service = Some(service); self.duties_service = Some(service);
self self
} }
pub fn validator_store(mut self, store: ValidatorStore<E>) -> Self { pub fn validator_store(mut self, store: ValidatorStore<T, E>) -> Self {
self.validator_store = Some(store); self.validator_store = Some(store);
self self
} }
@@ -70,9 +61,6 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
pub fn build(self) -> Result<BlockService<T, E>, String> { pub fn build(self) -> Result<BlockService<T, E>, String> {
Ok(BlockService { Ok(BlockService {
fork_service: self
.fork_service
.ok_or_else(|| "Cannot build BlockService without fork_service")?,
duties_service: self duties_service: self
.duties_service .duties_service
.ok_or_else(|| "Cannot build BlockService without duties_service")?, .ok_or_else(|| "Cannot build BlockService without duties_service")?,
@@ -95,8 +83,7 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
#[derive(Clone)] #[derive(Clone)]
pub struct BlockService<T: Clone, E: EthSpec> { pub struct BlockService<T: Clone, E: EthSpec> {
duties_service: DutiesService<T, E>, duties_service: DutiesService<T, E>,
fork_service: ForkService<T, E>, validator_store: ValidatorStore<T, E>,
validator_store: ValidatorStore<E>,
slot_clock: Arc<T>, slot_clock: Arc<T>,
beacon_node: RemoteBeaconNode<E>, beacon_node: RemoteBeaconNode<E>,
context: RuntimeContext<E>, context: RuntimeContext<E>,
@@ -167,29 +154,17 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockService<T, E> {
let service_3 = service.clone(); let service_3 = service.clone();
block_producers.next().map(move |validator_pubkey| { block_producers.next().map(move |validator_pubkey| {
service_2 service_1
.fork_service .validator_store
.fork() .randao_reveal(&validator_pubkey, slot.epoch(E::slots_per_epoch()))
.ok_or_else(|| "Fork is unknown, unable to sign".to_string()) .ok_or_else(|| "Unable to produce randao reveal".to_string())
.and_then(|fork| {
service_1
.validator_store
.randao_reveal(
&validator_pubkey,
slot.epoch(E::slots_per_epoch()),
&fork,
)
.map(|randao_reveal| (fork, randao_reveal))
.ok_or_else(|| "Unable to produce randao reveal".to_string())
})
.into_future() .into_future()
.and_then(move |(fork, randao_reveal)| { .and_then(move |randao_reveal| {
service_1 service_1
.beacon_node .beacon_node
.http .http
.validator() .validator()
.produce_block(slot, randao_reveal) .produce_block(slot, randao_reveal)
.map(|block| (fork, block))
.map_err(|e| { .map_err(|e| {
format!( format!(
"Error from beacon node when producing block: {:?}", "Error from beacon node when producing block: {:?}",
@@ -197,10 +172,10 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> BlockService<T, E> {
) )
}) })
}) })
.and_then(move |(fork, block)| { .and_then(move |block| {
service_2 service_2
.validator_store .validator_store
.sign_block(&validator_pubkey, block, &fork) .sign_block(&validator_pubkey, block)
.ok_or_else(|| "Unable to sign block".to_string()) .ok_or_else(|| "Unable to sign block".to_string())
}) })
.and_then(move |block| { .and_then(move |block| {

View File

@@ -124,7 +124,7 @@ impl DutiesStore {
#[derive(Clone)] #[derive(Clone)]
pub struct DutiesServiceBuilder<T: Clone, E: EthSpec> { pub struct DutiesServiceBuilder<T: Clone, E: EthSpec> {
store: Option<Arc<DutiesStore>>, store: Option<Arc<DutiesStore>>,
validator_store: Option<ValidatorStore<E>>, validator_store: Option<ValidatorStore<T, E>>,
slot_clock: Option<Arc<T>>, slot_clock: Option<Arc<T>>,
beacon_node: Option<RemoteBeaconNode<E>>, beacon_node: Option<RemoteBeaconNode<E>>,
context: Option<RuntimeContext<E>>, context: Option<RuntimeContext<E>>,
@@ -142,7 +142,7 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> DutiesServiceBuilder<T, E> {
} }
} }
pub fn validator_store(mut self, store: ValidatorStore<E>) -> Self { pub fn validator_store(mut self, store: ValidatorStore<T, E>) -> Self {
self.validator_store = Some(store); self.validator_store = Some(store);
self self
} }
@@ -184,7 +184,7 @@ impl<T: SlotClock + Clone + 'static, E: EthSpec> DutiesServiceBuilder<T, E> {
#[derive(Clone)] #[derive(Clone)]
pub struct DutiesService<T: Clone, E: EthSpec> { pub struct DutiesService<T: Clone, E: EthSpec> {
store: Arc<DutiesStore>, store: Arc<DutiesStore>,
validator_store: ValidatorStore<E>, validator_store: ValidatorStore<T, E>,
slot_clock: Arc<T>, slot_clock: Arc<T>,
beacon_node: RemoteBeaconNode<E>, beacon_node: RemoteBeaconNode<E>,
context: RuntimeContext<E>, context: RuntimeContext<E>,

View File

@@ -120,26 +120,35 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot), Duration::from_millis(context.eth2_config.spec.milliseconds_per_slot),
); );
let validator_store: ValidatorStore<T> = match &config.key_source { let fork_service = ForkServiceBuilder::new()
// Load pre-existing validators from the data dir. .slot_clock(slot_clock.clone())
// .beacon_node(beacon_node.clone())
// Use the `account_manager` to generate these files. .runtime_context(context.service_context("fork"))
KeySource::Disk => ValidatorStore::load_from_disk( .build()?;
config.data_dir.clone(),
context.eth2_config.spec.clone(), let validator_store: ValidatorStore<SystemTimeSlotClock, T> =
log_3.clone(), match &config.key_source {
)?, // Load pre-existing validators from the data dir.
// Generate ephemeral insecure keypairs for testing purposes. //
// // Use the `account_manager` to generate these files.
// Do not use in production. KeySource::Disk => ValidatorStore::load_from_disk(
KeySource::TestingKeypairRange(range) => { config.data_dir.clone(),
ValidatorStore::insecure_ephemeral_validators(
range.clone(),
context.eth2_config.spec.clone(), context.eth2_config.spec.clone(),
fork_service.clone(),
log_3.clone(), log_3.clone(),
)? )?,
} // Generate ephemeral insecure keypairs for testing purposes.
}; //
// Do not use in production.
KeySource::TestingKeypairRange(range) => {
ValidatorStore::insecure_ephemeral_validators(
range.clone(),
context.eth2_config.spec.clone(),
fork_service.clone(),
log_3.clone(),
)?
}
};
info!( info!(
log_3, log_3,
@@ -154,15 +163,8 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
.runtime_context(context.service_context("duties")) .runtime_context(context.service_context("duties"))
.build()?; .build()?;
let fork_service = ForkServiceBuilder::new()
.slot_clock(slot_clock.clone())
.beacon_node(beacon_node.clone())
.runtime_context(context.service_context("fork"))
.build()?;
let block_service = BlockServiceBuilder::new() let block_service = BlockServiceBuilder::new()
.duties_service(duties_service.clone()) .duties_service(duties_service.clone())
.fork_service(fork_service.clone())
.slot_clock(slot_clock.clone()) .slot_clock(slot_clock.clone())
.validator_store(validator_store.clone()) .validator_store(validator_store.clone())
.beacon_node(beacon_node.clone()) .beacon_node(beacon_node.clone())
@@ -171,7 +173,6 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
let attestation_service = AttestationServiceBuilder::new() let attestation_service = AttestationServiceBuilder::new()
.duties_service(duties_service.clone()) .duties_service(duties_service.clone())
.fork_service(fork_service.clone())
.slot_clock(slot_clock) .slot_clock(slot_clock)
.validator_store(validator_store) .validator_store(validator_store)
.beacon_node(beacon_node) .beacon_node(beacon_node)

View File

@@ -1,7 +1,9 @@
use crate::fork_service::ForkService;
use crate::validator_directory::{ValidatorDirectory, ValidatorDirectoryBuilder}; use crate::validator_directory::{ValidatorDirectory, ValidatorDirectoryBuilder};
use parking_lot::RwLock; use parking_lot::RwLock;
use rayon::prelude::*; use rayon::prelude::*;
use slog::{error, Logger}; use slog::{error, Logger};
use slot_clock::SlotClock;
use std::collections::HashMap; use std::collections::HashMap;
use std::fs::read_dir; use std::fs::read_dir;
use std::iter::FromIterator; use std::iter::FromIterator;
@@ -10,22 +12,28 @@ use std::ops::Range;
use std::path::PathBuf; use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use tempdir::TempDir; use tempdir::TempDir;
use tree_hash::{SignedRoot, TreeHash}; use tree_hash::TreeHash;
use types::{ use types::{
Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, Signature, Attestation, BeaconBlock, ChainSpec, Domain, Epoch, EthSpec, Fork, PublicKey, Signature,
}; };
#[derive(Clone)] #[derive(Clone)]
pub struct ValidatorStore<E> { pub struct ValidatorStore<T, E: EthSpec> {
validators: Arc<RwLock<HashMap<PublicKey, ValidatorDirectory>>>, validators: Arc<RwLock<HashMap<PublicKey, ValidatorDirectory>>>,
spec: Arc<ChainSpec>, spec: Arc<ChainSpec>,
log: Logger, log: Logger,
temp_dir: Option<Arc<TempDir>>, temp_dir: Option<Arc<TempDir>>,
fork_service: ForkService<T, E>,
_phantom: PhantomData<E>, _phantom: PhantomData<E>,
} }
impl<E: EthSpec> ValidatorStore<E> { impl<T: SlotClock + Clone + 'static, E: EthSpec> ValidatorStore<T, E> {
pub fn load_from_disk(base_dir: PathBuf, spec: ChainSpec, log: Logger) -> Result<Self, String> { pub fn load_from_disk(
base_dir: PathBuf,
spec: ChainSpec,
fork_service: ForkService<T, E>,
log: Logger,
) -> Result<Self, String> {
let validator_iter = read_dir(&base_dir) let validator_iter = read_dir(&base_dir)
.map_err(|e| format!("Failed to read base directory: {:?}", e))? .map_err(|e| format!("Failed to read base directory: {:?}", e))?
.filter_map(|validator_dir| { .filter_map(|validator_dir| {
@@ -60,6 +68,7 @@ impl<E: EthSpec> ValidatorStore<E> {
spec: Arc::new(spec), spec: Arc::new(spec),
log, log,
temp_dir: None, temp_dir: None,
fork_service,
_phantom: PhantomData, _phantom: PhantomData,
}) })
} }
@@ -67,6 +76,7 @@ impl<E: EthSpec> ValidatorStore<E> {
pub fn insecure_ephemeral_validators( pub fn insecure_ephemeral_validators(
range: Range<usize>, range: Range<usize>,
spec: ChainSpec, spec: ChainSpec,
fork_service: ForkService<T, E>,
log: Logger, log: Logger,
) -> Result<Self, String> { ) -> Result<Self, String> {
let temp_dir = TempDir::new("insecure_validator") let temp_dir = TempDir::new("insecure_validator")
@@ -100,6 +110,7 @@ impl<E: EthSpec> ValidatorStore<E> {
spec: Arc::new(spec), spec: Arc::new(spec),
log, log,
temp_dir: Some(Arc::new(temp_dir)), temp_dir: Some(Arc::new(temp_dir)),
fork_service,
_phantom: PhantomData, _phantom: PhantomData,
}) })
} }
@@ -116,22 +127,27 @@ impl<E: EthSpec> ValidatorStore<E> {
self.validators.read().len() self.validators.read().len()
} }
pub fn randao_reveal( fn fork(&self) -> Option<Fork> {
&self, if self.fork_service.fork().is_none() {
validator_pubkey: &PublicKey, error!(
epoch: Epoch, self.log,
fork: &Fork, "Unable to get Fork for signing";
) -> Option<Signature> { );
}
self.fork_service.fork()
}
pub fn randao_reveal(&self, validator_pubkey: &PublicKey, epoch: Epoch) -> Option<Signature> {
// TODO: check this against the slot clock to make sure it's not an early reveal? // TODO: check this against the slot clock to make sure it's not an early reveal?
self.validators self.validators
.read() .read()
.get(validator_pubkey) .get(validator_pubkey)
.and_then(|validator_dir| { .and_then(|validator_dir| {
validator_dir.voting_keypair.as_ref().map(|voting_keypair| { let voting_keypair = validator_dir.voting_keypair.as_ref()?;
let message = epoch.tree_hash_root(); let message = epoch.tree_hash_root();
let domain = self.spec.get_domain(epoch, Domain::Randao, &fork); let domain = self.spec.get_domain(epoch, Domain::Randao, &self.fork()?);
Signature::new(&message, domain, &voting_keypair.sk)
}) Some(Signature::new(&message, domain, &voting_keypair.sk))
}) })
} }
@@ -139,20 +155,15 @@ impl<E: EthSpec> ValidatorStore<E> {
&self, &self,
validator_pubkey: &PublicKey, validator_pubkey: &PublicKey,
mut block: BeaconBlock<E>, mut block: BeaconBlock<E>,
fork: &Fork,
) -> Option<BeaconBlock<E>> { ) -> Option<BeaconBlock<E>> {
// TODO: check for slashing. // TODO: check for slashing.
self.validators self.validators
.read() .read()
.get(validator_pubkey) .get(validator_pubkey)
.and_then(|validator_dir| { .and_then(|validator_dir| {
validator_dir.voting_keypair.as_ref().map(|voting_keypair| { let voting_keypair = validator_dir.voting_keypair.as_ref()?;
let epoch = block.slot.epoch(E::slots_per_epoch()); block.sign(&voting_keypair.sk, &self.fork()?, &self.spec);
let message = block.signed_root(); Some(block)
let domain = self.spec.get_domain(epoch, Domain::BeaconProposer, &fork);
block.signature = Signature::new(&message, domain, &voting_keypair.sk);
block
})
}) })
} }
@@ -161,34 +172,31 @@ impl<E: EthSpec> ValidatorStore<E> {
validator_pubkey: &PublicKey, validator_pubkey: &PublicKey,
validator_committee_position: usize, validator_committee_position: usize,
mut attestation: Attestation<E>, mut attestation: Attestation<E>,
fork: &Fork,
) -> Option<Attestation<E>> { ) -> Option<Attestation<E>> {
// TODO: check for slashing. // TODO: check for slashing.
self.validators self.validators
.read() .read()
.get(validator_pubkey) .get(validator_pubkey)
.and_then(|validator_dir| { .and_then(|validator_dir| {
validator_dir let voting_keypair = validator_dir.voting_keypair.as_ref()?;
.voting_keypair
.as_ref() attestation
.and_then(|voting_keypair| { .sign(
attestation &voting_keypair.sk,
.sign( validator_committee_position,
&voting_keypair.sk, &self.fork()?,
validator_committee_position, &self.spec,
fork, )
&self.spec, .map_err(|e| {
) error!(
.map_err(|e| { self.log,
error!( "Error whilst signing attestation";
self.log, "error" => format!("{:?}", e)
"Error whilst signing attestation"; )
"error" => format!("{:?}", e)
)
})
.map(|()| attestation)
.ok()
}) })
.ok()?;
Some(attestation)
}) })
} }
} }