Merge branch 'unstable' into vc-fallback

This commit is contained in:
Mac L
2024-06-05 16:20:15 +10:00
309 changed files with 9719 additions and 11817 deletions

View File

@@ -1,34 +1,47 @@
use clap::{App, Arg};
use clap::{builder::ArgPredicate, Arg, ArgAction, Command};
use clap_utils::{get_color_style, FLAG_HEADER};
pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
App::new("validator_client")
.visible_aliases(&["v", "vc", "validator"])
.setting(clap::AppSettings::ColoredHelp)
pub fn cli_app() -> Command {
Command::new("validator_client")
.visible_aliases(["v", "vc", "validator"])
.styles(get_color_style())
.display_order(0)
.about(
"When connected to a beacon node, performs the duties of a staked \
validator (e.g., proposing blocks and attestations).",
)
.arg(
Arg::with_name("beacon-nodes")
Arg::new("help")
.long("help")
.short('h')
.help("Prints help information")
.action(ArgAction::HelpLong)
.display_order(0)
.help_heading(FLAG_HEADER)
)
.arg(
Arg::new("beacon-nodes")
.long("beacon-nodes")
.value_name("NETWORK_ADDRESSES")
.help("Comma-separated addresses to one or more beacon node HTTP APIs. \
Default is http://localhost:5052."
)
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("proposer-nodes")
Arg::new("proposer-nodes")
.long("proposer-nodes")
.value_name("NETWORK_ADDRESSES")
.help("Comma-separated addresses to one or more beacon node HTTP APIs. \
These specify nodes that are used to send beacon block proposals. A failure will revert back to the standard beacon nodes specified in --beacon-nodes."
)
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
// TODO remove this flag in a future release
.arg(
Arg::with_name("disable-run-on-all")
Arg::new("disable-run-on-all")
.long("disable-run-on-all")
.value_name("DISABLE_RUN_ON_ALL")
.help("DEPRECATED. Use --broadcast. \
@@ -36,10 +49,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
and proposer preparation messages to all beacon nodes provided in the \
`--beacon-nodes flag`. This option changes that behaviour such that these \
api calls only go out to the first available and synced beacon node")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("broadcast")
Arg::new("broadcast")
.long("broadcast")
.value_name("API_TOPICS")
.help("Comma-separated list of beacon API topics to broadcast to all beacon nodes. \
@@ -47,10 +62,11 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
sync-committee. Default (when flag is omitted) is to broadcast \
subscriptions only."
)
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("validators-dir")
Arg::new("validators-dir")
.long("validators-dir")
.alias("validator-dir")
.value_name("VALIDATORS_DIR")
@@ -59,11 +75,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
each validator along with the common slashing protection database \
and the validator_definitions.yml"
)
.takes_value(true)
.action(ArgAction::Set)
.conflicts_with("datadir")
.display_order(0)
)
.arg(
Arg::with_name("secrets-dir")
Arg::new("secrets-dir")
.long("secrets-dir")
.value_name("SECRETS_DIRECTORY")
.help(
@@ -72,11 +89,15 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
name is the 0x-prefixed hex representation of the validators voting public \
key. Defaults to ~/.lighthouse/{network}/secrets.",
)
.takes_value(true)
.action(ArgAction::Set)
.conflicts_with("datadir")
.display_order(0)
)
.arg(
Arg::with_name("init-slashing-protection")
Arg::new("init-slashing-protection")
.long("init-slashing-protection")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.help(
"If present, do not require the slashing protection database to exist before \
running. You SHOULD NOT use this flag unless you're certain that a new \
@@ -84,78 +105,95 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
will have been initialized when you imported your validator keys. If you \
misplace your database and then run with this flag you risk being slashed."
)
.display_order(0)
)
.arg(
Arg::with_name("disable-auto-discover")
Arg::new("disable-auto-discover")
.long("disable-auto-discover")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.help(
"If present, do not attempt to discover new validators in the validators-dir. Validators \
will need to be manually added to the validator_definitions.yml file."
)
.display_order(0)
)
.arg(
Arg::with_name("use-long-timeouts")
Arg::new("use-long-timeouts")
.long("use-long-timeouts")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.help("If present, the validator client will use longer timeouts for requests \
made to the beacon node. This flag is generally not recommended, \
longer timeouts can cause missed duties when fallbacks are used.")
.display_order(0)
)
.arg(
Arg::with_name("beacon-nodes-tls-certs")
Arg::new("beacon-nodes-tls-certs")
.long("beacon-nodes-tls-certs")
.value_name("CERTIFICATE-FILES")
.takes_value(true)
.action(ArgAction::Set)
.help("Comma-separated paths to custom TLS certificates to use when connecting \
to a beacon node (and/or proposer node). These certificates must be in PEM format and are used \
in addition to the OS trust store. Commas must only be used as a \
delimiter, and must not be part of the certificate path.")
.display_order(0)
)
// This overwrites the graffiti configured in the beacon node.
.arg(
Arg::with_name("graffiti")
Arg::new("graffiti")
.long("graffiti")
.help("Specify your custom graffiti to be included in blocks.")
.value_name("GRAFFITI")
.takes_value(true)
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("graffiti-file")
Arg::new("graffiti-file")
.long("graffiti-file")
.help("Specify a graffiti file to load validator graffitis from.")
.value_name("GRAFFITI-FILE")
.takes_value(true)
.action(ArgAction::Set)
.conflicts_with("graffiti")
.display_order(0)
)
.arg(
Arg::with_name("suggested-fee-recipient")
Arg::new("suggested-fee-recipient")
.long("suggested-fee-recipient")
.help("Once the merge has happened, this address will receive transaction fees \
from blocks proposed by this validator client. If a fee recipient is \
configured in the validator definitions it takes priority over this value.")
.value_name("FEE-RECIPIENT")
.takes_value(true)
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("produce-block-v3")
Arg::new("produce-block-v3")
.long("produce-block-v3")
.help("Enable block production via the block v3 endpoint for this validator client. \
This should only be enabled when paired with a beacon node \
that has this endpoint implemented. This flag will be enabled by default in \
future.")
.takes_value(false)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("distributed")
Arg::new("distributed")
.long("distributed")
.help("Enables functionality required for running the validator in a distributed validator cluster.")
.takes_value(false)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
/* REST API related arguments */
.arg(
Arg::with_name("http")
Arg::new("http")
.long("http")
.help("Enable the RESTful HTTP API server. Disabled by default.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
/*
* Note: The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is
@@ -165,7 +203,7 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
* must also be used in order to make it clear to the user that this is unsafe.
*/
.arg(
Arg::with_name("http-address")
Arg::new("http-address")
.long("http-address")
.requires("http")
.value_name("ADDRESS")
@@ -175,26 +213,31 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
`--unencrypted-http-transport` flag to ensure the user is aware of the \
risks involved. For access via the Internet, users should apply \
transport-layer security like a HTTPS reverse-proxy or SSH tunnelling.")
.requires("unencrypted-http-transport"),
.requires("unencrypted-http-transport")
.display_order(0)
)
.arg(
Arg::with_name("unencrypted-http-transport")
.long("unencrypted-http-transport")
.help("This is a safety flag to ensure that the user is aware that the http \
transport is unencrypted and using a custom HTTP address is unsafe.")
.requires("http-address"),
Arg::new("unencrypted-http-transport")
.long("unencrypted-http-transport")
.help("This is a safety flag to ensure that the user is aware that the http \
transport is unencrypted and using a custom HTTP address is unsafe.")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.requires("http-address")
.display_order(0)
)
.arg(
Arg::with_name("http-port")
Arg::new("http-port")
.long("http-port")
.requires("http")
.value_name("PORT")
.help("Set the listen TCP port for the RESTful HTTP API server.")
.default_value_if("http", None, "5062")
.takes_value(true),
.default_value_if("http", ArgPredicate::IsPresent, "5062")
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("http-allow-origin")
Arg::new("http-allow-origin")
.long("http-allow-origin")
.requires("http")
.value_name("ORIGIN")
@@ -202,10 +245,11 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
Use * to allow any origin (not recommended in production). \
If no value is supplied, the CORS allowed origin is set to the listen \
address of this server (e.g., http://localhost:5062).")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("http-allow-keystore-export")
Arg::new("http-allow-keystore-export")
.long("http-allow-keystore-export")
.requires("http")
.help("If present, allow access to the DELETE /lighthouse/keystores HTTP \
@@ -213,44 +257,52 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
consumers who have access to the API token. This method is useful for \
exporting validators, however it should be used with caution since it \
exposes private key data to authorized users.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("http-store-passwords-in-secrets-dir")
Arg::new("http-store-passwords-in-secrets-dir")
.long("http-store-passwords-in-secrets-dir")
.requires("http")
.help("If present, any validators created via the HTTP will have keystore \
passwords stored in the secrets-dir rather than the validator \
definitions file.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
/* Prometheus metrics HTTP server related arguments */
.arg(
Arg::with_name("metrics")
Arg::new("metrics")
.long("metrics")
.help("Enable the Prometheus metrics HTTP server. Disabled by default.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("metrics-address")
Arg::new("metrics-address")
.long("metrics-address")
.requires("metrics")
.value_name("ADDRESS")
.help("Set the listen address for the Prometheus metrics HTTP server.")
.default_value_if("metrics", None, "127.0.0.1")
.takes_value(true),
.default_value_if("metrics", ArgPredicate::IsPresent, "127.0.0.1")
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("metrics-port")
Arg::new("metrics-port")
.long("metrics-port")
.requires("metrics")
.value_name("PORT")
.help("Set the listen TCP port for the Prometheus metrics HTTP server.")
.default_value_if("metrics", None, "5064")
.takes_value(true),
.default_value_if("metrics", ArgPredicate::IsPresent, "5064")
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("metrics-allow-origin")
Arg::new("metrics-allow-origin")
.long("metrics-allow-origin")
.requires("metrics")
.value_name("ORIGIN")
@@ -258,22 +310,25 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
Use * to allow any origin (not recommended in production). \
If no value is supplied, the CORS allowed origin is set to the listen \
address of this server (e.g., http://localhost:5064).")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("enable-high-validator-count-metrics")
Arg::new("enable-high-validator-count-metrics")
.long("enable-high-validator-count-metrics")
.help("Enable per validator metrics for > 64 validators. \
Note: This flag is automatically enabled for <= 64 validators. \
Enabling this metric for higher validator counts will lead to higher volume \
of prometheus metrics being collected.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
/*
* Explorer metrics
*/
.arg(
Arg::with_name("monitoring-endpoint")
Arg::new("monitoring-endpoint")
.long("monitoring-endpoint")
.value_name("ADDRESS")
.help("Enables the monitoring service for sending system metrics to a remote endpoint. \
@@ -282,19 +337,21 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
Note: This will send information to a remote sever which may identify and associate your \
validators, IP address and other personal information. Always use a HTTPS connection \
and never provide an untrusted URL.")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("monitoring-endpoint-period")
Arg::new("monitoring-endpoint-period")
.long("monitoring-endpoint-period")
.value_name("SECONDS")
.help("Defines how many seconds to wait between each message sent to \
the monitoring-endpoint. Default: 60s")
.requires("monitoring-endpoint")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("enable-doppelganger-protection")
Arg::new("enable-doppelganger-protection")
.long("enable-doppelganger-protection")
.value_name("ENABLE_DOPPELGANGER_PROTECTION")
.help("If this flag is set, Lighthouse will delay startup for three epochs and \
@@ -306,56 +363,62 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
to avoid potentially committing a slashable offense. Use this flag in order to \
ENABLE this functionality, without this flag Lighthouse will begin attesting \
immediately.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("builder-proposals")
Arg::new("builder-proposals")
.long("builder-proposals")
.alias("private-tx-proposals")
.help("If this flag is set, Lighthouse will query the Beacon Node for only block \
headers during proposals and will sign over headers. Useful for outsourcing \
execution payload construction during proposals.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("builder-registration-timestamp-override")
Arg::new("builder-registration-timestamp-override")
.long("builder-registration-timestamp-override")
.alias("builder-registration-timestamp-override")
.help("This flag takes a unix timestamp value that will be used to override the \
timestamp used in the builder api registration")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("gas-limit")
Arg::new("gas-limit")
.long("gas-limit")
.value_name("INTEGER")
.takes_value(true)
.action(ArgAction::Set)
.help("The gas limit to be used in all builder proposals for all validators managed \
by this validator client. Note this will not necessarily be used if the gas limit \
set here moves too far from the previous block's gas limit. [default: 30,000,000]")
.requires("builder-proposals"),
.requires("builder-proposals")
.display_order(0)
)
.arg(
Arg::with_name("latency-measurement-service")
.long("latency-measurement-service")
.value_name("BOOLEAN")
.help("Set to 'true' to enable a service that periodically attempts to measure latency to BNs. \
Set to 'false' to disable.")
.default_value("true")
.takes_value(true),
Arg::new("disable-latency-measurement-service")
.long("disable-latency-measurement-service")
.help("Disables the service that periodically attempts to measure latency to BNs.")
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("validator-registration-batch-size")
Arg::new("validator-registration-batch-size")
.long("validator-registration-batch-size")
.value_name("INTEGER")
.help("Defines the number of validators per \
validator/register_validator request sent to the BN. This value \
can be reduced to avoid timeouts from builders.")
.default_value("500")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("builder-boost-factor")
Arg::new("builder-boost-factor")
.long("builder-boost-factor")
.value_name("UINT64")
.help("Defines the boost factor, \
@@ -363,17 +426,20 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
when choosing between a builder payload header and payload from \
the local execution node.")
.conflicts_with("prefer-builder-proposals")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("prefer-builder-proposals")
Arg::new("prefer-builder-proposals")
.long("prefer-builder-proposals")
.help("If this flag is set, Lighthouse will always prefer blocks \
constructed by builders, regardless of payload value.")
.takes_value(false),
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("beacon-nodes-sync-tolerances")
Arg::new("beacon-nodes-sync-tolerances")
.long("beacon-nodes-sync-tolerances")
.value_name("SYNC_TOLERANCES")
.help("A comma-separated list of 3 values which sets the size of each sync distance range when \
@@ -395,10 +461,12 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
Nodes in the `Synced` range will tie-break based on their ordering in `--beacon-nodes`. \
This ensures the primary beacon node is prioritised. \
[default: 8,8,48]")
.takes_value(true)
.action(ArgAction::Set)
.help_heading(FLAG_HEADER)
.display_order(0)
)
.arg(
Arg::with_name("disable-slashing-protection-web3signer")
Arg::new("disable-slashing-protection-web3signer")
.long("disable-slashing-protection-web3signer")
.help("Disable Lighthouse's slashing protection for all web3signer keys. This can \
reduce the I/O burden on the VC but is only safe if slashing protection \
@@ -406,26 +474,30 @@ pub fn cli_app<'a, 'b>() -> App<'a, 'b> {
THIS FLAG UNLESS YOU ARE CERTAIN THAT SLASHING PROTECTION IS ENABLED ON \
THE REMOTE SIGNER. YOU WILL GET SLASHED IF YOU USE THIS FLAG WITHOUT \
ENABLING WEB3SIGNER'S SLASHING PROTECTION.")
.takes_value(false)
.action(ArgAction::SetTrue)
.help_heading(FLAG_HEADER)
.display_order(0)
)
/*
* Experimental/development options.
*/
.arg(
Arg::with_name("web3-signer-keep-alive-timeout")
Arg::new("web3-signer-keep-alive-timeout")
.long("web3-signer-keep-alive-timeout")
.value_name("MILLIS")
.default_value("20000")
.help("Keep-alive timeout for each web3signer connection. Set to 'null' to never \
timeout")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
.arg(
Arg::with_name("web3-signer-max-idle-connections")
Arg::new("web3-signer-max-idle-connections")
.long("web3-signer-max-idle-connections")
.value_name("COUNT")
.help("Maximum number of idle connections to maintain per web3signer host. Default \
is unlimited.")
.takes_value(true),
.action(ArgAction::Set)
.display_order(0)
)
}

View File

@@ -157,15 +157,15 @@ impl Config {
.unwrap_or_else(|| PathBuf::from("."));
let (mut validator_dir, mut secrets_dir) = (None, None);
if cli_args.value_of("datadir").is_some() {
if cli_args.get_one::<String>("datadir").is_some() {
let base_dir: PathBuf = parse_required(cli_args, "datadir")?;
validator_dir = Some(base_dir.join(DEFAULT_VALIDATOR_DIR));
secrets_dir = Some(base_dir.join(DEFAULT_SECRET_DIR));
}
if cli_args.value_of("validators-dir").is_some() {
if cli_args.get_one::<String>("validators-dir").is_some() {
validator_dir = Some(parse_required(cli_args, "validators-dir")?);
}
if cli_args.value_of("secrets-dir").is_some() {
if cli_args.get_one::<String>("secrets-dir").is_some() {
secrets_dir = Some(parse_required(cli_args, "secrets-dir")?);
}
@@ -201,11 +201,11 @@ impl Config {
.map_err(|e| format!("Unable to parse proposer node URL: {:?}", e))?;
}
config.disable_auto_discover = cli_args.is_present("disable-auto-discover");
config.init_slashing_protection = cli_args.is_present("init-slashing-protection");
config.use_long_timeouts = cli_args.is_present("use-long-timeouts");
config.disable_auto_discover = cli_args.get_flag("disable-auto-discover");
config.init_slashing_protection = cli_args.get_flag("init-slashing-protection");
config.use_long_timeouts = cli_args.get_flag("use-long-timeouts");
if let Some(graffiti_file_path) = cli_args.value_of("graffiti-file") {
if let Some(graffiti_file_path) = cli_args.get_one::<String>("graffiti-file") {
let mut graffiti_file = GraffitiFile::new(graffiti_file_path.into());
graffiti_file
.read_graffiti_file()
@@ -214,7 +214,7 @@ impl Config {
info!(log, "Successfully loaded graffiti file"; "path" => graffiti_file_path);
}
if let Some(input_graffiti) = cli_args.value_of("graffiti") {
if let Some(input_graffiti) = cli_args.get_one::<String>("graffiti") {
let graffiti_bytes = input_graffiti.as_bytes();
if graffiti_bytes.len() > GRAFFITI_BYTES_LEN {
return Err(format!(
@@ -243,11 +243,11 @@ impl Config {
config.beacon_nodes_tls_certs = Some(tls_certs.split(',').map(PathBuf::from).collect());
}
if cli_args.is_present("distributed") {
if cli_args.get_flag("distributed") {
config.distributed = true;
}
if cli_args.is_present("disable-run-on-all") {
if cli_args.get_flag("disable-run-on-all") {
warn!(
log,
"The --disable-run-on-all flag is deprecated";
@@ -255,7 +255,7 @@ impl Config {
);
config.broadcast_topics = vec![];
}
if let Some(broadcast_topics) = cli_args.value_of("broadcast") {
if let Some(broadcast_topics) = cli_args.get_one::<String>("broadcast") {
config.broadcast_topics = broadcast_topics
.split(',')
.filter(|t| *t != "none")
@@ -271,9 +271,9 @@ impl Config {
* Beacon node fallback
*/
config.beacon_node_fallback.disable_run_on_all = cli_args.is_present("disable-run-on-all");
config.beacon_node_fallback.disable_run_on_all = cli_args.get_flag("disable-run-on-all");
if let Some(sync_tolerance) = cli_args.value_of("beacon-nodes-sync-tolerances") {
if let Some(sync_tolerance) = cli_args.get_one::<String>("beacon-nodes-sync-tolerances") {
config.beacon_node_fallback.sync_tolerances =
BeaconNodeSyncDistanceTiers::from_str(sync_tolerance)?;
} else {
@@ -300,12 +300,12 @@ impl Config {
* Http API server
*/
if cli_args.is_present("http") {
if cli_args.get_flag("http") {
config.http_api.enabled = true;
}
if let Some(address) = cli_args.value_of("http-address") {
if cli_args.is_present("unencrypted-http-transport") {
if let Some(address) = cli_args.get_one::<String>("http-address") {
if cli_args.get_flag("unencrypted-http-transport") {
config.http_api.listen_addr = address
.parse::<IpAddr>()
.map_err(|_| "http-address is not a valid IP address.")?;
@@ -317,13 +317,13 @@ impl Config {
}
}
if let Some(port) = cli_args.value_of("http-port") {
if let Some(port) = cli_args.get_one::<String>("http-port") {
config.http_api.listen_port = port
.parse::<u16>()
.map_err(|_| "http-port is not a valid u16.")?;
}
if let Some(allow_origin) = cli_args.value_of("http-allow-origin") {
if let Some(allow_origin) = cli_args.get_one::<String>("http-allow-origin") {
// Pre-validate the config value to give feedback to the user on node startup, instead of
// as late as when the first API response is produced.
hyper::header::HeaderValue::from_str(allow_origin)
@@ -332,11 +332,11 @@ impl Config {
config.http_api.allow_origin = Some(allow_origin.to_string());
}
if cli_args.is_present("http-allow-keystore-export") {
if cli_args.get_flag("http-allow-keystore-export") {
config.http_api.allow_keystore_export = true;
}
if cli_args.is_present("http-store-passwords-in-secrets-dir") {
if cli_args.get_flag("http-store-passwords-in-secrets-dir") {
config.http_api.store_passwords_in_secrets_dir = true;
}
@@ -344,27 +344,27 @@ impl Config {
* Prometheus metrics HTTP server
*/
if cli_args.is_present("metrics") {
if cli_args.get_flag("metrics") {
config.http_metrics.enabled = true;
}
if cli_args.is_present("enable-high-validator-count-metrics") {
if cli_args.get_flag("enable-high-validator-count-metrics") {
config.enable_high_validator_count_metrics = true;
}
if let Some(address) = cli_args.value_of("metrics-address") {
if let Some(address) = cli_args.get_one::<String>("metrics-address") {
config.http_metrics.listen_addr = address
.parse::<IpAddr>()
.map_err(|_| "metrics-address is not a valid IP address.")?;
}
if let Some(port) = cli_args.value_of("metrics-port") {
if let Some(port) = cli_args.get_one::<String>("metrics-port") {
config.http_metrics.listen_port = port
.parse::<u16>()
.map_err(|_| "metrics-port is not a valid u16.")?;
}
if let Some(allow_origin) = cli_args.value_of("metrics-allow-origin") {
if let Some(allow_origin) = cli_args.get_one::<String>("metrics-allow-origin") {
// Pre-validate the config value to give feedback to the user on node startup, instead of
// as late as when the first API response is produced.
hyper::header::HeaderValue::from_str(allow_origin)
@@ -373,14 +373,14 @@ impl Config {
config.http_metrics.allow_origin = Some(allow_origin.to_string());
}
if cli_args.is_present(DISABLE_MALLOC_TUNING_FLAG) {
if cli_args.get_flag(DISABLE_MALLOC_TUNING_FLAG) {
config.http_metrics.allocator_metrics_enabled = false;
}
/*
* Explorer metrics
*/
if let Some(monitoring_endpoint) = cli_args.value_of("monitoring-endpoint") {
if let Some(monitoring_endpoint) = cli_args.get_one::<String>("monitoring-endpoint") {
let update_period_secs =
clap_utils::parse_optional(cli_args, "monitoring-endpoint-period")?;
config.monitoring_api = Some(monitoring_api::Config {
@@ -391,24 +391,24 @@ impl Config {
});
}
if cli_args.is_present("enable-doppelganger-protection") {
if cli_args.get_flag("enable-doppelganger-protection") {
config.enable_doppelganger_protection = true;
}
if cli_args.is_present("builder-proposals") {
if cli_args.get_flag("builder-proposals") {
config.builder_proposals = true;
}
if cli_args.is_present("produce-block-v3") {
if cli_args.get_flag("produce-block-v3") {
config.produce_block_v3 = true;
}
if cli_args.is_present("prefer-builder-proposals") {
if cli_args.get_flag("prefer-builder-proposals") {
config.prefer_builder_proposals = true;
}
config.gas_limit = cli_args
.value_of("gas-limit")
.get_one::<String>("gas-limit")
.map(|gas_limit| {
gas_limit
.parse::<u64>()
@@ -417,7 +417,7 @@ impl Config {
.transpose()?;
if let Some(registration_timestamp_override) =
cli_args.value_of("builder-registration-timestamp-override")
cli_args.get_one::<String>("builder-registration-timestamp-override")
{
config.builder_registration_timestamp_override = Some(
registration_timestamp_override
@@ -429,7 +429,7 @@ impl Config {
config.builder_boost_factor = parse_optional(cli_args, "builder-boost-factor")?;
config.enable_latency_measurement_service =
parse_optional(cli_args, "latency-measurement-service")?.unwrap_or(true);
!cli_args.get_flag("disable-latency-measurement-service");
config.validator_registration_batch_size =
parse_required(cli_args, "validator-registration-batch-size")?;
@@ -438,7 +438,7 @@ impl Config {
}
config.enable_web3signer_slashing_protection =
if cli_args.is_present("disable-slashing-protection-web3signer") {
if cli_args.get_flag("disable-slashing-protection-web3signer") {
warn!(
log,
"Slashing protection for remote keys disabled";

View File

@@ -88,14 +88,15 @@ const _: () = assert!({
/// bringing in the entire crate.
const _: () = assert!(ATTESTATION_SUBSCRIPTION_OFFSETS[0] > 2);
// The info in the enum variants is displayed in logging, clippy thinks it's dead code.
#[derive(Debug)]
pub enum Error {
UnableToReadSlotClock,
FailedToDownloadAttesters(String),
FailedToProduceSelectionProof(ValidatorStoreError),
InvalidModulo(ArithError),
Arith(ArithError),
SyncDutiesNotFound(u64),
FailedToDownloadAttesters(#[allow(dead_code)] String),
FailedToProduceSelectionProof(#[allow(dead_code)] ValidatorStoreError),
InvalidModulo(#[allow(dead_code)] ArithError),
Arith(#[allow(dead_code)] ArithError),
SyncDutiesNotFound(#[allow(dead_code)] u64),
}
impl From<ArithError> for Error {
@@ -214,6 +215,8 @@ pub struct DutiesService<T, E: EthSpec> {
pub sync_duties: SyncDutiesMap<E>,
/// Provides the canonical list of locally-managed validators.
pub validator_store: Arc<ValidatorStore<T, E>>,
/// Maps unknown validator pubkeys to the next slot time when a poll should be conducted again.
pub unknown_validator_next_poll_slots: RwLock<HashMap<PublicKeyBytes, Slot>>,
/// Tracks the current slot.
pub slot_clock: T,
/// Provides HTTP access to remote beacon nodes.
@@ -488,6 +491,24 @@ async fn poll_validator_indices<T: SlotClock + 'static, E: EthSpec>(
.is_some();
if !is_known {
let current_slot_opt = duties_service.slot_clock.now();
if let Some(current_slot) = current_slot_opt {
let is_first_slot_of_epoch = current_slot % E::slots_per_epoch() == 0;
// Query an unknown validator later if it was queried within the last epoch, or if
// the current slot is the first slot of an epoch.
let poll_later = duties_service
.unknown_validator_next_poll_slots
.read()
.get(&pubkey)
.map(|&poll_slot| poll_slot > current_slot || is_first_slot_of_epoch)
.unwrap_or(false);
if poll_later {
continue;
}
}
// Query the remote BN to resolve a pubkey to a validator index.
let download_result = duties_service
.beacon_nodes
@@ -528,10 +549,23 @@ async fn poll_validator_indices<T: SlotClock + 'static, E: EthSpec>(
.initialized_validators()
.write()
.set_index(&pubkey, response.data.index);
duties_service
.unknown_validator_next_poll_slots
.write()
.remove(&pubkey);
}
// This is not necessarily an error, it just means the validator is not yet known to
// the beacon chain.
Ok(None) => {
if let Some(current_slot) = current_slot_opt {
let next_poll_slot = current_slot.saturating_add(E::slots_per_epoch());
duties_service
.unknown_validator_next_poll_slots
.write()
.insert(pubkey, next_poll_slot);
}
debug!(
log,
"Validator without index";
@@ -887,7 +921,7 @@ async fn poll_beacon_attesters_for_epoch<T: SlotClock + 'static, E: EthSpec>(
"Attester duties re-org";
"prior_dependent_root" => %prior_dependent_root,
"dependent_root" => %dependent_root,
"msg" => "this may happen from time to time"
"note" => "this may happen from time to time"
)
}
*mut_value = (dependent_root, duty_and_proof);

View File

@@ -17,8 +17,8 @@ use warp::{http::Response, Filter};
#[derive(Debug)]
pub enum Error {
Warp(warp::Error),
Other(String),
Warp(#[allow(dead_code)] warp::Error),
Other(#[allow(dead_code)] String),
}
impl From<warp::Error> for Error {

View File

@@ -48,7 +48,7 @@ use notifier::spawn_notifier;
use parking_lot::RwLock;
use preparation_service::{PreparationService, PreparationServiceBuilder};
use reqwest::Certificate;
use slog::{error, info, warn, Logger};
use slog::{debug, error, info, warn, Logger};
use slot_clock::SlotClock;
use slot_clock::SystemTimeSlotClock;
use std::fs::File;
@@ -110,7 +110,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
/// and attestation production.
pub async fn new_from_cli(
context: RuntimeContext<E>,
cli_args: &ArgMatches<'_>,
cli_args: &ArgMatches,
) -> Result<Self, String> {
let config = Config::from_cli(cli_args, context.log())
.map_err(|e| format!("Unable to initialize config: {}", e))?;
@@ -122,6 +122,27 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
pub async fn new(context: RuntimeContext<E>, config: Config) -> Result<Self, String> {
let log = context.log().clone();
// Attempt to raise soft fd limit. The behavior is OS specific:
// `linux` - raise soft fd limit to hard
// `macos` - raise soft fd limit to `min(kernel limit, hard fd limit)`
// `windows` & rest - noop
match fdlimit::raise_fd_limit().map_err(|e| format!("Unable to raise fd limit: {}", e))? {
fdlimit::Outcome::LimitRaised { from, to } => {
debug!(
log,
"Raised soft open file descriptor resource limit";
"old_limit" => from,
"new_limit" => to
);
}
fdlimit::Outcome::Unsupported => {
debug!(
log,
"Raising soft open file descriptor resource limit is not supported"
);
}
};
info!(
log,
"Starting validator client";
@@ -464,6 +485,7 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
slot_clock: slot_clock.clone(),
beacon_nodes: beacon_nodes.clone(),
validator_store: validator_store.clone(),
unknown_validator_next_poll_slots: <_>::default(),
spec: context.eth2_config.spec.clone(),
context: duties_context,
enable_high_validator_count_metrics: config.enable_high_validator_count_metrics,

View File

@@ -7,7 +7,7 @@ use crate::http_metrics::metrics;
use eth2_keystore::Keystore;
use lockfile::Lockfile;
use parking_lot::Mutex;
use reqwest::Client;
use reqwest::{header::ACCEPT, Client};
use std::path::PathBuf;
use std::sync::Arc;
use task_executor::TaskExecutor;
@@ -243,6 +243,7 @@ impl SigningMethod {
// Request a signature from the Web3Signer instance via HTTP(S).
let response: SigningResponse = http_client
.post(signing_url.clone())
.header(ACCEPT, "application/json")
.json(&request)
.send()
.await