mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-29 10:54:24 +00:00
Tidy signing, reduce ForkService duplication
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
# CI & Testing
|
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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)]
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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| {
|
||||||
|
|||||||
@@ -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>,
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user