diff --git a/rust/Cargo.lock b/rust/Cargo.lock index 3e5bbcee3ba..c9761ad9e7e 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -11058,6 +11058,7 @@ dependencies = [ "alloy-op-evm", "alloy-op-hardforks", "alloy-primitives", + "alloy-rpc-types-admin", "alloy-rpc-types-engine", "alloy-rpc-types-eth", "clap", diff --git a/rust/op-reth/crates/node/Cargo.toml b/rust/op-reth/crates/node/Cargo.toml index 92df4eaf961..de80e7caceb 100644 --- a/rust/op-reth/crates/node/Cargo.toml +++ b/rust/op-reth/crates/node/Cargo.toml @@ -102,6 +102,7 @@ reth-trie-db.workspace = true alloy-network.workspace = true alloy-op-evm.workspace = true alloy-op-hardforks.workspace = true +alloy-rpc-types-admin.workspace = true futures.workspace = true op-alloy-network.workspace = true diff --git a/rust/op-reth/crates/node/tests/it/main.rs b/rust/op-reth/crates/node/tests/it/main.rs index 87fa15a8299..f49ed997a2e 100644 --- a/rust/op-reth/crates/node/tests/it/main.rs +++ b/rust/op-reth/crates/node/tests/it/main.rs @@ -8,4 +8,6 @@ mod rpc; mod custom_genesis; +mod p2p_version; + const fn main() {} diff --git a/rust/op-reth/crates/node/tests/it/p2p_version.rs b/rust/op-reth/crates/node/tests/it/p2p_version.rs new file mode 100644 index 00000000000..1640cbec7e2 --- /dev/null +++ b/rust/op-reth/crates/node/tests/it/p2p_version.rs @@ -0,0 +1,41 @@ +//! Verifies that two op-reth nodes negotiate the expected eth wire protocol version. +//! +//! The test is intentionally written to fail when upstream reth bumps the negotiated +//! version. That failure is the signal: it forces a conscious review of the new +//! version's behavior before we ship it, rather than silently inheriting a protocol +//! change on the next reth bump. + +use alloy_rpc_types_admin::EthPeerInfo; +use reth_optimism_node::utils::setup; +use reth_rpc_api::servers::AdminApiServer; +use std::time::Duration; +use tokio::time::{sleep, timeout}; + +const EXPECTED_ETH_VERSION: u64 = 69; + +#[tokio::test] +async fn peers_negotiate_eth_69() -> eyre::Result<()> { + reth_tracing::init_test_tracing(); + + let (nodes, _wallet) = setup(2).await?; + let admin_a = nodes[0].inner.add_ons_handle.admin_api(); + + let negotiated = timeout(Duration::from_secs(30), async { + loop { + let peers = admin_a.peers().await.expect("admin_peers rpc call"); + for p in peers { + if let Some(EthPeerInfo::Info(info)) = p.protocols.eth { + return info.version; + } + } + sleep(Duration::from_millis(200)).await; + } + }) + .await?; + + assert_eq!( + negotiated, EXPECTED_ETH_VERSION, + "expected eth/{EXPECTED_ETH_VERSION}, got eth/{negotiated}" + ); + Ok(()) +}