Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stub network crate #43

Merged
merged 11 commits into from
Nov 1, 2024
1,091 changes: 799 additions & 292 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ members = [
"anchor/http_api",
"anchor/http_metrics",
"anchor/qbft",
"anchor/network",
"anchor/common/version"
]
resolver = "2"

Expand All @@ -17,18 +19,23 @@ client = { path = "anchor/client" }
qbft = { path = "anchor/qbft" }
http_api = { path = "anchor/http_api" }
http_metrics = { path = "anchor/http_metrics" }
task_executor = { git = "https://github.com/sigp/lighthouse", branch = "anchor", default-features = false, features = [ "tracing", ] }
network = { path ="anchor/network"}
version = { path ="anchor/common/version"}
lighthouse_network = { git = "https://github.com/sigp/lighthouse", branch = "unstable"}
task_executor = { git = "https://github.com/sigp/lighthouse", branch = "unstable", default-features = false, features = [ "tracing", ] }
metrics = { git = "https://github.com/agemanning/lighthouse", branch = "modularize-vc" }
validator_metrics = { git = "https://github.com/agemanning/lighthouse", branch = "modularize-vc" }
sensitive_url = { git = "https://github.com/agemanning/lighthouse", branch = "modularize-vc" }
slot_clock = { git = "https://github.com/agemanning/lighthouse", branch = "modularize-vc" }
unused_port = { git = "https://github.com/sigp/lighthouse", branch = "unstable" }
derive_more = { version = "1.0.0", features = ["full"] }
async-channel = "1.9"
axum = "0.7.7"
clap = { version = "4.5.15", features = ["derive", "wrap_help"]}
discv5 = "0.8.0"
dirs = "5.0.1"
either = "1.13.0"
futures = "0.3.30"
# dirs = "3"
tower-http = {version = "0.6", features = ["cors"] }
hyper = "1.4"
parking_lot = "0.12"
Expand Down
9 changes: 3 additions & 6 deletions anchor/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ path = "src/lib.rs"
[dependencies]
task_executor = { workspace = true }
http_api = { workspace = true }
version = { workspace = true }
http_metrics = { workspace = true }
clap = { workspace = true }
serde = { workspace = true }
Expand All @@ -19,14 +20,10 @@ sensitive_url = { workspace = true }
dirs = { workspace = true }
hyper = { workspace = true }
tracing = { workspace = true }
network = { workspace = true }
unused_port = { workspace = true }
tokio = { workspace = true }
parking_lot = { workspace = true }
# Local dependencies
fdlimit = "0.3"
ethereum_hashing = "0.7.0"
git-version = "0.3.9"
target_info = "0.1.0"

[dev-dependencies]
regex = "1.11"

86 changes: 84 additions & 2 deletions anchor/client/src/cli.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
use clap::builder::styling::*;
use clap::builder::ArgPredicate;
use clap::builder::{ArgAction, ArgPredicate};
use clap::{Parser, ValueEnum};
use serde::{Deserialize, Serialize};
use strum::Display;
// use clap_utils::{get_color_style, FLAG_HEADER};
use crate::version::VERSION;
use ethereum_hashing::have_sha_extensions;
use std::net::IpAddr;
use std::path::PathBuf;
use std::sync::LazyLock;
use version::VERSION;

pub static SHORT_VERSION: LazyLock<String> = LazyLock::new(|| VERSION.replace("Anchor/", ""));
pub static LONG_VERSION: LazyLock<String> = LazyLock::new(|| {
Expand Down Expand Up @@ -210,6 +210,88 @@ pub struct Anchor {
)]
pub http_allow_origin: Option<String>,

/* Network related arguments */
#[clap(
long,
value_name = "ADDRESS",
help = "The address anchor will listen for UDP and TCP connections. To listen \
over IpV4 and IpV6 set this flag twice with the different values.\n\
Examples:\n\
- --listen-addresses '0.0.0.0' will listen over IPv4.\n\
- --listen-addresses '::' will listen over IPv6.\n\
- --listen-addresses '0.0.0.0' --listen-addresses '::' will listen over both \
IPv4 and IPv6. The order of the given addresses is not relevant. However, \
multiple IPv4, or multiple IPv6 addresses will not be accepted.",
num_args(0..=2),
action = ArgAction::Append,
default_value = "0.0.0.0",
)]
pub listen_addresses: Vec<IpAddr>,

#[clap(
long,
value_name = "PORT",
help = "The TCP/UDP ports to listen on. There are two UDP ports. \
The discovery UDP port will be set to this value and the Quic UDP port will be set to this value + 1. The discovery port can be modified by the \
--discovery-port flag and the quic port can be modified by the --quic-port flag. If listening over both IPv4 and IPv6 the --port flag \
will apply to the IPv4 address and --port6 to the IPv6 address.",
default_value = "9100",
action = ArgAction::Set,
)]
pub port: u16,

#[clap(
long,
value_name = "PORT",
help = "The TCP/UDP ports to listen on over IPv6 when listening over both IPv4 and \
IPv6. The Quic UDP port will be set to this value + 1.",
action = ArgAction::Set,
)]
pub port6: Option<u16>,

#[clap(
long,
value_name = "PORT",
help = "The UDP port that discovery will listen on. Defaults to `port`",
action = ArgAction::Set,
)]
pub discovery_port: Option<u16>,

#[clap(
long,
value_name = "PORT",
help = "The UDP port that discovery will listen on over IPv6 if listening over \
both IPv4 and IPv6. Defaults to `port6`",
action = ArgAction::Set,
)]
pub discovery_port6: Option<u16>,

#[clap(
long,
value_name = "PORT",
help = "The UDP port that quic will listen on. Defaults to `port` + 1",
action = ArgAction::Set,
)]
pub quic_port: Option<u16>,

#[clap(
long,
value_name = "PORT",
help = "The UDP port that quic will listen on over IPv6 if listening over \
both IPv4 and IPv6. Defaults to `port6` + 1",
action = ArgAction::Set,
)]
pub quic_port6: Option<u16>,

#[clap(
long,
help = "Sets all listening TCP/UDP ports to 0, allowing the OS to choose some \
arbitrary free ports.",
action = ArgAction::SetTrue,
hide = true,
)]
pub use_zero_ports: bool,

/* Prometheus metrics HTTP server related arguments */
#[clap(
long,
Expand Down
190 changes: 188 additions & 2 deletions anchor/client/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// use crate::{http_api, http_metrics};
// use clap_utils::{flags::DISABLE_MALLOC_TUNING_FLAG, parse_optional, parse_required};

use crate::cli::Anchor;
use network::{ListenAddr, ListenAddress};
use sensitive_url::SensitiveUrl;
use serde::{Deserialize, Serialize};
use std::fs;
use std::net::IpAddr;
use std::path::PathBuf;

use crate::cli::Anchor;
use tracing::warn;

pub const DEFAULT_BEACON_NODE: &str = "http://localhost:5052/";
pub const DEFAULT_EXECUTION_NODE: &str = "http://localhost:8545/";
Expand Down Expand Up @@ -34,6 +36,8 @@ pub struct Config {
pub allow_unsynced_beacon_node: bool,
/// Configuration for the HTTP REST API.
pub http_api: http_api::Config,
/// Configuration for the network stack.
pub network: network::Config,
/// Configuration for the HTTP REST API.
pub http_metrics: http_metrics::Config,
/// A list of custom certificates that the validator client will additionally use when
Expand Down Expand Up @@ -67,6 +71,7 @@ impl Default for Config {
allow_unsynced_beacon_node: false,
http_api: <_>::default(),
http_metrics: <_>::default(),
network: <_>::default(),
beacon_nodes_tls_certs: None,
execution_nodes_tls_certs: None,
}
Expand Down Expand Up @@ -118,6 +123,11 @@ pub fn from_cli(cli_args: &Anchor) -> Result<Config, String> {
.map_err(|e| format!("Unable to parse execution node URL: {:?}", e))?;
}

/*
* Network related
*/
config.network.listen_addresses = parse_listening_addresses(cli_args)?;

config.beacon_nodes_tls_certs = cli_args.beacon_nodes_tls_certs.clone();
config.execution_nodes_tls_certs = cli_args.execution_nodes_tls_certs.clone();

Expand Down Expand Up @@ -169,6 +179,182 @@ pub fn from_cli(cli_args: &Anchor) -> Result<Config, String> {
Ok(config)
}

/// Gets the listening_addresses for lighthouse based on the cli options.
pub fn parse_listening_addresses(cli_args: &Anchor) -> Result<ListenAddress, String> {
// parse the possible ips
let mut maybe_ipv4 = None;
let mut maybe_ipv6 = None;
for addr in cli_args.listen_addresses.iter() {
match addr {
IpAddr::V4(v4_addr) => match &maybe_ipv4 {
Some(first_ipv4_addr) => {
return Err(format!(
"When setting the --listen-address option twice, use an IpV4 address and an Ipv6 address. \
Got two IpV4 addresses {first_ipv4_addr} and {v4_addr}"
));
}
None => maybe_ipv4 = Some(v4_addr),
},
IpAddr::V6(v6_addr) => match &maybe_ipv6 {
Some(first_ipv6_addr) => {
return Err(format!(
"When setting the --listen-address option twice, use an IpV4 address and an Ipv6 address. \
Got two IpV6 addresses {first_ipv6_addr} and {v6_addr}"
));
}
None => maybe_ipv6 = Some(v6_addr),
},
}
}

// Now put everything together
let listening_addresses = match (maybe_ipv4, maybe_ipv6) {
(None, None) => {
// This should never happen unless clap is broken
return Err("No listening addresses provided".into());
}
(None, Some(ipv6)) => {
// A single ipv6 address was provided. Set the ports
if cli_args.port6.is_some() {
warn!("When listening only over IPv6, use the --port flag. The value of --port6 will be ignored.");
}

if cli_args.discovery_port6.is_some() {
warn!("When listening only over IPv6, use the --discovery-port flag. The value of --discovery-port6 will be ignored.")
}

if cli_args.quic_port6.is_some() {
warn!("When listening only over IPv6, use the --quic-port flag. The value of --quic-port6 will be ignored.")
}

// use zero ports if required. If not, use the given port.
let tcp_port = cli_args
.use_zero_ports
.then(unused_port::unused_tcp6_port)
.transpose()?
.unwrap_or(cli_args.port);

// use zero ports if required. If not, use the specific udp port. If none given, use
// the tcp port.
let disc_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp6_port)
.transpose()?
.or(cli_args.discovery_port)
.unwrap_or(tcp_port);

let quic_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp6_port)
.transpose()?
.or(cli_args.quic_port)
.unwrap_or(if tcp_port == 0 { 0 } else { tcp_port + 1 });

ListenAddress::V6(ListenAddr {
addr: *ipv6,
quic_port,
disc_port,
tcp_port,
})
}
(Some(ipv4), None) => {
// A single ipv4 address was provided. Set the ports

// use zero ports if required. If not, use the given port.
let tcp_port = cli_args
.use_zero_ports
.then(unused_port::unused_tcp4_port)
.transpose()?
.unwrap_or(cli_args.port);
// use zero ports if required. If not, use the specific discovery port. If none given, use
// the tcp port.
let disc_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp4_port)
.transpose()?
.or(cli_args.discovery_port)
.unwrap_or(tcp_port);
// use zero ports if required. If not, use the specific quic port. If none given, use
// the tcp port + 1.
let quic_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp4_port)
.transpose()?
.or(cli_args.quic_port)
.unwrap_or(if tcp_port == 0 { 0 } else { tcp_port + 1 });

ListenAddress::V4(ListenAddr {
addr: *ipv4,
disc_port,
quic_port,
tcp_port,
})
}
(Some(ipv4), Some(ipv6)) => {
let ipv4_tcp_port = cli_args
.use_zero_ports
.then(unused_port::unused_tcp4_port)
.transpose()?
.unwrap_or(cli_args.port);
let ipv4_disc_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp4_port)
.transpose()?
.or(cli_args.discovery_port)
.unwrap_or(ipv4_tcp_port);
let ipv4_quic_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp4_port)
.transpose()?
.or(cli_args.quic_port)
.unwrap_or(if ipv4_tcp_port == 0 {
0
} else {
ipv4_tcp_port + 1
});

let ipv6_tcp_port = cli_args
.use_zero_ports
.then(unused_port::unused_tcp6_port)
.transpose()?
.unwrap_or(cli_args.port);
let ipv6_disc_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp6_port)
.transpose()?
.or(cli_args.discovery_port6)
.unwrap_or(ipv6_tcp_port);
let ipv6_quic_port = cli_args
.use_zero_ports
.then(unused_port::unused_udp6_port)
.transpose()?
.or(cli_args.quic_port6)
.unwrap_or(if ipv6_tcp_port == 0 {
0
} else {
ipv6_tcp_port + 1
});

ListenAddress::DualStack(
ListenAddr {
addr: *ipv4,
disc_port: ipv4_disc_port,
quic_port: ipv4_quic_port,
tcp_port: ipv4_tcp_port,
},
ListenAddr {
addr: *ipv6,
disc_port: ipv6_disc_port,
quic_port: ipv6_quic_port,
tcp_port: ipv6_tcp_port,
},
)
}
};

Ok(listening_addresses)
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading