mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-21 22:04:44 +00:00
Migrate validator client to clap derive (#6300)
Partially #5900 Migrate the validator client cli to clap derive
This commit is contained in:
@@ -1,490 +1,478 @@
|
||||
use clap::{builder::ArgPredicate, Arg, ArgAction, Command};
|
||||
use clap_utils::{get_color_style, FLAG_HEADER};
|
||||
use beacon_node_fallback::ApiTopic;
|
||||
use clap::builder::ArgPredicate;
|
||||
pub use clap::{FromArgMatches, Parser};
|
||||
use clap_utils::get_color_style;
|
||||
use clap_utils::FLAG_HEADER;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
use types::Address;
|
||||
|
||||
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 \
|
||||
#[derive(Parser, Clone, Deserialize, Serialize, Debug)]
|
||||
#[clap(
|
||||
name = "validator_client",
|
||||
visible_aliases = &["v", "vc", "validator"],
|
||||
about = "When connected to a beacon node, performs the duties of a staked \
|
||||
validator (e.g., proposing blocks and attestations).",
|
||||
)
|
||||
.arg(
|
||||
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."
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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."
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("broadcast")
|
||||
.long("broadcast")
|
||||
.value_name("API_TOPICS")
|
||||
.help("Comma-separated list of beacon API topics to broadcast to all beacon nodes. \
|
||||
Possible values are: none, attestations, blocks, subscriptions, \
|
||||
sync-committee. Default (when flag is omitted) is to broadcast \
|
||||
subscriptions only."
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("validators-dir")
|
||||
.long("validators-dir")
|
||||
.alias("validator-dir")
|
||||
.value_name("VALIDATORS_DIR")
|
||||
.help(
|
||||
"The directory which contains the validator keystores, deposit data for \
|
||||
each validator along with the common slashing protection database \
|
||||
and the validator_definitions.yml"
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.conflicts_with("datadir")
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("secrets-dir")
|
||||
.long("secrets-dir")
|
||||
.value_name("SECRETS_DIRECTORY")
|
||||
.help(
|
||||
"The directory which contains the password to unlock the validator \
|
||||
voting keypairs. Each password should be contained in a file where the \
|
||||
name is the 0x-prefixed hex representation of the validators voting public \
|
||||
key. Defaults to ~/.lighthouse/{network}/secrets.",
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.conflicts_with("datadir")
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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 \
|
||||
slashing protection database is required. Usually, your database \
|
||||
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::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::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::new("beacon-nodes-tls-certs")
|
||||
.long("beacon-nodes-tls-certs")
|
||||
.value_name("CERTIFICATE-FILES")
|
||||
.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::new("graffiti")
|
||||
.long("graffiti")
|
||||
.help("Specify your custom graffiti to be included in blocks.")
|
||||
.value_name("GRAFFITI")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("graffiti-file")
|
||||
.long("graffiti-file")
|
||||
.help("Specify a graffiti file to load validator graffitis from.")
|
||||
.value_name("GRAFFITI-FILE")
|
||||
.action(ArgAction::Set)
|
||||
.conflicts_with("graffiti")
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("distributed")
|
||||
.long("distributed")
|
||||
.help("Enables functionality required for running the validator in a distributed validator cluster.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
/* REST API related arguments */
|
||||
.arg(
|
||||
Arg::new("http")
|
||||
.long("http")
|
||||
.help("Enable the RESTful HTTP API server. Disabled by default.")
|
||||
.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
|
||||
* unsafe to publish on a public network.
|
||||
*
|
||||
* If the `--http-address` flag is used, the `--unencrypted-http-transport` flag
|
||||
* must also be used in order to make it clear to the user that this is unsafe.
|
||||
*/
|
||||
.arg(
|
||||
Arg::new("http-address")
|
||||
.long("http-address")
|
||||
.requires("http")
|
||||
.value_name("ADDRESS")
|
||||
.help("Set the address for the HTTP address. The HTTP server is not encrypted \
|
||||
and therefore it is unsafe to publish on a public network. When this \
|
||||
flag is used, it additionally requires the explicit use of the \
|
||||
`--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")
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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::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", ArgPredicate::IsPresent, "5062")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("http-allow-origin")
|
||||
.long("http-allow-origin")
|
||||
.requires("http")
|
||||
.value_name("ORIGIN")
|
||||
.help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
styles = get_color_style(),
|
||||
next_line_help = true,
|
||||
term_width = 80,
|
||||
disable_help_flag = true,
|
||||
disable_help_subcommand = true,
|
||||
display_order = 0,
|
||||
)]
|
||||
pub struct ValidatorClient {
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "NETWORK_ADDRESSES",
|
||||
value_delimiter = ',',
|
||||
help = "Comma-separated addresses to one or more beacon node HTTP APIs. \
|
||||
Default is http://localhost:5052.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub beacon_nodes: Option<Vec<String>>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "NETWORK_ADDRESSES",
|
||||
value_delimiter = ',',
|
||||
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.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub proposer_nodes: Option<Vec<String>>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "API_TOPICS",
|
||||
value_delimiter = ',',
|
||||
help = "Comma-separated list of beacon API topics to broadcast to all beacon nodes. \
|
||||
Default (when flag is omitted) is to broadcast subscriptions only.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub broadcast: Option<Vec<ApiTopic>>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
alias = "validator-dir",
|
||||
value_name = "VALIDATORS_DIR",
|
||||
conflicts_with = "datadir",
|
||||
help = "The directory which contains the validator keystores, deposit data for \
|
||||
each validator along with the common slashing protection database \
|
||||
and the validator_definitions.yml",
|
||||
display_order = 0
|
||||
)]
|
||||
pub validators_dir: Option<PathBuf>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "SECRETS_DIRECTORY",
|
||||
conflicts_with = "datadir",
|
||||
help = "The directory which contains the password to unlock the validator \
|
||||
voting keypairs. Each password should be contained in a file where the \
|
||||
name is the 0x-prefixed hex representation of the validators voting public \
|
||||
key. Defaults to ~/.lighthouse/{network}/secrets.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub secrets_dir: Option<PathBuf>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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 \
|
||||
slashing protection database is required. Usually, your database \
|
||||
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,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub init_slashing_protection: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub disable_auto_discover: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub use_long_timeouts: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "CERTIFICATE-FILES",
|
||||
value_delimiter = ',',
|
||||
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
|
||||
)]
|
||||
pub beacon_nodes_tls_certs: Option<Vec<String>>,
|
||||
|
||||
// This overwrites the graffiti configured in the beacon node.
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "GRAFFITI",
|
||||
help = "Specify your custom graffiti to be included in blocks.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub graffiti: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "GRAFFITI-FILE",
|
||||
conflicts_with = "graffiti",
|
||||
help = "Specify a graffiti file to load validator graffitis from.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub graffiti_file: Option<PathBuf>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "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.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub suggested_fee_recipient: Option<Address>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "Enables functionality required for running the validator in a distributed validator cluster.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub distributed: bool,
|
||||
|
||||
/* REST API related arguments */
|
||||
#[clap(
|
||||
long,
|
||||
help = "Enable the RESTful HTTP API server. Disabled by default.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub http: bool,
|
||||
|
||||
/*
|
||||
* Note: The HTTP server is **not** encrypted (i.e., not HTTPS) and therefore it is
|
||||
* unsafe to publish on a public network.
|
||||
*
|
||||
* If the `--http-address` flag is used, the `--unencrypted-http-transport` flag
|
||||
* must also be used in order to make it clear to the user that this is unsafe.
|
||||
*/
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "ADDRESS",
|
||||
requires = "unencrypted_http_transport",
|
||||
help = "Set the address for the HTTP address. The HTTP server is not encrypted \
|
||||
and therefore it is unsafe to publish on a public network. When this \
|
||||
flag is used, it additionally requires the explicit use of the \
|
||||
`--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.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub http_address: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
requires = "http_address",
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub unencrypted_http_transport: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "PORT",
|
||||
default_value_t = 5062,
|
||||
help = "Set the listen TCP port for the RESTful HTTP API server.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub http_port: u16,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "ORIGIN",
|
||||
help = "Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
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).")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("http-allow-keystore-export")
|
||||
.long("http-allow-keystore-export")
|
||||
.requires("http")
|
||||
.help("If present, allow access to the DELETE /lighthouse/keystores HTTP \
|
||||
API method, which allows exporting keystores and passwords to HTTP API \
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("http-token-path")
|
||||
.long("http-token-path")
|
||||
.requires("http")
|
||||
.value_name("HTTP_TOKEN_PATH")
|
||||
.help(
|
||||
"Path to file containing the HTTP API token for validator client authentication. \
|
||||
If not specified, defaults to {validators-dir}/api-token.txt."
|
||||
)
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
/* Prometheus metrics HTTP server related arguments */
|
||||
.arg(
|
||||
Arg::new("metrics")
|
||||
.long("metrics")
|
||||
.help("Enable the Prometheus metrics HTTP server. Disabled by default.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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", ArgPredicate::IsPresent, "127.0.0.1")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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", ArgPredicate::IsPresent, "5064")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("metrics-allow-origin")
|
||||
.long("metrics-allow-origin")
|
||||
.requires("metrics")
|
||||
.value_name("ORIGIN")
|
||||
.help("Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
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).")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
/*
|
||||
* Explorer metrics
|
||||
*/
|
||||
.arg(
|
||||
Arg::new("monitoring-endpoint")
|
||||
.long("monitoring-endpoint")
|
||||
.value_name("ADDRESS")
|
||||
.help("Enables the monitoring service for sending system metrics to a remote endpoint. \
|
||||
address of this server (e.g., http://localhost:5062).",
|
||||
display_order = 0
|
||||
)]
|
||||
pub http_allow_origin: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
requires = "http",
|
||||
help = "If present, allow access to the DELETE /lighthouse/keystores HTTP \
|
||||
API method, which allows exporting keystores and passwords to HTTP API \
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub http_allow_keystore_export: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub http_store_passwords_in_secrets_dir: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
requires = "http",
|
||||
help = "Path to file containing the HTTP API token for validator client authentication. \
|
||||
If not specified, defaults to {validators-dir}/api-token.txt.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub http_token_path: Option<String>,
|
||||
|
||||
/* Prometheus metrics HTTP server related arguments */
|
||||
#[clap(
|
||||
long,
|
||||
help = "Enable the Prometheus metrics HTTP server. Disabled by default.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub metrics: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "ADDRESS",
|
||||
requires = "metrics",
|
||||
default_value_if("metrics", ArgPredicate::IsPresent, "127.0.0.1"),
|
||||
help = "Set the listen address for the Prometheus metrics HTTP server. [default: 127.0.0.1]",
|
||||
display_order = 0
|
||||
)]
|
||||
pub metrics_address: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "PORT",
|
||||
requires = "metrics",
|
||||
default_value_t = 5064,
|
||||
help = "Set the listen TCP port for the Prometheus metrics HTTP server.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub metrics_port: u16,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "ORIGIN",
|
||||
requires = "metrics",
|
||||
help = "Set the value of the Access-Control-Allow-Origin response HTTP header. \
|
||||
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).",
|
||||
display_order = 0
|
||||
)]
|
||||
pub metrics_allow_origin: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub enable_high_validator_count_metrics: bool,
|
||||
|
||||
/* Explorer metrics */
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "ADDRESS",
|
||||
help = "Enables the monitoring service for sending system metrics to a remote endpoint. \
|
||||
This can be used to monitor your setup on certain services (e.g. beaconcha.in). \
|
||||
This flag sets the endpoint where the beacon node metrics will be sent. \
|
||||
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.")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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 \
|
||||
monitor for messages on the network by any of the validators managed by this \
|
||||
client. This will result in three (possibly four) epochs worth of missed \
|
||||
attestations. If an attestation is detected during this period, it means it is \
|
||||
very likely that you are running a second validator client with the same keys. \
|
||||
This validator client will immediately shutdown if this is detected in order \
|
||||
to avoid potentially committing a slashable offense. Use this flag in order to \
|
||||
ENABLE this functionality, without this flag Lighthouse will begin attesting \
|
||||
immediately.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("gas-limit")
|
||||
.long("gas-limit")
|
||||
.value_name("INTEGER")
|
||||
.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")
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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::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")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
Arg::new("builder-boost-factor")
|
||||
.long("builder-boost-factor")
|
||||
.value_name("UINT64")
|
||||
.help("Defines the boost factor, \
|
||||
a percentage multiplier to apply to the builder's payload value \
|
||||
when choosing between a builder payload header and payload from \
|
||||
the local execution node.")
|
||||
.conflicts_with("prefer-builder-proposals")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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 \
|
||||
determining the health of each connected beacon node. \
|
||||
The first value determines the `Synced` range. \
|
||||
If a connected beacon node is synced to within this number of slots it is considered 'Synced'. \
|
||||
The second value determines the `Small` sync distance range. \
|
||||
This range starts immediately after the `Synced` range. \
|
||||
The third value determines the `Medium` sync distance range. \
|
||||
This range starts immediately after the `Small` range. \
|
||||
Any sync distance value beyond that is considered `Large`. \
|
||||
For example, a value of `8,8,48` would have ranges like the following: \
|
||||
`Synced`: 0..=8 \
|
||||
`Small`: 9..=16 \
|
||||
`Medium`: 17..=64 \
|
||||
`Large`: 65.. \
|
||||
These values are used to determine what ordering beacon node fallbacks are used in. \
|
||||
Generally, `Synced` nodes are preferred over `Small` and so on. \
|
||||
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]")
|
||||
.action(ArgAction::Set)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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 \
|
||||
is enabled on the remote signer and is implemented correctly. DO NOT ENABLE \
|
||||
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.")
|
||||
.action(ArgAction::SetTrue)
|
||||
.help_heading(FLAG_HEADER)
|
||||
.display_order(0)
|
||||
)
|
||||
/*
|
||||
* Experimental/development options.
|
||||
*/
|
||||
.arg(
|
||||
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")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
.arg(
|
||||
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.")
|
||||
.action(ArgAction::Set)
|
||||
.display_order(0)
|
||||
)
|
||||
and never provide an untrusted URL.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub monitoring_endpoint: Option<String>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "SECONDS",
|
||||
requires = "monitoring_endpoint",
|
||||
default_value_t = 60,
|
||||
help = "Defines how many seconds to wait between each message sent to \
|
||||
the monitoring-endpoint.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub monitoring_endpoint_period: u64,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "BOOLEAN",
|
||||
help = "If this flag is set, Lighthouse will delay startup for three epochs and \
|
||||
monitor for messages on the network by any of the validators managed by this \
|
||||
client. This will result in three (possibly four) epochs worth of missed \
|
||||
attestations. If an attestation is detected during this period, it means it is \
|
||||
very likely that you are running a second validator client with the same keys. \
|
||||
This validator client will immediately shutdown if this is detected in order \
|
||||
to avoid potentially committing a slashable offense. Use this flag in order to \
|
||||
ENABLE this functionality, without this flag Lighthouse will begin attesting \
|
||||
immediately.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub enable_doppelganger_protection: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub builder_proposals: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "UNIX-TIMESTAMP",
|
||||
help = "This flag takes a unix timestamp value that will be used to override the \
|
||||
timestamp used in the builder api registration.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub builder_registration_timestamp_override: Option<u64>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "INTEGER",
|
||||
default_value_t = 30_000_000,
|
||||
requires = "builder_proposals",
|
||||
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.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub gas_limit: u64,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "BOOLEAN",
|
||||
help = "Disables the service that periodically attempts to measure latency to BNs.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub disable_latency_measurement_service: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "INTEGER",
|
||||
default_value_t = 500,
|
||||
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.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub validator_registration_batch_size: usize,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "UINT64",
|
||||
help = "Defines the boost factor, \
|
||||
a percentage multiplier to apply to the builder's payload value \
|
||||
when choosing between a builder payload header and payload from \
|
||||
the local execution node.",
|
||||
conflicts_with = "prefer_builder_proposals",
|
||||
display_order = 0
|
||||
)]
|
||||
pub builder_boost_factor: Option<u64>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "If this flag is set, Lighthouse will always prefer blocks \
|
||||
constructed by builders, regardless of payload value.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub prefer_builder_proposals: bool,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
help = "A comma-separated list of 3 values which sets the size of each sync distance range when \
|
||||
determining the health of each connected beacon node. \
|
||||
The first value determines the `Synced` range. \
|
||||
If a connected beacon node is synced to within this number of slots it is considered 'Synced'. \
|
||||
The second value determines the `Small` sync distance range. \
|
||||
This range starts immediately after the `Synced` range. \
|
||||
The third value determines the `Medium` sync distance range. \
|
||||
This range starts immediately after the `Small` range. \
|
||||
Any sync distance value beyond that is considered `Large`. \
|
||||
For example, a value of `8,8,48` would have ranges like the following: \
|
||||
`Synced`: 0..=8 \
|
||||
`Small`: 9..=16 \
|
||||
`Medium`: 17..=64 \
|
||||
`Large`: 65.. \
|
||||
These values are used to determine what ordering beacon node fallbacks are used in. \
|
||||
Generally, `Synced` nodes are preferred over `Small` and so on. \
|
||||
Nodes in the `Synced` range will tie-break based on their ordering in `--beacon-nodes`. \
|
||||
This ensures the primary beacon node is prioritised.",
|
||||
display_order = 0,
|
||||
value_delimiter = ',',
|
||||
default_value = "8,8,48",
|
||||
help_heading = FLAG_HEADER,
|
||||
value_name = "SYNC_TOLERANCES"
|
||||
)]
|
||||
pub beacon_nodes_sync_tolerances: Vec<u64>,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
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 \
|
||||
is enabled on the remote signer and is implemented correctly. DO NOT ENABLE \
|
||||
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.",
|
||||
display_order = 0,
|
||||
help_heading = FLAG_HEADER
|
||||
)]
|
||||
pub disable_slashing_protection_web3signer: bool,
|
||||
|
||||
/* Experimental/development options */
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "MILLIS",
|
||||
default_value_t = 20000,
|
||||
help = "Keep-alive timeout for each web3signer connection. Set to '0' to never \
|
||||
timeout.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub web3_signer_keep_alive_timeout: u64,
|
||||
|
||||
#[clap(
|
||||
long,
|
||||
value_name = "COUNT",
|
||||
help = "Maximum number of idle connections to maintain per web3signer host. Default \
|
||||
is unlimited.",
|
||||
display_order = 0
|
||||
)]
|
||||
pub web3_signer_max_idle_connections: Option<usize>,
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
use beacon_node_fallback::{beacon_node_health::BeaconNodeSyncDistanceTiers, ApiTopic};
|
||||
use crate::cli::ValidatorClient;
|
||||
use beacon_node_fallback::beacon_node_health::BeaconNodeSyncDistanceTiers;
|
||||
use beacon_node_fallback::ApiTopic;
|
||||
use clap::ArgMatches;
|
||||
use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, parse_optional, parse_required};
|
||||
use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, parse_required};
|
||||
use directory::{
|
||||
get_network_dir, DEFAULT_HARDCODED_NETWORK, DEFAULT_ROOT_DIR, DEFAULT_SECRET_DIR,
|
||||
DEFAULT_VALIDATOR_DIR,
|
||||
@@ -14,9 +16,8 @@ use slog::{info, warn, Logger};
|
||||
use std::fs;
|
||||
use std::net::IpAddr;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
use types::{Address, GRAFFITI_BYTES_LEN};
|
||||
use types::GRAFFITI_BYTES_LEN;
|
||||
use validator_http_api::{self, PK_FILENAME};
|
||||
use validator_http_metrics;
|
||||
use validator_store::Config as ValidatorStoreConfig;
|
||||
@@ -132,7 +133,11 @@ impl Default for Config {
|
||||
impl Config {
|
||||
/// Returns a `Default` implementation of `Self` with some parameters modified by the supplied
|
||||
/// `cli_args`.
|
||||
pub fn from_cli(cli_args: &ArgMatches, log: &Logger) -> Result<Config, String> {
|
||||
pub fn from_cli(
|
||||
cli_args: &ArgMatches,
|
||||
validator_client_config: &ValidatorClient,
|
||||
log: &Logger,
|
||||
) -> Result<Config, String> {
|
||||
let mut config = Config::default();
|
||||
|
||||
let default_root_dir = dirs::home_dir()
|
||||
@@ -145,11 +150,12 @@ impl Config {
|
||||
validator_dir = Some(base_dir.join(DEFAULT_VALIDATOR_DIR));
|
||||
secrets_dir = Some(base_dir.join(DEFAULT_SECRET_DIR));
|
||||
}
|
||||
if cli_args.get_one::<String>("validators-dir").is_some() {
|
||||
validator_dir = Some(parse_required(cli_args, "validators-dir")?);
|
||||
|
||||
if let Some(validator_dir_path) = validator_client_config.validators_dir.as_ref() {
|
||||
validator_dir = Some(validator_dir_path.clone());
|
||||
}
|
||||
if cli_args.get_one::<String>("secrets-dir").is_some() {
|
||||
secrets_dir = Some(parse_required(cli_args, "secrets-dir")?);
|
||||
if let Some(secrets_dir_path) = validator_client_config.secrets_dir.as_ref() {
|
||||
secrets_dir = Some(secrets_dir_path.clone());
|
||||
}
|
||||
|
||||
config.validator_dir = validator_dir.unwrap_or_else(|| {
|
||||
@@ -169,35 +175,36 @@ impl Config {
|
||||
.map_err(|e| format!("Failed to create {:?}: {:?}", config.validator_dir, e))?;
|
||||
}
|
||||
|
||||
if let Some(beacon_nodes) = parse_optional::<String>(cli_args, "beacon-nodes")? {
|
||||
if let Some(beacon_nodes) = validator_client_config.beacon_nodes.as_ref() {
|
||||
config.beacon_nodes = beacon_nodes
|
||||
.split(',')
|
||||
.map(SensitiveUrl::parse)
|
||||
.iter()
|
||||
.map(|s| SensitiveUrl::parse(s))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(|e| format!("Unable to parse beacon node URL: {:?}", e))?;
|
||||
}
|
||||
if let Some(proposer_nodes) = parse_optional::<String>(cli_args, "proposer-nodes")? {
|
||||
|
||||
if let Some(proposer_nodes) = validator_client_config.proposer_nodes.as_ref() {
|
||||
config.proposer_nodes = proposer_nodes
|
||||
.split(',')
|
||||
.map(SensitiveUrl::parse)
|
||||
.iter()
|
||||
.map(|s| SensitiveUrl::parse(s))
|
||||
.collect::<Result<_, _>>()
|
||||
.map_err(|e| format!("Unable to parse proposer node URL: {:?}", e))?;
|
||||
}
|
||||
|
||||
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");
|
||||
config.disable_auto_discover = validator_client_config.disable_auto_discover;
|
||||
config.init_slashing_protection = validator_client_config.init_slashing_protection;
|
||||
config.use_long_timeouts = validator_client_config.use_long_timeouts;
|
||||
|
||||
if let Some(graffiti_file_path) = cli_args.get_one::<String>("graffiti-file") {
|
||||
if let Some(graffiti_file_path) = validator_client_config.graffiti_file.as_ref() {
|
||||
let mut graffiti_file = GraffitiFile::new(graffiti_file_path.into());
|
||||
graffiti_file
|
||||
.read_graffiti_file()
|
||||
.map_err(|e| format!("Error reading graffiti file: {:?}", e))?;
|
||||
config.graffiti_file = Some(graffiti_file);
|
||||
info!(log, "Successfully loaded graffiti file"; "path" => graffiti_file_path);
|
||||
info!(log, "Successfully loaded graffiti file"; "path" => graffiti_file_path.to_str());
|
||||
}
|
||||
|
||||
if let Some(input_graffiti) = cli_args.get_one::<String>("graffiti") {
|
||||
if let Some(input_graffiti) = validator_client_config.graffiti.as_ref() {
|
||||
let graffiti_bytes = input_graffiti.as_bytes();
|
||||
if graffiti_bytes.len() > GRAFFITI_BYTES_LEN {
|
||||
return Err(format!(
|
||||
@@ -216,55 +223,40 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(input_fee_recipient) =
|
||||
parse_optional::<Address>(cli_args, "suggested-fee-recipient")?
|
||||
{
|
||||
if let Some(input_fee_recipient) = validator_client_config.suggested_fee_recipient {
|
||||
config.validator_store.fee_recipient = Some(input_fee_recipient);
|
||||
}
|
||||
|
||||
if let Some(tls_certs) = parse_optional::<String>(cli_args, "beacon-nodes-tls-certs")? {
|
||||
config.beacon_nodes_tls_certs = Some(tls_certs.split(',').map(PathBuf::from).collect());
|
||||
if let Some(tls_certs) = validator_client_config.beacon_nodes_tls_certs.as_ref() {
|
||||
config.beacon_nodes_tls_certs = Some(tls_certs.iter().map(PathBuf::from).collect());
|
||||
}
|
||||
|
||||
if cli_args.get_flag("distributed") {
|
||||
config.distributed = true;
|
||||
}
|
||||
config.distributed = validator_client_config.distributed;
|
||||
|
||||
if let Some(broadcast_topics) = cli_args.get_one::<String>("broadcast") {
|
||||
config.broadcast_topics = broadcast_topics
|
||||
.split(',')
|
||||
.filter(|t| *t != "none")
|
||||
.map(|t| {
|
||||
t.trim()
|
||||
.parse::<ApiTopic>()
|
||||
.map_err(|_| format!("Unknown API topic to broadcast: {t}"))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
if let Some(mut broadcast_topics) = validator_client_config.broadcast.clone() {
|
||||
broadcast_topics.retain(|topic| *topic != ApiTopic::None);
|
||||
config.broadcast_topics = broadcast_topics;
|
||||
}
|
||||
|
||||
/*
|
||||
* Beacon node fallback
|
||||
*/
|
||||
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 {
|
||||
config.beacon_node_fallback.sync_tolerances = BeaconNodeSyncDistanceTiers::default();
|
||||
}
|
||||
config.beacon_node_fallback.sync_tolerances = BeaconNodeSyncDistanceTiers::from_vec(
|
||||
&validator_client_config.beacon_nodes_sync_tolerances,
|
||||
)?;
|
||||
|
||||
/*
|
||||
* Web3 signer
|
||||
*/
|
||||
if let Some(s) = parse_optional::<String>(cli_args, "web3-signer-keep-alive-timeout")? {
|
||||
config.initialized_validators.web3_signer_keep_alive_timeout = if s == "null" {
|
||||
None
|
||||
} else {
|
||||
Some(Duration::from_millis(
|
||||
s.parse().map_err(|_| "invalid timeout value".to_string())?,
|
||||
))
|
||||
}
|
||||
if validator_client_config.web3_signer_keep_alive_timeout == 0 {
|
||||
config.initialized_validators.web3_signer_keep_alive_timeout = None
|
||||
} else {
|
||||
config.initialized_validators.web3_signer_keep_alive_timeout = Some(
|
||||
Duration::from_millis(validator_client_config.web3_signer_keep_alive_timeout),
|
||||
);
|
||||
}
|
||||
if let Some(n) = parse_optional::<usize>(cli_args, "web3-signer-max-idle-connections")? {
|
||||
|
||||
if let Some(n) = validator_client_config.web3_signer_max_idle_connections {
|
||||
config
|
||||
.initialized_validators
|
||||
.web3_signer_max_idle_connections = Some(n);
|
||||
@@ -274,12 +266,10 @@ impl Config {
|
||||
* Http API server
|
||||
*/
|
||||
|
||||
if cli_args.get_flag("http") {
|
||||
config.http_api.enabled = true;
|
||||
}
|
||||
config.http_api.enabled = validator_client_config.http;
|
||||
|
||||
if let Some(address) = cli_args.get_one::<String>("http-address") {
|
||||
if cli_args.get_flag("unencrypted-http-transport") {
|
||||
if let Some(address) = &validator_client_config.http_address {
|
||||
if validator_client_config.unencrypted_http_transport {
|
||||
config.http_api.listen_addr = address
|
||||
.parse::<IpAddr>()
|
||||
.map_err(|_| "http-address is not a valid IP address.")?;
|
||||
@@ -291,13 +281,9 @@ impl Config {
|
||||
}
|
||||
}
|
||||
|
||||
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.")?;
|
||||
}
|
||||
config.http_api.listen_port = validator_client_config.http_port;
|
||||
|
||||
if let Some(allow_origin) = cli_args.get_one::<String>("http-allow-origin") {
|
||||
if let Some(allow_origin) = validator_client_config.http_allow_origin.as_ref() {
|
||||
// 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)
|
||||
@@ -306,15 +292,11 @@ impl Config {
|
||||
config.http_api.allow_origin = Some(allow_origin.to_string());
|
||||
}
|
||||
|
||||
if cli_args.get_flag("http-allow-keystore-export") {
|
||||
config.http_api.allow_keystore_export = true;
|
||||
}
|
||||
config.http_api.allow_keystore_export = validator_client_config.http_allow_keystore_export;
|
||||
config.http_api.store_passwords_in_secrets_dir =
|
||||
validator_client_config.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;
|
||||
}
|
||||
|
||||
if let Some(http_token_path) = cli_args.get_one::<String>("http-token-path") {
|
||||
if let Some(http_token_path) = &validator_client_config.http_token_path {
|
||||
config.http_api.http_token_path = PathBuf::from(http_token_path);
|
||||
} else {
|
||||
// For backward compatibility, default to the path under the validator dir if not provided.
|
||||
@@ -325,27 +307,19 @@ impl Config {
|
||||
* Prometheus metrics HTTP server
|
||||
*/
|
||||
|
||||
if cli_args.get_flag("metrics") {
|
||||
config.http_metrics.enabled = true;
|
||||
}
|
||||
config.http_metrics.enabled = validator_client_config.metrics;
|
||||
config.enable_high_validator_count_metrics =
|
||||
validator_client_config.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.get_one::<String>("metrics-address") {
|
||||
config.http_metrics.listen_addr = address
|
||||
if let Some(metrics_address) = &validator_client_config.metrics_address {
|
||||
config.http_metrics.listen_addr = metrics_address
|
||||
.parse::<IpAddr>()
|
||||
.map_err(|_| "metrics-address is not a valid IP address.")?;
|
||||
}
|
||||
|
||||
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.")?;
|
||||
}
|
||||
config.http_metrics.listen_port = validator_client_config.metrics_port;
|
||||
|
||||
if let Some(allow_origin) = cli_args.get_one::<String>("metrics-allow-origin") {
|
||||
if let Some(allow_origin) = validator_client_config.metrics_allow_origin.as_ref() {
|
||||
// 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)
|
||||
@@ -361,9 +335,8 @@ impl Config {
|
||||
/*
|
||||
* Explorer metrics
|
||||
*/
|
||||
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")?;
|
||||
if let Some(monitoring_endpoint) = validator_client_config.monitoring_endpoint.as_ref() {
|
||||
let update_period_secs = Some(validator_client_config.monitoring_endpoint_period);
|
||||
config.monitoring_api = Some(monitoring_api::Config {
|
||||
db_path: None,
|
||||
freezer_db_path: None,
|
||||
@@ -372,56 +345,34 @@ impl Config {
|
||||
});
|
||||
}
|
||||
|
||||
if cli_args.get_flag("enable-doppelganger-protection") {
|
||||
config.enable_doppelganger_protection = true;
|
||||
}
|
||||
config.enable_doppelganger_protection =
|
||||
validator_client_config.enable_doppelganger_protection;
|
||||
config.validator_store.builder_proposals = validator_client_config.builder_proposals;
|
||||
config.validator_store.prefer_builder_proposals =
|
||||
validator_client_config.prefer_builder_proposals;
|
||||
config.validator_store.gas_limit = Some(validator_client_config.gas_limit);
|
||||
|
||||
if cli_args.get_flag("builder-proposals") {
|
||||
config.validator_store.builder_proposals = true;
|
||||
}
|
||||
|
||||
if cli_args.get_flag("prefer-builder-proposals") {
|
||||
config.validator_store.prefer_builder_proposals = true;
|
||||
}
|
||||
|
||||
config.validator_store.gas_limit = cli_args
|
||||
.get_one::<String>("gas-limit")
|
||||
.map(|gas_limit| {
|
||||
gas_limit
|
||||
.parse::<u64>()
|
||||
.map_err(|_| "gas-limit is not a valid u64.")
|
||||
})
|
||||
.transpose()?;
|
||||
|
||||
if let Some(registration_timestamp_override) =
|
||||
cli_args.get_one::<String>("builder-registration-timestamp-override")
|
||||
{
|
||||
config.builder_registration_timestamp_override = Some(
|
||||
registration_timestamp_override
|
||||
.parse::<u64>()
|
||||
.map_err(|_| "builder-registration-timestamp-override is not a valid u64.")?,
|
||||
);
|
||||
}
|
||||
|
||||
config.validator_store.builder_boost_factor =
|
||||
parse_optional(cli_args, "builder-boost-factor")?;
|
||||
config.builder_registration_timestamp_override =
|
||||
validator_client_config.builder_registration_timestamp_override;
|
||||
|
||||
config.validator_store.builder_boost_factor = validator_client_config.builder_boost_factor;
|
||||
config.enable_latency_measurement_service =
|
||||
!cli_args.get_flag("disable-latency-measurement-service");
|
||||
!validator_client_config.disable_latency_measurement_service;
|
||||
|
||||
config.validator_registration_batch_size =
|
||||
parse_required(cli_args, "validator-registration-batch-size")?;
|
||||
validator_client_config.validator_registration_batch_size;
|
||||
|
||||
if config.validator_registration_batch_size == 0 {
|
||||
return Err("validator-registration-batch-size cannot be 0".to_string());
|
||||
}
|
||||
|
||||
config.validator_store.enable_web3signer_slashing_protection =
|
||||
if cli_args.get_flag("disable-slashing-protection-web3signer") {
|
||||
if validator_client_config.disable_slashing_protection_web3signer {
|
||||
warn!(
|
||||
log,
|
||||
"Slashing protection for remote keys disabled";
|
||||
"info" => "ensure slashing protection on web3signer is enabled or you WILL \
|
||||
get slashed"
|
||||
get slashed"
|
||||
);
|
||||
false
|
||||
} else {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
mod cli;
|
||||
pub mod cli;
|
||||
pub mod config;
|
||||
mod latency;
|
||||
mod notifier;
|
||||
|
||||
pub use cli::cli_app;
|
||||
use crate::cli::ValidatorClient;
|
||||
pub use config::Config;
|
||||
use initialized_validators::InitializedValidators;
|
||||
use metrics::set_gauge;
|
||||
@@ -11,11 +11,10 @@ use monitoring_api::{MonitoringHttpClient, ProcessType};
|
||||
use sensitive_url::SensitiveUrl;
|
||||
use slashing_protection::{SlashingDatabase, SLASHING_PROTECTION_FILENAME};
|
||||
|
||||
use account_utils::validator_definitions::ValidatorDefinitions;
|
||||
use beacon_node_fallback::{
|
||||
start_fallback_updater_service, BeaconNodeFallback, CandidateBeaconNode,
|
||||
};
|
||||
|
||||
use account_utils::validator_definitions::ValidatorDefinitions;
|
||||
use clap::ArgMatches;
|
||||
use doppelganger_service::DoppelgangerService;
|
||||
use environment::RuntimeContext;
|
||||
@@ -96,8 +95,9 @@ impl<E: EthSpec> ProductionValidatorClient<E> {
|
||||
pub async fn new_from_cli(
|
||||
context: RuntimeContext<E>,
|
||||
cli_args: &ArgMatches,
|
||||
validator_client_config: &ValidatorClient,
|
||||
) -> Result<Self, String> {
|
||||
let config = Config::from_cli(cli_args, context.log())
|
||||
let config = Config::from_cli(cli_args, validator_client_config, context.log())
|
||||
.map_err(|e| format!("Unable to initialize config: {}", e))?;
|
||||
Self::new(context, config).await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user