mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(net): IP resolution in docker (#10681)
Co-authored-by: Cody Wang <cody.wang@coinbase.com>
This commit is contained in:
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -3845,6 +3845,16 @@ dependencies = [
|
|||||||
"unicode-normalization",
|
"unicode-normalization",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "if-addrs"
|
||||||
|
version = "0.13.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a78a89907582615b19f6f0da1af18abf6ff08be259395669b834b057a7ee92d8"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"windows-sys 0.52.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "impl-codec"
|
name = "impl-codec"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -7435,6 +7445,7 @@ name = "reth-net-nat"
|
|||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
|
"if-addrs",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"reth-tracing",
|
"reth-tracing",
|
||||||
"serde_with",
|
"serde_with",
|
||||||
|
|||||||
@ -536,6 +536,7 @@ tower-http = "0.5"
|
|||||||
|
|
||||||
# p2p
|
# p2p
|
||||||
discv5 = "0.7.0"
|
discv5 = "0.7.0"
|
||||||
|
if-addrs = "0.13"
|
||||||
|
|
||||||
# rpc
|
# rpc
|
||||||
jsonrpsee = "0.24"
|
jsonrpsee = "0.24"
|
||||||
|
|||||||
5
book/cli/reth/debug/execution.md
vendored
5
book/cli/reth/debug/execution.md
vendored
@ -228,6 +228,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
--to <TO>
|
--to <TO>
|
||||||
The maximum block height
|
The maximum block height
|
||||||
|
|
||||||
|
|||||||
5
book/cli/reth/debug/in-memory-merkle.md
vendored
5
book/cli/reth/debug/in-memory-merkle.md
vendored
@ -228,6 +228,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
--retries <RETRIES>
|
--retries <RETRIES>
|
||||||
The number of retries per request
|
The number of retries per request
|
||||||
|
|
||||||
|
|||||||
5
book/cli/reth/debug/merkle.md
vendored
5
book/cli/reth/debug/merkle.md
vendored
@ -228,6 +228,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
--retries <RETRIES>
|
--retries <RETRIES>
|
||||||
The number of retries per request
|
The number of retries per request
|
||||||
|
|
||||||
|
|||||||
5
book/cli/reth/debug/replay-engine.md
vendored
5
book/cli/reth/debug/replay-engine.md
vendored
@ -228,6 +228,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
--engine-api-store <PATH>
|
--engine-api-store <PATH>
|
||||||
The path to read engine API messages from
|
The path to read engine API messages from
|
||||||
|
|
||||||
|
|||||||
5
book/cli/reth/node.md
vendored
5
book/cli/reth/node.md
vendored
@ -220,6 +220,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
RPC:
|
RPC:
|
||||||
--http
|
--http
|
||||||
Enable the HTTP-RPC server
|
Enable the HTTP-RPC server
|
||||||
|
|||||||
5
book/cli/reth/p2p.md
vendored
5
book/cli/reth/p2p.md
vendored
@ -205,6 +205,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
Datadir:
|
Datadir:
|
||||||
--datadir <DATA_DIR>
|
--datadir <DATA_DIR>
|
||||||
The path to the data dir for all reth files and subdirectories.
|
The path to the data dir for all reth files and subdirectories.
|
||||||
|
|||||||
5
book/cli/reth/stage/run.md
vendored
5
book/cli/reth/stage/run.md
vendored
@ -271,6 +271,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
Logging:
|
Logging:
|
||||||
--log.stdout.format <FORMAT>
|
--log.stdout.format <FORMAT>
|
||||||
The format to use for logs written to stdout
|
The format to use for logs written to stdout
|
||||||
|
|||||||
5
book/cli/reth/stage/unwind.md
vendored
5
book/cli/reth/stage/unwind.md
vendored
@ -233,6 +233,11 @@ Networking:
|
|||||||
|
|
||||||
[default: 25600]
|
[default: 25600]
|
||||||
|
|
||||||
|
--net-if.experimental <IF_NAME>
|
||||||
|
Name of network interface used to communicate with peers.
|
||||||
|
|
||||||
|
If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
|
||||||
--offline
|
--offline
|
||||||
If this is enabled, then all stages except headers, bodies, and sender recovery will be unwound
|
If this is enabled, then all stages except headers, bodies, and sender recovery will be unwound
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ reqwest.workspace = true
|
|||||||
serde_with = { workspace = true, optional = true }
|
serde_with = { workspace = true, optional = true }
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
tokio = { workspace = true, features = ["time"] }
|
tokio = { workspace = true, features = ["time"] }
|
||||||
|
if-addrs.workspace = true
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reth-tracing.workspace = true
|
reth-tracing.workspace = true
|
||||||
|
|||||||
@ -12,6 +12,10 @@
|
|||||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||||
|
|
||||||
|
pub mod net_if;
|
||||||
|
|
||||||
|
pub use net_if::{NetInterfaceError, DEFAULT_NET_IF_NAME};
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
fmt,
|
fmt,
|
||||||
future::{poll_fn, Future},
|
future::{poll_fn, Future},
|
||||||
|
|||||||
55
crates/net/nat/src/net_if.rs
Normal file
55
crates/net/nat/src/net_if.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
//! IP resolution on non-host Docker network.
|
||||||
|
|
||||||
|
#![cfg(not(target_os = "windows"))]
|
||||||
|
|
||||||
|
use std::{io, net::IpAddr};
|
||||||
|
|
||||||
|
/// The 'eth0' interface tends to be the default interface that docker containers use to
|
||||||
|
/// communicate with each other.
|
||||||
|
pub const DEFAULT_NET_IF_NAME: &str = "eth0";
|
||||||
|
|
||||||
|
/// Errors resolving network interface IP.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum NetInterfaceError {
|
||||||
|
/// Error reading OS interfaces.
|
||||||
|
#[error("failed to read OS interfaces: {0}")]
|
||||||
|
Io(io::Error),
|
||||||
|
/// No interface found with given name.
|
||||||
|
#[error("interface not found: {0}, found other interfaces: {1:?}")]
|
||||||
|
IFNotFound(String, Vec<String>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads IP of OS interface with given name, if exists.
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
pub fn resolve_net_if_ip(if_name: &str) -> Result<IpAddr, NetInterfaceError> {
|
||||||
|
match if_addrs::get_if_addrs() {
|
||||||
|
Ok(ifs) => {
|
||||||
|
let ip = ifs.iter().find(|i| i.name == if_name).map(|i| i.ip());
|
||||||
|
match ip {
|
||||||
|
Some(ip) => Ok(ip),
|
||||||
|
None => {
|
||||||
|
let ifs = ifs.into_iter().map(|i| i.name.as_str().into()).collect();
|
||||||
|
Err(NetInterfaceError::IFNotFound(if_name.into(), ifs))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => Err(NetInterfaceError::Io(err)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::net::Ipv4Addr;
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn read_docker_if_addr() {
|
||||||
|
const LOCALHOST_IF: [&str; 2] = ["lo0", "lo"];
|
||||||
|
|
||||||
|
let ip = resolve_net_if_ip(LOCALHOST_IF[0])
|
||||||
|
.unwrap_or_else(|_| resolve_net_if_ip(LOCALHOST_IF[1]).unwrap());
|
||||||
|
|
||||||
|
assert_eq!(ip, Ipv4Addr::LOCALHOST);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,7 +15,7 @@ use reth_discv5::{
|
|||||||
discv5::ListenConfig, DEFAULT_COUNT_BOOTSTRAP_LOOKUPS, DEFAULT_DISCOVERY_V5_PORT,
|
discv5::ListenConfig, DEFAULT_COUNT_BOOTSTRAP_LOOKUPS, DEFAULT_DISCOVERY_V5_PORT,
|
||||||
DEFAULT_SECONDS_BOOTSTRAP_LOOKUP_INTERVAL, DEFAULT_SECONDS_LOOKUP_INTERVAL,
|
DEFAULT_SECONDS_BOOTSTRAP_LOOKUP_INTERVAL, DEFAULT_SECONDS_LOOKUP_INTERVAL,
|
||||||
};
|
};
|
||||||
use reth_net_nat::NatResolver;
|
use reth_net_nat::{NatResolver, DEFAULT_NET_IF_NAME};
|
||||||
use reth_network::{
|
use reth_network::{
|
||||||
transactions::{
|
transactions::{
|
||||||
constants::{
|
constants::{
|
||||||
@ -35,6 +35,7 @@ use reth_network::{
|
|||||||
};
|
};
|
||||||
use reth_network_peers::{mainnet_nodes, TrustedPeer};
|
use reth_network_peers::{mainnet_nodes, TrustedPeer};
|
||||||
use secp256k1::SecretKey;
|
use secp256k1::SecretKey;
|
||||||
|
use tracing::error;
|
||||||
|
|
||||||
use crate::version::P2P_CLIENT_VERSION;
|
use crate::version::P2P_CLIENT_VERSION;
|
||||||
|
|
||||||
@ -148,9 +149,38 @@ pub struct NetworkArgs {
|
|||||||
/// Max capacity of cache of hashes for transactions pending fetch.
|
/// Max capacity of cache of hashes for transactions pending fetch.
|
||||||
#[arg(long = "max-tx-pending-fetch", value_name = "COUNT", default_value_t = DEFAULT_MAX_CAPACITY_CACHE_PENDING_FETCH, verbatim_doc_comment)]
|
#[arg(long = "max-tx-pending-fetch", value_name = "COUNT", default_value_t = DEFAULT_MAX_CAPACITY_CACHE_PENDING_FETCH, verbatim_doc_comment)]
|
||||||
pub max_capacity_cache_txns_pending_fetch: u32,
|
pub max_capacity_cache_txns_pending_fetch: u32,
|
||||||
|
|
||||||
|
/// Name of network interface used to communicate with peers.
|
||||||
|
///
|
||||||
|
/// If flag is set, but no value is passed, the default interface for docker `eth0` is tried.
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
#[arg(long = "net-if.experimental", conflicts_with = "addr", value_name = "IF_NAME")]
|
||||||
|
pub net_if: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NetworkArgs {
|
impl NetworkArgs {
|
||||||
|
/// Returns the resolved IP address.
|
||||||
|
pub fn resolved_addr(&self) -> IpAddr {
|
||||||
|
#[cfg(not(target_os = "windows"))]
|
||||||
|
if let Some(ref if_name) = self.net_if {
|
||||||
|
let if_name = if if_name.is_empty() { DEFAULT_NET_IF_NAME } else { if_name };
|
||||||
|
return match reth_net_nat::net_if::resolve_net_if_ip(if_name) {
|
||||||
|
Ok(addr) => addr,
|
||||||
|
Err(err) => {
|
||||||
|
error!(target: "reth::cli",
|
||||||
|
if_name,
|
||||||
|
%err,
|
||||||
|
"Failed to read network interface IP"
|
||||||
|
);
|
||||||
|
|
||||||
|
DEFAULT_DISCOVERY_ADDR
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.addr
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the resolved bootnodes if any are provided.
|
/// Returns the resolved bootnodes if any are provided.
|
||||||
pub fn resolved_bootnodes(&self) -> Option<Vec<NodeRecord>> {
|
pub fn resolved_bootnodes(&self) -> Option<Vec<NodeRecord>> {
|
||||||
self.bootnodes.clone().map(|bootnodes| {
|
self.bootnodes.clone().map(|bootnodes| {
|
||||||
@ -176,6 +206,7 @@ impl NetworkArgs {
|
|||||||
secret_key: SecretKey,
|
secret_key: SecretKey,
|
||||||
default_peers_file: PathBuf,
|
default_peers_file: PathBuf,
|
||||||
) -> NetworkConfigBuilder {
|
) -> NetworkConfigBuilder {
|
||||||
|
let addr = self.resolved_addr();
|
||||||
let chain_bootnodes = self
|
let chain_bootnodes = self
|
||||||
.resolved_bootnodes()
|
.resolved_bootnodes()
|
||||||
.unwrap_or_else(|| chain_spec.bootnodes().unwrap_or_else(mainnet_nodes));
|
.unwrap_or_else(|| chain_spec.bootnodes().unwrap_or_else(mainnet_nodes));
|
||||||
@ -224,11 +255,11 @@ impl NetworkArgs {
|
|||||||
})
|
})
|
||||||
// apply discovery settings
|
// apply discovery settings
|
||||||
.apply(|builder| {
|
.apply(|builder| {
|
||||||
let rlpx_socket = (self.addr, self.port).into();
|
let rlpx_socket = (addr, self.port).into();
|
||||||
self.discovery.apply_to_builder(builder, rlpx_socket, chain_bootnodes)
|
self.discovery.apply_to_builder(builder, rlpx_socket, chain_bootnodes)
|
||||||
})
|
})
|
||||||
.listener_addr(SocketAddr::new(
|
.listener_addr(SocketAddr::new(
|
||||||
self.addr, // set discovery port based on instance number
|
addr, // set discovery port based on instance number
|
||||||
self.port,
|
self.port,
|
||||||
))
|
))
|
||||||
.discovery_addr(SocketAddr::new(
|
.discovery_addr(SocketAddr::new(
|
||||||
@ -303,6 +334,7 @@ impl Default for NetworkArgs {
|
|||||||
max_pending_pool_imports: DEFAULT_MAX_COUNT_PENDING_POOL_IMPORTS,
|
max_pending_pool_imports: DEFAULT_MAX_COUNT_PENDING_POOL_IMPORTS,
|
||||||
max_seen_tx_history: DEFAULT_MAX_COUNT_TRANSACTIONS_SEEN_BY_PEER,
|
max_seen_tx_history: DEFAULT_MAX_COUNT_TRANSACTIONS_SEEN_BY_PEER,
|
||||||
max_capacity_cache_txns_pending_fetch: DEFAULT_MAX_CAPACITY_CACHE_PENDING_FETCH,
|
max_capacity_cache_txns_pending_fetch: DEFAULT_MAX_CAPACITY_CACHE_PENDING_FETCH,
|
||||||
|
net_if: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user