mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 18:32:42 +00:00
Altair validator client and HTTP API (#2404)
## Proposed Changes * Implement the validator client and HTTP API changes necessary to support Altair Co-authored-by: realbigsean <seananderson33@gmail.com> Co-authored-by: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -5,12 +5,12 @@ mod check_synced;
|
||||
mod cli;
|
||||
mod config;
|
||||
mod duties_service;
|
||||
mod fork_service;
|
||||
mod graffiti_file;
|
||||
mod http_metrics;
|
||||
mod initialized_validators;
|
||||
mod key_cache;
|
||||
mod notifier;
|
||||
mod sync_committee_service;
|
||||
mod validator_store;
|
||||
|
||||
mod doppelganger_service;
|
||||
@@ -31,9 +31,7 @@ use block_service::{BlockService, BlockServiceBuilder};
|
||||
use clap::ArgMatches;
|
||||
use duties_service::DutiesService;
|
||||
use environment::RuntimeContext;
|
||||
use eth2::types::StateId;
|
||||
use eth2::{reqwest::ClientBuilder, BeaconNodeHttpClient, StatusCode, Timeouts};
|
||||
use fork_service::{ForkService, ForkServiceBuilder};
|
||||
use http_api::ApiSecret;
|
||||
use initialized_validators::InitializedValidators;
|
||||
use notifier::spawn_notifier;
|
||||
@@ -46,11 +44,12 @@ use std::marker::PhantomData;
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use sync_committee_service::SyncCommitteeService;
|
||||
use tokio::{
|
||||
sync::mpsc,
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
use types::{EthSpec, Fork, Hash256};
|
||||
use types::{EthSpec, Hash256};
|
||||
use validator_store::ValidatorStore;
|
||||
|
||||
/// The interval between attempts to contact the beacon node during startup.
|
||||
@@ -66,6 +65,7 @@ const HTTP_ATTESTER_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_LIVENESS_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_PROPOSAL_TIMEOUT_QUOTIENT: u32 = 2;
|
||||
const HTTP_PROPOSER_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
const HTTP_SYNC_DUTIES_TIMEOUT_QUOTIENT: u32 = 4;
|
||||
|
||||
const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger";
|
||||
|
||||
@@ -73,9 +73,9 @@ const DOPPELGANGER_SERVICE_NAME: &str = "doppelganger";
|
||||
pub struct ProductionValidatorClient<T: EthSpec> {
|
||||
context: RuntimeContext<T>,
|
||||
duties_service: Arc<DutiesService<SystemTimeSlotClock, T>>,
|
||||
fork_service: ForkService<SystemTimeSlotClock, T>,
|
||||
block_service: BlockService<SystemTimeSlotClock, T>,
|
||||
attestation_service: AttestationService<SystemTimeSlotClock, T>,
|
||||
sync_committee_service: SyncCommitteeService<SystemTimeSlotClock, T>,
|
||||
doppelganger_service: Option<Arc<DoppelgangerService>>,
|
||||
validator_store: Arc<ValidatorStore<SystemTimeSlotClock, T>>,
|
||||
http_api_listen_addr: Option<SocketAddr>,
|
||||
@@ -263,6 +263,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
liveness: slot_duration / HTTP_LIVENESS_TIMEOUT_QUOTIENT,
|
||||
proposal: slot_duration / HTTP_PROPOSAL_TIMEOUT_QUOTIENT,
|
||||
proposer_duties: slot_duration / HTTP_PROPOSER_DUTIES_TIMEOUT_QUOTIENT,
|
||||
sync_duties: slot_duration / HTTP_SYNC_DUTIES_TIMEOUT_QUOTIENT,
|
||||
}
|
||||
} else {
|
||||
Timeouts::set_all(slot_duration)
|
||||
@@ -293,7 +294,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
BeaconNodeFallback::new(candidates, context.eth2_config.spec.clone(), log.clone());
|
||||
|
||||
// Perform some potentially long-running initialization tasks.
|
||||
let (genesis_time, genesis_validators_root, fork) = tokio::select! {
|
||||
let (genesis_time, genesis_validators_root) = tokio::select! {
|
||||
tuple = init_from_beacon_node(&beacon_nodes, &context) => tuple?,
|
||||
() = context.executor.exit() => return Err("Shutting down".to_string())
|
||||
};
|
||||
@@ -313,13 +314,6 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
let beacon_nodes = Arc::new(beacon_nodes);
|
||||
start_fallback_updater_service(context.clone(), beacon_nodes.clone())?;
|
||||
|
||||
let fork_service = ForkServiceBuilder::new()
|
||||
.fork(fork)
|
||||
.slot_clock(slot_clock.clone())
|
||||
.beacon_nodes(beacon_nodes.clone())
|
||||
.log(log.clone())
|
||||
.build()?;
|
||||
|
||||
let doppelganger_service = if config.enable_doppelganger_protection {
|
||||
Some(Arc::new(DoppelgangerService::new(
|
||||
context
|
||||
@@ -331,16 +325,15 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
None
|
||||
};
|
||||
|
||||
let validator_store: Arc<ValidatorStore<SystemTimeSlotClock, T>> =
|
||||
Arc::new(ValidatorStore::new(
|
||||
validators,
|
||||
slashing_protection,
|
||||
genesis_validators_root,
|
||||
context.eth2_config.spec.clone(),
|
||||
fork_service.clone(),
|
||||
doppelganger_service.clone(),
|
||||
log.clone(),
|
||||
));
|
||||
let validator_store = Arc::new(ValidatorStore::new(
|
||||
validators,
|
||||
slashing_protection,
|
||||
genesis_validators_root,
|
||||
context.eth2_config.spec.clone(),
|
||||
doppelganger_service.clone(),
|
||||
slot_clock.clone(),
|
||||
log.clone(),
|
||||
));
|
||||
|
||||
info!(
|
||||
log,
|
||||
@@ -359,6 +352,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
let duties_service = Arc::new(DutiesService {
|
||||
attesters: <_>::default(),
|
||||
proposers: <_>::default(),
|
||||
sync_duties: <_>::default(),
|
||||
slot_clock: slot_clock.clone(),
|
||||
beacon_nodes: beacon_nodes.clone(),
|
||||
validator_store: validator_store.clone(),
|
||||
@@ -394,6 +388,14 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
.runtime_context(context.service_context("attestation".into()))
|
||||
.build()?;
|
||||
|
||||
let sync_committee_service = SyncCommitteeService::new(
|
||||
duties_service.clone(),
|
||||
validator_store.clone(),
|
||||
slot_clock,
|
||||
beacon_nodes.clone(),
|
||||
context.service_context("sync_committee".into()),
|
||||
);
|
||||
|
||||
// Wait until genesis has occured.
|
||||
//
|
||||
// It seems most sensible to move this into the `start_service` function, but I'm caution
|
||||
@@ -406,9 +408,9 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
Ok(Self {
|
||||
context,
|
||||
duties_service,
|
||||
fork_service,
|
||||
block_service,
|
||||
attestation_service,
|
||||
sync_committee_service,
|
||||
doppelganger_service,
|
||||
validator_store,
|
||||
config,
|
||||
@@ -427,11 +429,6 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
|
||||
duties_service::start_update_service(self.duties_service.clone(), block_service_tx);
|
||||
|
||||
self.fork_service
|
||||
.clone()
|
||||
.start_update_service(&self.context)
|
||||
.map_err(|e| format!("Unable to start fork service: {}", e))?;
|
||||
|
||||
self.block_service
|
||||
.clone()
|
||||
.start_update_service(block_service_rx)
|
||||
@@ -442,6 +439,11 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
.start_update_service(&self.context.eth2_config.spec)
|
||||
.map_err(|e| format!("Unable to start attestation service: {}", e))?;
|
||||
|
||||
self.sync_committee_service
|
||||
.clone()
|
||||
.start_update_service(&self.context.eth2_config.spec)
|
||||
.map_err(|e| format!("Unable to start sync committee service: {}", e))?;
|
||||
|
||||
if let Some(doppelganger_service) = self.doppelganger_service.clone() {
|
||||
DoppelgangerService::start_update_service(
|
||||
doppelganger_service,
|
||||
@@ -461,7 +463,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
let api_secret = ApiSecret::create_or_open(&self.config.validator_dir)?;
|
||||
|
||||
self.http_api_listen_addr = if self.config.http_api.enabled {
|
||||
let ctx: Arc<http_api::Context<SystemTimeSlotClock, T>> = Arc::new(http_api::Context {
|
||||
let ctx = Arc::new(http_api::Context {
|
||||
runtime: self.context.executor.runtime(),
|
||||
api_secret,
|
||||
validator_store: Some(self.validator_store.clone()),
|
||||
@@ -495,7 +497,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
async fn init_from_beacon_node<E: EthSpec>(
|
||||
beacon_nodes: &BeaconNodeFallback<SystemTimeSlotClock, E>,
|
||||
context: &RuntimeContext<E>,
|
||||
) -> Result<(u64, Hash256, Fork), String> {
|
||||
) -> Result<(u64, Hash256), String> {
|
||||
loop {
|
||||
beacon_nodes.update_unready_candidates().await;
|
||||
let num_available = beacon_nodes.num_available().await;
|
||||
@@ -554,33 +556,7 @@ async fn init_from_beacon_node<E: EthSpec>(
|
||||
sleep(RETRY_DELAY).await;
|
||||
};
|
||||
|
||||
let fork = loop {
|
||||
match beacon_nodes
|
||||
.first_success(RequireSynced::No, |node| async move {
|
||||
node.get_beacon_states_fork(StateId::Head).await
|
||||
})
|
||||
.await
|
||||
{
|
||||
Ok(Some(fork)) => break fork.data,
|
||||
Ok(None) => {
|
||||
info!(
|
||||
context.log(),
|
||||
"Failed to get fork, state not found";
|
||||
);
|
||||
}
|
||||
Err(errors) => {
|
||||
error!(
|
||||
context.log(),
|
||||
"Failed to get fork";
|
||||
"error" => %errors
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sleep(RETRY_DELAY).await;
|
||||
};
|
||||
|
||||
Ok((genesis.genesis_time, genesis.genesis_validators_root, fork))
|
||||
Ok((genesis.genesis_time, genesis.genesis_validators_root))
|
||||
}
|
||||
|
||||
async fn wait_for_genesis<E: EthSpec>(
|
||||
|
||||
Reference in New Issue
Block a user