reth_cli_commands/p2p/
bootnode.rs1use clap::Parser;
4use reth_cli_util::{get_secret_key, load_secret_key::rng_secret_key};
5use reth_discv4::{DiscoveryUpdate, Discv4, Discv4Config};
6use reth_discv5::{discv5::Event, Config, Discv5};
7use reth_net_nat::NatResolver;
8use reth_network_peers::NodeRecord;
9use secp256k1::SecretKey;
10use std::{net::SocketAddr, path::PathBuf};
11use tokio::select;
12use tokio_stream::StreamExt;
13use tracing::info;
14
15#[derive(Parser, Debug)]
17pub struct Command {
18 #[arg(long, default_value = "0.0.0.0:30301")]
20 pub addr: SocketAddr,
21
22 #[arg(long, value_name = "PATH")]
29 pub p2p_secret_key: Option<PathBuf>,
30
31 #[arg(long, default_value = "any")]
33 pub nat: NatResolver,
34
35 #[arg(long)]
37 pub v5: bool,
38}
39
40impl Command {
41 pub async fn execute(self) -> eyre::Result<()> {
43 info!("Bootnode started with config: {self:?}");
44
45 let sk = self.network_secret()?;
46 let local_enr = NodeRecord::from_secret_key(self.addr, &sk);
47
48 let config = Discv4Config::builder().external_ip_resolver(Some(self.nat)).build();
49
50 let (_discv4, mut discv4_service) = Discv4::bind(self.addr, local_enr, sk, config).await?;
51
52 info!("Started discv4 at address: {local_enr:?}");
53
54 let mut discv4_updates = discv4_service.update_stream();
55 discv4_service.spawn();
56
57 let mut discv5_updates = None;
59
60 if self.v5 {
61 info!("Starting discv5");
62 let config = Config::builder(self.addr).build();
63 let (_discv5, updates, _local_enr_discv5) = Discv5::start(&sk, config).await?;
64 discv5_updates = Some(updates);
65 };
66
67 loop {
69 select! {
70 update = discv4_updates.next() => {
72 if let Some(update) = update {
73 match update {
74 DiscoveryUpdate::Added(record) => {
75 info!("(Discv4) new peer added, peer_id={:?}", record.id);
76 }
77 DiscoveryUpdate::Removed(peer_id) => {
78 info!("(Discv4) peer with peer-id={:?} removed", peer_id);
79 }
80 _ => {}
81 }
82 } else {
83 info!("(Discv4) update stream ended.");
84 break;
85 }
86 }
87 update = async {
89 if let Some(updates) = &mut discv5_updates {
90 updates.recv().await
91 } else {
92 futures::future::pending().await
93 }
94 } => {
95 if let Some(update) = update {
96 if let Event::SessionEstablished(enr, _) = update {
97 info!("(Discv5) new peer added, peer_id={:?}", enr.id());
98 }
99 } else {
100 info!("(Discv5) update stream ended.");
101 break;
102 }
103 }
104 }
105 }
106
107 Ok(())
108 }
109
110 fn network_secret(&self) -> eyre::Result<SecretKey> {
111 match &self.p2p_secret_key {
112 Some(path) => Ok(get_secret_key(path)?),
113 None => Ok(rng_secret_key()),
114 }
115 }
116}