From 392e2ae9320bfd61d12add6497c1ea7df5bf82f9 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 1 Oct 2024 17:59:08 +1000 Subject: [PATCH 1/6] Starting to modularize the VC --- Cargo.lock | 162 ++++++++++++++++- Cargo.toml | 19 +- common/eth2/src/lib.rs | 168 ------------------ validator_client/Cargo.toml | 1 + .../beacon_node_fallback/Cargo.toml | 23 +++ .../src/check_synced.rs | 2 +- .../src/lib.rs} | 5 +- .../doppelganger_service/Cargo.toml | 22 +++ .../src/lib.rs} | 22 ++- validator_client/duties_service/Cargo.toml | 26 +++ .../src/attestation_service.rs | 0 .../{ => duties_service}/src/block_service.rs | 0 .../src/lib.rs} | 94 +++++----- .../src/preparation_service.rs | 0 .../src}/sync.rs | 18 +- .../src/sync_committee_service.rs | 0 validator_client/http_api/Cargo.toml | 15 ++ .../http_api => http_api/src}/api_secret.rs | 0 .../src}/create_signed_voluntary_exit.rs | 0 .../src}/create_validator.rs | 0 .../http_api => http_api/src}/graffiti.rs | 0 .../http_api => http_api/src}/keystores.rs | 0 .../http_api/mod.rs => http_api/src/lib.rs} | 0 .../http_api => http_api/src}/remotekeys.rs | 0 .../http_api => http_api/src}/test_utils.rs | 0 .../{src/http_api => http_api/src}/tests.rs | 0 .../src}/tests/keystores.rs | 0 validator_client/http_metrics/Cargo.toml | 23 +++ .../mod.rs => http_metrics/src/lib.rs} | 71 ++++++-- .../initialized_validators/Cargo.toml | 33 ++++ .../src/key_cache.rs | 0 .../src/lib.rs} | 18 +- validator_client/signing_method/Cargo.toml | 23 +++ .../src/lib.rs} | 13 +- .../src}/web3signer.rs | 0 validator_client/src/lib.rs | 23 ++- validator_client/validator_metrics/Cargo.toml | 15 ++ .../src/lib.rs} | 60 ------- validator_client/validator_store/Cargo.toml | 24 +++ .../src/lib.rs} | 121 ++++++++----- 40 files changed, 629 insertions(+), 372 deletions(-) create mode 100644 validator_client/beacon_node_fallback/Cargo.toml rename validator_client/{ => beacon_node_fallback}/src/check_synced.rs (98%) rename validator_client/{src/beacon_node_fallback.rs => beacon_node_fallback/src/lib.rs} (99%) create mode 100644 validator_client/doppelganger_service/Cargo.toml rename validator_client/{src/doppelganger_service.rs => doppelganger_service/src/lib.rs} (98%) create mode 100644 validator_client/duties_service/Cargo.toml rename validator_client/{ => duties_service}/src/attestation_service.rs (100%) rename validator_client/{ => duties_service}/src/block_service.rs (100%) rename validator_client/{src/duties_service.rs => duties_service/src/lib.rs} (95%) rename validator_client/{ => duties_service}/src/preparation_service.rs (100%) rename validator_client/{src/duties_service => duties_service/src}/sync.rs (98%) rename validator_client/{ => duties_service}/src/sync_committee_service.rs (100%) create mode 100644 validator_client/http_api/Cargo.toml rename validator_client/{src/http_api => http_api/src}/api_secret.rs (100%) rename validator_client/{src/http_api => http_api/src}/create_signed_voluntary_exit.rs (100%) rename validator_client/{src/http_api => http_api/src}/create_validator.rs (100%) rename validator_client/{src/http_api => http_api/src}/graffiti.rs (100%) rename validator_client/{src/http_api => http_api/src}/keystores.rs (100%) rename validator_client/{src/http_api/mod.rs => http_api/src/lib.rs} (100%) rename validator_client/{src/http_api => http_api/src}/remotekeys.rs (100%) rename validator_client/{src/http_api => http_api/src}/test_utils.rs (100%) rename validator_client/{src/http_api => http_api/src}/tests.rs (100%) rename validator_client/{src/http_api => http_api/src}/tests/keystores.rs (100%) create mode 100644 validator_client/http_metrics/Cargo.toml rename validator_client/{src/http_metrics/mod.rs => http_metrics/src/lib.rs} (68%) create mode 100644 validator_client/initialized_validators/Cargo.toml rename validator_client/{ => initialized_validators}/src/key_cache.rs (100%) rename validator_client/{src/initialized_validators.rs => initialized_validators/src/lib.rs} (99%) create mode 100644 validator_client/signing_method/Cargo.toml rename validator_client/{src/signing_method.rs => signing_method/src/lib.rs} (96%) rename validator_client/{src/signing_method => signing_method/src}/web3signer.rs (100%) create mode 100644 validator_client/validator_metrics/Cargo.toml rename validator_client/{src/http_metrics/metrics.rs => validator_metrics/src/lib.rs} (82%) create mode 100644 validator_client/validator_store/Cargo.toml rename validator_client/{src/validator_store.rs => validator_store/src/lib.rs} (91%) diff --git a/Cargo.lock b/Cargo.lock index 94eb9038447..510be1dcd9e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -660,9 +660,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -686,7 +686,7 @@ dependencies = [ "serde_urlencoded", "sync_wrapper 1.0.1", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -694,9 +694,9 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -707,7 +707,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", "tracing", @@ -863,6 +863,22 @@ dependencies = [ "unused_port", ] +[[package]] +name = "beacon_node_fallback" +version = "0.1.0" +dependencies = [ + "environment", + "eth2", + "futures", + "serde", + "slog", + "slot_clock", + "strum", + "tokio", + "types", + "validator_metrics", +] + [[package]] name = "beacon_processor" version = "0.1.0" @@ -2210,6 +2226,21 @@ dependencies = [ "syn 2.0.77", ] +[[package]] +name = "doppelganger_service" +version = "0.1.0" +dependencies = [ + "beacon_node_fallback", + "environment", + "eth2", + "parking_lot 0.12.3", + "slog", + "slot_clock", + "task_executor", + "tokio", + "types", +] + [[package]] name = "dsl_auto_type" version = "0.1.2" @@ -2236,6 +2267,25 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "duties_service" +version = "0.1.0" +dependencies = [ + "beacon_node_fallback", + "doppelganger_service", + "environment", + "eth2", + "futures", + "parking_lot 0.12.3", + "safe_arith", + "slog", + "slot_clock", + "tokio", + "types", + "validator_metrics", + "validator_store", +] + [[package]] name = "ecdsa" version = "0.14.8" @@ -4016,6 +4066,8 @@ dependencies = [ "hyper 1.4.1", "pin-project-lite", "tokio", + "tower 0.4.13", + "tower-service", ] [[package]] @@ -4197,6 +4249,31 @@ dependencies = [ "hashbrown 0.14.5", ] +[[package]] +name = "initialized_validators" +version = "0.1.0" +dependencies = [ + "account_utils", + "bincode", + "bls", + "eth2_keystore", + "filesystem", + "lighthouse_metrics", + "lockfile", + "parking_lot 0.12.3", + "rand", + "reqwest", + "serde", + "serde_json", + "signing_method", + "slog", + "tokio", + "types", + "url", + "validator_dir", + "validator_metrics", +] + [[package]] name = "inout" version = "0.1.3" @@ -7723,6 +7800,22 @@ dependencies = [ "rand_core", ] +[[package]] +name = "signing_method" +version = "0.1.0" +dependencies = [ + "eth2_keystore", + "ethereum_serde_utils", + "lockfile", + "parking_lot 0.12.3", + "reqwest", + "serde", + "task_executor", + "types", + "url", + "validator_metrics", +] + [[package]] name = "simple_asn1" version = "0.6.2" @@ -8758,6 +8851,21 @@ dependencies = [ "tokio", "tower-layer", "tower-service", +] + +[[package]] +name = "tower" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper 0.1.2", + "tokio", + "tower-layer", + "tower-service", "tracing", ] @@ -9187,6 +9295,7 @@ dependencies = [ "types", "url", "validator_dir", + "validator_metrics", "warp", "warp_utils", ] @@ -9209,6 +9318,22 @@ dependencies = [ "types", ] +[[package]] +name = "validator_http_metrics" +version = "0.1.0" +dependencies = [ + "axum", + "lighthouse_metrics", + "lighthouse_version", + "malloc_utils", + "parking_lot 0.12.3", + "serde", + "slog", + "slot_clock", + "warp", + "warp_utils", +] + [[package]] name = "validator_manager" version = "0.1.0" @@ -9232,6 +9357,31 @@ dependencies = [ "validator_client", ] +[[package]] +name = "validator_metrics" +version = "0.1.0" +dependencies = [ + "lighthouse_metrics", + "malloc_utils", +] + +[[package]] +name = "validator_store" +version = "0.1.0" +dependencies = [ + "account_utils", + "doppelganger_service", + "initialized_validators", + "parking_lot 0.12.3", + "signing_method", + "slashing_protection", + "slog", + "slot_clock", + "task_executor", + "types", + "validator_metrics", +] + [[package]] name = "valuable" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 125231ad20e..d419e9f33d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -83,7 +83,15 @@ members = [ "testing/web3signer_tests", "validator_client", + "validator_client/beacon_node_fallback", + "validator_client/doppelganger_service", + "validator_client/duties_service", + "validator_client/http_metrics", + "validator_client/initialized_validators", + "validator_client/signing_method", "validator_client/slashing_protection", + "validator_client/validator_metrics", + "validator_client/validator_store", "validator_manager", @@ -101,6 +109,7 @@ alloy-consensus = "0.3.0" anyhow = "1" arbitrary = { version = "1", features = ["derive"] } async-channel = "1.9.0" +axum = "0.7.7" bincode = "1" bitvec = "1" byteorder = "1" @@ -169,7 +178,7 @@ superstruct = "0.8" syn = "1" sysinfo = "0.26" tempfile = "3" -tokio = { version = "1", features = ["rt-multi-thread", "sync", "signal"] } +tokio = { version = "1", features = ["rt-multi-thread", "sync", "signal", "macros"] } tokio-stream = { version = "0.1", features = ["sync"] } tokio-util = { version = "0.7", features = ["codec", "compat", "time"] } tracing = "0.1.40" @@ -189,12 +198,15 @@ zip = "0.6" account_utils = { path = "common/account_utils" } beacon_chain = { path = "beacon_node/beacon_chain" } beacon_node = { path = "beacon_node" } +beacon_node_fallback = { path = "validator_client/beacon_node_fallback" } beacon_processor = { path = "beacon_node/beacon_processor" } bls = { path = "crypto/bls" } clap_utils = { path = "common/clap_utils" } compare_fields = { path = "common/compare_fields" } deposit_contract = { path = "common/deposit_contract" } directory = { path = "common/directory" } +doppelganger_service = { path = "validator_client/doppelganger_service" } +duties_service = { path = "validator_client/duties_service" } environment = { path = "lighthouse/environment" } eth1 = { path = "beacon_node/eth1" } eth1_test_rig = { path = "testing/eth1_test_rig" } @@ -211,6 +223,7 @@ fork_choice = { path = "consensus/fork_choice" } genesis = { path = "beacon_node/genesis" } gossipsub = { path = "beacon_node/lighthouse_network/gossipsub/" } http_api = { path = "beacon_node/http_api" } +initialized_validators = { path = "validator_client/initialized_validators" } int_to_bytes = { path = "consensus/int_to_bytes" } kzg = { path = "crypto/kzg" } lighthouse_metrics = { path = "common/lighthouse_metrics" } @@ -228,6 +241,7 @@ pretty_reqwest_error = { path = "common/pretty_reqwest_error" } proto_array = { path = "consensus/proto_array" } safe_arith = { path = "consensus/safe_arith" } sensitive_url = { path = "common/sensitive_url" } +signing_method = { path = "validator_client/signing_method" } slasher = { path = "slasher", default-features = false } slashing_protection = { path = "validator_client/slashing_protection" } slot_clock = { path = "common/slot_clock" } @@ -239,6 +253,9 @@ types = { path = "consensus/types" } unused_port = { path = "common/unused_port" } validator_client = { path = "validator_client" } validator_dir = { path = "common/validator_dir" } +validator_http_metrics = { path = "validator_client/http_metrics" } +validator_metrics = { path = "validator_client/validator_metrics" } +validator_store= { path = "validator_client/validator_store" } warp_utils = { path = "common/warp_utils" } [profile.maxperf] diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index 2805d36b90c..ca91f43eb17 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -2471,171 +2471,3 @@ impl BeaconNodeHttpClient { &self, epoch: Epoch, indices: &[u64], - ) -> Result>, Error> { - let mut path = self.eth_path(V1)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("duties") - .push("attester") - .push(&epoch.to_string()); - - self.post_with_timeout_and_response( - path, - &ValidatorIndexDataRef(indices), - self.timeouts.attester_duties, - ) - .await - } - - /// `POST v1/validator/aggregate_and_proofs` - pub async fn post_validator_aggregate_and_proof_v1( - &self, - aggregates: &[SignedAggregateAndProof], - ) -> Result<(), Error> { - let mut path = self.eth_path(V1)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("aggregate_and_proofs"); - - self.post_with_timeout(path, &aggregates, self.timeouts.attestation) - .await?; - - Ok(()) - } - - /// `POST v2/validator/aggregate_and_proofs` - pub async fn post_validator_aggregate_and_proof_v2( - &self, - aggregates: &[SignedAggregateAndProof], - fork_name: ForkName, - ) -> Result<(), Error> { - let mut path = self.eth_path(V2)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("aggregate_and_proofs"); - - self.post_with_timeout_and_consensus_header( - path, - &aggregates, - self.timeouts.attestation, - fork_name, - ) - .await?; - - Ok(()) - } - - /// `POST validator/beacon_committee_subscriptions` - pub async fn post_validator_beacon_committee_subscriptions( - &self, - subscriptions: &[BeaconCommitteeSubscription], - ) -> Result<(), Error> { - let mut path = self.eth_path(V1)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("beacon_committee_subscriptions"); - - self.post_with_timeout( - path, - &subscriptions, - self.timeouts.attestation_subscriptions, - ) - .await?; - - Ok(()) - } - - /// `POST validator/sync_committee_subscriptions` - pub async fn post_validator_sync_committee_subscriptions( - &self, - subscriptions: &[SyncCommitteeSubscription], - ) -> Result<(), Error> { - let mut path = self.eth_path(V1)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("sync_committee_subscriptions"); - - self.post(path, &subscriptions).await?; - - Ok(()) - } - - /// `GET events?topics` - pub async fn get_events( - &self, - topic: &[EventTopic], - ) -> Result, Error>>, Error> { - let mut path = self.eth_path(V1)?; - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("events"); - - let topic_string = topic - .iter() - .map(|i| i.to_string()) - .collect::>() - .join(","); - path.query_pairs_mut().append_pair("topics", &topic_string); - - Ok(self - .client - .get(path) - .send() - .await? - .bytes_stream() - .map(|next| match next { - Ok(bytes) => EventKind::from_sse_bytes(bytes.as_ref()), - Err(e) => Err(Error::HttpClient(e.into())), - })) - } - - /// `POST validator/duties/sync/{epoch}` - pub async fn post_validator_duties_sync( - &self, - epoch: Epoch, - indices: &[u64], - ) -> Result>, Error> { - let mut path = self.eth_path(V1)?; - - path.path_segments_mut() - .map_err(|()| Error::InvalidUrl(self.server.clone()))? - .push("validator") - .push("duties") - .push("sync") - .push(&epoch.to_string()); - - self.post_with_timeout_and_response( - path, - &ValidatorIndexDataRef(indices), - self.timeouts.sync_duties, - ) - .await - } -} - -/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an -/// appropriate error message. -pub async fn ok_or_error(response: Response) -> Result { - let status = response.status(); - - if status == StatusCode::OK { - Ok(response) - } else if let Ok(message) = response.json().await { - match message { - ResponseError::Message(message) => Err(Error::ServerMessage(message)), - ResponseError::Indexed(indexed) => Err(Error::ServerIndexedMessage(indexed)), - } - } else { - Err(Error::StatusCode(status)) - } -} diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index bff40b41d5f..d77292ecd17 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -53,6 +53,7 @@ lighthouse_metrics = { workspace = true } monitoring_api = { workspace = true } sensitive_url = { workspace = true } task_executor = { workspace = true } +validator_metrics = { workspace = true } reqwest = { workspace = true, features = ["native-tls"] } url = { workspace = true } malloc_utils = { workspace = true } diff --git a/validator_client/beacon_node_fallback/Cargo.toml b/validator_client/beacon_node_fallback/Cargo.toml new file mode 100644 index 00000000000..9f08eec3a32 --- /dev/null +++ b/validator_client/beacon_node_fallback/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "beacon_node_fallback" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "beacon_node_fallback" +path = "src/lib.rs" + +[dependencies] +environment = { workspace = true } +eth2 = { workspace = true } +futures = { workspace = true } +serde = { workspace = true } +slog = { workspace = true } +slot_clock = { workspace = true } +strum = { workspace = true } +tokio = { workspace = true } +types = { workspace = true } +validator_metrics = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/check_synced.rs b/validator_client/beacon_node_fallback/src/check_synced.rs similarity index 98% rename from validator_client/src/check_synced.rs rename to validator_client/beacon_node_fallback/src/check_synced.rs index 6437682512d..4290fcf87f8 100644 --- a/validator_client/src/check_synced.rs +++ b/validator_client/beacon_node_fallback/src/check_synced.rs @@ -1,4 +1,4 @@ -use crate::beacon_node_fallback::CandidateError; +use super::CandidateError; use eth2::BeaconNodeHttpClient; use slog::{debug, error, warn, Logger}; use slot_clock::SlotClock; diff --git a/validator_client/src/beacon_node_fallback.rs b/validator_client/beacon_node_fallback/src/lib.rs similarity index 99% rename from validator_client/src/beacon_node_fallback.rs rename to validator_client/beacon_node_fallback/src/lib.rs index 58d7f9d8eef..4bfbacc4a56 100644 --- a/validator_client/src/beacon_node_fallback.rs +++ b/validator_client/beacon_node_fallback/src/lib.rs @@ -2,8 +2,8 @@ //! "fallback" behaviour; it will try a request on all of the nodes until one or none of them //! succeed. -use crate::check_synced::check_synced; -use crate::http_metrics::metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_REQUESTS}; +mod check_synced; +use check_synced::check_synced; use environment::RuntimeContext; use eth2::BeaconNodeHttpClient; use futures::future; @@ -19,6 +19,7 @@ use std::time::{Duration, Instant}; use strum::{EnumString, EnumVariantNames}; use tokio::{sync::RwLock, time::sleep}; use types::{ChainSpec, Config, EthSpec}; +use validator_metrics::{inc_counter_vec, ENDPOINT_ERRORS, ENDPOINT_REQUESTS}; /// Message emitted when the VC detects the BN is using a different spec. const UPDATE_REQUIRED_LOG_HINT: &str = "this VC or the remote BN may need updating"; diff --git a/validator_client/doppelganger_service/Cargo.toml b/validator_client/doppelganger_service/Cargo.toml new file mode 100644 index 00000000000..e145dc24081 --- /dev/null +++ b/validator_client/doppelganger_service/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "doppelganger_service" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "doppelganger_service" +path = "src/lib.rs" + +[dependencies] +beacon_node_fallback = { workspace = true } +environment = { workspace = true } +eth2 = { workspace = true } +parking_lot = { workspace = true } +slog = { workspace = true } +slot_clock = { workspace = true } +task_executor = { workspace = true } +tokio = { workspace = true } +types = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/doppelganger_service.rs b/validator_client/doppelganger_service/src/lib.rs similarity index 98% rename from validator_client/src/doppelganger_service.rs rename to validator_client/doppelganger_service/src/lib.rs index 2c8eca85601..7781b640e2d 100644 --- a/validator_client/src/doppelganger_service.rs +++ b/validator_client/doppelganger_service/src/lib.rs @@ -29,9 +29,7 @@ //! //! Doppelganger protection is a best-effort, last-line-of-defence mitigation. Do not rely upon it. -use crate::beacon_node_fallback::{BeaconNodeFallback, RequireSynced}; -use crate::validator_store::ValidatorStore; -use crate::OfflineOnFailure; +use beacon_node_fallback::{BeaconNodeFallback, OfflineOnFailure, RequireSynced}; use environment::RuntimeContext; use eth2::types::LivenessResponseData; use parking_lot::RwLock; @@ -115,6 +113,13 @@ struct LivenessResponses { /// validators on the network. pub const DEFAULT_REMAINING_DETECTION_EPOCHS: u64 = 1; +/// This crate cannot depend on ValidatorStore as validator_store depends on this crate and +/// initialises the doppelganger protection. For this reason, we abstract the validator store +/// functions this service needs through the following trait +pub trait DoppelGangerValidatorStore { + fn validator_index(&self, pubkey: &PublicKeyBytes) -> Option; +} + /// Store the per-validator status of doppelganger checking. #[derive(Debug, PartialEq)] pub struct DoppelgangerState { @@ -283,13 +288,18 @@ impl DoppelgangerService { /// Starts a reoccurring future which will try to keep the doppelganger service updated each /// slot. - pub fn start_update_service( + pub fn start_update_service( service: Arc, context: RuntimeContext, - validator_store: Arc>, + validator_store: Arc, beacon_nodes: Arc>, slot_clock: T, - ) -> Result<(), String> { + ) -> Result<(), String> + where + E: EthSpec, + T: 'static + SlotClock, + V: DoppelGangerValidatorStore + Send + Sync + 'static, + { // Define the `get_index` function as one that uses the validator store. let get_index = move |pubkey| validator_store.validator_index(&pubkey); diff --git a/validator_client/duties_service/Cargo.toml b/validator_client/duties_service/Cargo.toml new file mode 100644 index 00000000000..50b8ff3f5db --- /dev/null +++ b/validator_client/duties_service/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "duties_service" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "duties_service" +path = "src/lib.rs" + +[dependencies] +beacon_node_fallback = { workspace = true } +validator_metrics = { workspace = true } +validator_store = { workspace = true } +doppelganger_service = { workspace = true } +environment = { workspace = true } +eth2 = { workspace = true } +futures = { workspace = true } +parking_lot = { workspace = true } +safe_arith = { workspace = true } +slog = { workspace = true } +slot_clock = { workspace = true } +tokio = { workspace = true } +types = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/attestation_service.rs b/validator_client/duties_service/src/attestation_service.rs similarity index 100% rename from validator_client/src/attestation_service.rs rename to validator_client/duties_service/src/attestation_service.rs diff --git a/validator_client/src/block_service.rs b/validator_client/duties_service/src/block_service.rs similarity index 100% rename from validator_client/src/block_service.rs rename to validator_client/duties_service/src/block_service.rs diff --git a/validator_client/src/duties_service.rs b/validator_client/duties_service/src/lib.rs similarity index 95% rename from validator_client/src/duties_service.rs rename to validator_client/duties_service/src/lib.rs index faa157a8592..b0aae269c33 100644 --- a/validator_client/src/duties_service.rs +++ b/validator_client/duties_service/src/lib.rs @@ -8,13 +8,9 @@ pub mod sync; -use crate::beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; -use crate::http_metrics::metrics::{get_int_gauge, set_int_gauge, ATTESTATION_DUTY}; -use crate::{ - block_service::BlockServiceNotification, - http_metrics::metrics, - validator_store::{DoppelgangerStatus, Error as ValidatorStoreError, ValidatorStore}, -}; +use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; +use block_service::BlockServiceNotification; +use doppelganger_service::DoppelgangerStatus; use environment::RuntimeContext; use eth2::types::{ AttesterData, BeaconCommitteeSubscription, DutiesResponse, ProposerData, StateId, ValidatorId, @@ -33,6 +29,8 @@ use sync::poll_sync_committee_duties; use sync::SyncDutiesMap; use tokio::{sync::mpsc::Sender, time::sleep}; use types::{ChainSpec, Epoch, EthSpec, Hash256, PublicKeyBytes, SelectionProof, Slot}; +use validator_metrics::{get_int_gauge, set_int_gauge, ATTESTATION_DUTY}; +use validator_store::{Error as ValidatorStoreError, ValidatorStore}; /// Only retain `HISTORICAL_DUTIES_EPOCHS` duties prior to the current epoch. const HISTORICAL_DUTIES_EPOCHS: u64 = 2; @@ -473,8 +471,10 @@ pub fn start_update_service( async fn poll_validator_indices( duties_service: &DutiesService, ) { - let _timer = - metrics::start_timer_vec(&metrics::DUTIES_SERVICE_TIMES, &[metrics::UPDATE_INDICES]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_INDICES], + ); let log = duties_service.context.log(); @@ -521,9 +521,9 @@ async fn poll_validator_indices( RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::VALIDATOR_ID_HTTP_GET], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::VALIDATOR_ID_HTTP_GET], ); beacon_node .get_beacon_states_validator_id( @@ -608,9 +608,9 @@ async fn poll_validator_indices( async fn poll_beacon_attesters( duties_service: &Arc>, ) -> Result<(), Error> { - let current_epoch_timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::UPDATE_ATTESTERS_CURRENT_EPOCH], + let current_epoch_timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_ATTESTERS_CURRENT_EPOCH], ); let log = duties_service.context.log(); @@ -661,12 +661,16 @@ async fn poll_beacon_attesters( ) } - update_per_validator_duty_metrics::(duties_service, current_epoch, current_slot); + update_per_validator_duty_validator_metrics::( + duties_service, + current_epoch, + current_slot, + ); drop(current_epoch_timer); - let next_epoch_timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::UPDATE_ATTESTERS_NEXT_EPOCH], + let next_epoch_timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_ATTESTERS_NEXT_EPOCH], ); // Download the duties and update the duties for the next epoch. @@ -683,11 +687,13 @@ async fn poll_beacon_attesters( ) } - update_per_validator_duty_metrics::(duties_service, next_epoch, current_slot); + update_per_validator_duty_validator_metrics::(duties_service, next_epoch, current_slot); drop(next_epoch_timer); - let subscriptions_timer = - metrics::start_timer_vec(&metrics::DUTIES_SERVICE_TIMES, &[metrics::SUBSCRIPTIONS]); + let subscriptions_timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::SUBSCRIPTIONS], + ); // This vector is intentionally oversized by 10% so that it won't reallocate. // Each validator has 2 attestation duties occuring in the current and next epoch, for which @@ -749,9 +755,9 @@ async fn poll_beacon_attesters( OfflineOnFailure::Yes, ApiTopic::Subscriptions, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::SUBSCRIPTIONS_HTTP_POST], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::SUBSCRIPTIONS_HTTP_POST], ); beacon_node .post_validator_beacon_committee_subscriptions(subscriptions_ref) @@ -824,9 +830,9 @@ async fn poll_beacon_attesters_for_epoch( return Ok(()); } - let fetch_timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::UPDATE_ATTESTERS_FETCH], + let fetch_timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_ATTESTERS_FETCH], ); // Request duties for all uninitialized validators. If there isn't any, we will just request for @@ -892,9 +898,9 @@ async fn poll_beacon_attesters_for_epoch( drop(fetch_timer); - let _store_timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::UPDATE_ATTESTERS_STORE], + let _store_timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_ATTESTERS_STORE], ); debug!( @@ -1041,9 +1047,9 @@ async fn post_validator_duties_attester( RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::ATTESTER_DUTIES_HTTP_POST], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::ATTESTER_DUTIES_HTTP_POST], ); beacon_node .post_validator_duties_attester(epoch, validator_indices) @@ -1102,9 +1108,9 @@ async fn fill_in_selection_proofs( continue; } - let timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::ATTESTATION_SELECTION_PROOFS], + let timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::ATTESTATION_SELECTION_PROOFS], ); // Sign selection proofs (serially). @@ -1236,8 +1242,10 @@ async fn poll_beacon_proposers( duties_service: &DutiesService, block_service_tx: &mut Sender, ) -> Result<(), Error> { - let _timer = - metrics::start_timer_vec(&metrics::DUTIES_SERVICE_TIMES, &[metrics::UPDATE_PROPOSERS]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::UPDATE_PROPOSERS], + ); let log = duties_service.context.log(); @@ -1277,9 +1285,9 @@ async fn poll_beacon_proposers( RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::DUTIES_SERVICE_TIMES, - &[metrics::PROPOSER_DUTIES_HTTP_GET], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::DUTIES_SERVICE_TIMES, + &[validator_metrics::PROPOSER_DUTIES_HTTP_GET], ); beacon_node .get_validator_duties_proposer(current_epoch) @@ -1358,7 +1366,7 @@ async fn poll_beacon_proposers( "Detected new block proposer"; "current_slot" => current_slot, ); - metrics::inc_counter(&metrics::PROPOSAL_CHANGED); + validator_metrics::inc_counter(&validator_metrics::PROPOSAL_CHANGED); } } diff --git a/validator_client/src/preparation_service.rs b/validator_client/duties_service/src/preparation_service.rs similarity index 100% rename from validator_client/src/preparation_service.rs rename to validator_client/duties_service/src/preparation_service.rs diff --git a/validator_client/src/duties_service/sync.rs b/validator_client/duties_service/src/sync.rs similarity index 98% rename from validator_client/src/duties_service/sync.rs rename to validator_client/duties_service/src/sync.rs index 3618b47146f..6055f8f610c 100644 --- a/validator_client/src/duties_service/sync.rs +++ b/validator_client/duties_service/src/sync.rs @@ -1,11 +1,6 @@ -use crate::beacon_node_fallback::{OfflineOnFailure, RequireSynced}; -use crate::{ - doppelganger_service::DoppelgangerStatus, - duties_service::{DutiesService, Error}, - http_metrics::metrics, - validator_store::Error as ValidatorStoreError, -}; - +use super::{DutiesService, Error}; +use beacon_node_fallback::{OfflineOnFailure, RequireSynced}; +use doppelganger_service::DoppelgangerStatus; use futures::future::join_all; use parking_lot::{MappedRwLockReadGuard, RwLock, RwLockReadGuard, RwLockWriteGuard}; use slog::{crit, debug, info, warn}; @@ -14,6 +9,7 @@ use std::collections::{HashMap, HashSet}; use std::marker::PhantomData; use std::sync::Arc; use types::{ChainSpec, EthSpec, PublicKeyBytes, Slot, SyncDuty, SyncSelectionProof, SyncSubnetId}; +use validator_store::Error as ValidatorStoreError; /// Number of epochs in advance to compute selection proofs when not in `distributed` mode. pub const AGGREGATION_PRE_COMPUTE_EPOCHS: u64 = 2; @@ -446,9 +442,9 @@ pub async fn poll_sync_committee_duties_for_period"] + +[lib] +name = "validator_http_api" +path = "src/lib.rs" + +[dependencies] +warp_utils = { workspace = true } +warp = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/http_api/api_secret.rs b/validator_client/http_api/src/api_secret.rs similarity index 100% rename from validator_client/src/http_api/api_secret.rs rename to validator_client/http_api/src/api_secret.rs diff --git a/validator_client/src/http_api/create_signed_voluntary_exit.rs b/validator_client/http_api/src/create_signed_voluntary_exit.rs similarity index 100% rename from validator_client/src/http_api/create_signed_voluntary_exit.rs rename to validator_client/http_api/src/create_signed_voluntary_exit.rs diff --git a/validator_client/src/http_api/create_validator.rs b/validator_client/http_api/src/create_validator.rs similarity index 100% rename from validator_client/src/http_api/create_validator.rs rename to validator_client/http_api/src/create_validator.rs diff --git a/validator_client/src/http_api/graffiti.rs b/validator_client/http_api/src/graffiti.rs similarity index 100% rename from validator_client/src/http_api/graffiti.rs rename to validator_client/http_api/src/graffiti.rs diff --git a/validator_client/src/http_api/keystores.rs b/validator_client/http_api/src/keystores.rs similarity index 100% rename from validator_client/src/http_api/keystores.rs rename to validator_client/http_api/src/keystores.rs diff --git a/validator_client/src/http_api/mod.rs b/validator_client/http_api/src/lib.rs similarity index 100% rename from validator_client/src/http_api/mod.rs rename to validator_client/http_api/src/lib.rs diff --git a/validator_client/src/http_api/remotekeys.rs b/validator_client/http_api/src/remotekeys.rs similarity index 100% rename from validator_client/src/http_api/remotekeys.rs rename to validator_client/http_api/src/remotekeys.rs diff --git a/validator_client/src/http_api/test_utils.rs b/validator_client/http_api/src/test_utils.rs similarity index 100% rename from validator_client/src/http_api/test_utils.rs rename to validator_client/http_api/src/test_utils.rs diff --git a/validator_client/src/http_api/tests.rs b/validator_client/http_api/src/tests.rs similarity index 100% rename from validator_client/src/http_api/tests.rs rename to validator_client/http_api/src/tests.rs diff --git a/validator_client/src/http_api/tests/keystores.rs b/validator_client/http_api/src/tests/keystores.rs similarity index 100% rename from validator_client/src/http_api/tests/keystores.rs rename to validator_client/http_api/src/tests/keystores.rs diff --git a/validator_client/http_metrics/Cargo.toml b/validator_client/http_metrics/Cargo.toml new file mode 100644 index 00000000000..a4882c7f321 --- /dev/null +++ b/validator_client/http_metrics/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "validator_http_metrics" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "validator_http_metrics" +path = "src/lib.rs" + +[dependencies] +axum = { workspace = true } +malloc_utils = { workspace = true } +slot_clock = { workspace = true } +lighthouse_metrics = { workspace = true } +parking_lot = { workspace = true } +serde = { workspace = true } +slog = { workspace = true } +warp_utils = { workspace = true } +warp = { workspace = true } +lighthouse_version = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/http_metrics/mod.rs b/validator_client/http_metrics/src/lib.rs similarity index 68% rename from validator_client/src/http_metrics/mod.rs rename to validator_client/http_metrics/src/lib.rs index 67cab2bdc37..e576d2f1655 100644 --- a/validator_client/src/http_metrics/mod.rs +++ b/validator_client/http_metrics/src/lib.rs @@ -1,9 +1,6 @@ //! This crate provides a HTTP server that is solely dedicated to serving the `/metrics` endpoint. //! //! For other endpoints, see the `http_api` crate. -pub mod metrics; - -use crate::{DutiesService, ValidatorStore}; use lighthouse_version::version_with_platform; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; @@ -12,7 +9,6 @@ use slot_clock::SystemTimeSlotClock; use std::future::Future; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; -use types::EthSpec; use warp::{http::Response, Filter}; #[derive(Debug)] @@ -34,18 +30,18 @@ impl From for Error { } /// Contains objects which have shared access from inside/outside of the metrics server. -pub struct Shared { - pub validator_store: Option>>, - pub duties_service: Option>>, +pub struct Shared { + pub validator_store: Option>, + pub duties_service: Option>, pub genesis_time: Option, } /// A wrapper around all the items required to spawn the HTTP server. /// /// The server will gracefully handle the case where any fields are `None`. -pub struct Context { +pub struct Context { pub config: Config, - pub shared: RwLock>, + pub shared: RwLock>, pub log: Logger, } @@ -86,8 +82,8 @@ impl Default for Config { /// /// Returns an error if the server is unable to bind or there is another error during /// configuration. -pub fn serve( - ctx: Arc>, +pub fn serve( + ctx: Arc>, shutdown: impl Future + Send + Sync + 'static, ) -> Result<(SocketAddr, impl Future), Error> { let config = &ctx.config; @@ -156,3 +152,56 @@ pub fn serve( Ok((listening_socket, server)) } + +pub fn gather_prometheus_metrics(ctx: &Context) -> std::result::Result { + let mut buffer = vec![]; + let encoder = TextEncoder::new(); + + { + let shared = ctx.shared.read(); + + if let Some(genesis_time) = shared.genesis_time { + if let Ok(now) = SystemTime::now().duration_since(UNIX_EPOCH) { + let distance = now.as_secs() as i64 - genesis_time as i64; + set_gauge(&GENESIS_DISTANCE, distance); + } + } + + if let Some(duties_service) = &shared.duties_service { + if let Some(slot) = duties_service.slot_clock.now() { + let current_epoch = slot.epoch(E::slots_per_epoch()); + let next_epoch = current_epoch + 1; + + set_int_gauge( + &PROPOSER_COUNT, + &[CURRENT_EPOCH], + duties_service.proposer_count(current_epoch) as i64, + ); + set_int_gauge( + &ATTESTER_COUNT, + &[CURRENT_EPOCH], + duties_service.attester_count(current_epoch) as i64, + ); + set_int_gauge( + &ATTESTER_COUNT, + &[NEXT_EPOCH], + duties_service.attester_count(next_epoch) as i64, + ); + } + } + } + + // It's important to ensure these metrics are explicitly enabled in the case that users aren't + // using glibc and this function causes panics. + if ctx.config.allocator_metrics_enabled { + scrape_allocator_metrics(); + } + + warp_utils::metrics::scrape_health_metrics(); + + encoder + .encode(&lighthouse_metrics::gather(), &mut buffer) + .unwrap(); + + String::from_utf8(buffer).map_err(|e| format!("Failed to encode prometheus info: {:?}", e)) +} diff --git a/validator_client/initialized_validators/Cargo.toml b/validator_client/initialized_validators/Cargo.toml new file mode 100644 index 00000000000..403061335f9 --- /dev/null +++ b/validator_client/initialized_validators/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "initialized_validators" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "initialized_validators" +path = "src/lib.rs" + +[dependencies] +signing_method = { workspace = true } +account_utils = { workspace = true } +eth2_keystore = { workspace = true } +lighthouse_metrics = { workspace = true } +lockfile = { workspace = true } +parking_lot = { workspace = true } +reqwest = { workspace = true } +slog = { workspace = true } +types = { workspace = true } +url = { workspace = true } +validator_dir = { workspace = true } +rand = { workspace = true } +serde = { workspace = true } +serde_json = { workspace = true } +bls = { workspace = true } +tokio = { workspace = true } +bincode = { workspace = true } +filesystem = { workspace = true } +validator_metrics = { workspace = true } + + +[dev-dependencies] diff --git a/validator_client/src/key_cache.rs b/validator_client/initialized_validators/src/key_cache.rs similarity index 100% rename from validator_client/src/key_cache.rs rename to validator_client/initialized_validators/src/key_cache.rs diff --git a/validator_client/src/initialized_validators.rs b/validator_client/initialized_validators/src/lib.rs similarity index 99% rename from validator_client/src/initialized_validators.rs rename to validator_client/initialized_validators/src/lib.rs index c94115e5ec5..1334056069d 100644 --- a/validator_client/src/initialized_validators.rs +++ b/validator_client/initialized_validators/src/lib.rs @@ -6,7 +6,8 @@ //! The `InitializedValidators` struct in this file serves as the source-of-truth of which //! validators are managed by this validator client. -use crate::signing_method::SigningMethod; +pub mod key_cache; + use account_utils::{ read_password, read_password_from_user, read_password_string, validator_definitions::{ @@ -20,6 +21,7 @@ use lighthouse_metrics::set_gauge; use lockfile::{Lockfile, LockfileError}; use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use reqwest::{Certificate, Client, Error as ReqwestError, Identity}; +use signing_method::SigningMethod; use slog::{debug, error, info, warn, Logger}; use std::collections::{HashMap, HashSet}; use std::fs::{self, File}; @@ -32,9 +34,7 @@ use types::{Address, Graffiti, Keypair, PublicKey, PublicKeyBytes}; use url::{ParseError, Url}; use validator_dir::Builder as ValidatorDirBuilder; -use crate::key_cache; -use crate::key_cache::KeyCache; -use crate::Config; +use key_cache::KeyCache; /// Default timeout for a request to a remote signer for a signature. /// @@ -45,6 +45,12 @@ const DEFAULT_REMOTE_SIGNER_REQUEST_TIMEOUT: Duration = Duration::from_secs(12); // Use TTY instead of stdin to capture passwords from users. const USE_STDIN: bool = false; +// The configuration for initialised validators. +pub struct Config { + pub web3_signer_keep_alive_timeout: Option, + pub web3_signer_max_idle_connections: Option, +} + pub enum OnDecryptFailure { /// If the key cache fails to decrypt, create a new cache. CreateNew, @@ -1380,11 +1386,11 @@ impl InitializedValidators { // Update the enabled and total validator counts set_gauge( - &crate::http_metrics::metrics::ENABLED_VALIDATORS_COUNT, + &validator_metrics::ENABLED_VALIDATORS_COUNT, self.num_enabled() as i64, ); set_gauge( - &crate::http_metrics::metrics::TOTAL_VALIDATORS_COUNT, + &validator_metrics::TOTAL_VALIDATORS_COUNT, self.num_total() as i64, ); Ok(()) diff --git a/validator_client/signing_method/Cargo.toml b/validator_client/signing_method/Cargo.toml new file mode 100644 index 00000000000..668b151b4ff --- /dev/null +++ b/validator_client/signing_method/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "signing_method" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "signing_method" +path = "src/lib.rs" + +[dependencies] +eth2_keystore = { workspace = true } +lockfile = { workspace = true } +parking_lot = { workspace = true } +reqwest = { workspace = true } +task_executor = { workspace = true } +types = { workspace = true } +url = { workspace = true } +validator_metrics = { workspace = true } +serde = { workspace = true } +ethereum_serde_utils = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/signing_method.rs b/validator_client/signing_method/src/lib.rs similarity index 96% rename from validator_client/src/signing_method.rs rename to validator_client/signing_method/src/lib.rs index d89c9b82292..2fe4af39d3a 100644 --- a/validator_client/src/signing_method.rs +++ b/validator_client/signing_method/src/lib.rs @@ -3,7 +3,6 @@ //! - Via a local `Keypair`. //! - Via a remote signer (Web3Signer) -use crate::http_metrics::metrics; use eth2_keystore::Keystore; use lockfile::Lockfile; use parking_lot::Mutex; @@ -166,8 +165,10 @@ impl SigningMethod { ) -> Result { match self { SigningMethod::LocalKeystore { voting_keypair, .. } => { - let _timer = - metrics::start_timer_vec(&metrics::SIGNING_TIMES, &[metrics::LOCAL_KEYSTORE]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::SIGNING_TIMES, + &[validator_metrics::LOCAL_KEYSTORE], + ); let voting_keypair = voting_keypair.clone(); // Spawn a blocking task to produce the signature. This avoids blocking the core @@ -187,8 +188,10 @@ impl SigningMethod { http_client, .. } => { - let _timer = - metrics::start_timer_vec(&metrics::SIGNING_TIMES, &[metrics::WEB3SIGNER]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::SIGNING_TIMES, + &[validator_metrics::WEB3SIGNER], + ); // Map the message into a Web3Signer type. let object = match signable_message { diff --git a/validator_client/src/signing_method/web3signer.rs b/validator_client/signing_method/src/web3signer.rs similarity index 100% rename from validator_client/src/signing_method/web3signer.rs rename to validator_client/signing_method/src/web3signer.rs diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index dff50582dfe..934453882c0 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -5,7 +5,6 @@ mod check_synced; mod cli; mod duties_service; mod graffiti_file; -mod http_metrics; mod key_cache; mod latency; mod notifier; @@ -151,14 +150,14 @@ impl ProductionValidatorClient { ); // Optionally start the metrics server. - let http_metrics_ctx = if config.http_metrics.enabled { - let shared = http_metrics::Shared { + let validator_metrics_ctx = if config.http_metrics.enabled { + let shared = validator_metrics::Shared { validator_store: None, genesis_time: None, duties_service: None, }; - let ctx: Arc> = Arc::new(http_metrics::Context { + let ctx: Arc> = Arc::new(validator_metrics::Context { config: config.http_metrics.clone(), shared: RwLock::new(shared), log: log.clone(), @@ -166,7 +165,7 @@ impl ProductionValidatorClient { let exit = context.executor.exit(); - let (_listen_addr, server) = http_metrics::serve(ctx.clone(), exit) + let (_listen_addr, server) = validator_metrics::serve(ctx.clone(), exit) .map_err(|e| format!("Unable to start metrics API server: {:?}", e))?; context @@ -377,20 +376,20 @@ impl ProductionValidatorClient { // Set the count for beacon node fallbacks excluding the primary beacon node. set_gauge( - &http_metrics::metrics::ETH2_FALLBACK_CONFIGURED, + &validator_metrics::metrics::ETH2_FALLBACK_CONFIGURED, num_nodes.saturating_sub(1) as i64, ); // Set the total beacon node count. set_gauge( - &http_metrics::metrics::TOTAL_BEACON_NODES_COUNT, + &validator_metrics::metrics::TOTAL_BEACON_NODES_COUNT, num_nodes as i64, ); // Initialize the number of connected, synced beacon nodes to 0. - set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0); - set_gauge(&http_metrics::metrics::SYNCED_BEACON_NODES_COUNT, 0); + set_gauge(&validator_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0); + set_gauge(&validator_metrics::metrics::SYNCED_BEACON_NODES_COUNT, 0); // Initialize the number of connected, avaliable beacon nodes to 0. - set_gauge(&http_metrics::metrics::AVAILABLE_BEACON_NODES_COUNT, 0); + set_gauge(&validator_metrics::metrics::AVAILABLE_BEACON_NODES_COUNT, 0); let mut beacon_nodes: BeaconNodeFallback<_, E> = BeaconNodeFallback::new( candidates, @@ -413,7 +412,7 @@ impl ProductionValidatorClient { }; // Update the metrics server. - if let Some(ctx) = &http_metrics_ctx { + if let Some(ctx) = &validator_metrics_ctx { ctx.shared.write().genesis_time = Some(genesis_time); } @@ -487,7 +486,7 @@ impl ProductionValidatorClient { }); // Update the metrics server. - if let Some(ctx) = &http_metrics_ctx { + if let Some(ctx) = &validator_metrics_ctx { ctx.shared.write().validator_store = Some(validator_store.clone()); ctx.shared.write().duties_service = Some(duties_service.clone()); } diff --git a/validator_client/validator_metrics/Cargo.toml b/validator_client/validator_metrics/Cargo.toml new file mode 100644 index 00000000000..442113c115b --- /dev/null +++ b/validator_client/validator_metrics/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "validator_metrics" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "validator_metrics" +path = "src/lib.rs" + +[dependencies] +malloc_utils = { workspace = true } +lighthouse_metrics = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/http_metrics/metrics.rs b/validator_client/validator_metrics/src/lib.rs similarity index 82% rename from validator_client/src/http_metrics/metrics.rs rename to validator_client/validator_metrics/src/lib.rs index 8bc569c67a2..bacc9a109d2 100644 --- a/validator_client/src/http_metrics/metrics.rs +++ b/validator_client/validator_metrics/src/lib.rs @@ -1,9 +1,4 @@ -use super::Context; -use malloc_utils::scrape_allocator_metrics; -use slot_clock::SlotClock; use std::sync::LazyLock; -use std::time::{SystemTime, UNIX_EPOCH}; -use types::EthSpec; pub const SUCCESS: &str = "success"; pub const SLASHABLE: &str = "slashable"; @@ -267,58 +262,3 @@ pub static VC_BEACON_NODE_LATENCY_PRIMARY_ENDPOINT: LazyLock> "Round-trip latency for the primary BN endpoint", ) }); - -pub fn gather_prometheus_metrics( - ctx: &Context, -) -> std::result::Result { - let mut buffer = vec![]; - let encoder = TextEncoder::new(); - - { - let shared = ctx.shared.read(); - - if let Some(genesis_time) = shared.genesis_time { - if let Ok(now) = SystemTime::now().duration_since(UNIX_EPOCH) { - let distance = now.as_secs() as i64 - genesis_time as i64; - set_gauge(&GENESIS_DISTANCE, distance); - } - } - - if let Some(duties_service) = &shared.duties_service { - if let Some(slot) = duties_service.slot_clock.now() { - let current_epoch = slot.epoch(E::slots_per_epoch()); - let next_epoch = current_epoch + 1; - - set_int_gauge( - &PROPOSER_COUNT, - &[CURRENT_EPOCH], - duties_service.proposer_count(current_epoch) as i64, - ); - set_int_gauge( - &ATTESTER_COUNT, - &[CURRENT_EPOCH], - duties_service.attester_count(current_epoch) as i64, - ); - set_int_gauge( - &ATTESTER_COUNT, - &[NEXT_EPOCH], - duties_service.attester_count(next_epoch) as i64, - ); - } - } - } - - // It's important to ensure these metrics are explicitly enabled in the case that users aren't - // using glibc and this function causes panics. - if ctx.config.allocator_metrics_enabled { - scrape_allocator_metrics(); - } - - warp_utils::metrics::scrape_health_metrics(); - - encoder - .encode(&lighthouse_metrics::gather(), &mut buffer) - .unwrap(); - - String::from_utf8(buffer).map_err(|e| format!("Failed to encode prometheus info: {:?}", e)) -} diff --git a/validator_client/validator_store/Cargo.toml b/validator_client/validator_store/Cargo.toml new file mode 100644 index 00000000000..262dbecaa6a --- /dev/null +++ b/validator_client/validator_store/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "validator_store" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "validator_store" +path = "src/lib.rs" + +[dependencies] +account_utils = { workspace = true } +doppelganger_service = { workspace = true } +initialized_validators = { workspace = true } +parking_lot = { workspace = true } +signing_method = { workspace = true } +slashing_protection = { workspace = true } +slog = { workspace = true } +slot_clock = { workspace = true } +task_executor = { workspace = true } +types = { workspace = true } +validator_metrics = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/validator_store.rs b/validator_client/validator_store/src/lib.rs similarity index 91% rename from validator_client/src/validator_store.rs rename to validator_client/validator_store/src/lib.rs index 8a9e125936e..bc5425b2b7c 100644 --- a/validator_client/src/validator_store.rs +++ b/validator_client/validator_store/src/lib.rs @@ -1,12 +1,8 @@ -use crate::{ - doppelganger_service::DoppelgangerService, - http_metrics::metrics, - initialized_validators::InitializedValidators, - signing_method::{Error as SigningError, SignableMessage, SigningContext, SigningMethod}, - Config, -}; use account_utils::validator_definitions::{PasswordStorage, ValidatorDefinition}; +use doppelganger_service::{DoppelgangerService, DoppelgangerStatus}; +use initialized_validators::InitializedValidators; use parking_lot::{Mutex, RwLock}; +use signing_method::{Error as SigningError, SignableMessage, SigningContext, SigningMethod}; use slashing_protection::{ interchange::Interchange, InterchangeError, NotSafe, Safe, SlashingDatabase, }; @@ -26,9 +22,6 @@ use types::{ ValidatorRegistrationData, VoluntaryExit, }; -pub use crate::doppelganger_service::DoppelgangerStatus; -use crate::preparation_service::ProposalData; - #[derive(Debug, PartialEq)] pub enum Error { DoppelgangerProtected(PublicKeyBytes), @@ -48,6 +41,29 @@ impl From for Error { } } +pub struct Config { + /// Fallback fallback address. + pub fee_recipient: Option
, + /// Fallback gas limit. + pub gas_limit: Option, + /// Enable use of the blinded block endpoints during proposals. + pub builder_proposals: bool, + /// Enable slashing protection even while using web3signer keys. + pub enable_web3signer_slashing_protection: bool, + /// If true, Lighthouse will prefer builder proposals, if available. + pub prefer_builder_proposals: bool, + /// Specifies the boost factor, a percentage multiplier to apply to the builder's payload value. + pub builder_boost_factor: Option, +} + +/// A helper struct, used for passing data from the validator store to services. +pub struct ProposalData { + pub validator_index: Option, + pub fee_recipient: Option
, + pub gas_limit: u64, + pub builder_proposals: bool, +} + /// Number of epochs of slashing protection history to keep. /// /// This acts as a maximum safe-guard against clock drift. @@ -591,7 +607,10 @@ impl ValidatorStore { match slashing_status { // We can safely sign this block without slashing. Ok(Safe::Valid) => { - metrics::inc_counter_vec(&metrics::SIGNED_BLOCKS_TOTAL, &[metrics::SUCCESS]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_BLOCKS_TOTAL, + &[validator_metrics::SUCCESS], + ); let signature = signing_method .get_signature::( @@ -608,7 +627,10 @@ impl ValidatorStore { self.log, "Skipping signing of previously signed block"; ); - metrics::inc_counter_vec(&metrics::SIGNED_BLOCKS_TOTAL, &[metrics::SAME_DATA]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_BLOCKS_TOTAL, + &[validator_metrics::SAME_DATA], + ); Err(Error::SameData) } Err(NotSafe::UnregisteredValidator(pk)) => { @@ -618,7 +640,10 @@ impl ValidatorStore { "msg" => "Carefully consider running with --init-slashing-protection (see --help)", "public_key" => format!("{:?}", pk) ); - metrics::inc_counter_vec(&metrics::SIGNED_BLOCKS_TOTAL, &[metrics::UNREGISTERED]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_BLOCKS_TOTAL, + &[validator_metrics::UNREGISTERED], + ); Err(Error::Slashable(NotSafe::UnregisteredValidator(pk))) } Err(e) => { @@ -627,7 +652,10 @@ impl ValidatorStore { "Not signing slashable block"; "error" => format!("{:?}", e) ); - metrics::inc_counter_vec(&metrics::SIGNED_BLOCKS_TOTAL, &[metrics::SLASHABLE]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_BLOCKS_TOTAL, + &[validator_metrics::SLASHABLE], + ); Err(Error::Slashable(e)) } } @@ -682,7 +710,10 @@ impl ValidatorStore { .add_signature(&signature, validator_committee_position) .map_err(Error::UnableToSignAttestation)?; - metrics::inc_counter_vec(&metrics::SIGNED_ATTESTATIONS_TOTAL, &[metrics::SUCCESS]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_ATTESTATIONS_TOTAL, + &[validator_metrics::SUCCESS], + ); Ok(()) } @@ -691,9 +722,9 @@ impl ValidatorStore { self.log, "Skipping signing of previously signed attestation" ); - metrics::inc_counter_vec( - &metrics::SIGNED_ATTESTATIONS_TOTAL, - &[metrics::SAME_DATA], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_ATTESTATIONS_TOTAL, + &[validator_metrics::SAME_DATA], ); Err(Error::SameData) } @@ -704,9 +735,9 @@ impl ValidatorStore { "msg" => "Carefully consider running with --init-slashing-protection (see --help)", "public_key" => format!("{:?}", pk) ); - metrics::inc_counter_vec( - &metrics::SIGNED_ATTESTATIONS_TOTAL, - &[metrics::UNREGISTERED], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_ATTESTATIONS_TOTAL, + &[validator_metrics::UNREGISTERED], ); Err(Error::Slashable(NotSafe::UnregisteredValidator(pk))) } @@ -717,9 +748,9 @@ impl ValidatorStore { "attestation" => format!("{:?}", attestation.data()), "error" => format!("{:?}", e) ); - metrics::inc_counter_vec( - &metrics::SIGNED_ATTESTATIONS_TOTAL, - &[metrics::SLASHABLE], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_ATTESTATIONS_TOTAL, + &[validator_metrics::SLASHABLE], ); Err(Error::Slashable(e)) } @@ -744,7 +775,10 @@ impl ValidatorStore { ) .await?; - metrics::inc_counter_vec(&metrics::SIGNED_VOLUNTARY_EXITS_TOTAL, &[metrics::SUCCESS]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_VOLUNTARY_EXITS_TOTAL, + &[validator_metrics::SUCCESS], + ); Ok(SignedVoluntaryExit { message: voluntary_exit, @@ -770,9 +804,9 @@ impl ValidatorStore { ) .await?; - metrics::inc_counter_vec( - &metrics::SIGNED_VALIDATOR_REGISTRATIONS_TOTAL, - &[metrics::SUCCESS], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_VALIDATOR_REGISTRATIONS_TOTAL, + &[validator_metrics::SUCCESS], ); Ok(SignedValidatorRegistrationData { @@ -808,7 +842,10 @@ impl ValidatorStore { ) .await?; - metrics::inc_counter_vec(&metrics::SIGNED_AGGREGATES_TOTAL, &[metrics::SUCCESS]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_AGGREGATES_TOTAL, + &[validator_metrics::SUCCESS], + ); Ok(SignedAggregateAndProof::from_aggregate_and_proof( message, signature, @@ -844,7 +881,10 @@ impl ValidatorStore { .await .map_err(Error::UnableToSign)?; - metrics::inc_counter_vec(&metrics::SIGNED_SELECTION_PROOFS_TOTAL, &[metrics::SUCCESS]); + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_SELECTION_PROOFS_TOTAL, + &[validator_metrics::SUCCESS], + ); Ok(signature.into()) } @@ -863,9 +903,9 @@ impl ValidatorStore { // Bypass `with_validator_signing_method`: sync committee messages are not slashable. let signing_method = self.doppelganger_bypassed_signing_method(*validator_pubkey)?; - metrics::inc_counter_vec( - &metrics::SIGNED_SYNC_SELECTION_PROOFS_TOTAL, - &[metrics::SUCCESS], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_SYNC_SELECTION_PROOFS_TOTAL, + &[validator_metrics::SUCCESS], ); let message = SyncAggregatorSelectionData { @@ -912,9 +952,9 @@ impl ValidatorStore { .await .map_err(Error::UnableToSign)?; - metrics::inc_counter_vec( - &metrics::SIGNED_SYNC_COMMITTEE_MESSAGES_TOTAL, - &[metrics::SUCCESS], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_SYNC_COMMITTEE_MESSAGES_TOTAL, + &[validator_metrics::SUCCESS], ); Ok(SyncCommitteeMessage { @@ -954,9 +994,9 @@ impl ValidatorStore { .await .map_err(Error::UnableToSign)?; - metrics::inc_counter_vec( - &metrics::SIGNED_SYNC_COMMITTEE_CONTRIBUTIONS_TOTAL, - &[metrics::SUCCESS], + validator_metrics::inc_counter_vec( + &validator_metrics::SIGNED_SYNC_COMMITTEE_CONTRIBUTIONS_TOTAL, + &[validator_metrics::SUCCESS], ); Ok(SignedContributionAndProof { message, signature }) @@ -1030,7 +1070,8 @@ impl ValidatorStore { info!(self.log, "Pruning slashing protection DB"; "epoch" => current_epoch); } - let _timer = metrics::start_timer(&metrics::SLASHING_PROTECTION_PRUNE_TIMES); + let _timer = + validator_metrics::start_timer(&validator_metrics::SLASHING_PROTECTION_PRUNE_TIMES); let new_min_target_epoch = current_epoch.saturating_sub(SLASHING_PROTECTION_HISTORY_EPOCHS); let new_min_slot = new_min_target_epoch.start_slot(E::slots_per_epoch()); From d82c4f7b7781718a31e7c7ad0697064e35f38a03 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 1 Oct 2024 18:03:05 +1000 Subject: [PATCH 2/6] Revert changes to eth2 --- common/eth2/src/lib.rs | 168 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/common/eth2/src/lib.rs b/common/eth2/src/lib.rs index ca91f43eb17..2805d36b90c 100644 --- a/common/eth2/src/lib.rs +++ b/common/eth2/src/lib.rs @@ -2471,3 +2471,171 @@ impl BeaconNodeHttpClient { &self, epoch: Epoch, indices: &[u64], + ) -> Result>, Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("duties") + .push("attester") + .push(&epoch.to_string()); + + self.post_with_timeout_and_response( + path, + &ValidatorIndexDataRef(indices), + self.timeouts.attester_duties, + ) + .await + } + + /// `POST v1/validator/aggregate_and_proofs` + pub async fn post_validator_aggregate_and_proof_v1( + &self, + aggregates: &[SignedAggregateAndProof], + ) -> Result<(), Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("aggregate_and_proofs"); + + self.post_with_timeout(path, &aggregates, self.timeouts.attestation) + .await?; + + Ok(()) + } + + /// `POST v2/validator/aggregate_and_proofs` + pub async fn post_validator_aggregate_and_proof_v2( + &self, + aggregates: &[SignedAggregateAndProof], + fork_name: ForkName, + ) -> Result<(), Error> { + let mut path = self.eth_path(V2)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("aggregate_and_proofs"); + + self.post_with_timeout_and_consensus_header( + path, + &aggregates, + self.timeouts.attestation, + fork_name, + ) + .await?; + + Ok(()) + } + + /// `POST validator/beacon_committee_subscriptions` + pub async fn post_validator_beacon_committee_subscriptions( + &self, + subscriptions: &[BeaconCommitteeSubscription], + ) -> Result<(), Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("beacon_committee_subscriptions"); + + self.post_with_timeout( + path, + &subscriptions, + self.timeouts.attestation_subscriptions, + ) + .await?; + + Ok(()) + } + + /// `POST validator/sync_committee_subscriptions` + pub async fn post_validator_sync_committee_subscriptions( + &self, + subscriptions: &[SyncCommitteeSubscription], + ) -> Result<(), Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("sync_committee_subscriptions"); + + self.post(path, &subscriptions).await?; + + Ok(()) + } + + /// `GET events?topics` + pub async fn get_events( + &self, + topic: &[EventTopic], + ) -> Result, Error>>, Error> { + let mut path = self.eth_path(V1)?; + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("events"); + + let topic_string = topic + .iter() + .map(|i| i.to_string()) + .collect::>() + .join(","); + path.query_pairs_mut().append_pair("topics", &topic_string); + + Ok(self + .client + .get(path) + .send() + .await? + .bytes_stream() + .map(|next| match next { + Ok(bytes) => EventKind::from_sse_bytes(bytes.as_ref()), + Err(e) => Err(Error::HttpClient(e.into())), + })) + } + + /// `POST validator/duties/sync/{epoch}` + pub async fn post_validator_duties_sync( + &self, + epoch: Epoch, + indices: &[u64], + ) -> Result>, Error> { + let mut path = self.eth_path(V1)?; + + path.path_segments_mut() + .map_err(|()| Error::InvalidUrl(self.server.clone()))? + .push("validator") + .push("duties") + .push("sync") + .push(&epoch.to_string()); + + self.post_with_timeout_and_response( + path, + &ValidatorIndexDataRef(indices), + self.timeouts.sync_duties, + ) + .await + } +} + +/// Returns `Ok(response)` if the response is a `200 OK` response. Otherwise, creates an +/// appropriate error message. +pub async fn ok_or_error(response: Response) -> Result { + let status = response.status(); + + if status == StatusCode::OK { + Ok(response) + } else if let Ok(message) = response.json().await { + match message { + ResponseError::Message(message) => Err(Error::ServerMessage(message)), + ResponseError::Indexed(indexed) => Err(Error::ServerIndexedMessage(indexed)), + } + } else { + Err(Error::StatusCode(status)) + } +} From d7cba1ce54ddd85e6cb7ba451fa8b85211360acb Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 2 Oct 2024 12:41:46 +1000 Subject: [PATCH 3/6] More progress --- Cargo.lock | 51 ++++++++++++++++++- Cargo.toml | 5 ++ validator_client/duties_service/Cargo.toml | 2 + .../duties_service/src/block_service.rs | 46 ++++++++--------- validator_client/duties_service/src/lib.rs | 9 ++-- validator_client/graffiti_file/Cargo.toml | 17 +++++++ .../src/lib.rs} | 22 ++++++++ validator_client/http_api/Cargo.toml | 30 +++++++++++ .../src/create_signed_voluntary_exit.rs | 2 +- .../http_api/src/create_validator.rs | 2 +- validator_client/http_api/src/graffiti.rs | 2 +- validator_client/http_api/src/keystores.rs | 7 ++- validator_client/http_api/src/lib.rs | 8 +-- validator_client/http_api/src/remotekeys.rs | 3 +- validator_client/http_api/src/test_utils.rs | 13 +++-- validator_client/http_metrics/Cargo.toml | 1 - .../initialized_validators/src/lib.rs | 2 +- validator_client/src/lib.rs | 21 -------- 18 files changed, 171 insertions(+), 72 deletions(-) create mode 100644 validator_client/graffiti_file/Cargo.toml rename validator_client/{src/graffiti_file.rs => graffiti_file/src/lib.rs} (89%) diff --git a/Cargo.lock b/Cargo.lock index 510be1dcd9e..48b8f22b79f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2272,10 +2272,12 @@ name = "duties_service" version = "0.1.0" dependencies = [ "beacon_node_fallback", + "bls", "doppelganger_service", "environment", "eth2", "futures", + "graffiti_file", "parking_lot 0.12.3", "safe_arith", "slog", @@ -3547,6 +3549,16 @@ dependencies = [ "web-time", ] +[[package]] +name = "graffiti_file" +version = "0.1.0" +dependencies = [ + "bls", + "serde", + "slog", + "types", +] + [[package]] name = "group" version = "0.12.1" @@ -9318,11 +9330,48 @@ dependencies = [ "types", ] +[[package]] +name = "validator_http_api" +version = "0.1.0" +dependencies = [ + "account_utils", + "bls", + "deposit_contract", + "doppelganger_service", + "eth2", + "eth2_keystore", + "ethereum_serde_utils", + "filesystem", + "graffiti_file", + "initialized_validators", + "lighthouse_version", + "logging", + "parking_lot 0.12.3", + "rand", + "sensitive_url", + "serde", + "signing_method", + "slashing_protection", + "slog", + "slot_clock", + "sysinfo", + "system_health", + "task_executor", + "tempfile", + "tokio", + "tokio-stream", + "types", + "url", + "validator_dir", + "validator_store", + "warp", + "warp_utils", +] + [[package]] name = "validator_http_metrics" version = "0.1.0" dependencies = [ - "axum", "lighthouse_metrics", "lighthouse_version", "malloc_utils", diff --git a/Cargo.toml b/Cargo.toml index d419e9f33d7..3d8e6abac02 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -86,6 +86,8 @@ members = [ "validator_client/beacon_node_fallback", "validator_client/doppelganger_service", "validator_client/duties_service", + "validator_client/graffiti_file", + "validator_client/http_api", "validator_client/http_metrics", "validator_client/initialized_validators", "validator_client/signing_method", @@ -138,6 +140,7 @@ exit-future = "0.2" fnv = "1" fs2 = "0.4" futures = "0.3" +graffiti_file = { path = "validator_client/graffiti_file" } hex = "0.4" hashlink = "0.9.0" hyper = "1" @@ -248,11 +251,13 @@ slot_clock = { path = "common/slot_clock" } state_processing = { path = "consensus/state_processing" } store = { path = "beacon_node/store" } swap_or_not_shuffle = { path = "consensus/swap_or_not_shuffle" } +system_health = { path = "common/system_health" } task_executor = { path = "common/task_executor" } types = { path = "consensus/types" } unused_port = { path = "common/unused_port" } validator_client = { path = "validator_client" } validator_dir = { path = "common/validator_dir" } +validator_http_api = { path = "validator_client/http_api" } validator_http_metrics = { path = "validator_client/http_metrics" } validator_metrics = { path = "validator_client/validator_metrics" } validator_store= { path = "validator_client/validator_store" } diff --git a/validator_client/duties_service/Cargo.toml b/validator_client/duties_service/Cargo.toml index 50b8ff3f5db..46fa0156bf5 100644 --- a/validator_client/duties_service/Cargo.toml +++ b/validator_client/duties_service/Cargo.toml @@ -12,6 +12,7 @@ path = "src/lib.rs" beacon_node_fallback = { workspace = true } validator_metrics = { workspace = true } validator_store = { workspace = true } +graffiti_file = { workspace = true } doppelganger_service = { workspace = true } environment = { workspace = true } eth2 = { workspace = true } @@ -22,5 +23,6 @@ slog = { workspace = true } slot_clock = { workspace = true } tokio = { workspace = true } types = { workspace = true } +bls = { workspace = true } [dev-dependencies] diff --git a/validator_client/duties_service/src/block_service.rs b/validator_client/duties_service/src/block_service.rs index af11d82eb53..192f2bbb9e2 100644 --- a/validator_client/duties_service/src/block_service.rs +++ b/validator_client/duties_service/src/block_service.rs @@ -1,18 +1,11 @@ -use crate::beacon_node_fallback::{Error as FallbackError, Errors}; -use crate::{ - beacon_node_fallback::{ApiTopic, BeaconNodeFallback, RequireSynced}, - determine_graffiti, - graffiti_file::GraffitiFile, - OfflineOnFailure, -}; -use crate::{ - http_metrics::metrics, - validator_store::{Error as ValidatorStoreError, ValidatorStore}, +use beacon_node_fallback::{ + ApiTopic, BeaconNodeFallback, Error as FallbackError, Errors, OfflineOnFailure, RequireSynced, }; use bls::SignatureBytes; use environment::RuntimeContext; use eth2::types::{FullBlockContents, PublishBlockRequest}; use eth2::{BeaconNodeHttpClient, StatusCode}; +use graffiti_file::{determine_graffiti, GraffitiFile}; use slog::{crit, debug, error, info, trace, warn, Logger}; use slot_clock::SlotClock; use std::fmt::Debug; @@ -25,6 +18,7 @@ use types::{ BlindedBeaconBlock, BlockType, EthSpec, Graffiti, PublicKeyBytes, SignedBlindedBeaconBlock, Slot, }; +use validator_store::{Error as ValidatorStoreError, ValidatorStore}; #[derive(Debug)] pub enum BlockError { @@ -272,8 +266,10 @@ impl BlockService { /// Attempt to produce a block for any block producers in the `ValidatorStore`. async fn do_update(&self, notification: BlockServiceNotification) -> Result<(), ()> { let log = self.context.log(); - let _timer = - metrics::start_timer_vec(&metrics::BLOCK_SERVICE_TIMES, &[metrics::FULL_UPDATE]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::BLOCK_SERVICE_TIMES, + &[validator_metrics::FULL_UPDATE], + ); let slot = self.slot_clock.now().ok_or_else(move || { crit!(log, "Duties manager failed to read slot clock"); @@ -362,7 +358,7 @@ impl BlockService { unsigned_block: UnsignedBlock, ) -> Result<(), BlockError> { let log = self.context.log(); - let signing_timer = metrics::start_timer(&metrics::BLOCK_SIGNING_TIMES); + let signing_timer = validator_metrics::start_timer(&validator_metrics::BLOCK_SIGNING_TIMES); let res = match unsigned_block { UnsignedBlock::Full(block_contents) => { @@ -447,8 +443,10 @@ impl BlockService { builder_boost_factor: Option, ) -> Result<(), BlockError> { let log = self.context.log(); - let _timer = - metrics::start_timer_vec(&metrics::BLOCK_SERVICE_TIMES, &[metrics::BEACON_BLOCK]); + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::BLOCK_SERVICE_TIMES, + &[validator_metrics::BEACON_BLOCK], + ); let randao_reveal = match self .validator_store @@ -507,9 +505,9 @@ impl BlockService { RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _get_timer = metrics::start_timer_vec( - &metrics::BLOCK_SERVICE_TIMES, - &[metrics::BEACON_BLOCK_HTTP_GET], + let _get_timer = validator_metrics::start_timer_vec( + &validator_metrics::BLOCK_SERVICE_TIMES, + &[validator_metrics::BEACON_BLOCK_HTTP_GET], ); Self::get_validator_block( beacon_node, @@ -553,9 +551,9 @@ impl BlockService { let slot = signed_block.slot(); match signed_block { SignedBlock::Full(signed_block) => { - let _post_timer = metrics::start_timer_vec( - &metrics::BLOCK_SERVICE_TIMES, - &[metrics::BEACON_BLOCK_HTTP_POST], + let _post_timer = validator_metrics::start_timer_vec( + &validator_metrics::BLOCK_SERVICE_TIMES, + &[validator_metrics::BEACON_BLOCK_HTTP_POST], ); beacon_node .post_beacon_blocks(signed_block) @@ -563,9 +561,9 @@ impl BlockService { .or_else(|e| handle_block_post_error(e, slot, log))? } SignedBlock::Blinded(signed_block) => { - let _post_timer = metrics::start_timer_vec( - &metrics::BLOCK_SERVICE_TIMES, - &[metrics::BLINDED_BEACON_BLOCK_HTTP_POST], + let _post_timer = validator_metrics::start_timer_vec( + &validator_metrics::BLOCK_SERVICE_TIMES, + &[validator_metrics::BLINDED_BEACON_BLOCK_HTTP_POST], ); beacon_node .post_beacon_blinded_blocks(signed_block) diff --git a/validator_client/duties_service/src/lib.rs b/validator_client/duties_service/src/lib.rs index b0aae269c33..ae38e6b8f99 100644 --- a/validator_client/duties_service/src/lib.rs +++ b/validator_client/duties_service/src/lib.rs @@ -6,6 +6,7 @@ //! The `DutiesService` is also responsible for sending events to the `BlockService` which trigger //! block production. +mod block_service; pub mod sync; use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; @@ -661,11 +662,7 @@ async fn poll_beacon_attesters( ) } - update_per_validator_duty_validator_metrics::( - duties_service, - current_epoch, - current_slot, - ); + update_per_validator_duty_metrics::(duties_service, current_epoch, current_slot); drop(current_epoch_timer); let next_epoch_timer = validator_metrics::start_timer_vec( @@ -687,7 +684,7 @@ async fn poll_beacon_attesters( ) } - update_per_validator_duty_validator_metrics::(duties_service, next_epoch, current_slot); + update_per_validator_duty_metrics::(duties_service, next_epoch, current_slot); drop(next_epoch_timer); let subscriptions_timer = validator_metrics::start_timer_vec( diff --git a/validator_client/graffiti_file/Cargo.toml b/validator_client/graffiti_file/Cargo.toml new file mode 100644 index 00000000000..4cb33b44fed --- /dev/null +++ b/validator_client/graffiti_file/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "graffiti_file" +version = "0.1.0" +edition = { workspace = true } +authors = ["Sigma Prime "] + +[lib] +name = "graffiti_file" +path = "src/lib.rs" + +[dependencies] +serde = { workspace = true } +bls = { workspace = true } +types = { workspace = true } +slog = { workspace = true } + +[dev-dependencies] diff --git a/validator_client/src/graffiti_file.rs b/validator_client/graffiti_file/src/lib.rs similarity index 89% rename from validator_client/src/graffiti_file.rs rename to validator_client/graffiti_file/src/lib.rs index 29da3dca5a7..aa2679eea2a 100644 --- a/validator_client/src/graffiti_file.rs +++ b/validator_client/graffiti_file/src/lib.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use slog::warn; use std::collections::HashMap; use std::fs::File; use std::io::{prelude::*, BufReader}; @@ -176,3 +177,24 @@ mod tests { ); } } + +// 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: &slog::Logger, + graffiti_file: Option, + validator_definition_graffiti: Option, + graffiti_flag: Option, +) -> Option { + 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) +} diff --git a/validator_client/http_api/Cargo.toml b/validator_client/http_api/Cargo.toml index 319e6997c00..415c5bc17ad 100644 --- a/validator_client/http_api/Cargo.toml +++ b/validator_client/http_api/Cargo.toml @@ -9,6 +9,36 @@ name = "validator_http_api" path = "src/lib.rs" [dependencies] +account_utils = { workspace = true } +bls = { workspace = true } +deposit_contract = { workspace = true } +doppelganger_service = { workspace = true } +graffiti_file = { workspace = true } +eth2 = { workspace = true } +eth2_keystore = { workspace = true } +ethereum_serde_utils = { workspace = true } +initialized_validators = { workspace = true } +lighthouse_version = { workspace = true } +logging = { workspace = true } +parking_lot = { workspace = true } +filesystem = { workspace = true } +rand = { workspace = true } +serde = { workspace = true } +signing_method = { workspace = true } +sensitive_url = { workspace = true } +slashing_protection = { workspace = true } +slog = { workspace = true } +slot_clock = { workspace = true } +sysinfo = { workspace = true } +system_health = { workspace = true } +task_executor = { workspace = true } +tempfile = { workspace = true } +tokio = { workspace = true } +tokio-stream = { workspace = true } +types = { workspace = true } +validator_dir = { workspace = true } +validator_store = { workspace = true } +url = { workspace = true } warp_utils = { workspace = true } warp = { workspace = true } diff --git a/validator_client/http_api/src/create_signed_voluntary_exit.rs b/validator_client/http_api/src/create_signed_voluntary_exit.rs index a9586da57ec..32269b202b0 100644 --- a/validator_client/http_api/src/create_signed_voluntary_exit.rs +++ b/validator_client/http_api/src/create_signed_voluntary_exit.rs @@ -1,10 +1,10 @@ -use crate::validator_store::ValidatorStore; use bls::{PublicKey, PublicKeyBytes}; use eth2::types::GenericResponse; use slog::{info, Logger}; use slot_clock::SlotClock; use std::sync::Arc; use types::{Epoch, EthSpec, SignedVoluntaryExit, VoluntaryExit}; +use validator_store::ValidatorStore; pub async fn create_signed_voluntary_exit( pubkey: PublicKey, diff --git a/validator_client/http_api/src/create_validator.rs b/validator_client/http_api/src/create_validator.rs index afa5d4fed17..dfd092e8b46 100644 --- a/validator_client/http_api/src/create_validator.rs +++ b/validator_client/http_api/src/create_validator.rs @@ -1,4 +1,3 @@ -use crate::ValidatorStore; use account_utils::validator_definitions::{PasswordStorage, ValidatorDefinition}; use account_utils::{ eth2_keystore::Keystore, @@ -11,6 +10,7 @@ use std::path::{Path, PathBuf}; use types::ChainSpec; use types::EthSpec; use validator_dir::{keystore_password_path, Builder as ValidatorDirBuilder}; +use validator_store::ValidatorStore; /// Create some validator EIP-2335 keystores and store them on disk. Then, enroll the validators in /// this validator client. diff --git a/validator_client/http_api/src/graffiti.rs b/validator_client/http_api/src/graffiti.rs index 79d4fd61f3a..86238a697c6 100644 --- a/validator_client/http_api/src/graffiti.rs +++ b/validator_client/http_api/src/graffiti.rs @@ -1,8 +1,8 @@ -use crate::validator_store::ValidatorStore; use bls::PublicKey; use slot_clock::SlotClock; use std::sync::Arc; use types::{graffiti::GraffitiString, EthSpec, Graffiti}; +use validator_store::ValidatorStore; pub fn get_graffiti( validator_pubkey: PublicKey, diff --git a/validator_client/http_api/src/keystores.rs b/validator_client/http_api/src/keystores.rs index 074c5783475..96a44a3ee94 100644 --- a/validator_client/http_api/src/keystores.rs +++ b/validator_client/http_api/src/keystores.rs @@ -1,8 +1,4 @@ //! Implementation of the standard keystore management API. -use crate::{ - initialized_validators::Error, signing_method::SigningMethod, InitializedValidators, - ValidatorStore, -}; use account_utils::{validator_definitions::PasswordStorage, ZeroizeString}; use eth2::lighthouse_vc::{ std_types::{ @@ -13,6 +9,8 @@ use eth2::lighthouse_vc::{ types::{ExportKeystoresResponse, SingleExportKeystoresResponse}, }; use eth2_keystore::Keystore; +use initialized_validators::{Error, InitializedValidators}; +use signing_method::SigningMethod; use slog::{info, warn, Logger}; use slot_clock::SlotClock; use std::path::PathBuf; @@ -21,6 +19,7 @@ use task_executor::TaskExecutor; use tokio::runtime::Handle; use types::{EthSpec, PublicKeyBytes}; use validator_dir::{keystore_password_path, Builder as ValidatorDirBuilder}; +use validator_store::ValidatorStore; use warp::Rejection; use warp_utils::reject::{custom_bad_request, custom_server_error}; diff --git a/validator_client/http_api/src/lib.rs b/validator_client/http_api/src/lib.rs index 3d7cab8e5e0..17148687ce9 100644 --- a/validator_client/http_api/src/lib.rs +++ b/validator_client/http_api/src/lib.rs @@ -8,10 +8,12 @@ mod tests; pub mod test_utils; -use crate::http_api::graffiti::{delete_graffiti, get_graffiti, set_graffiti}; +use graffiti::{delete_graffiti, get_graffiti, set_graffiti}; + +use create_signed_voluntary_exit::create_signed_voluntary_exit; +use graffiti_file::{determine_graffiti, GraffitiFile}; +use validator_store::ValidatorStore; -use crate::http_api::create_signed_voluntary_exit::create_signed_voluntary_exit; -use crate::{determine_graffiti, GraffitiFile, ValidatorStore}; use account_utils::{ mnemonic_from_phrase, validator_definitions::{SigningDefinition, ValidatorDefinition, Web3SignerDefinition}, diff --git a/validator_client/http_api/src/remotekeys.rs b/validator_client/http_api/src/remotekeys.rs index 053bbcb4b2d..289be571825 100644 --- a/validator_client/http_api/src/remotekeys.rs +++ b/validator_client/http_api/src/remotekeys.rs @@ -1,5 +1,4 @@ //! Implementation of the standard remotekey management API. -use crate::{initialized_validators::Error, InitializedValidators, ValidatorStore}; use account_utils::validator_definitions::{ SigningDefinition, ValidatorDefinition, Web3SignerDefinition, }; @@ -8,6 +7,7 @@ use eth2::lighthouse_vc::std_types::{ ImportRemotekeyStatus, ImportRemotekeysRequest, ImportRemotekeysResponse, ListRemotekeysResponse, SingleListRemotekeysResponse, Status, }; +use initialized_validators::{Error, InitializedValidators}; use slog::{info, warn, Logger}; use slot_clock::SlotClock; use std::sync::Arc; @@ -15,6 +15,7 @@ use task_executor::TaskExecutor; use tokio::runtime::Handle; use types::{EthSpec, PublicKeyBytes}; use url::Url; +use validator_store::ValidatorStore; use warp::Rejection; use warp_utils::reject::custom_server_error; diff --git a/validator_client/http_api/src/test_utils.rs b/validator_client/http_api/src/test_utils.rs index 8bb56e87a32..ea2f93c1d37 100644 --- a/validator_client/http_api/src/test_utils.rs +++ b/validator_client/http_api/src/test_utils.rs @@ -1,21 +1,19 @@ -use crate::doppelganger_service::DoppelgangerService; -use crate::key_cache::{KeyCache, CACHE_FILENAME}; -use crate::{ - http_api::{ApiSecret, Config as HttpConfig, Context}, - initialized_validators::{InitializedValidators, OnDecryptFailure}, - Config, ValidatorDefinitions, ValidatorStore, -}; +use crate::{ApiSecret, Config as HttpConfig, Context}; +use account_utils::validator_definitions::ValidatorDefinitions; use account_utils::{ eth2_wallet::WalletBuilder, mnemonic_from_phrase, random_mnemonic, random_password, ZeroizeString, }; use deposit_contract::decode_eth1_tx_data; +use doppelganger_service::DoppelgangerService; use eth2::{ lighthouse_vc::{http_client::ValidatorClientHttpClient, types::*}, types::ErrorMessage as ApiErrorMessage, Error as ApiError, }; use eth2_keystore::KeystoreBuilder; +use initialized_validators::key_cache::{KeyCache, CACHE_FILENAME}; +use initialized_validators::{Config, InitializedValidators, OnDecryptFailure}; use logging::test_logger; use parking_lot::RwLock; use sensitive_url::SensitiveUrl; @@ -29,6 +27,7 @@ use std::time::Duration; use task_executor::test_utils::TestRuntime; use tempfile::{tempdir, TempDir}; use tokio::sync::oneshot; +use validator_store::ValidatorStore; pub const PASSWORD_BYTES: &[u8] = &[42, 50, 37]; pub const TEST_DEFAULT_FEE_RECIPIENT: Address = Address::repeat_byte(42); diff --git a/validator_client/http_metrics/Cargo.toml b/validator_client/http_metrics/Cargo.toml index a4882c7f321..99cdb70c8bd 100644 --- a/validator_client/http_metrics/Cargo.toml +++ b/validator_client/http_metrics/Cargo.toml @@ -9,7 +9,6 @@ name = "validator_http_metrics" path = "src/lib.rs" [dependencies] -axum = { workspace = true } malloc_utils = { workspace = true } slot_clock = { workspace = true } lighthouse_metrics = { workspace = true } diff --git a/validator_client/initialized_validators/src/lib.rs b/validator_client/initialized_validators/src/lib.rs index 1334056069d..d359f2801a4 100644 --- a/validator_client/initialized_validators/src/lib.rs +++ b/validator_client/initialized_validators/src/lib.rs @@ -1200,7 +1200,7 @@ impl InitializedValidators { /// A validator is considered "already known" and skipped if the public key is already known. /// I.e., if there are two different definitions with the same public key then the second will /// be ignored. - pub(crate) async fn update_validators(&mut self) -> Result<(), Error> { + pub async fn update_validators(&mut self) -> Result<(), Error> { //use key cache if available let mut key_stores = HashMap::new(); diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 934453882c0..3e1aa9cdb5b 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -847,24 +847,3 @@ pub fn load_pem_certificate>(pem_path: P) -> Result, - validator_definition_graffiti: Option, - graffiti_flag: Option, -) -> Option { - 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) -} From ec088c2bcae2ae3726d2e085e42b171098dfd5e1 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Wed, 2 Oct 2024 17:50:25 +1000 Subject: [PATCH 4/6] More progress --- Cargo.lock | 86 +++++++------------ Cargo.toml | 4 +- validator_client/Cargo.toml | 56 ++++-------- validator_client/http_api/src/test_utils.rs | 10 +-- validator_client/http_metrics/Cargo.toml | 8 +- validator_client/http_metrics/src/lib.rs | 30 ++++--- .../initialized_validators/Cargo.toml | 4 - .../initialized_validators/src/lib.rs | 1 + validator_client/signing_method/Cargo.toml | 4 - validator_client/src/config.rs | 34 +++----- validator_client/src/lib.rs | 52 +++++------ .../Cargo.toml | 7 +- .../src/attestation_service.rs | 46 +++++----- .../src/block_service.rs | 0 .../src/duties_service.rs} | 9 +- .../validator_services/src/lib.rs | 6 ++ .../src/preparation_service.rs | 14 +-- .../src/sync.rs | 2 +- .../src/sync_committee_service.rs | 9 +- validator_client/validator_store/src/lib.rs | 1 + 20 files changed, 150 insertions(+), 233 deletions(-) rename validator_client/{duties_service => validator_services}/Cargo.toml (89%) rename validator_client/{duties_service => validator_services}/src/attestation_service.rs (95%) rename validator_client/{duties_service => validator_services}/src/block_service.rs (100%) rename validator_client/{duties_service/src/lib.rs => validator_services/src/duties_service.rs} (99%) create mode 100644 validator_client/validator_services/src/lib.rs rename validator_client/{duties_service => validator_services}/src/preparation_service.rs (97%) rename validator_client/{duties_service => validator_services}/src/sync.rs (99%) rename validator_client/{duties_service => validator_services}/src/sync_committee_service.rs (99%) diff --git a/Cargo.lock b/Cargo.lock index 48b8f22b79f..e309cecd7c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2267,27 +2267,6 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" -[[package]] -name = "duties_service" -version = "0.1.0" -dependencies = [ - "beacon_node_fallback", - "bls", - "doppelganger_service", - "environment", - "eth2", - "futures", - "graffiti_file", - "parking_lot 0.12.3", - "safe_arith", - "slog", - "slot_clock", - "tokio", - "types", - "validator_metrics", - "validator_store", -] - [[package]] name = "ecdsa" version = "0.14.8" @@ -9261,55 +9240,30 @@ name = "validator_client" version = "0.3.5" dependencies = [ "account_utils", - "bincode", - "bls", + "beacon_node_fallback", "clap", "clap_utils", - "deposit_contract", "directory", "dirs", - "environment", "eth2", - "eth2_keystore", - "ethereum_serde_utils", "fdlimit", - "filesystem", - "futures", - "hex", + "graffiti_file", "hyper 1.4.1", + "initialized_validators", "itertools 0.10.5", - "libsecp256k1", "lighthouse_metrics", - "lighthouse_version", - "lockfile", - "logging", - "malloc_utils", "monitoring_api", - "parking_lot 0.12.3", - "rand", - "reqwest", - "ring 0.16.20", - "safe_arith", "sensitive_url", "serde", - "serde_json", "slashing_protection", "slog", - "slot_clock", - "strum", - "sysinfo", - "system_health", - "task_executor", - "tempfile", "tokio", - "tokio-stream", - "tree_hash", "types", - "url", - "validator_dir", + "validator_http_api", + "validator_http_metrics", "validator_metrics", - "warp", - "warp_utils", + "validator_services", + "validator_store", ] [[package]] @@ -9379,6 +9333,10 @@ dependencies = [ "serde", "slog", "slot_clock", + "types", + "validator_metrics", + "validator_services", + "validator_store", "warp", "warp_utils", ] @@ -9414,6 +9372,28 @@ dependencies = [ "malloc_utils", ] +[[package]] +name = "validator_services" +version = "0.1.0" +dependencies = [ + "beacon_node_fallback", + "bls", + "doppelganger_service", + "environment", + "eth2", + "futures", + "graffiti_file", + "parking_lot 0.12.3", + "safe_arith", + "slog", + "slot_clock", + "tokio", + "tree_hash", + "types", + "validator_metrics", + "validator_store", +] + [[package]] name = "validator_store" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 3d8e6abac02..83ad9748e15 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,6 @@ members = [ "validator_client", "validator_client/beacon_node_fallback", "validator_client/doppelganger_service", - "validator_client/duties_service", "validator_client/graffiti_file", "validator_client/http_api", "validator_client/http_metrics", @@ -93,6 +92,7 @@ members = [ "validator_client/signing_method", "validator_client/slashing_protection", "validator_client/validator_metrics", + "validator_client/validator_services", "validator_client/validator_store", "validator_manager", @@ -209,7 +209,7 @@ compare_fields = { path = "common/compare_fields" } deposit_contract = { path = "common/deposit_contract" } directory = { path = "common/directory" } doppelganger_service = { path = "validator_client/doppelganger_service" } -duties_service = { path = "validator_client/duties_service" } +validator_services = { path = "validator_client/validator_services" } environment = { path = "lighthouse/environment" } eth1 = { path = "beacon_node/eth1" } eth1_test_rig = { path = "testing/eth1_test_rig" } diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index d77292ecd17..1d2baa7c098 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "validator_client" version = "0.3.5" -authors = ["Paul Hauner ", "Age Manning ", "Luke Anderson "] +authors = ["Sigma Prime "] edition = { workspace = true } [lib] @@ -13,52 +13,26 @@ tokio = { workspace = true } itertools = { workspace = true } [dependencies] -tree_hash = { workspace = true } +account_utils = { workspace = true } +beacon_node_fallback = { workspace = true } clap = { workspace = true } -slashing_protection = { workspace = true } -slot_clock = { workspace = true } -types = { workspace = true } -safe_arith = { workspace = true } -serde = { workspace = true } -bincode = { workspace = true } -serde_json = { workspace = true } -slog = { workspace = true } -tokio = { workspace = true } -tokio-stream = { workspace = true } -futures = { workspace = true } -dirs = { workspace = true } +clap_utils = { workspace = true } directory = { workspace = true } -lockfile = { workspace = true } -environment = { workspace = true } -parking_lot = { workspace = true } -filesystem = { workspace = true } -hex = { workspace = true } -deposit_contract = { workspace = true } -bls = { workspace = true } +dirs = { workspace = true } eth2 = { workspace = true } -tempfile = { workspace = true } -validator_dir = { workspace = true } -clap_utils = { workspace = true } -eth2_keystore = { workspace = true } -account_utils = { workspace = true } -lighthouse_version = { workspace = true } -warp_utils = { workspace = true } -warp = { workspace = true } +graffiti_file= { workspace = true } hyper = { workspace = true } -ethereum_serde_utils = { workspace = true } -libsecp256k1 = { workspace = true } -ring = { workspace = true } -rand = { workspace = true, features = ["small_rng"] } +initialized_validators = { workspace = true } lighthouse_metrics = { workspace = true } monitoring_api = { workspace = true } sensitive_url = { workspace = true } -task_executor = { workspace = true } +slashing_protection = { workspace = true } +serde = { workspace = true } +slog = { workspace = true } +types = { workspace = true } +validator_http_api = { workspace = true } +validator_http_metrics = { workspace = true } validator_metrics = { workspace = true } -reqwest = { workspace = true, features = ["native-tls"] } -url = { workspace = true } -malloc_utils = { workspace = true } -sysinfo = { workspace = true } -system_health = { path = "../common/system_health" } -logging = { workspace = true } -strum = { workspace = true } +validator_services = { workspace = true } +validator_store = { workspace = true } fdlimit = "0.3.0" diff --git a/validator_client/http_api/src/test_utils.rs b/validator_client/http_api/src/test_utils.rs index ea2f93c1d37..13590d5830f 100644 --- a/validator_client/http_api/src/test_utils.rs +++ b/validator_client/http_api/src/test_utils.rs @@ -13,7 +13,7 @@ use eth2::{ }; use eth2_keystore::KeystoreBuilder; use initialized_validators::key_cache::{KeyCache, CACHE_FILENAME}; -use initialized_validators::{Config, InitializedValidators, OnDecryptFailure}; +use initialized_validators::{InitializedValidators, OnDecryptFailure}; use logging::test_logger; use parking_lot::RwLock; use sensitive_url::SensitiveUrl; @@ -27,7 +27,7 @@ use std::time::Duration; use task_executor::test_utils::TestRuntime; use tempfile::{tempdir, TempDir}; use tokio::sync::oneshot; -use validator_store::ValidatorStore; +use validator_store::{Config as ValidatorStoreConfig, ValidatorStore}; pub const PASSWORD_BYTES: &[u8] = &[42, 50, 37]; pub const TEST_DEFAULT_FEE_RECIPIENT: Address = Address::repeat_byte(42); @@ -88,16 +88,14 @@ impl ApiTester { let api_secret = ApiSecret::create_or_open(validator_dir.path()).unwrap(); let api_pubkey = api_secret.api_token(); - let config = Config { - validator_dir: validator_dir.path().into(), - secrets_dir: secrets_dir.path().into(), + let config = ValidatorStoreConfig { fee_recipient: Some(TEST_DEFAULT_FEE_RECIPIENT), ..Default::default() }; let spec = E::default_spec(); - let slashing_db_path = config.validator_dir.join(SLASHING_PROTECTION_FILENAME); + let slashing_db_path = validator_dir.path().join(SLASHING_PROTECTION_FILENAME); let slashing_protection = SlashingDatabase::open_or_create(&slashing_db_path).unwrap(); let slot_clock = diff --git a/validator_client/http_metrics/Cargo.toml b/validator_client/http_metrics/Cargo.toml index 99cdb70c8bd..fc1fb48301e 100644 --- a/validator_client/http_metrics/Cargo.toml +++ b/validator_client/http_metrics/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = { workspace = true } authors = ["Sigma Prime "] -[lib] -name = "validator_http_metrics" -path = "src/lib.rs" - [dependencies] malloc_utils = { workspace = true } slot_clock = { workspace = true } @@ -18,5 +14,9 @@ slog = { workspace = true } warp_utils = { workspace = true } warp = { workspace = true } lighthouse_version = { workspace = true } +validator_services = { workspace = true } +validator_store = { workspace = true } +validator_metrics = { workspace = true } +types = { workspace = true } [dev-dependencies] diff --git a/validator_client/http_metrics/src/lib.rs b/validator_client/http_metrics/src/lib.rs index e576d2f1655..2aeeae69599 100644 --- a/validator_client/http_metrics/src/lib.rs +++ b/validator_client/http_metrics/src/lib.rs @@ -1,14 +1,20 @@ //! This crate provides a HTTP server that is solely dedicated to serving the `/metrics` endpoint. //! //! For other endpoints, see the `http_api` crate. + use lighthouse_version::version_with_platform; +use malloc_utils::scrape_allocator_metrics; use parking_lot::RwLock; use serde::{Deserialize, Serialize}; use slog::{crit, info, Logger}; -use slot_clock::SystemTimeSlotClock; +use slot_clock::{SlotClock, SystemTimeSlotClock}; use std::future::Future; use std::net::{IpAddr, Ipv4Addr, SocketAddr}; use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; +use types::EthSpec; +use validator_services::duties_service::DutiesService; +use validator_store::ValidatorStore; use warp::{http::Response, Filter}; #[derive(Debug)] @@ -30,18 +36,18 @@ impl From for Error { } /// Contains objects which have shared access from inside/outside of the metrics server. -pub struct Shared { - pub validator_store: Option>, - pub duties_service: Option>, +pub struct Shared { + pub validator_store: Option>>, + pub duties_service: Option>>, pub genesis_time: Option, } /// A wrapper around all the items required to spawn the HTTP server. /// /// The server will gracefully handle the case where any fields are `None`. -pub struct Context { +pub struct Context { pub config: Config, - pub shared: RwLock>, + pub shared: RwLock>, pub log: Logger, } @@ -82,8 +88,8 @@ impl Default for Config { /// /// Returns an error if the server is unable to bind or there is another error during /// configuration. -pub fn serve( - ctx: Arc>, +pub fn serve( + ctx: Arc>, shutdown: impl Future + Send + Sync + 'static, ) -> Result<(SocketAddr, impl Future), Error> { let config = &ctx.config; @@ -116,7 +122,7 @@ pub fn serve( .map(move || inner_ctx.clone()) .and_then(|ctx: Arc>| async move { Ok::<_, warp::Rejection>( - metrics::gather_prometheus_metrics(&ctx) + gather_prometheus_metrics(&ctx) .map(|body| { Response::builder() .status(200) @@ -153,7 +159,11 @@ pub fn serve( Ok((listening_socket, server)) } -pub fn gather_prometheus_metrics(ctx: &Context) -> std::result::Result { +pub fn gather_prometheus_metrics( + ctx: &Context, +) -> std::result::Result { + use validator_metrics::*; + let mut buffer = vec![]; let encoder = TextEncoder::new(); diff --git a/validator_client/initialized_validators/Cargo.toml b/validator_client/initialized_validators/Cargo.toml index 403061335f9..2ca64ca25e4 100644 --- a/validator_client/initialized_validators/Cargo.toml +++ b/validator_client/initialized_validators/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = { workspace = true } authors = ["Sigma Prime "] -[lib] -name = "initialized_validators" -path = "src/lib.rs" - [dependencies] signing_method = { workspace = true } account_utils = { workspace = true } diff --git a/validator_client/initialized_validators/src/lib.rs b/validator_client/initialized_validators/src/lib.rs index d359f2801a4..563615e0124 100644 --- a/validator_client/initialized_validators/src/lib.rs +++ b/validator_client/initialized_validators/src/lib.rs @@ -46,6 +46,7 @@ const DEFAULT_REMOTE_SIGNER_REQUEST_TIMEOUT: Duration = Duration::from_secs(12); const USE_STDIN: bool = false; // The configuration for initialised validators. +#[derive(Default, Clone)] pub struct Config { pub web3_signer_keep_alive_timeout: Option, pub web3_signer_max_idle_connections: Option, diff --git a/validator_client/signing_method/Cargo.toml b/validator_client/signing_method/Cargo.toml index 668b151b4ff..8077abb7370 100644 --- a/validator_client/signing_method/Cargo.toml +++ b/validator_client/signing_method/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = { workspace = true } authors = ["Sigma Prime "] -[lib] -name = "signing_method" -path = "src/lib.rs" - [dependencies] eth2_keystore = { workspace = true } lockfile = { workspace = true } diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index 204c5b8b6cc..c4916f77684 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -1,6 +1,4 @@ -use crate::beacon_node_fallback::ApiTopic; -use crate::graffiti_file::GraffitiFile; -use crate::{http_api, http_metrics}; +use beacon_node_fallback::ApiTopic; use clap::ArgMatches; use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, parse_optional, parse_required}; use directory::{ @@ -8,6 +6,7 @@ use directory::{ DEFAULT_VALIDATOR_DIR, }; use eth2::types::Graffiti; +use graffiti_file::GraffitiFile; use sensitive_url::SensitiveUrl; use serde::{Deserialize, Serialize}; use slog::{info, warn, Logger}; @@ -16,6 +15,9 @@ use std::net::IpAddr; use std::path::PathBuf; use std::time::Duration; use types::{Address, GRAFFITI_BYTES_LEN}; +use validator_http_api; +use validator_http_metrics; +use validator_store::Config as ValidatorStoreConfig; pub const DEFAULT_BEACON_NODE: &str = "http://localhost:5052/"; pub const DEFAULT_WEB3SIGNER_KEEP_ALIVE: Option = Some(Duration::from_secs(20)); @@ -23,6 +25,9 @@ pub const DEFAULT_WEB3SIGNER_KEEP_ALIVE: Option = Some(Duration::from_ /// Stores the core configuration for this validator instance. #[derive(Clone, Serialize, Deserialize)] pub struct Config { + #[serde(flatten)] + /// Configuration parameters for the validator store. + pub validator_store: ValidatorStoreConfig, /// The data directory, which stores all validator databases pub validator_dir: PathBuf, /// The directory containing the passwords to unlock validator keystores. @@ -46,12 +51,10 @@ pub struct Config { pub graffiti: Option, /// Graffiti file to load per validator graffitis. pub graffiti_file: Option, - /// Fallback fallback address. - pub fee_recipient: Option
, /// Configuration for the HTTP REST API. - pub http_api: http_api::Config, + pub http_api: validator_http_api::Config, /// Configuration for the HTTP REST API. - pub http_metrics: http_metrics::Config, + pub http_metrics: validator_http_metrics::Config, /// Configuration for sending metrics to a remote explorer endpoint. pub monitoring_api: Option, /// If true, enable functionality that monitors the network for attestations or proposals from @@ -63,11 +66,7 @@ pub struct Config { /// (<= 64 validators) pub enable_high_validator_count_metrics: bool, /// Enable use of the blinded block endpoints during proposals. - pub builder_proposals: bool, - /// Overrides the timestamp field in builder api ValidatorRegistrationV1 pub builder_registration_timestamp_override: Option, - /// Fallback gas limit. - pub gas_limit: Option, /// 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>, @@ -77,12 +76,6 @@ pub struct Config { pub enable_latency_measurement_service: bool, /// Defines the number of validators per `validator/register_validator` request sent to the BN. pub validator_registration_batch_size: usize, - /// Enable slashing protection even while using web3signer keys. - pub enable_web3signer_slashing_protection: bool, - /// Specifies the boost factor, a percentage multiplier to apply to the builder's payload value. - pub builder_boost_factor: Option, - /// If true, Lighthouse will prefer builder proposals, if available. - pub prefer_builder_proposals: bool, /// Whether we are running with distributed network support. pub distributed: bool, pub web3_signer_keep_alive_timeout: Option, @@ -104,6 +97,7 @@ impl Default for Config { let beacon_nodes = vec![SensitiveUrl::parse(DEFAULT_BEACON_NODE) .expect("beacon_nodes must always be a valid url.")]; Self { + validator_store: ValidatorStoreConfig::default(), validator_dir, secrets_dir, beacon_nodes, @@ -114,22 +108,16 @@ impl Default for Config { use_long_timeouts: false, graffiti: None, graffiti_file: None, - fee_recipient: None, http_api: <_>::default(), http_metrics: <_>::default(), monitoring_api: None, enable_doppelganger_protection: false, enable_high_validator_count_metrics: false, beacon_nodes_tls_certs: None, - builder_proposals: false, builder_registration_timestamp_override: None, - gas_limit: None, broadcast_topics: vec![ApiTopic::Subscriptions], enable_latency_measurement_service: true, validator_registration_batch_size: 500, - enable_web3signer_slashing_protection: true, - builder_boost_factor: None, - prefer_builder_proposals: false, distributed: false, web3_signer_keep_alive_timeout: DEFAULT_WEB3SIGNER_KEEP_ALIVE, web3_signer_max_idle_connections: None, diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 3e1aa9cdb5b..4975202d128 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -1,50 +1,30 @@ -mod attestation_service; -mod beacon_node_fallback; -mod block_service; -mod check_synced; mod cli; -mod duties_service; -mod graffiti_file; -mod key_cache; +pub mod config; mod latency; mod notifier; -mod preparation_service; -mod signing_method; -mod sync_committee_service; - -pub mod config; -mod doppelganger_service; -pub mod http_api; -pub mod initialized_validators; -pub mod validator_store; -pub use beacon_node_fallback::ApiTopic; pub use cli::cli_app; pub use config::Config; use initialized_validators::InitializedValidators; use lighthouse_metrics::set_gauge; use monitoring_api::{MonitoringHttpClient, ProcessType}; use sensitive_url::SensitiveUrl; -pub use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME}; +use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME}; -use crate::beacon_node_fallback::{ - start_fallback_updater_service, BeaconNodeFallback, CandidateBeaconNode, OfflineOnFailure, - RequireSynced, +use beacon_node_fallback::{ + start_fallback_updater_service, ApiTopic, BeaconNodeFallback, CandidateBeaconNode, + OfflineOnFailure, RequireSynced, }; -use crate::doppelganger_service::DoppelgangerService; -use crate::graffiti_file::GraffitiFile; -use crate::initialized_validators::Error::UnableToOpenVotingKeystore; + use account_utils::validator_definitions::ValidatorDefinitions; -use attestation_service::{AttestationService, AttestationServiceBuilder}; -use block_service::{BlockService, BlockServiceBuilder}; use clap::ArgMatches; -use duties_service::{sync::SyncDutiesMap, DutiesService}; +use doppelganger_service::DoppelgangerService; use environment::RuntimeContext; use eth2::{reqwest::ClientBuilder, types::Graffiti, BeaconNodeHttpClient, StatusCode, Timeouts}; -use http_api::ApiSecret; +use graffiti_file::GraffitiFile; +use initialized_validators::Error::UnableToOpenVotingKeystore; use notifier::spawn_notifier; use parking_lot::RwLock; -use preparation_service::{PreparationService, PreparationServiceBuilder}; use reqwest::Certificate; use slog::{debug, error, info, warn, Logger}; use slot_clock::SlotClock; @@ -56,12 +36,20 @@ use std::net::SocketAddr; use std::path::Path; 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, Hash256, PublicKeyBytes}; +use validator_http_api::ApiSecret; +use validator_services::{ + attestation_service::{AttestationService, AttestationServiceBuilder}, + block_service::{BlockService, BlockServiceBuilder}, + duties_service::{self, DutiesService}, + preparation_service::{PreparationService, PreparationServiceBuilder}, + sync::SyncDutiesMap, + sync_committee_service::SyncCommitteeService, +}; use validator_store::ValidatorStore; /// The interval between attempts to contact the beacon node during startup. @@ -559,7 +547,7 @@ impl ProductionValidatorClient { 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::new(http_api::Context { + let ctx = Arc::new(validator_http_api::Context { task_executor: self.context.executor.clone(), api_secret, validator_store: Some(self.validator_store.clone()), @@ -577,7 +565,7 @@ impl ProductionValidatorClient { let exit = self.context.executor.exit(); - let (listen_addr, server) = http_api::serve(ctx, exit) + let (listen_addr, server) = validator_http_api::serve(ctx, exit) .map_err(|e| format!("Unable to start HTTP API server: {:?}", e))?; self.context diff --git a/validator_client/duties_service/Cargo.toml b/validator_client/validator_services/Cargo.toml similarity index 89% rename from validator_client/duties_service/Cargo.toml rename to validator_client/validator_services/Cargo.toml index 46fa0156bf5..00927b3c411 100644 --- a/validator_client/duties_service/Cargo.toml +++ b/validator_client/validator_services/Cargo.toml @@ -1,13 +1,9 @@ [package] -name = "duties_service" +name = "validator_services" version = "0.1.0" edition = { workspace = true } authors = ["Sigma Prime "] -[lib] -name = "duties_service" -path = "src/lib.rs" - [dependencies] beacon_node_fallback = { workspace = true } validator_metrics = { workspace = true } @@ -23,6 +19,7 @@ slog = { workspace = true } slot_clock = { workspace = true } tokio = { workspace = true } types = { workspace = true } +tree_hash = { workspace = true } bls = { workspace = true } [dev-dependencies] diff --git a/validator_client/duties_service/src/attestation_service.rs b/validator_client/validator_services/src/attestation_service.rs similarity index 95% rename from validator_client/duties_service/src/attestation_service.rs rename to validator_client/validator_services/src/attestation_service.rs index 30fe508a2c2..21b264f80b7 100644 --- a/validator_client/duties_service/src/attestation_service.rs +++ b/validator_client/validator_services/src/attestation_service.rs @@ -1,10 +1,5 @@ -use crate::beacon_node_fallback::{ApiTopic, BeaconNodeFallback, RequireSynced}; -use crate::{ - duties_service::{DutiesService, DutyAndProof}, - http_metrics::metrics, - validator_store::{Error as ValidatorStoreError, ValidatorStore}, - OfflineOnFailure, -}; +use crate::duties_service::{DutiesService, DutyAndProof}; +use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; use environment::RuntimeContext; use futures::future::join_all; use slog::{crit, debug, error, info, trace, warn}; @@ -15,6 +10,7 @@ use std::sync::Arc; use tokio::time::{sleep, sleep_until, Duration, Instant}; use tree_hash::TreeHash; use types::{Attestation, AttestationData, ChainSpec, CommitteeIndex, EthSpec, Slot}; +use validator_store::{Error as ValidatorStoreError, ValidatorStore}; /// Builds an `AttestationService`. pub struct AttestationServiceBuilder { @@ -239,9 +235,9 @@ impl AttestationService { aggregate_production_instant: Instant, ) -> Result<(), ()> { let log = self.context.log(); - let attestations_timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::ATTESTATIONS], + let attestations_timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::ATTESTATIONS], ); // There's not need to produce `Attestation` or `SignedAggregateAndProof` if we do not have @@ -279,9 +275,9 @@ impl AttestationService { sleep_until(aggregate_production_instant).await; // Start the metrics timer *after* we've done the delay. - let _aggregates_timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::AGGREGATES], + let _aggregates_timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::AGGREGATES], ); // Then download, sign and publish a `SignedAggregateAndProof` for each @@ -343,9 +339,9 @@ impl AttestationService { RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::ATTESTATIONS_HTTP_GET], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::ATTESTATIONS_HTTP_GET], ); beacon_node .get_validator_attestation_data(slot, committee_index) @@ -463,9 +459,9 @@ impl AttestationService { OfflineOnFailure::Yes, ApiTopic::Attestations, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::ATTESTATIONS_HTTP_POST], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::ATTESTATIONS_HTTP_POST], ); if fork_name.electra_enabled() { beacon_node @@ -544,9 +540,9 @@ impl AttestationService { RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::AGGREGATES_HTTP_GET], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::AGGREGATES_HTTP_GET], ); if fork_name.electra_enabled() { beacon_node @@ -641,9 +637,9 @@ impl AttestationService { RequireSynced::No, OfflineOnFailure::Yes, |beacon_node| async move { - let _timer = metrics::start_timer_vec( - &metrics::ATTESTATION_SERVICE_TIMES, - &[metrics::AGGREGATES_HTTP_POST], + let _timer = validator_metrics::start_timer_vec( + &validator_metrics::ATTESTATION_SERVICE_TIMES, + &[validator_metrics::AGGREGATES_HTTP_POST], ); if fork_name.electra_enabled() { beacon_node diff --git a/validator_client/duties_service/src/block_service.rs b/validator_client/validator_services/src/block_service.rs similarity index 100% rename from validator_client/duties_service/src/block_service.rs rename to validator_client/validator_services/src/block_service.rs diff --git a/validator_client/duties_service/src/lib.rs b/validator_client/validator_services/src/duties_service.rs similarity index 99% rename from validator_client/duties_service/src/lib.rs rename to validator_client/validator_services/src/duties_service.rs index ae38e6b8f99..cf41d565230 100644 --- a/validator_client/duties_service/src/lib.rs +++ b/validator_client/validator_services/src/duties_service.rs @@ -6,11 +6,10 @@ //! The `DutiesService` is also responsible for sending events to the `BlockService` which trigger //! block production. -mod block_service; -pub mod sync; - +use crate::block_service::BlockServiceNotification; +use crate::sync::poll_sync_committee_duties; +use crate::sync::SyncDutiesMap; use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; -use block_service::BlockServiceNotification; use doppelganger_service::DoppelgangerStatus; use environment::RuntimeContext; use eth2::types::{ @@ -26,8 +25,6 @@ use std::collections::{hash_map, BTreeMap, HashMap, HashSet}; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::time::Duration; -use sync::poll_sync_committee_duties; -use sync::SyncDutiesMap; use tokio::{sync::mpsc::Sender, time::sleep}; use types::{ChainSpec, Epoch, EthSpec, Hash256, PublicKeyBytes, SelectionProof, Slot}; use validator_metrics::{get_int_gauge, set_int_gauge, ATTESTATION_DUTY}; diff --git a/validator_client/validator_services/src/lib.rs b/validator_client/validator_services/src/lib.rs new file mode 100644 index 00000000000..abf8fab3cb6 --- /dev/null +++ b/validator_client/validator_services/src/lib.rs @@ -0,0 +1,6 @@ +pub mod attestation_service; +pub mod block_service; +pub mod duties_service; +pub mod preparation_service; +pub mod sync; +pub mod sync_committee_service; diff --git a/validator_client/duties_service/src/preparation_service.rs b/validator_client/validator_services/src/preparation_service.rs similarity index 97% rename from validator_client/duties_service/src/preparation_service.rs rename to validator_client/validator_services/src/preparation_service.rs index 474f9f47609..341deaa5fb0 100644 --- a/validator_client/duties_service/src/preparation_service.rs +++ b/validator_client/validator_services/src/preparation_service.rs @@ -1,7 +1,6 @@ -use crate::beacon_node_fallback::{ApiTopic, BeaconNodeFallback, RequireSynced}; -use crate::validator_store::{DoppelgangerStatus, Error as ValidatorStoreError, ValidatorStore}; -use crate::OfflineOnFailure; +use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; use bls::PublicKeyBytes; +use doppelganger_service::DoppelgangerStatus; use environment::RuntimeContext; use parking_lot::RwLock; use slog::{debug, error, info, warn}; @@ -16,6 +15,7 @@ use types::{ Address, ChainSpec, EthSpec, ProposerPreparationData, SignedValidatorRegistrationData, ValidatorRegistrationData, }; +use validator_store::{Error as ValidatorStoreError, ProposalData, ValidatorStore}; /// Number of epochs before the Bellatrix hard fork to begin posting proposer preparations. const PROPOSER_PREPARATION_LOOKAHEAD_EPOCHS: u64 = 2; @@ -502,11 +502,3 @@ impl PreparationService { Ok(()) } } - -/// A helper struct, used for passing data from the validator store to services. -pub struct ProposalData { - pub(crate) validator_index: Option, - pub(crate) fee_recipient: Option
, - pub(crate) gas_limit: u64, - pub(crate) builder_proposals: bool, -} diff --git a/validator_client/duties_service/src/sync.rs b/validator_client/validator_services/src/sync.rs similarity index 99% rename from validator_client/duties_service/src/sync.rs rename to validator_client/validator_services/src/sync.rs index 6055f8f610c..93dae81caab 100644 --- a/validator_client/duties_service/src/sync.rs +++ b/validator_client/validator_services/src/sync.rs @@ -1,4 +1,4 @@ -use super::{DutiesService, Error}; +use crate::duties_service::{DutiesService, Error}; use beacon_node_fallback::{OfflineOnFailure, RequireSynced}; use doppelganger_service::DoppelgangerStatus; use futures::future::join_all; diff --git a/validator_client/duties_service/src/sync_committee_service.rs b/validator_client/validator_services/src/sync_committee_service.rs similarity index 99% rename from validator_client/duties_service/src/sync_committee_service.rs rename to validator_client/validator_services/src/sync_committee_service.rs index f7abb3855a3..1c7c9d3a733 100644 --- a/validator_client/duties_service/src/sync_committee_service.rs +++ b/validator_client/validator_services/src/sync_committee_service.rs @@ -1,9 +1,5 @@ -use crate::beacon_node_fallback::{ApiTopic, BeaconNodeFallback, RequireSynced}; -use crate::{ - duties_service::DutiesService, - validator_store::{Error as ValidatorStoreError, ValidatorStore}, - OfflineOnFailure, -}; +use crate::duties_service::DutiesService; +use beacon_node_fallback::{ApiTopic, BeaconNodeFallback, OfflineOnFailure, RequireSynced}; use environment::RuntimeContext; use eth2::types::BlockId; use futures::future::join_all; @@ -19,6 +15,7 @@ use types::{ ChainSpec, EthSpec, Hash256, PublicKeyBytes, Slot, SyncCommitteeSubscription, SyncContributionData, SyncDuty, SyncSelectionProof, SyncSubnetId, }; +use validator_store::{Error as ValidatorStoreError, ValidatorStore}; pub const SUBSCRIPTION_LOOKAHEAD_EPOCHS: u64 = 4; diff --git a/validator_client/validator_store/src/lib.rs b/validator_client/validator_store/src/lib.rs index bc5425b2b7c..a997f0ea607 100644 --- a/validator_client/validator_store/src/lib.rs +++ b/validator_client/validator_store/src/lib.rs @@ -41,6 +41,7 @@ impl From for Error { } } +#[derive(Default, Clone)] pub struct Config { /// Fallback fallback address. pub fee_recipient: Option
, From 56bc62b82b913c5bd5242931b9380dc6b8ec90ab Mon Sep 17 00:00:00 2001 From: Age Manning Date: Thu, 3 Oct 2024 15:16:57 +1000 Subject: [PATCH 5/6] Compiles --- Cargo.lock | 7 ++++ testing/node_test_rig/Cargo.toml | 1 + testing/node_test_rig/src/lib.rs | 3 +- testing/simulator/src/basic_sim.rs | 3 +- testing/simulator/src/fallback_sim.rs | 3 +- validator_client/Cargo.toml | 8 +++- .../doppelganger_service/src/lib.rs | 4 +- .../initialized_validators/src/lib.rs | 14 ++++++- validator_client/src/config.rs | 31 ++++++++------- validator_client/src/latency.rs | 10 ++--- validator_client/src/lib.rs | 38 +++++++++---------- validator_client/src/notifier.rs | 11 +++--- validator_client/validator_store/Cargo.toml | 1 + validator_client/validator_store/src/lib.rs | 11 +++++- 14 files changed, 92 insertions(+), 53 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e309cecd7c2..080779a3ace 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5767,6 +5767,7 @@ name = "node_test_rig" version = "0.2.0" dependencies = [ "beacon_node", + "beacon_node_fallback", "environment", "eth2", "execution_layer", @@ -9245,6 +9246,8 @@ dependencies = [ "clap_utils", "directory", "dirs", + "doppelganger_service", + "environment", "eth2", "fdlimit", "graffiti_file", @@ -9253,10 +9256,13 @@ dependencies = [ "itertools 0.10.5", "lighthouse_metrics", "monitoring_api", + "parking_lot 0.12.3", + "reqwest", "sensitive_url", "serde", "slashing_protection", "slog", + "slot_clock", "tokio", "types", "validator_http_api", @@ -9402,6 +9408,7 @@ dependencies = [ "doppelganger_service", "initialized_validators", "parking_lot 0.12.3", + "serde", "signing_method", "slashing_protection", "slog", diff --git a/testing/node_test_rig/Cargo.toml b/testing/node_test_rig/Cargo.toml index 4696d8d2f1d..97e73b8a2f3 100644 --- a/testing/node_test_rig/Cargo.toml +++ b/testing/node_test_rig/Cargo.toml @@ -11,6 +11,7 @@ types = { workspace = true } tempfile = { workspace = true } eth2 = { workspace = true } validator_client = { workspace = true } +beacon_node_fallback = { workspace = true } validator_dir = { workspace = true, features = ["insecure_keys"] } sensitive_url = { workspace = true } execution_layer = { workspace = true } diff --git a/testing/node_test_rig/src/lib.rs b/testing/node_test_rig/src/lib.rs index 33208986428..6b453a8cbcb 100644 --- a/testing/node_test_rig/src/lib.rs +++ b/testing/node_test_rig/src/lib.rs @@ -16,12 +16,13 @@ use validator_client::ProductionValidatorClient; use validator_dir::insecure_keys::build_deterministic_validator_dirs; pub use beacon_node::{ClientConfig, ClientGenesis, ProductionClient}; +pub use beacon_node_fallback::ApiTopic; pub use environment; pub use eth2; pub use execution_layer::test_utils::{ Config as MockServerConfig, MockExecutionConfig, MockServer, }; -pub use validator_client::{ApiTopic, Config as ValidatorConfig}; +pub use validator_client::Config as ValidatorConfig; /// The global timeout for HTTP requests to the beacon node. const HTTP_TIMEOUT: Duration = Duration::from_secs(8); diff --git a/testing/simulator/src/basic_sim.rs b/testing/simulator/src/basic_sim.rs index 16badaffc2d..b3cdfd67638 100644 --- a/testing/simulator/src/basic_sim.rs +++ b/testing/simulator/src/basic_sim.rs @@ -172,7 +172,8 @@ pub fn run_basic_sim(matches: &ArgMatches) -> Result<(), String> { executor.spawn( async move { let mut validator_config = testing_validator_config(); - validator_config.fee_recipient = Some(SUGGESTED_FEE_RECIPIENT.into()); + validator_config.validator_store.fee_recipient = + Some(SUGGESTED_FEE_RECIPIENT.into()); println!("Adding validator client {}", i); // Enable broadcast on every 4th node. diff --git a/testing/simulator/src/fallback_sim.rs b/testing/simulator/src/fallback_sim.rs index 73984aadad7..897c97cf933 100644 --- a/testing/simulator/src/fallback_sim.rs +++ b/testing/simulator/src/fallback_sim.rs @@ -175,7 +175,8 @@ pub fn run_fallback_sim(matches: &ArgMatches) -> Result<(), String> { executor.spawn( async move { let mut validator_config = testing_validator_config(); - validator_config.fee_recipient = Some(SUGGESTED_FEE_RECIPIENT.into()); + validator_config.validator_store.fee_recipient = + Some(SUGGESTED_FEE_RECIPIENT.into()); println!("Adding validator client {}", i); network_1 .add_validator_client_with_fallbacks( diff --git a/validator_client/Cargo.toml b/validator_client/Cargo.toml index 1d2baa7c098..4a34cf54fd6 100644 --- a/validator_client/Cargo.toml +++ b/validator_client/Cargo.toml @@ -18,21 +18,27 @@ beacon_node_fallback = { workspace = true } clap = { workspace = true } clap_utils = { workspace = true } directory = { workspace = true } +doppelganger_service = { workspace = true } dirs = { workspace = true } eth2 = { workspace = true } -graffiti_file= { workspace = true } +environment = { workspace = true } +graffiti_file = { workspace = true } hyper = { workspace = true } initialized_validators = { workspace = true } lighthouse_metrics = { workspace = true } monitoring_api = { workspace = true } +parking_lot = { workspace = true } +reqwest = { workspace = true } sensitive_url = { workspace = true } slashing_protection = { workspace = true } serde = { workspace = true } slog = { workspace = true } +slot_clock = { workspace = true } types = { workspace = true } validator_http_api = { workspace = true } validator_http_metrics = { workspace = true } validator_metrics = { workspace = true } validator_services = { workspace = true } validator_store = { workspace = true } +tokio = { workspace = true } fdlimit = "0.3.0" diff --git a/validator_client/doppelganger_service/src/lib.rs b/validator_client/doppelganger_service/src/lib.rs index 7781b640e2d..6f9784d0719 100644 --- a/validator_client/doppelganger_service/src/lib.rs +++ b/validator_client/doppelganger_service/src/lib.rs @@ -117,7 +117,7 @@ pub const DEFAULT_REMAINING_DETECTION_EPOCHS: u64 = 1; /// initialises the doppelganger protection. For this reason, we abstract the validator store /// functions this service needs through the following trait pub trait DoppelGangerValidatorStore { - fn validator_index(&self, pubkey: &PublicKeyBytes) -> Option; + fn get_validator_index(&self, pubkey: &PublicKeyBytes) -> Option; } /// Store the per-validator status of doppelganger checking. @@ -301,7 +301,7 @@ impl DoppelgangerService { V: DoppelGangerValidatorStore + Send + Sync + 'static, { // Define the `get_index` function as one that uses the validator store. - let get_index = move |pubkey| validator_store.validator_index(&pubkey); + let get_index = move |pubkey| validator_store.get_validator_index(&pubkey); // Define the `get_liveness` function as one that queries the beacon node API. let log = service.log.clone(); diff --git a/validator_client/initialized_validators/src/lib.rs b/validator_client/initialized_validators/src/lib.rs index 563615e0124..9abb7130f57 100644 --- a/validator_client/initialized_validators/src/lib.rs +++ b/validator_client/initialized_validators/src/lib.rs @@ -21,6 +21,7 @@ use lighthouse_metrics::set_gauge; use lockfile::{Lockfile, LockfileError}; use parking_lot::{MappedMutexGuard, Mutex, MutexGuard}; use reqwest::{Certificate, Client, Error as ReqwestError, Identity}; +use serde::{Deserialize, Serialize}; use signing_method::SigningMethod; use slog::{debug, error, info, warn, Logger}; use std::collections::{HashMap, HashSet}; @@ -45,13 +46,24 @@ const DEFAULT_REMOTE_SIGNER_REQUEST_TIMEOUT: Duration = Duration::from_secs(12); // Use TTY instead of stdin to capture passwords from users. const USE_STDIN: bool = false; +pub const DEFAULT_WEB3SIGNER_KEEP_ALIVE: Option = Some(Duration::from_secs(20)); + // The configuration for initialised validators. -#[derive(Default, Clone)] +#[derive(Clone, Serialize, Deserialize)] pub struct Config { pub web3_signer_keep_alive_timeout: Option, pub web3_signer_max_idle_connections: Option, } +impl Default for Config { + fn default() -> Self { + Config { + web3_signer_keep_alive_timeout: DEFAULT_WEB3SIGNER_KEEP_ALIVE, + web3_signer_max_idle_connections: None, + } + } +} + pub enum OnDecryptFailure { /// If the key cache fails to decrypt, create a new cache. CreateNew, diff --git a/validator_client/src/config.rs b/validator_client/src/config.rs index c4916f77684..f37b32c3f34 100644 --- a/validator_client/src/config.rs +++ b/validator_client/src/config.rs @@ -7,6 +7,7 @@ use directory::{ }; use eth2::types::Graffiti; use graffiti_file::GraffitiFile; +use initialized_validators::Config as InitializedValidatorsConfig; use sensitive_url::SensitiveUrl; use serde::{Deserialize, Serialize}; use slog::{info, warn, Logger}; @@ -20,13 +21,12 @@ use validator_http_metrics; use validator_store::Config as ValidatorStoreConfig; pub const DEFAULT_BEACON_NODE: &str = "http://localhost:5052/"; -pub const DEFAULT_WEB3SIGNER_KEEP_ALIVE: Option = Some(Duration::from_secs(20)); /// Stores the core configuration for this validator instance. #[derive(Clone, Serialize, Deserialize)] pub struct Config { - #[serde(flatten)] /// Configuration parameters for the validator store. + #[serde(flatten)] pub validator_store: ValidatorStoreConfig, /// The data directory, which stores all validator databases pub validator_dir: PathBuf, @@ -78,8 +78,9 @@ pub struct Config { pub validator_registration_batch_size: usize, /// Whether we are running with distributed network support. pub distributed: bool, - pub web3_signer_keep_alive_timeout: Option, - pub web3_signer_max_idle_connections: Option, + /// Configuration for the initialized validators + #[serde(flatten)] + pub initialized_validators: InitializedValidatorsConfig, } impl Default for Config { @@ -119,8 +120,7 @@ impl Default for Config { enable_latency_measurement_service: true, validator_registration_batch_size: 500, distributed: false, - web3_signer_keep_alive_timeout: DEFAULT_WEB3SIGNER_KEEP_ALIVE, - web3_signer_max_idle_connections: None, + initialized_validators: <_>::default(), } } } @@ -215,7 +215,7 @@ impl Config { if let Some(input_fee_recipient) = parse_optional::
(cli_args, "suggested-fee-recipient")? { - config.fee_recipient = Some(input_fee_recipient); + config.validator_store.fee_recipient = Some(input_fee_recipient); } if let Some(tls_certs) = parse_optional::(cli_args, "beacon-nodes-tls-certs")? { @@ -250,7 +250,7 @@ impl Config { * Web3 signer */ if let Some(s) = parse_optional::(cli_args, "web3-signer-keep-alive-timeout")? { - config.web3_signer_keep_alive_timeout = if s == "null" { + config.initialized_validators.web3_signer_keep_alive_timeout = if s == "null" { None } else { Some(Duration::from_millis( @@ -259,7 +259,9 @@ impl Config { } } if let Some(n) = parse_optional::(cli_args, "web3-signer-max-idle-connections")? { - config.web3_signer_max_idle_connections = Some(n); + config + .initialized_validators + .web3_signer_max_idle_connections = Some(n); } /* @@ -362,11 +364,11 @@ impl Config { } if cli_args.get_flag("builder-proposals") { - config.builder_proposals = true; + config.validator_store.builder_proposals = true; } if cli_args.get_flag("prefer-builder-proposals") { - config.prefer_builder_proposals = true; + config.validator_store.prefer_builder_proposals = true; } if cli_args.get_flag("produce-block-v3") { @@ -377,7 +379,7 @@ impl Config { ); } - config.gas_limit = cli_args + config.validator_store.gas_limit = cli_args .get_one::("gas-limit") .map(|gas_limit| { gas_limit @@ -396,7 +398,8 @@ impl Config { ); } - config.builder_boost_factor = parse_optional(cli_args, "builder-boost-factor")?; + config.validator_store.builder_boost_factor = + parse_optional(cli_args, "builder-boost-factor")?; config.enable_latency_measurement_service = !cli_args.get_flag("disable-latency-measurement-service"); @@ -418,7 +421,7 @@ impl Config { return Err("validator-registration-batch-size cannot be 0".to_string()); } - config.enable_web3signer_slashing_protection = + config.validator_store.enable_web3signer_slashing_protection = if cli_args.get_flag("disable-slashing-protection-web3signer") { warn!( log, diff --git a/validator_client/src/latency.rs b/validator_client/src/latency.rs index 7e752f29235..22f02c7c0bc 100644 --- a/validator_client/src/latency.rs +++ b/validator_client/src/latency.rs @@ -1,4 +1,4 @@ -use crate::{http_metrics::metrics, BeaconNodeFallback}; +use beacon_node_fallback::BeaconNodeFallback; use environment::RuntimeContext; use slog::debug; use slot_clock::SlotClock; @@ -44,14 +44,14 @@ pub fn start_latency_service( "node" => &measurement.beacon_node_id, "latency" => latency.as_millis(), ); - metrics::observe_timer_vec( - &metrics::VC_BEACON_NODE_LATENCY, + validator_metrics::observe_timer_vec( + &validator_metrics::VC_BEACON_NODE_LATENCY, &[&measurement.beacon_node_id], latency, ); if i == 0 { - metrics::observe_duration( - &metrics::VC_BEACON_NODE_LATENCY_PRIMARY_ENDPOINT, + validator_metrics::observe_duration( + &validator_metrics::VC_BEACON_NODE_LATENCY_PRIMARY_ENDPOINT, latency, ); } diff --git a/validator_client/src/lib.rs b/validator_client/src/lib.rs index 4975202d128..21f19030637 100644 --- a/validator_client/src/lib.rs +++ b/validator_client/src/lib.rs @@ -12,16 +12,15 @@ use sensitive_url::SensitiveUrl; use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME}; use beacon_node_fallback::{ - start_fallback_updater_service, ApiTopic, BeaconNodeFallback, CandidateBeaconNode, - OfflineOnFailure, RequireSynced, + start_fallback_updater_service, BeaconNodeFallback, CandidateBeaconNode, OfflineOnFailure, + RequireSynced, }; use account_utils::validator_definitions::ValidatorDefinitions; use clap::ArgMatches; use doppelganger_service::DoppelgangerService; use environment::RuntimeContext; -use eth2::{reqwest::ClientBuilder, types::Graffiti, BeaconNodeHttpClient, StatusCode, Timeouts}; -use graffiti_file::GraffitiFile; +use eth2::{reqwest::ClientBuilder, BeaconNodeHttpClient, StatusCode, Timeouts}; use initialized_validators::Error::UnableToOpenVotingKeystore; use notifier::spawn_notifier; use parking_lot::RwLock; @@ -40,7 +39,7 @@ use tokio::{ sync::mpsc, time::{sleep, Duration}, }; -use types::{EthSpec, Hash256, PublicKeyBytes}; +use types::{EthSpec, Hash256}; use validator_http_api::ApiSecret; use validator_services::{ attestation_service::{AttestationService, AttestationServiceBuilder}, @@ -139,21 +138,22 @@ impl ProductionValidatorClient { // Optionally start the metrics server. let validator_metrics_ctx = if config.http_metrics.enabled { - let shared = validator_metrics::Shared { + let shared = validator_http_metrics::Shared { validator_store: None, genesis_time: None, duties_service: None, }; - let ctx: Arc> = Arc::new(validator_metrics::Context { - config: config.http_metrics.clone(), - shared: RwLock::new(shared), - log: log.clone(), - }); + let ctx: Arc> = + Arc::new(validator_http_metrics::Context { + config: config.http_metrics.clone(), + shared: RwLock::new(shared), + log: log.clone(), + }); let exit = context.executor.exit(); - let (_listen_addr, server) = validator_metrics::serve(ctx.clone(), exit) + let (_listen_addr, server) = validator_http_metrics::serve(ctx.clone(), exit) .map_err(|e| format!("Unable to start metrics API server: {:?}", e))?; context @@ -201,7 +201,7 @@ impl ProductionValidatorClient { let validators = InitializedValidators::from_definitions( validator_defs, config.validator_dir.clone(), - config.clone(), + config.initialized_validators.clone(), log.clone(), ) .await @@ -364,20 +364,20 @@ impl ProductionValidatorClient { // Set the count for beacon node fallbacks excluding the primary beacon node. set_gauge( - &validator_metrics::metrics::ETH2_FALLBACK_CONFIGURED, + &validator_metrics::ETH2_FALLBACK_CONFIGURED, num_nodes.saturating_sub(1) as i64, ); // Set the total beacon node count. set_gauge( - &validator_metrics::metrics::TOTAL_BEACON_NODES_COUNT, + &validator_metrics::TOTAL_BEACON_NODES_COUNT, num_nodes as i64, ); // Initialize the number of connected, synced beacon nodes to 0. - set_gauge(&validator_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0); - set_gauge(&validator_metrics::metrics::SYNCED_BEACON_NODES_COUNT, 0); + set_gauge(&validator_metrics::ETH2_FALLBACK_CONNECTED, 0); + set_gauge(&validator_metrics::SYNCED_BEACON_NODES_COUNT, 0); // Initialize the number of connected, avaliable beacon nodes to 0. - set_gauge(&validator_metrics::metrics::AVAILABLE_BEACON_NODES_COUNT, 0); + set_gauge(&validator_metrics::AVAILABLE_BEACON_NODES_COUNT, 0); let mut beacon_nodes: BeaconNodeFallback<_, E> = BeaconNodeFallback::new( candidates, @@ -437,7 +437,7 @@ impl ProductionValidatorClient { context.eth2_config.spec.clone(), doppelganger_service.clone(), slot_clock.clone(), - &config, + &config.validator_store, context.executor.clone(), log.clone(), )); diff --git a/validator_client/src/notifier.rs b/validator_client/src/notifier.rs index 819201978f8..95bf2bad47d 100644 --- a/validator_client/src/notifier.rs +++ b/validator_client/src/notifier.rs @@ -1,4 +1,3 @@ -use crate::http_metrics; use crate::{DutiesService, ProductionValidatorClient}; use lighthouse_metrics::set_gauge; use slog::{error, info, Logger}; @@ -41,17 +40,17 @@ async fn notify( ) { let num_available = duties_service.beacon_nodes.num_available().await; set_gauge( - &http_metrics::metrics::AVAILABLE_BEACON_NODES_COUNT, + &validator_metrics::AVAILABLE_BEACON_NODES_COUNT, num_available as i64, ); let num_synced = duties_service.beacon_nodes.num_synced().await; set_gauge( - &http_metrics::metrics::SYNCED_BEACON_NODES_COUNT, + &validator_metrics::SYNCED_BEACON_NODES_COUNT, num_synced as i64, ); let num_total = duties_service.beacon_nodes.num_total(); set_gauge( - &http_metrics::metrics::TOTAL_BEACON_NODES_COUNT, + &validator_metrics::TOTAL_BEACON_NODES_COUNT, num_total as i64, ); if num_synced > 0 { @@ -73,9 +72,9 @@ async fn notify( } let num_synced_fallback = duties_service.beacon_nodes.num_synced_fallback().await; if num_synced_fallback > 0 { - set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 1); + set_gauge(&validator_metrics::ETH2_FALLBACK_CONNECTED, 1); } else { - set_gauge(&http_metrics::metrics::ETH2_FALLBACK_CONNECTED, 0); + set_gauge(&validator_metrics::ETH2_FALLBACK_CONNECTED, 0); } if let Some(slot) = duties_service.slot_clock.now() { diff --git a/validator_client/validator_store/Cargo.toml b/validator_client/validator_store/Cargo.toml index 262dbecaa6a..cdb7ca3c544 100644 --- a/validator_client/validator_store/Cargo.toml +++ b/validator_client/validator_store/Cargo.toml @@ -13,6 +13,7 @@ account_utils = { workspace = true } doppelganger_service = { workspace = true } initialized_validators = { workspace = true } parking_lot = { workspace = true } +serde = { workspace = true } signing_method = { workspace = true } slashing_protection = { workspace = true } slog = { workspace = true } diff --git a/validator_client/validator_store/src/lib.rs b/validator_client/validator_store/src/lib.rs index a997f0ea607..68dca368aec 100644 --- a/validator_client/validator_store/src/lib.rs +++ b/validator_client/validator_store/src/lib.rs @@ -1,7 +1,8 @@ use account_utils::validator_definitions::{PasswordStorage, ValidatorDefinition}; -use doppelganger_service::{DoppelgangerService, DoppelgangerStatus}; +use doppelganger_service::{DoppelGangerValidatorStore, DoppelgangerService, DoppelgangerStatus}; use initialized_validators::InitializedValidators; use parking_lot::{Mutex, RwLock}; +use serde::{Deserialize, Serialize}; use signing_method::{Error as SigningError, SignableMessage, SigningContext, SigningMethod}; use slashing_protection::{ interchange::Interchange, InterchangeError, NotSafe, Safe, SlashingDatabase, @@ -41,7 +42,7 @@ impl From for Error { } } -#[derive(Default, Clone)] +#[derive(Default, Clone, Serialize, Deserialize)] pub struct Config { /// Fallback fallback address. pub fee_recipient: Option
, @@ -94,6 +95,12 @@ pub struct ValidatorStore { _phantom: PhantomData, } +impl DoppelGangerValidatorStore for ValidatorStore { + fn get_validator_index(&self, pubkey: &PublicKeyBytes) -> Option { + self.validator_index(pubkey) + } +} + impl ValidatorStore { // All arguments are different types. Making the fields `pub` is undesired. A builder seems // unnecessary. From 37db36352463c8ee78eca105b0d6a36cbb4f9128 Mon Sep 17 00:00:00 2001 From: Age Manning Date: Tue, 8 Oct 2024 18:06:12 +1100 Subject: [PATCH 6/6] Fix some lints --- Cargo.lock | 4 ++ .../src/beacon_node_health.rs | 2 +- .../beacon_node_fallback/src/lib.rs | 2 +- .../doppelganger_service/Cargo.toml | 6 +-- validator_client/graffiti_file/Cargo.toml | 2 + validator_client/graffiti_file/src/lib.rs | 42 +++++++++---------- .../src/attestation_service.rs | 1 + .../validator_services/src/block_service.rs | 1 + .../src/preparation_service.rs | 1 + 9 files changed, 34 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4fb25b6318b..7e09482b729 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2237,6 +2237,8 @@ dependencies = [ "beacon_node_fallback", "environment", "eth2", + "futures", + "logging", "parking_lot 0.12.3", "slog", "slot_clock", @@ -3539,8 +3541,10 @@ name = "graffiti_file" version = "0.1.0" dependencies = [ "bls", + "hex", "serde", "slog", + "tempfile", "types", ] diff --git a/validator_client/beacon_node_fallback/src/beacon_node_health.rs b/validator_client/beacon_node_fallback/src/beacon_node_health.rs index 828e0d50e59..e5b04876560 100644 --- a/validator_client/beacon_node_fallback/src/beacon_node_health.rs +++ b/validator_client/beacon_node_fallback/src/beacon_node_health.rs @@ -319,7 +319,7 @@ mod tests { BeaconNodeHealth, BeaconNodeHealthTier, BeaconNodeSyncDistanceTiers, IsOptimistic, SyncDistanceTier, }; - use crate::beacon_node_fallback::Config; + use crate::Config; use std::str::FromStr; use types::Slot; diff --git a/validator_client/beacon_node_fallback/src/lib.rs b/validator_client/beacon_node_fallback/src/lib.rs index 66c0ac1b02b..95a221f1897 100644 --- a/validator_client/beacon_node_fallback/src/lib.rs +++ b/validator_client/beacon_node_fallback/src/lib.rs @@ -739,7 +739,7 @@ impl ApiTopic { mod tests { use super::*; use crate::beacon_node_health::BeaconNodeHealthTier; - use crate::SensitiveUrl; + use eth2::SensitiveUrl; use eth2::Timeouts; use std::str::FromStr; use strum::VariantNames; diff --git a/validator_client/doppelganger_service/Cargo.toml b/validator_client/doppelganger_service/Cargo.toml index e145dc24081..e5f7d3f2ba2 100644 --- a/validator_client/doppelganger_service/Cargo.toml +++ b/validator_client/doppelganger_service/Cargo.toml @@ -4,10 +4,6 @@ version = "0.1.0" edition = { workspace = true } authors = ["Sigma Prime "] -[lib] -name = "doppelganger_service" -path = "src/lib.rs" - [dependencies] beacon_node_fallback = { workspace = true } environment = { workspace = true } @@ -20,3 +16,5 @@ tokio = { workspace = true } types = { workspace = true } [dev-dependencies] +futures = { workspace = true } +logging = {workspace = true } diff --git a/validator_client/graffiti_file/Cargo.toml b/validator_client/graffiti_file/Cargo.toml index 4cb33b44fed..02e48849d10 100644 --- a/validator_client/graffiti_file/Cargo.toml +++ b/validator_client/graffiti_file/Cargo.toml @@ -15,3 +15,5 @@ types = { workspace = true } slog = { workspace = true } [dev-dependencies] +tempfile = { workspace = true } +hex = { workspace = true } diff --git a/validator_client/graffiti_file/src/lib.rs b/validator_client/graffiti_file/src/lib.rs index aa2679eea2a..0328c14eeb5 100644 --- a/validator_client/graffiti_file/src/lib.rs +++ b/validator_client/graffiti_file/src/lib.rs @@ -101,6 +101,27 @@ fn read_line(line: &str) -> Result<(Option, Graffiti), Error> { } } +// 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: &slog::Logger, + graffiti_file: Option, + validator_definition_graffiti: Option, + graffiti_flag: Option, +) -> Option { + 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) +} + #[cfg(test)] mod tests { use super::*; @@ -177,24 +198,3 @@ mod tests { ); } } - -// 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: &slog::Logger, - graffiti_file: Option, - validator_definition_graffiti: Option, - graffiti_flag: Option, -) -> Option { - 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) -} diff --git a/validator_client/validator_services/src/attestation_service.rs b/validator_client/validator_services/src/attestation_service.rs index ed2931519f4..e31ad4f661b 100644 --- a/validator_client/validator_services/src/attestation_service.rs +++ b/validator_client/validator_services/src/attestation_service.rs @@ -13,6 +13,7 @@ use types::{Attestation, AttestationData, ChainSpec, CommitteeIndex, EthSpec, Sl use validator_store::{Error as ValidatorStoreError, ValidatorStore}; /// Builds an `AttestationService`. +#[derive(Default)] pub struct AttestationServiceBuilder { duties_service: Option>>, validator_store: Option>>, diff --git a/validator_client/validator_services/src/block_service.rs b/validator_client/validator_services/src/block_service.rs index e0280fc8829..b4a75764e15 100644 --- a/validator_client/validator_services/src/block_service.rs +++ b/validator_client/validator_services/src/block_service.rs @@ -43,6 +43,7 @@ impl From> for BlockError { } /// Builds a `BlockService`. +#[derive(Default)] pub struct BlockServiceBuilder { validator_store: Option>>, slot_clock: Option>, diff --git a/validator_client/validator_services/src/preparation_service.rs b/validator_client/validator_services/src/preparation_service.rs index d67c2fd4280..480f4af2b3c 100644 --- a/validator_client/validator_services/src/preparation_service.rs +++ b/validator_client/validator_services/src/preparation_service.rs @@ -24,6 +24,7 @@ const PROPOSER_PREPARATION_LOOKAHEAD_EPOCHS: u64 = 2; const EPOCHS_PER_VALIDATOR_REGISTRATION_SUBMISSION: u64 = 1; /// Builds an `PreparationService`. +#[derive(Default)] pub struct PreparationServiceBuilder { validator_store: Option>>, slot_clock: Option,