mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-22 14:24:44 +00:00
Merge branch 'unstable' into validator-manager
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use crate::beacon_node_fallback::{Error as FallbackError, Errors};
|
||||
use crate::{
|
||||
beacon_node_fallback::{BeaconNodeFallback, RequireSynced},
|
||||
determine_graffiti,
|
||||
graffiti_file::GraffitiFile,
|
||||
OfflineOnFailure,
|
||||
};
|
||||
@@ -11,7 +12,9 @@ use slog::{crit, debug, error, info, trace, warn};
|
||||
use slot_clock::SlotClock;
|
||||
use std::ops::Deref;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use tokio::sync::mpsc;
|
||||
use tokio::time::sleep;
|
||||
use types::{BlindedPayload, BlockType, EthSpec, ExecPayload, FullPayload, PublicKeyBytes, Slot};
|
||||
|
||||
#[derive(Debug)]
|
||||
@@ -43,6 +46,7 @@ pub struct BlockServiceBuilder<T, E: EthSpec> {
|
||||
context: Option<RuntimeContext<E>>,
|
||||
graffiti: Option<Graffiti>,
|
||||
graffiti_file: Option<GraffitiFile>,
|
||||
block_delay: Option<Duration>,
|
||||
}
|
||||
|
||||
impl<T: SlotClock + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
|
||||
@@ -54,6 +58,7 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
|
||||
context: None,
|
||||
graffiti: None,
|
||||
graffiti_file: None,
|
||||
block_delay: None,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,6 +92,11 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn block_delay(mut self, block_delay: Option<Duration>) -> Self {
|
||||
self.block_delay = block_delay;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<BlockService<T, E>, String> {
|
||||
Ok(BlockService {
|
||||
inner: Arc::new(Inner {
|
||||
@@ -104,6 +114,7 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockServiceBuilder<T, E> {
|
||||
.ok_or("Cannot build BlockService without runtime_context")?,
|
||||
graffiti: self.graffiti,
|
||||
graffiti_file: self.graffiti_file,
|
||||
block_delay: self.block_delay,
|
||||
}),
|
||||
})
|
||||
}
|
||||
@@ -117,6 +128,7 @@ pub struct Inner<T, E: EthSpec> {
|
||||
context: RuntimeContext<E>,
|
||||
graffiti: Option<Graffiti>,
|
||||
graffiti_file: Option<GraffitiFile>,
|
||||
block_delay: Option<Duration>,
|
||||
}
|
||||
|
||||
/// Attempts to produce attestations for any block producer(s) at the start of the epoch.
|
||||
@@ -161,6 +173,16 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
||||
async move {
|
||||
while let Some(notif) = notification_rx.recv().await {
|
||||
let service = self.clone();
|
||||
|
||||
if let Some(delay) = service.block_delay {
|
||||
debug!(
|
||||
service.context.log(),
|
||||
"Delaying block production by {}ms",
|
||||
delay.as_millis()
|
||||
);
|
||||
sleep(delay).await;
|
||||
}
|
||||
|
||||
service.do_update(notif).await.ok();
|
||||
}
|
||||
debug!(log, "Block service shutting down");
|
||||
@@ -298,18 +320,13 @@ impl<T: SlotClock + 'static, E: EthSpec> BlockService<T, E> {
|
||||
})?
|
||||
.into();
|
||||
|
||||
let graffiti = self
|
||||
.graffiti_file
|
||||
.clone()
|
||||
.and_then(|mut g| match g.load_graffiti(&validator_pubkey) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
warn!(log, "Failed to read graffiti file"; "error" => ?e);
|
||||
None
|
||||
}
|
||||
})
|
||||
.or_else(|| self.validator_store.graffiti(&validator_pubkey))
|
||||
.or(self.graffiti);
|
||||
let graffiti = determine_graffiti(
|
||||
&validator_pubkey,
|
||||
log,
|
||||
self.graffiti_file.clone(),
|
||||
self.validator_store.graffiti(&validator_pubkey),
|
||||
self.graffiti,
|
||||
);
|
||||
|
||||
let randao_reveal_ref = &randao_reveal;
|
||||
let self_ref = &self;
|
||||
|
||||
@@ -330,5 +330,17 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
|
||||
by this validator client. Note this will not necessarily be used if the gas limit \
|
||||
set here moves too far from the previous block's gas limit. [default: 30,000,000]")
|
||||
.requires("builder-proposals"),
|
||||
)
|
||||
)
|
||||
/*
|
||||
* Experimental/development options.
|
||||
*/
|
||||
.arg(
|
||||
Arg::with_name("block-delay-ms")
|
||||
.long("block-delay-ms")
|
||||
.value_name("MILLIS")
|
||||
.hidden(true)
|
||||
.help("Time to delay block production from the start of the slot. Should only be \
|
||||
used for testing.")
|
||||
.takes_value(true),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use slog::{info, warn, Logger};
|
||||
use std::fs;
|
||||
use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Duration;
|
||||
use types::{Address, GRAFFITI_BYTES_LEN};
|
||||
|
||||
pub const DEFAULT_BEACON_NODE: &str = "http://localhost:5052/";
|
||||
@@ -61,6 +62,10 @@ pub struct Config {
|
||||
/// A list of custom certificates that the validator client will additionally use when
|
||||
/// connecting to a beacon node over SSL/TLS.
|
||||
pub beacon_nodes_tls_certs: Option<Vec<PathBuf>>,
|
||||
/// Delay from the start of the slot to wait before publishing a block.
|
||||
///
|
||||
/// This is *not* recommended in prod and should only be used for testing.
|
||||
pub block_delay: Option<Duration>,
|
||||
/// Disables publishing http api requests to all beacon nodes for select api calls.
|
||||
pub disable_run_on_all: bool,
|
||||
}
|
||||
@@ -95,6 +100,7 @@ impl Default for Config {
|
||||
monitoring_api: None,
|
||||
enable_doppelganger_protection: false,
|
||||
beacon_nodes_tls_certs: None,
|
||||
block_delay: None,
|
||||
builder_proposals: false,
|
||||
builder_registration_timestamp_override: None,
|
||||
gas_limit: None,
|
||||
@@ -349,6 +355,13 @@ impl Config {
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* Experimental
|
||||
*/
|
||||
if let Some(delay_ms) = parse_optional::<u64>(cli_args, "block-delay-ms")? {
|
||||
config.block_delay = Some(Duration::from_millis(delay_ms));
|
||||
}
|
||||
|
||||
Ok(config)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ mod tests;
|
||||
|
||||
pub mod test_utils;
|
||||
|
||||
use crate::ValidatorStore;
|
||||
use crate::{determine_graffiti, GraffitiFile, ValidatorStore};
|
||||
use account_utils::{
|
||||
mnemonic_from_phrase,
|
||||
validator_definitions::{
|
||||
@@ -17,13 +17,14 @@ pub use api_secret::ApiSecret;
|
||||
use create_validator::{create_validators_mnemonic, create_validators_web3signer};
|
||||
use eth2::lighthouse_vc::{
|
||||
std_types::{AuthResponse, GetFeeRecipientResponse, GetGasLimitResponse},
|
||||
types::{self as api_types, GenericResponse, PublicKey, PublicKeyBytes},
|
||||
types::{self as api_types, GenericResponse, Graffiti, PublicKey, PublicKeyBytes},
|
||||
};
|
||||
use lighthouse_version::version_with_platform;
|
||||
use parking_lot::RwLock;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use slog::{crit, info, warn, Logger};
|
||||
use slot_clock::SlotClock;
|
||||
use std::collections::HashMap;
|
||||
use std::future::Future;
|
||||
use std::marker::PhantomData;
|
||||
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
||||
@@ -70,6 +71,8 @@ pub struct Context<T: SlotClock, E: EthSpec> {
|
||||
pub validator_store: Option<Arc<ValidatorStore<T, E>>>,
|
||||
pub validator_dir: Option<PathBuf>,
|
||||
pub secrets_dir: Option<PathBuf>,
|
||||
pub graffiti_file: Option<GraffitiFile>,
|
||||
pub graffiti_flag: Option<Graffiti>,
|
||||
pub spec: ChainSpec,
|
||||
pub config: Config,
|
||||
pub log: Logger,
|
||||
@@ -199,6 +202,12 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
},
|
||||
);
|
||||
|
||||
let inner_graffiti_file = ctx.graffiti_file.clone();
|
||||
let graffiti_file_filter = warp::any().map(move || inner_graffiti_file.clone());
|
||||
|
||||
let inner_graffiti_flag = ctx.graffiti_flag;
|
||||
let graffiti_flag_filter = warp::any().map(move || inner_graffiti_flag);
|
||||
|
||||
let inner_ctx = ctx.clone();
|
||||
let log_filter = warp::any().map(move || inner_ctx.log.clone());
|
||||
|
||||
@@ -351,6 +360,42 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
})
|
||||
});
|
||||
|
||||
let get_lighthouse_ui_graffiti = warp::path("lighthouse")
|
||||
.and(warp::path("ui"))
|
||||
.and(warp::path("graffiti"))
|
||||
.and(warp::path::end())
|
||||
.and(validator_store_filter.clone())
|
||||
.and(graffiti_file_filter)
|
||||
.and(graffiti_flag_filter)
|
||||
.and(signer.clone())
|
||||
.and(log_filter.clone())
|
||||
.and_then(
|
||||
|validator_store: Arc<ValidatorStore<T, E>>,
|
||||
graffiti_file: Option<GraffitiFile>,
|
||||
graffiti_flag: Option<Graffiti>,
|
||||
signer,
|
||||
log| {
|
||||
blocking_signed_json_task(signer, move || {
|
||||
let mut result = HashMap::new();
|
||||
for (key, graffiti_definition) in validator_store
|
||||
.initialized_validators()
|
||||
.read()
|
||||
.get_all_validators_graffiti()
|
||||
{
|
||||
let graffiti = determine_graffiti(
|
||||
key,
|
||||
&log,
|
||||
graffiti_file.clone(),
|
||||
graffiti_definition,
|
||||
graffiti_flag,
|
||||
);
|
||||
result.insert(key.to_string(), graffiti.map(|g| g.as_utf8_lossy()));
|
||||
}
|
||||
Ok(api_types::GenericResponse::from(result))
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// POST lighthouse/validators/
|
||||
let post_validators = warp::path("lighthouse")
|
||||
.and(warp::path("validators"))
|
||||
@@ -1028,6 +1073,7 @@ pub fn serve<T: 'static + SlotClock + Clone, E: EthSpec>(
|
||||
.or(get_lighthouse_validators)
|
||||
.or(get_lighthouse_validators_pubkey)
|
||||
.or(get_lighthouse_ui_health)
|
||||
.or(get_lighthouse_ui_graffiti)
|
||||
.or(get_fee_recipient)
|
||||
.or(get_gas_limit)
|
||||
.or(get_std_keystores)
|
||||
|
||||
@@ -123,6 +123,8 @@ impl ApiTester {
|
||||
validator_dir: Some(validator_dir.path().into()),
|
||||
secrets_dir: Some(secrets_dir.path().into()),
|
||||
validator_store: Some(validator_store.clone()),
|
||||
graffiti_file: None,
|
||||
graffiti_flag: Some(Graffiti::default()),
|
||||
spec: E::default_spec(),
|
||||
config: HttpConfig {
|
||||
enabled: true,
|
||||
|
||||
@@ -660,6 +660,15 @@ impl InitializedValidators {
|
||||
self.validators.get(public_key).and_then(|v| v.graffiti)
|
||||
}
|
||||
|
||||
/// Returns a `HashMap` of `public_key` -> `graffiti` for all initialized validators.
|
||||
pub fn get_all_validators_graffiti(&self) -> HashMap<&PublicKeyBytes, Option<Graffiti>> {
|
||||
let mut result = HashMap::new();
|
||||
for public_key in self.validators.keys() {
|
||||
result.insert(public_key, self.graffiti(public_key));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
/// Returns the `suggested_fee_recipient` for a given public key specified in the
|
||||
/// `ValidatorDefinitions`.
|
||||
pub fn suggested_fee_recipient(&self, public_key: &PublicKeyBytes) -> Option<Address> {
|
||||
|
||||
@@ -30,13 +30,14 @@ use crate::beacon_node_fallback::{
|
||||
RequireSynced,
|
||||
};
|
||||
use crate::doppelganger_service::DoppelgangerService;
|
||||
use crate::graffiti_file::GraffitiFile;
|
||||
use account_utils::validator_definitions::ValidatorDefinitions;
|
||||
use attestation_service::{AttestationService, AttestationServiceBuilder};
|
||||
use block_service::{BlockService, BlockServiceBuilder};
|
||||
use clap::ArgMatches;
|
||||
use duties_service::DutiesService;
|
||||
use environment::RuntimeContext;
|
||||
use eth2::{reqwest::ClientBuilder, BeaconNodeHttpClient, StatusCode, Timeouts};
|
||||
use eth2::{reqwest::ClientBuilder, types::Graffiti, BeaconNodeHttpClient, StatusCode, Timeouts};
|
||||
use http_api::ApiSecret;
|
||||
use notifier::spawn_notifier;
|
||||
use parking_lot::RwLock;
|
||||
@@ -57,7 +58,7 @@ use tokio::{
|
||||
sync::mpsc,
|
||||
time::{sleep, Duration},
|
||||
};
|
||||
use types::{EthSpec, Hash256};
|
||||
use types::{EthSpec, Hash256, PublicKeyBytes};
|
||||
use validator_store::ValidatorStore;
|
||||
|
||||
/// The interval between attempts to contact the beacon node during startup.
|
||||
@@ -426,6 +427,7 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
.runtime_context(context.service_context("block".into()))
|
||||
.graffiti(config.graffiti)
|
||||
.graffiti_file(config.graffiti_file.clone())
|
||||
.block_delay(config.block_delay)
|
||||
.build()?;
|
||||
|
||||
let attestation_service = AttestationServiceBuilder::new()
|
||||
@@ -527,6 +529,8 @@ impl<T: EthSpec> ProductionValidatorClient<T> {
|
||||
validator_store: Some(self.validator_store.clone()),
|
||||
validator_dir: Some(self.config.validator_dir.clone()),
|
||||
secrets_dir: Some(self.config.secrets_dir.clone()),
|
||||
graffiti_file: self.config.graffiti_file.clone(),
|
||||
graffiti_flag: self.config.graffiti,
|
||||
spec: self.context.eth2_config.spec.clone(),
|
||||
config: self.config.http_api.clone(),
|
||||
log: log.clone(),
|
||||
@@ -727,3 +731,24 @@ pub fn load_pem_certificate<P: AsRef<Path>>(pem_path: P) -> Result<Certificate,
|
||||
.map_err(|e| format!("Unable to read certificate file: {}", e))?;
|
||||
Certificate::from_pem(&buf).map_err(|e| format!("Unable to parse certificate: {}", e))
|
||||
}
|
||||
|
||||
// Given the various graffiti control methods, determine the graffiti that will be used for
|
||||
// the next block produced by the validator with the given public key.
|
||||
pub fn determine_graffiti(
|
||||
validator_pubkey: &PublicKeyBytes,
|
||||
log: &Logger,
|
||||
graffiti_file: Option<GraffitiFile>,
|
||||
validator_definition_graffiti: Option<Graffiti>,
|
||||
graffiti_flag: Option<Graffiti>,
|
||||
) -> Option<Graffiti> {
|
||||
graffiti_file
|
||||
.and_then(|mut g| match g.load_graffiti(validator_pubkey) {
|
||||
Ok(g) => g,
|
||||
Err(e) => {
|
||||
warn!(log, "Failed to read graffiti file"; "error" => ?e);
|
||||
None
|
||||
}
|
||||
})
|
||||
.or(validator_definition_graffiti)
|
||||
.or(graffiti_flag)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user