Skip to main content

bb_runtime/framework/
inbound_dedup.rs

1//! `InboundDedup` - sliding-window seen-message tracker per
2//! ENGINE.md §10.4.
3//!
4//! Recv-flavoured wire ops consult this set to discard envelopes
5//! that repeat a recently-seen message hash. Storage is bounded -
6//! when the window fills, the oldest entry is evicted.
7//!
8//! lands a simple LRU-by-insertion-order implementation;
9use std::collections::{HashSet, VecDeque};
10
11/// Default rolling window (8192 distinct message hashes). Picked to
12/// be roughly 2× the default ingress capacity so duplicates from
13/// concurrent peers don't collide with recent legit traffic.
14pub const DEFAULT_WINDOW_SIZE: usize = 8192;
15
16/// Sliding-window seen-message tracker.
17pub struct InboundDedup {
18    seen: HashSet<u64>,
19    order: VecDeque<u64>,
20    capacity: usize,
21}
22
23impl Default for InboundDedup {
24    fn default() -> Self {
25        Self::new()
26    }
27}
28
29impl InboundDedup {
30    /// Construct with the default window size.
31    pub fn new() -> Self {
32        Self::with_capacity(DEFAULT_WINDOW_SIZE)
33    }
34
35    /// Construct with a custom window size. Sizes below 1 are
36    /// clamped to 1.
37    pub fn with_capacity(capacity: usize) -> Self {
38        let capacity = capacity.max(1);
39        Self {
40            seen: HashSet::with_capacity(capacity),
41            order: VecDeque::with_capacity(capacity),
42            capacity,
43        }
44    }
45
46    /// Has this hash been seen within the current window?
47    pub fn contains(&self, hash: u64) -> bool {
48        self.seen.contains(&hash)
49    }
50
51    /// Mark `hash` as seen. Returns `true` if the entry was
52    /// already present (a duplicate). On insertion the oldest
53    /// entry is evicted if the window is full.
54    pub fn record(&mut self, hash: u64) -> bool {
55        if !self.seen.insert(hash) {
56            return true;
57        }
58        self.order.push_back(hash);
59        if self.order.len() > self.capacity {
60            if let Some(evicted) = self.order.pop_front() {
61                self.seen.remove(&evicted);
62            }
63        }
64        false
65    }
66
67    /// Clear the entire window.
68    pub fn clear(&mut self) {
69        self.seen.clear();
70        self.order.clear();
71    }
72
73    /// Current window size (number of distinct entries).
74    pub fn len(&self) -> usize {
75        self.order.len()
76    }
77
78    /// `true` when no messages have been recorded yet.
79    pub fn is_empty(&self) -> bool {
80        self.order.is_empty()
81    }
82
83    /// Configured window capacity.
84    pub fn capacity(&self) -> usize {
85        self.capacity
86    }
87}
88