From 2bfa2defc4c8159d447905886b287046344465eb Mon Sep 17 00:00:00 2001 From: int88 <106391185+int88@users.noreply.github.com> Date: Sat, 3 Aug 2024 12:36:36 +0800 Subject: [PATCH] implement part of `reth p2p rlpx ping` (#9762) Co-authored-by: Matthias Seitz --- Cargo.lock | 4 + book/SUMMARY.md | 2 + book/cli/SUMMARY.md | 2 + book/cli/reth/p2p.md | 1 + book/cli/reth/p2p/rlpx.md | 104 ++++++++++++++++++ book/cli/reth/p2p/rlpx/ping.md | 104 ++++++++++++++++++ crates/cli/commands/Cargo.toml | 4 + .../cli/commands/src/{p2p.rs => p2p/mod.rs} | 9 +- crates/cli/commands/src/p2p/rlpx.rs | 51 +++++++++ crates/net/eth-wire/src/p2pstream.rs | 2 +- 10 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 book/cli/reth/p2p/rlpx.md create mode 100644 book/cli/reth/p2p/rlpx/ping.md rename crates/cli/commands/src/{p2p.rs => p2p/mod.rs} (96%) create mode 100644 crates/cli/commands/src/p2p/rlpx.rs diff --git a/Cargo.lock b/Cargo.lock index 9fdcf1374257..d3cdeb97d44b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6560,11 +6560,14 @@ dependencies = [ "reth-db-common", "reth-discv4", "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", @@ -6577,6 +6580,7 @@ dependencies = [ "reth-static-file-types", "reth-trie", "reth-trie-db", + "secp256k1", "serde", "serde_json", "tokio", diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 69f88b285349..f93daeaba397 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -62,6 +62,8 @@ - [`reth p2p`](./cli/reth/p2p.md) - [`reth p2p header`](./cli/reth/p2p/header.md) - [`reth p2p body`](./cli/reth/p2p/body.md) + - [`reth p2p rlpx`](./cli/reth/p2p/rlpx.md) + - [`reth p2p rlpx ping`](./cli/reth/p2p/rlpx/ping.md) - [`reth config`](./cli/reth/config.md) - [`reth debug`](./cli/reth/debug.md) - [`reth debug execution`](./cli/reth/debug/execution.md) diff --git a/book/cli/SUMMARY.md b/book/cli/SUMMARY.md index 5f02f1e9ee04..4cc86c7a3649 100644 --- a/book/cli/SUMMARY.md +++ b/book/cli/SUMMARY.md @@ -32,6 +32,8 @@ - [`reth p2p`](./reth/p2p.md) - [`reth p2p header`](./reth/p2p/header.md) - [`reth p2p body`](./reth/p2p/body.md) + - [`reth p2p rlpx`](./reth/p2p/rlpx.md) + - [`reth p2p rlpx ping`](./reth/p2p/rlpx/ping.md) - [`reth config`](./reth/config.md) - [`reth debug`](./reth/debug.md) - [`reth debug execution`](./reth/debug/execution.md) diff --git a/book/cli/reth/p2p.md b/book/cli/reth/p2p.md index 5bc48aaf02b8..1b031049fac8 100644 --- a/book/cli/reth/p2p.md +++ b/book/cli/reth/p2p.md @@ -9,6 +9,7 @@ Usage: reth p2p [OPTIONS] Commands: header Download block header body Download block body + rlpx RLPx commands help Print this message or the help of the given subcommand(s) Options: diff --git a/book/cli/reth/p2p/rlpx.md b/book/cli/reth/p2p/rlpx.md new file mode 100644 index 000000000000..dd73e437aa42 --- /dev/null +++ b/book/cli/reth/p2p/rlpx.md @@ -0,0 +1,104 @@ +# reth p2p rlpx + +RLPx commands + +```bash +$ reth p2p rlpx --help +Usage: reth p2p rlpx [OPTIONS] + +Commands: + ping ping node + help Print this message or the help of the given subcommand(s) + +Options: + --instance + Add a new instance of a node. + + Configures the ports of the node to avoid conflicts with the defaults. This is useful for running multiple nodes on the same machine. + + Max number of instances is 200. It is chosen in a way so that it's not possible to have port numbers that conflict with each other. + + Changes to the following port numbers: - `DISCOVERY_PORT`: default + `instance` - 1 - `AUTH_PORT`: default + `instance` * 100 - 100 - `HTTP_RPC_PORT`: default - `instance` + 1 - `WS_RPC_PORT`: default + `instance` * 2 - 2 + + [default: 1] + + -h, --help + Print help (see a summary with '-h') + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + [default: always] + + Possible values: + - always: Colors on + - auto: Colors on + - never: Colors off + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output +``` \ No newline at end of file diff --git a/book/cli/reth/p2p/rlpx/ping.md b/book/cli/reth/p2p/rlpx/ping.md new file mode 100644 index 000000000000..222b57735bc3 --- /dev/null +++ b/book/cli/reth/p2p/rlpx/ping.md @@ -0,0 +1,104 @@ +# reth p2p rlpx ping + +ping node + +```bash +$ reth p2p rlpx ping --help +Usage: reth p2p rlpx ping [OPTIONS] + +Arguments: + + The node to ping + +Options: + --instance + Add a new instance of a node. + + Configures the ports of the node to avoid conflicts with the defaults. This is useful for running multiple nodes on the same machine. + + Max number of instances is 200. It is chosen in a way so that it's not possible to have port numbers that conflict with each other. + + Changes to the following port numbers: - `DISCOVERY_PORT`: default + `instance` - 1 - `AUTH_PORT`: default + `instance` * 100 - 100 - `HTTP_RPC_PORT`: default - `instance` + 1 - `WS_RPC_PORT`: default + `instance` * 2 - 2 + + [default: 1] + + -h, --help + Print help (see a summary with '-h') + +Logging: + --log.stdout.format + The format to use for logs written to stdout + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.stdout.filter + The filter to use for logs written to stdout + + [default: ] + + --log.file.format + The format to use for logs written to the log file + + [default: terminal] + + Possible values: + - json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging + - log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications + - terminal: Represents terminal-friendly formatting for logs + + --log.file.filter + The filter to use for logs written to the log file + + [default: debug] + + --log.file.directory + The path to put log files in + + [default: /logs] + + --log.file.max-size + The maximum size (in MB) of one log file + + [default: 200] + + --log.file.max-files + The maximum amount of log files that will be stored. If set to 0, background file logging is disabled + + [default: 5] + + --log.journald + Write logs to journald + + --log.journald.filter + The filter to use for logs written to journald + + [default: error] + + --color + Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting + + [default: always] + + Possible values: + - always: Colors on + - auto: Colors on + - never: Colors off + +Display: + -v, --verbosity... + Set the minimum log level. + + -v Errors + -vv Warnings + -vvv Info + -vvvv Debug + -vvvvv Traces (warning: very verbose!) + + -q, --quiet + Silence all log output +``` \ No newline at end of file diff --git a/crates/cli/commands/Cargo.toml b/crates/cli/commands/Cargo.toml index 1d9983ad8d45..673cd179934c 100644 --- a/crates/cli/commands/Cargo.toml +++ b/crates/cli/commands/Cargo.toml @@ -20,11 +20,14 @@ reth-db = { workspace = true, features = ["mdbx"] } reth-db-api.workspace = true reth-db-common.workspace = true reth-downloaders.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 @@ -51,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 659e63387b0d..9c1b45eb20dd 100644 --- a/crates/cli/commands/src/p2p.rs +++ b/crates/cli/commands/src/p2p/mod.rs @@ -18,6 +18,8 @@ use reth_node_core::{ }; use reth_primitives::BlockHashOrNumber; +mod rlpx; + /// `reth p2p` command #[derive(Debug, Parser)] pub struct Command { @@ -69,10 +71,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()); @@ -152,6 +156,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 000000000000..f0bd5e6328bb --- /dev/null +++ b/crates/cli/commands/src/p2p/rlpx.rs @@ -0,0 +1,51 @@ +//! RLPx subcommand of P2P Debugging tool. + +use clap::{Parser, Subcommand}; +use reth_ecies::stream::ECIESStream; +use reth_eth_wire::{HelloMessage, UnauthedP2PStream}; +use reth_network::config::rng_secret_key; +use reth_network_peers::{pk2id, AnyNode}; +use secp256k1::SECP256K1; +use tokio::net::TcpStream; + +/// RLPx commands +#[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 node_record = node + .node_record() + .ok_or_else(|| eyre::eyre!("failed to parse node {}", node))?; + 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. + node: AnyNode, + }, +} diff --git a/crates/net/eth-wire/src/p2pstream.rs b/crates/net/eth-wire/src/p2pstream.rs index 466987768ead..01394e8648ce 100644 --- a/crates/net/eth-wire/src/p2pstream.rs +++ b/crates/net/eth-wire/src/p2pstream.rs @@ -302,7 +302,7 @@ impl P2PStream { } /// Queues in a _snappy_ encoded [`P2PMessage::Ping`] message. - fn send_ping(&mut self) { + pub fn send_ping(&mut self) { self.outgoing_messages.push_back(Bytes::from(alloy_rlp::encode(P2PMessage::Ping))); } }