diff --git a/src/node/handlers/discovery.rs b/src/node/handlers/discovery.rs index 9a66477..3df02a6 100644 --- a/src/node/handlers/discovery.rs +++ b/src/node/handlers/discovery.rs @@ -7,13 +7,13 @@ use crate::node::Node; use crate::node::reject::DiscoveryReject; -use crate::proto::discovery::{DiscoveryAction, LookupRequest, LookupResponse}; +use crate::proto::discovery::{ + DiscoveryAction, LookupRequest, LookupResponse, MAX_RECENT_DISCOVERY_REQUESTS, +}; use crate::transport::{TransportAddr, TransportId}; use crate::{NodeAddr, PeerIdentity}; use tracing::{debug, info, trace, warn}; -const MAX_RECENT_DISCOVERY_REQUESTS: usize = 4096; - /// Shell adapter exposing the live routing tables to the sans-IO discovery /// core's `RoutingView` read seam. Lives in `node` so it can read `Node`'s /// private `peers` map and call the crate-private tree/bloom predicates. @@ -483,7 +483,11 @@ impl Node { let origin = *self.node_addr(); let origin_coords = self.tree_state().my_coords().clone(); - let request = LookupRequest::generate(*target, origin, origin_coords, ttl, 0); + let request_id = { + use rand::RngExt; + rand::rng().random() + }; + let request = LookupRequest::new(request_id, *target, origin, origin_coords, ttl, 0); // Tree-peer bloom-match selection + single encode live in the sans-IO // core. The core keeps the tree-only (no non-tree fallback) behavior; diff --git a/src/node/tests/discovery.rs b/src/node/tests/discovery.rs index 7d823c8..21eb6fd 100644 --- a/src/node/tests/discovery.rs +++ b/src/node/tests/discovery.rs @@ -1022,11 +1022,11 @@ async fn test_open_discovery_sweep_queues_eligible_skips_filtered() { /// (t=1100ms, 3100ms, 7100ms) and unreachable at t=15100ms. /// 2. **Fresh `initiate_lookup` per attempt** — `req_initiated` counter /// increments by exactly one on each retry. The actual `request_id` -/// is generated by `LookupRequest::generate(...)` via `rand::random()` -/// inside `initiate_lookup` and is not stored on the originator -/// side, so per-attempt freshness is verified indirectly: each -/// `req_initiated` increment corresponds to one fresh -/// `LookupRequest::generate` call. +/// is drawn via `rand::rng().random()` at the shell inside +/// `initiate_lookup` and passed to `LookupRequest::new(...)`; it is +/// not stored on the originator side, so per-attempt freshness is +/// verified indirectly: each `req_initiated` increment corresponds +/// to one fresh `initiate_lookup` call. /// 3. **Final-timeout state transitions** — `pending_lookups` entry is /// removed, `discovery.resp_timed_out` counter ticks, queued packet /// is drained, and an ICMPv6 Destination Unreachable frame is diff --git a/src/proto/discovery/limits.rs b/src/proto/discovery/limits.rs index aed6cf6..c3e9dc6 100644 --- a/src/proto/discovery/limits.rs +++ b/src/proto/discovery/limits.rs @@ -16,6 +16,14 @@ use crate::NodeAddr; use alloc::collections::BTreeMap; +// ============================================================================ +// Receive-side: Request dedup cache bound +// ============================================================================ + +/// Maximum number of recent LookupRequests retained for dedup and +/// reverse-path routing before the cache is treated as full. +pub(crate) const MAX_RECENT_DISCOVERY_REQUESTS: usize = 4096; + // ============================================================================ // Originator-side: Discovery Backoff // ============================================================================ diff --git a/src/proto/discovery/mod.rs b/src/proto/discovery/mod.rs index f3c68cd..883b85e 100644 --- a/src/proto/discovery/mod.rs +++ b/src/proto/discovery/mod.rs @@ -26,7 +26,9 @@ pub(crate) use core::{ initiate_gate, on_response_accepted, plan_forward, plan_initiate, plan_response_route, poll_pending, }; -pub(crate) use limits::{DiscoveryBackoff, DiscoveryForwardRateLimiter}; +pub(crate) use limits::{ + DiscoveryBackoff, DiscoveryForwardRateLimiter, MAX_RECENT_DISCOVERY_REQUESTS, +}; #[cfg(test)] pub(crate) use state::RecentRequest; pub(crate) use state::{Discovery, PendingLookup}; diff --git a/src/proto/discovery/tests/wire.rs b/src/proto/discovery/tests/wire.rs index 12e0092..29f5dc1 100644 --- a/src/proto/discovery/tests/wire.rs +++ b/src/proto/discovery/tests/wire.rs @@ -36,8 +36,9 @@ fn test_lookup_request_generate() { let origin = make_node_addr(2); let coords = make_coords(&[2, 0]); - let req1 = LookupRequest::generate(target, origin, coords.clone(), 5, 0); - let req2 = LookupRequest::generate(target, origin, coords, 5, 0); + use rand::RngExt; + let req1 = LookupRequest::new(rand::rng().random(), target, origin, coords.clone(), 5, 0); + let req2 = LookupRequest::new(rand::rng().random(), target, origin, coords, 5, 0); // Random IDs should differ assert_ne!(req1.request_id, req2.request_id); diff --git a/src/proto/discovery/wire.rs b/src/proto/discovery/wire.rs index de7a80a..e61806c 100644 --- a/src/proto/discovery/wire.rs +++ b/src/proto/discovery/wire.rs @@ -48,19 +48,6 @@ impl LookupRequest { } } - /// Generate a new request with a random ID. - pub fn generate( - target: NodeAddr, - origin: NodeAddr, - origin_coords: TreeCoordinate, - ttl: u8, - min_mtu: u16, - ) -> Self { - use rand::RngExt; - let request_id = rand::rng().random(); - Self::new(request_id, target, origin, origin_coords, ttl, min_mtu) - } - /// Decrement TTL for forwarding. /// /// Returns false if TTL was already 0.