mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-01-24 22:58:13 -05:00
feat(cli): add bootnode command (#15347)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
3
Cargo.lock
generated
3
Cargo.lock
generated
@@ -7127,6 +7127,7 @@ dependencies = [
|
||||
"reth-db-api",
|
||||
"reth-db-common",
|
||||
"reth-discv4",
|
||||
"reth-discv5",
|
||||
"reth-downloaders",
|
||||
"reth-ecies",
|
||||
"reth-eth-wire",
|
||||
@@ -7135,6 +7136,7 @@ dependencies = [
|
||||
"reth-evm",
|
||||
"reth-exex",
|
||||
"reth-fs-util",
|
||||
"reth-net-nat",
|
||||
"reth-network",
|
||||
"reth-network-p2p",
|
||||
"reth-network-peers",
|
||||
@@ -7158,6 +7160,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
"tokio-stream",
|
||||
"toml",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
@@ -27,6 +27,7 @@ reth-eth-wire.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-exex.workspace = true
|
||||
reth-fs-util.workspace = true
|
||||
reth-net-nat.workspace = true
|
||||
reth-network = { workspace = true, features = ["serde"] }
|
||||
reth-network-p2p.workspace = true
|
||||
reth-network-peers = { workspace = true, features = ["secp256k1"] }
|
||||
@@ -47,6 +48,8 @@ reth-trie = { workspace = true, features = ["metrics"] }
|
||||
reth-trie-db = { workspace = true, features = ["metrics"] }
|
||||
reth-trie-common = { workspace = true, optional = true }
|
||||
reth-primitives-traits.workspace = true
|
||||
reth-discv4.workspace = true
|
||||
reth-discv5.workspace = true
|
||||
|
||||
# ethereum
|
||||
alloy-eips.workspace = true
|
||||
@@ -68,6 +71,7 @@ serde_json.workspace = true
|
||||
tracing.workspace = true
|
||||
backon.workspace = true
|
||||
secp256k1 = { workspace = true, features = ["global-context", "std", "recovery"] }
|
||||
tokio-stream.workspace = true
|
||||
|
||||
# io
|
||||
fdlimit.workspace = true
|
||||
@@ -84,7 +88,6 @@ arbitrary = { workspace = true, optional = true }
|
||||
proptest-arbitrary-interop = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
reth-discv4.workspace = true
|
||||
reth-ethereum-cli.workspace = true
|
||||
|
||||
[features]
|
||||
|
||||
107
crates/cli/commands/src/p2p/bootnode.rs
Normal file
107
crates/cli/commands/src/p2p/bootnode.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
//! Standalone bootnode command
|
||||
|
||||
use clap::Parser;
|
||||
use reth_discv4::{DiscoveryUpdate, Discv4, Discv4Config};
|
||||
use reth_discv5::{discv5::Event, Config, Discv5};
|
||||
use reth_net_nat::NatResolver;
|
||||
use reth_network_peers::NodeRecord;
|
||||
use std::{net::SocketAddr, str::FromStr};
|
||||
use tokio::select;
|
||||
use tokio_stream::StreamExt;
|
||||
use tracing::info;
|
||||
|
||||
/// Satrt a discovery only bootnode.
|
||||
#[derive(Parser, Debug)]
|
||||
pub struct Command {
|
||||
/// Listen address for the bootnode (default: ":30301").
|
||||
#[arg(long, default_value = ":30301")]
|
||||
pub addr: String,
|
||||
|
||||
/// Generate a new node key and save it to the specified file.
|
||||
#[arg(long, default_value = "")]
|
||||
pub gen_key: String,
|
||||
|
||||
/// Private key filename for the node.
|
||||
#[arg(long, default_value = "")]
|
||||
pub node_key: String,
|
||||
|
||||
/// NAT resolution method (any|none|upnp|publicip|extip:\<IP\>)
|
||||
#[arg(long, default_value = "any")]
|
||||
pub nat: NatResolver,
|
||||
|
||||
/// Run a v5 topic discovery bootnode.
|
||||
#[arg(long)]
|
||||
pub v5: bool,
|
||||
}
|
||||
|
||||
impl Command {
|
||||
/// Execute the bootnode command.
|
||||
pub async fn execute(self) -> eyre::Result<()> {
|
||||
info!("Bootnode started with config: {:?}", self);
|
||||
let sk = reth_network::config::rng_secret_key();
|
||||
let socket_addr = SocketAddr::from_str(&self.addr)?;
|
||||
let local_enr = NodeRecord::from_secret_key(socket_addr, &sk);
|
||||
|
||||
let config = Discv4Config::builder().external_ip_resolver(Some(self.nat)).build();
|
||||
|
||||
let (_discv4, mut discv4_service) =
|
||||
Discv4::bind(socket_addr, local_enr, sk, config).await?;
|
||||
|
||||
info!("Started discv4 at address:{:?}", socket_addr);
|
||||
|
||||
let mut discv4_updates = discv4_service.update_stream();
|
||||
discv4_service.spawn();
|
||||
|
||||
// Optional discv5 update event listener if v5 is enabled
|
||||
let mut discv5_updates = None;
|
||||
|
||||
if self.v5 {
|
||||
info!("Starting discv5");
|
||||
let config = Config::builder(socket_addr).build();
|
||||
let (_discv5, updates, _local_enr_discv5) = Discv5::start(&sk, config).await?;
|
||||
discv5_updates = Some(updates);
|
||||
};
|
||||
|
||||
// event info loop for logging
|
||||
loop {
|
||||
select! {
|
||||
//discv4 updates
|
||||
update = discv4_updates.next() => {
|
||||
if let Some(update) = update {
|
||||
match update {
|
||||
DiscoveryUpdate::Added(record) => {
|
||||
info!("(Discv4) new peer added, peer_id={:?}", record.id);
|
||||
}
|
||||
DiscoveryUpdate::Removed(peer_id) => {
|
||||
info!("(Discv4) peer with peer-id={:?} removed", peer_id);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
} else {
|
||||
info!("(Discv4) update stream ended.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
//if discv5, discv5 update stream, else do nothing
|
||||
update = async {
|
||||
if let Some(updates) = &mut discv5_updates {
|
||||
updates.recv().await
|
||||
} else {
|
||||
futures::future::pending().await
|
||||
}
|
||||
} => {
|
||||
if let Some(update) = update {
|
||||
if let Event::SessionEstablished(enr, _) = update {
|
||||
info!("(Discv5) new peer added, peer_id={:?}", enr.id());
|
||||
}
|
||||
} else {
|
||||
info!("(Discv5) update stream ended.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ use reth_node_core::{
|
||||
utils::get_single_header,
|
||||
};
|
||||
|
||||
pub mod bootnode;
|
||||
mod rlpx;
|
||||
|
||||
/// `reth p2p` command
|
||||
|
||||
Reference in New Issue
Block a user