From c60cb47bd3192f9f7bf03f5034f1289597be94d9 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 6 May 2026 21:48:07 +0200 Subject: [PATCH 1/3] Remove peer_id from advertised address --- light-base/src/network_service.rs | 91 ++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) diff --git a/light-base/src/network_service.rs b/light-base/src/network_service.rs index e51cd14305..1f5cbaca92 100644 --- a/light-base/src/network_service.rs +++ b/light-base/src/network_service.rs @@ -2873,7 +2873,24 @@ async fn background_task(mut task: BackgroundTask) { let mut valid_addrs = Vec::with_capacity(addrs.len()); for addr in addrs { match Multiaddr::from_bytes(addr) { - Ok(a) => { + Ok(mut a) => { + // Advertised libp2p addresses canonically end with /p2p/. + // Strip-and-validate the suffix at this discovery boundary, + // matching the convention used for chain-spec bootnodes + // (`smoldot::chain_spec::ChainSpec::boot_nodes`). + if !pop_p2p_if_matches(&mut a, &peer_id) { + log!( + &task.platform, + Debug, + "network", + "discovered-address-peer-id-mismatch", + chain = &task.network[chain_id].log_name, + announced_peer_id = peer_id, + addr = &a, + obtained_from = requestee_peer_id + ); + continue; + } if platform::address_parse::multiaddr_to_address(&a) .ok() .map_or(false, |addr| { @@ -3481,3 +3498,75 @@ async fn background_task(mut task: BackgroundTask) { } } } + +/// If `addr` ends with `Protocol::P2p()`, validate that the embedded peer-id +/// matches `expected_peer.as_bytes()` and pop the component. Returns `false` (caller must discard +/// the address) on mismatch; `true` otherwise. No-op when the address has no `/p2p/` suffix. +/// +/// Used on the Kademlia FindNode reply path so that addresses advertised in the canonical +/// `//p2p/` form (libp2p convention) become acceptable to the transport +/// classifier in [`platform::address_parse::multiaddr_to_address`], which expects the suffix +/// to have been stripped beforehand. Validating against the announced peer-id mirrors the +/// inline strip-and-validate idiom used in `smoldot::chain_spec::ChainSpec::boot_nodes` and in +/// polkadot-sdk's `cumulus/client/bootnodes/src/advertisement.rs`. +fn pop_p2p_if_matches( + addr: &mut smoldot::libp2p::multiaddr::Multiaddr, + expected_peer: &smoldot::libp2p::peer_id::PeerId, +) -> bool { + use smoldot::libp2p::multiaddr::Protocol; + match addr.iter().last() { + Some(Protocol::P2p(mh)) => { + if mh.into_bytes() == expected_peer.as_bytes() { + addr.pop(); + true + } else { + false + } + } + _ => true, + } +} + +#[cfg(test)] +mod tests { + use super::pop_p2p_if_matches; + use smoldot::libp2p::{multiaddr::Multiaddr, peer_id::PeerId}; + + // Two distinct, valid PeerIds. The first is reused from existing smoldot tests in + // `lib/src/libp2p/multiaddr.rs:629`; the second is the bootnode peer-id observed in the + // test environment that motivated this change. + const PEER_A: &str = "12D3KooWDpJ7As7BWAwRMfu1VU2WCqNjvq387JEYKDBj4kx6nXTN"; + const PEER_B: &str = "12D3KooWQk1yQtG1YugyKjiQf6KNk8VjGGAT5xy1FWcnRKN4yXYJ"; + + fn peer(s: &str) -> PeerId { + PeerId::from_bytes(bs58::decode(s).into_vec().unwrap()).unwrap() + } + + #[test] + fn no_suffix_passes_through_unchanged() { + let mut addr: Multiaddr = "/ip4/127.0.0.1/tcp/30333/ws".parse().unwrap(); + let before = addr.clone(); + assert!(pop_p2p_if_matches(&mut addr, &peer(PEER_A))); + assert_eq!(addr, before); + } + + #[test] + fn matching_suffix_is_stripped() { + let mut addr: Multiaddr = format!("/ip4/127.0.0.1/tcp/30333/ws/p2p/{PEER_A}") + .parse() + .unwrap(); + assert!(pop_p2p_if_matches(&mut addr, &peer(PEER_A))); + let expected: Multiaddr = "/ip4/127.0.0.1/tcp/30333/ws".parse().unwrap(); + assert_eq!(addr, expected); + } + + #[test] + fn mismatched_suffix_rejects_and_keeps_addr() { + let original: Multiaddr = format!("/ip4/127.0.0.1/tcp/30333/ws/p2p/{PEER_A}") + .parse() + .unwrap(); + let mut addr = original.clone(); + assert!(!pop_p2p_if_matches(&mut addr, &peer(PEER_B))); + assert_eq!(addr, original); + } +} From 5405b21e5735844482c477237dbfcb18d7176f85 Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 6 May 2026 22:16:55 +0200 Subject: [PATCH 2/3] doc stripped --- light-base/src/lib.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/light-base/src/lib.rs b/light-base/src/lib.rs index 86137c3a64..db19da4bbe 100644 --- a/light-base/src/lib.rs +++ b/light-base/src/lib.rs @@ -1148,7 +1148,10 @@ fn start_services( let network_service_chain = network_service.add_chain(network_service::ConfigChain { log_name: log_name.clone(), - num_out_slots: 4, + // Locally bumped from 4 → 16 to test bitswap_v1_get throughput against + // the bulletin-stress-test smoldot scenario (see polkadot-bulletin-chain + // workspace `[patch.crates-io]`). Upstream this if results are good. + num_out_slots: 16, grandpa_protocol_finalized_block_height: match &config { StartServicesChainTy::SubstrateCompatible { chain_information } if matches!( From 465805b9417e81b7595f45ab68c4552d8dd9574a Mon Sep 17 00:00:00 2001 From: Michal Kucharczyk <1728078+michalkucharczyk@users.noreply.github.com> Date: Wed, 6 May 2026 22:26:30 +0200 Subject: [PATCH 3/3] doc stripped again --- light-base/src/lib.rs | 5 +---- light-base/src/network_service.rs | 16 ++-------------- 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/light-base/src/lib.rs b/light-base/src/lib.rs index db19da4bbe..86137c3a64 100644 --- a/light-base/src/lib.rs +++ b/light-base/src/lib.rs @@ -1148,10 +1148,7 @@ fn start_services( let network_service_chain = network_service.add_chain(network_service::ConfigChain { log_name: log_name.clone(), - // Locally bumped from 4 → 16 to test bitswap_v1_get throughput against - // the bulletin-stress-test smoldot scenario (see polkadot-bulletin-chain - // workspace `[patch.crates-io]`). Upstream this if results are good. - num_out_slots: 16, + num_out_slots: 4, grandpa_protocol_finalized_block_height: match &config { StartServicesChainTy::SubstrateCompatible { chain_information } if matches!( diff --git a/light-base/src/network_service.rs b/light-base/src/network_service.rs index 1f5cbaca92..2779e84e0a 100644 --- a/light-base/src/network_service.rs +++ b/light-base/src/network_service.rs @@ -2874,10 +2874,6 @@ async fn background_task(mut task: BackgroundTask) { for addr in addrs { match Multiaddr::from_bytes(addr) { Ok(mut a) => { - // Advertised libp2p addresses canonically end with /p2p/. - // Strip-and-validate the suffix at this discovery boundary, - // matching the convention used for chain-spec bootnodes - // (`smoldot::chain_spec::ChainSpec::boot_nodes`). if !pop_p2p_if_matches(&mut a, &peer_id) { log!( &task.platform, @@ -3499,16 +3495,8 @@ async fn background_task(mut task: BackgroundTask) { } } -/// If `addr` ends with `Protocol::P2p()`, validate that the embedded peer-id -/// matches `expected_peer.as_bytes()` and pop the component. Returns `false` (caller must discard -/// the address) on mismatch; `true` otherwise. No-op when the address has no `/p2p/` suffix. -/// -/// Used on the Kademlia FindNode reply path so that addresses advertised in the canonical -/// `//p2p/` form (libp2p convention) become acceptable to the transport -/// classifier in [`platform::address_parse::multiaddr_to_address`], which expects the suffix -/// to have been stripped beforehand. Validating against the announced peer-id mirrors the -/// inline strip-and-validate idiom used in `smoldot::chain_spec::ChainSpec::boot_nodes` and in -/// polkadot-sdk's `cumulus/client/bootnodes/src/advertisement.rs`. +/// Pops a trailing `/p2p/` from `addr` if it matches `expected_peer`. Returns `false` +/// (caller must discard the address) on mismatch. fn pop_p2p_if_matches( addr: &mut smoldot::libp2p::multiaddr::Multiaddr, expected_peer: &smoldot::libp2p::peer_id::PeerId,