Skip to content

Commit

Permalink
Stub network crate (#43)
Browse files Browse the repository at this point in the history
Co-authored-by: Age Manning <[email protected]>
  • Loading branch information
jimmygchen and AgeManning authored Nov 1, 2024
1 parent 09e7aaa commit 4956972
Show file tree
Hide file tree
Showing 18 changed files with 1,519 additions and 307 deletions.
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

0 comments on commit 4956972

Please sign in to comment.