Merge branch 'unstable' into validator-manager

This commit is contained in:
Paul Hauner
2022-12-14 16:38:52 +11:00
94 changed files with 3666 additions and 1785 deletions

View File

@@ -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;

View File

@@ -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),
)
}

View File

@@ -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)
}
}

View File

@@ -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)

View File

@@ -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,

View File

@@ -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> {

View File

@@ -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)
}