diff --git a/Cargo.lock b/Cargo.lock index 51d5fdc83d895..2692396be62da 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6514,6 +6514,7 @@ dependencies = [ "comfy-table", "confy", "crossterm", + "discv5", "eyre", "fdlimit", "futures", @@ -6533,12 +6534,16 @@ dependencies = [ "reth-db-api", "reth-db-common", "reth-discv4", + "reth-discv5", "reth-downloaders", + "reth-ecies", + "reth-eth-wire", "reth-evm", "reth-exex", "reth-fs-util", "reth-network", "reth-network-p2p", + "reth-network-peers", "reth-node-builder", "reth-node-core", "reth-node-events", @@ -6549,6 +6554,7 @@ dependencies = [ "reth-static-file", "reth-static-file-types", "reth-trie", + "secp256k1", "serde", "serde_json", "tokio", diff --git a/crates/cli/commands/Cargo.toml b/crates/cli/commands/Cargo.toml index 35ed25eda66d8..86b0cde59945e 100644 --- a/crates/cli/commands/Cargo.toml +++ b/crates/cli/commands/Cargo.toml @@ -20,11 +20,15 @@ reth-db = { workspace = true, features = ["mdbx"] } reth-db-api.workspace = true reth-db-common.workspace = true reth-downloaders.workspace = true +reth-discv5.workspace = true +reth-ecies.workspace = true +reth-eth-wire.workspace = true reth-evm.workspace = true reth-exex.workspace = true reth-fs-util.workspace = true reth-network = { workspace = true, features = ["serde"] } reth-network-p2p.workspace = true +reth-network-peers = { workspace = true, features = ["secp256k1"] } reth-node-builder.workspace = true reth-node-core.workspace = true reth-node-events.workspace = true @@ -39,6 +43,7 @@ reth-trie = { workspace = true, features = ["metrics"] } itertools.workspace = true futures.workspace = true tokio.workspace = true +discv5 = { workspace = true, features = ["libp2p"] } # misc ahash = "0.8" @@ -49,6 +54,7 @@ serde.workspace = true serde_json.workspace = true tracing.workspace = true backon.workspace = true +secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery"] } # io fdlimit.workspace = true diff --git a/crates/cli/commands/src/p2p.rs b/crates/cli/commands/src/p2p/mod.rs similarity index 96% rename from crates/cli/commands/src/p2p.rs rename to crates/cli/commands/src/p2p/mod.rs index 0fdefac8bd886..e004a9a245ef8 100644 --- a/crates/cli/commands/src/p2p.rs +++ b/crates/cli/commands/src/p2p/mod.rs @@ -17,6 +17,8 @@ use reth_node_core::{ use reth_primitives::BlockHashOrNumber; use std::{path::PathBuf, sync::Arc}; +mod rlpx; + /// `reth p2p` command #[derive(Debug, Parser)] pub struct Command { @@ -68,10 +70,12 @@ pub enum Subcommands { #[arg(value_parser = hash_or_num_value_parser)] id: BlockHashOrNumber, }, + // RLPx utilities + Rlpx(rlpx::Command), } impl Command { /// Execute `p2p` command - pub async fn execute(&self) -> eyre::Result<()> { + pub async fn execute(self) -> eyre::Result<()> { let data_dir = self.datadir.clone().resolve_datadir(self.chain.chain); let config_path = self.config.clone().unwrap_or_else(|| data_dir.config()); @@ -151,6 +155,9 @@ impl Command { let body = result.into_iter().next().unwrap(); println!("Successfully downloaded body: {body:?}") } + Subcommands::Rlpx(command) => { + command.execute().await?; + } } Ok(()) diff --git a/crates/cli/commands/src/p2p/rlpx.rs b/crates/cli/commands/src/p2p/rlpx.rs new file mode 100644 index 0000000000000..fa667120ba0da --- /dev/null +++ b/crates/cli/commands/src/p2p/rlpx.rs @@ -0,0 +1,54 @@ +//! RLPx subcommand of P2P Debugging tool. + +use clap::{Parser, Subcommand}; +use discv5::Enr; +use reth_discv5::enr::EnrCombinedKeyWrapper; +use reth_ecies::stream::ECIESStream; +use reth_eth_wire::{HelloMessage, UnauthedP2PStream}; +use reth_network::config::rng_secret_key; +use reth_network_peers::{pk2id, NodeRecord}; +use secp256k1::SECP256K1; +use tokio::net::TcpStream; + +/// The arguments for the `reth p2p rlpx` command +#[derive(Parser, Debug)] +pub struct Command { + #[clap(subcommand)] + subcommand: Subcommands, +} + +impl Command { + // Execute `p2p rlpx` command. + pub async fn execute(self) -> eyre::Result<()> { + match self.subcommand { + Subcommands::Ping { node } => { + let key = rng_secret_key(); + let enr = node.parse::().unwrap(); + let enr = EnrCombinedKeyWrapper(enr).into(); + let node_record = NodeRecord::try_from(&enr).unwrap(); + let outgoing = + TcpStream::connect((node_record.address, node_record.tcp_port)).await?; + let ecies_stream = ECIESStream::connect(outgoing, key, node_record.id).await?; + + let peer_id = pk2id(&key.public_key(SECP256K1)); + let hello = HelloMessage::builder(peer_id).build(); + + let (_, their_hello) = + UnauthedP2PStream::new(ecies_stream).handshake(hello).await?; + + println!("{:#?}", their_hello); + } + } + Ok(()) + } +} + +#[derive(Subcommand, Debug)] +enum Subcommands { + /// ping node + Ping { + /// The node to ping. + #[arg(long, short)] + node: String, + }, +}