implement part of reth p2p rlpx ping (#9762)

Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
int88
2024-08-03 12:36:36 +08:00
committed by GitHub
parent 52cdcf0a9a
commit 2bfa2defc4
10 changed files with 281 additions and 2 deletions

4
Cargo.lock generated
View File

@ -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",

View File

@ -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)

2
book/cli/SUMMARY.md vendored
View File

@ -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)

View File

@ -9,6 +9,7 @@ Usage: reth p2p [OPTIONS] <COMMAND>
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:

104
book/cli/reth/p2p/rlpx.md vendored Normal file
View File

@ -0,0 +1,104 @@
# reth p2p rlpx
RLPx commands
```bash
$ reth p2p rlpx --help
Usage: reth p2p rlpx [OPTIONS] <COMMAND>
Commands:
ping ping node
help Print this message or the help of the given subcommand(s)
Options:
--instance <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 <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 <FILTER>
The filter to use for logs written to stdout
[default: ]
--log.file.format <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 <FILTER>
The filter to use for logs written to the log file
[default: debug]
--log.file.directory <PATH>
The path to put log files in
[default: <CACHE_DIR>/logs]
--log.file.max-size <SIZE>
The maximum size (in MB) of one log file
[default: 200]
--log.file.max-files <COUNT>
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 <FILTER>
The filter to use for logs written to journald
[default: error]
--color <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
```

104
book/cli/reth/p2p/rlpx/ping.md vendored Normal file
View File

@ -0,0 +1,104 @@
# reth p2p rlpx ping
ping node
```bash
$ reth p2p rlpx ping --help
Usage: reth p2p rlpx ping [OPTIONS] <NODE>
Arguments:
<NODE>
The node to ping
Options:
--instance <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 <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 <FILTER>
The filter to use for logs written to stdout
[default: ]
--log.file.format <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 <FILTER>
The filter to use for logs written to the log file
[default: debug]
--log.file.directory <PATH>
The path to put log files in
[default: <CACHE_DIR>/logs]
--log.file.max-size <SIZE>
The maximum size (in MB) of one log file
[default: 200]
--log.file.max-files <COUNT>
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 <FILTER>
The filter to use for logs written to journald
[default: error]
--color <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
```

View File

@ -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

View File

@ -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(())

View File

@ -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,
},
}

View File

@ -302,7 +302,7 @@ impl<S> P2PStream<S> {
}
/// 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)));
}
}