Skip to main content

commonware_broadcast/buffered/
mod.rs

1//! Broadcast messages to and cache messages from untrusted peers.
2//!
3//! # Overview
4//!
5//! The core of the module is the [Engine]. It is responsible for:
6//! - Accepting and caching messages from other participants
7//! - Broadcasting messages to all peers
8//! - Serving cached messages on-demand
9//!
10//! # Message Caching
11//!
12//! The engine receives messages from other peers and caches them. The cache is a bounded queue of
13//! messages per peer. When the cache is full, the oldest message is removed to make room for the
14//! new one.
15//!
16//! Messages referenced by multiple senders stay cached until the last per-sender deque that
17//! contains them is evicted (meaning redundant messages are only stored once).
18//!
19//! # Peer Management
20//!
21//! Only peers in `latest.primary` may buffer messages (see [commonware_p2p::Provider]). When a peer
22//! is no longer in `latest.primary`, its buffered messages are evicted unless buffered by any other
23//! primary peer.
24
25mod config;
26pub use config::Config;
27mod engine;
28pub use engine::Engine;
29mod ingress;
30pub use ingress::Mailbox;
31pub(crate) use ingress::Message;
32mod metrics;
33
34#[cfg(test)]
35pub mod mocks;
36
37#[cfg(test)]
38mod tests {
39    use super::{mocks::TestMessage, *};
40    use crate::Broadcaster;
41    use commonware_actor::{
42        mailbox::{Overflow, Policy},
43        Feedback,
44    };
45    use commonware_codec::RangeCfg;
46    use commonware_cryptography::{
47        ed25519::{PrivateKey, PublicKey},
48        Digestible, Hasher, Sha256, Signer as _,
49    };
50    use commonware_macros::test_traced;
51    use commonware_p2p::{
52        simulated::{Link, Network, Oracle, Receiver, Sender},
53        Manager as _, Recipients, Sender as _, TrackedPeers,
54    };
55    use commonware_runtime::{
56        deterministic, telemetry::metrics::count_running_tasks, Clock, Error, IoBuf, Metrics as _,
57        Quota, Runner, Supervisor as _,
58    };
59    use commonware_utils::NZUsize;
60    use std::{
61        collections::{BTreeMap, VecDeque},
62        num::NonZeroU32,
63        time::Duration,
64    };
65
66    // Number of messages to cache per sender
67    const CACHE_SIZE: usize = 10;
68
69    // Enough time to receive a cached message. Cannot be instantaneous as the test runtime
70    // requires some time to switch context.
71    const A_JIFFY: Duration = Duration::from_millis(10);
72
73    // Network speed for the simulated network
74    const NETWORK_SPEED: Duration = Duration::from_millis(100);
75
76    // Enough time for a message to propagate through the network
77    const NETWORK_SPEED_WITH_BUFFER: Duration = Duration::from_millis(200);
78
79    /// Default rate limit set high enough to not interfere with normal operation
80    const TEST_QUOTA: Quota = Quota::per_second(NonZeroU32::MAX);
81
82    type Registrations = BTreeMap<
83        PublicKey,
84        (
85            Sender<PublicKey, deterministic::Context>,
86            Receiver<PublicKey>,
87        ),
88    >;
89
90    async fn initialize_simulation(
91        context: deterministic::Context,
92        num_peers: u32,
93        success_rate: f64,
94    ) -> (
95        Vec<PublicKey>,
96        Registrations,
97        Oracle<PublicKey, deterministic::Context>,
98    ) {
99        let (network, oracle) = Network::<deterministic::Context, PublicKey>::new(
100            context,
101            commonware_p2p::simulated::Config {
102                max_size: 1024 * 1024,
103                disconnect_on_block: true,
104                tracked_peer_sets: NZUsize!(1),
105            },
106        );
107        network.start();
108
109        let mut schemes = (0..num_peers)
110            .map(|i| PrivateKey::from_seed(i as u64))
111            .collect::<Vec<_>>();
112        schemes.sort_by_key(|s| s.public_key());
113        let peers: Vec<PublicKey> = schemes.iter().map(|c| c.public_key()).collect();
114
115        let mut registrations: Registrations = BTreeMap::new();
116        for peer in peers.iter() {
117            let (sender, receiver) = oracle
118                .control(peer.clone())
119                .register(0, TEST_QUOTA)
120                .await
121                .unwrap();
122            registrations.insert(peer.clone(), (sender, receiver));
123        }
124
125        // Add links between all peers
126        let link = Link {
127            latency: NETWORK_SPEED,
128            jitter: Duration::ZERO,
129            success_rate,
130        };
131        for p1 in peers.iter() {
132            for p2 in peers.iter() {
133                if p2 == p1 {
134                    continue;
135                }
136                oracle
137                    .add_link(p1.clone(), p2.clone(), link.clone())
138                    .await
139                    .unwrap();
140            }
141        }
142
143        // Track all peers so the simulated network allows message delivery.
144        let all_peers = commonware_utils::ordered::Set::from_iter_dedup(peers.clone());
145        oracle.manager().track(0, all_peers);
146
147        (peers, registrations, oracle)
148    }
149
150    #[test]
151    fn policy_handles_closed_responders() {
152        let mut overflow = <Message<PublicKey, TestMessage> as Policy>::Overflow::default();
153        let pending_subscribe = TestMessage::shared(b"pending_subscribe");
154        let pending_get = TestMessage::shared(b"pending_get");
155        let open_subscribe = TestMessage::shared(b"open_subscribe");
156        let open_get = TestMessage::shared(b"open_get");
157        let current_get = TestMessage::shared(b"current_get");
158
159        let (closed_responder, closed_receiver) = commonware_utils::channel::oneshot::channel();
160        <Message<PublicKey, TestMessage> as Policy>::handle(
161            &mut overflow,
162            Message::Subscribe {
163                digest: pending_subscribe.digest(),
164                responder: closed_responder,
165            },
166        );
167        drop(closed_receiver);
168
169        let (open_responder, _open_receiver) = commonware_utils::channel::oneshot::channel();
170        <Message<PublicKey, TestMessage> as Policy>::handle(
171            &mut overflow,
172            Message::Subscribe {
173                digest: open_subscribe.digest(),
174                responder: open_responder,
175            },
176        );
177
178        let (closed_responder, closed_receiver) = commonware_utils::channel::oneshot::channel();
179        <Message<PublicKey, TestMessage> as Policy>::handle(
180            &mut overflow,
181            Message::Get {
182                digest: pending_get.digest(),
183                responder: closed_responder,
184            },
185        );
186        drop(closed_receiver);
187
188        let (open_responder, _open_receiver) = commonware_utils::channel::oneshot::channel();
189        <Message<PublicKey, TestMessage> as Policy>::handle(
190            &mut overflow,
191            Message::Get {
192                digest: open_get.digest(),
193                responder: open_responder,
194            },
195        );
196
197        let (current_responder, current_receiver) = commonware_utils::channel::oneshot::channel();
198        drop(current_receiver);
199        <Message<PublicKey, TestMessage> as Policy>::handle(
200            &mut overflow,
201            Message::Get {
202                digest: current_get.digest(),
203                responder: current_responder,
204            },
205        );
206
207        let mut drained = VecDeque::new();
208        overflow.drain(|message| {
209            drained.push_back(message);
210            None
211        });
212
213        assert_eq!(drained.len(), 2);
214        assert!(drained.iter().any(|message| matches!(
215            message,
216            Message::Subscribe { digest, responder }
217                if *digest == open_subscribe.digest() && !responder.is_closed()
218        )));
219        assert!(drained.iter().any(|message| matches!(
220            message,
221            Message::Get { digest, responder }
222                if *digest == open_get.digest() && !responder.is_closed()
223        )));
224    }
225
226    #[test]
227    fn policy_drain_continues_until_rejected_message() {
228        let mut overflow = <Message<PublicKey, TestMessage> as Policy>::Overflow::default();
229        let first = TestMessage::shared(b"first");
230        let second = TestMessage::shared(b"second");
231        let third = TestMessage::shared(b"third");
232
233        let (closed_responder, closed_receiver) = commonware_utils::channel::oneshot::channel();
234        <Message<PublicKey, TestMessage> as Policy>::handle(
235            &mut overflow,
236            Message::Subscribe {
237                digest: TestMessage::shared(b"closed").digest(),
238                responder: closed_responder,
239            },
240        );
241        drop(closed_receiver);
242
243        let (first_responder, _first_receiver) = commonware_utils::channel::oneshot::channel();
244        <Message<PublicKey, TestMessage> as Policy>::handle(
245            &mut overflow,
246            Message::Get {
247                digest: first.digest(),
248                responder: first_responder,
249            },
250        );
251        let (second_responder, _second_receiver) = commonware_utils::channel::oneshot::channel();
252        <Message<PublicKey, TestMessage> as Policy>::handle(
253            &mut overflow,
254            Message::Get {
255                digest: second.digest(),
256                responder: second_responder,
257            },
258        );
259        let (third_responder, _third_receiver) = commonware_utils::channel::oneshot::channel();
260        <Message<PublicKey, TestMessage> as Policy>::handle(
261            &mut overflow,
262            Message::Get {
263                digest: third.digest(),
264                responder: third_responder,
265            },
266        );
267
268        let mut drained = VecDeque::new();
269        overflow.drain(|message| {
270            drained.push_back(message);
271            if drained.len() == 3 {
272                drained.pop_back()
273            } else {
274                None
275            }
276        });
277
278        assert_eq!(drained.len(), 2);
279        assert!(matches!(
280            &drained[0],
281            Message::Get { digest, responder }
282                if *digest == first.digest() && !responder.is_closed()
283        ));
284        assert!(matches!(
285            &drained[1],
286            Message::Get { digest, responder }
287                if *digest == second.digest() && !responder.is_closed()
288        ));
289
290        overflow.drain(|message| {
291            drained.push_back(message);
292            None
293        });
294        assert_eq!(drained.len(), 3);
295        assert!(matches!(
296            &drained[2],
297            Message::Get { digest, responder }
298                if *digest == third.digest() && !responder.is_closed()
299        ));
300    }
301
302    #[test]
303    fn policy_drain_stops_after_returned_message_closes() {
304        let mut overflow = <Message<PublicKey, TestMessage> as Policy>::Overflow::default();
305        let first = TestMessage::shared(b"first");
306        let second = TestMessage::shared(b"second");
307
308        let (first_responder, first_receiver) = commonware_utils::channel::oneshot::channel();
309        <Message<PublicKey, TestMessage> as Policy>::handle(
310            &mut overflow,
311            Message::Get {
312                digest: first.digest(),
313                responder: first_responder,
314            },
315        );
316        let (second_responder, _second_receiver) = commonware_utils::channel::oneshot::channel();
317        <Message<PublicKey, TestMessage> as Policy>::handle(
318            &mut overflow,
319            Message::Get {
320                digest: second.digest(),
321                responder: second_responder,
322            },
323        );
324
325        let mut first_receiver = Some(first_receiver);
326        let mut attempts = 0;
327        overflow.drain(|message| {
328            attempts += 1;
329            drop(first_receiver.take());
330            Some(message)
331        });
332        assert_eq!(attempts, 1);
333
334        let mut drained = VecDeque::new();
335        overflow.drain(|message| {
336            drained.push_back(message);
337            None
338        });
339        assert_eq!(drained.len(), 1);
340        assert!(matches!(
341            &drained[0],
342            Message::Get { digest, responder }
343                if *digest == second.digest() && !responder.is_closed()
344        ));
345    }
346
347    async fn spawn_peer_engines(
348        context: deterministic::Context,
349        oracle: &Oracle<PublicKey, deterministic::Context>,
350        registrations: &mut Registrations,
351    ) -> BTreeMap<PublicKey, Mailbox<PublicKey, TestMessage>> {
352        let mut mailboxes = BTreeMap::new();
353        while let Some((peer, network)) = registrations.pop_first() {
354            let context = context.child("peer").with_attribute("public_key", &peer);
355            let config = Config {
356                public_key: peer.clone(),
357                mailbox_size: NZUsize!(1024),
358                deque_size: CACHE_SIZE,
359                priority: false,
360                codec_config: RangeCfg::from(..),
361                peer_provider: oracle.manager(),
362            };
363            let (engine, engine_mailbox) =
364                Engine::<_, PublicKey, TestMessage, _>::new(context, config);
365            mailboxes.insert(peer.clone(), engine_mailbox);
366            engine.start(network);
367        }
368
369        // Let each engine run until it applies the peer set from `initialize_simulation` so
370        // `latest_primary_peers` is populated before any broadcast.
371        context.sleep(A_JIFFY).await;
372        mailboxes
373    }
374
375    #[test_traced]
376    fn test_broadcast() {
377        let runner = deterministic::Runner::timed(Duration::from_secs(5));
378        runner.start(|context| async move {
379            let (peers, mut registrations, oracle) =
380                initialize_simulation(context.child("network"), 4, 1.0).await;
381            let mailboxes =
382                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
383
384            // Send a single broadcast message from the first peer
385            let message = TestMessage::shared(b"hello world test message");
386            let first_mailbox = mailboxes.get(peers.first().unwrap()).unwrap().clone();
387            assert!(first_mailbox
388                .broadcast(Recipients::All, message.clone())
389                .accepted());
390
391            // Allow time for propagation
392            context.sleep(Duration::from_secs(1)).await;
393
394            // Check that all peers received the message
395            for peer in peers.iter() {
396                let mailbox = mailboxes.get(peer).unwrap().clone();
397                let digest = message.digest();
398                let receiver = mailbox.subscribe(digest);
399                let received_message = receiver.await.ok();
400                assert_eq!(received_message.unwrap(), message.clone());
401            }
402
403            // Send another message
404            let message = TestMessage::shared(b"hello world again");
405            assert!(first_mailbox
406                .broadcast(Recipients::All, message.clone())
407                .accepted());
408
409            // Allow time for propagation
410            context.sleep(Duration::from_secs(1)).await;
411
412            // Check that all peers received the new message
413            let mut found = 0;
414            for peer in peers.iter() {
415                let mailbox = mailboxes.get(peer).unwrap().clone();
416                let digest = message.digest();
417                let receiver = mailbox.get(digest).await;
418                if let Some(receiver) = receiver {
419                    assert_eq!(receiver, message.clone());
420                    found += 1;
421                }
422            }
423            assert!(found > 0, "No peers received the message");
424        });
425    }
426
427    #[test_traced]
428    fn test_self_retrieval() {
429        let runner = deterministic::Runner::timed(Duration::from_secs(5));
430        runner.start(|context| async move {
431            // Initialize simulation with 1 peer
432            let (peers, mut registrations, oracle) =
433                initialize_simulation(context.child("network"), 1, 1.0).await;
434            let mailboxes =
435                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
436
437            // Set up mailbox for Peer A
438            let mailbox_a = mailboxes.get(&peers[0]).unwrap().clone();
439
440            // Create a test message
441            let m1 = TestMessage::shared(b"hello world");
442            let digest_m1 = m1.digest();
443
444            // Attempt immediate retrieval before broadcasting
445            let receiver_before = mailbox_a.get(digest_m1).await;
446            assert!(receiver_before.is_none());
447
448            // Attempt retrieval before broadcasting
449            let receiver_before = mailbox_a.subscribe(digest_m1);
450
451            // Broadcast the message
452            assert!(mailbox_a.broadcast(Recipients::All, m1.clone()).accepted());
453
454            // Wait for the pre-broadcast retrieval to complete
455            let msg_before = receiver_before
456                .await
457                .expect("Pre-broadcast retrieval failed");
458            assert_eq!(msg_before, m1);
459
460            // Attempt immediate retrieval after broadcasting
461            let receiver_after = mailbox_a.get(digest_m1).await;
462            assert_eq!(receiver_after, Some(m1.clone()));
463
464            // Perform a second retrieval after the broadcast
465            let receiver_after = mailbox_a.subscribe(digest_m1);
466
467            // Measure the time taken for the second retrieval
468            let start = context.current();
469            let msg_after = receiver_after
470                .await
471                .expect("Post-broadcast retrieval failed");
472            let duration = context.current().duration_since(start).unwrap();
473
474            // Verify the second retrieval matches the original message
475            assert_eq!(msg_after, m1);
476
477            // Verify the second retrieval was instant (less than 10ms)
478            assert!(duration < A_JIFFY, "get not instant");
479        });
480    }
481
482    #[test_traced]
483    fn test_packet_loss() {
484        let runner = deterministic::Runner::timed(Duration::from_secs(30));
485        runner.start(|context| async move {
486            let (peers, mut registrations, oracle) =
487                initialize_simulation(context.child("network"), 10, 0.1).await;
488            let mailboxes =
489                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
490
491            // Create a message and grab an arbitrary mailbox
492            let message = TestMessage::shared(b"hello world test message");
493            let first_mailbox = mailboxes.get(peers.first().unwrap()).unwrap().clone();
494
495            // Retry until all peers receive the message (or timeout)
496            let digest = message.digest();
497            for i in 0..100 {
498                // Broadcast the message
499                assert!(first_mailbox
500                    .broadcast(Recipients::All, message.clone())
501                    .accepted());
502                context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
503
504                // Check if all peers received the message
505                let mut all_received = true;
506                for peer in peers.iter() {
507                    let mailbox = mailboxes.get(peer).unwrap().clone();
508                    let receiver = mailbox.subscribe(digest);
509                    let has = match context.timeout(A_JIFFY, receiver).await {
510                        Ok(r) => r.is_ok(),
511                        Err(Error::Timeout) => false,
512                        Err(e) => panic!("unexpected error: {e:?}"),
513                    };
514                    all_received &= has;
515                }
516                // If all received, we're done
517                if all_received {
518                    assert!(i > 0, "Message received on first try");
519                    return;
520                }
521            }
522            panic!("Not all peers received the message after retries");
523        });
524    }
525
526    #[test_traced]
527    fn test_get_cached() {
528        let runner = deterministic::Runner::timed(Duration::from_secs(5));
529        runner.start(|context| async move {
530            let (peers, mut registrations, oracle) =
531                initialize_simulation(context.child("network"), 2, 1.0).await;
532            let mailboxes =
533                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
534
535            // Broadcast a message
536            let message = TestMessage::shared(b"cached message");
537            let first_mailbox = mailboxes.get(peers.first().unwrap()).unwrap().clone();
538            assert!(first_mailbox
539                .broadcast(Recipients::All, message.clone())
540                .accepted());
541
542            // Wait for propagation
543            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
544
545            // Get from cache (should be instant)
546            let digest = message.digest();
547            let mailbox = mailboxes.get(peers.last().unwrap()).unwrap().clone();
548            let receiver = mailbox.subscribe(digest);
549            let start = context.current();
550            let received = receiver.await.expect("failed to get cached message");
551            let duration = context.current().duration_since(start).unwrap();
552            assert_eq!(received, message);
553            assert!(duration < A_JIFFY, "get not instant",);
554        });
555    }
556
557    #[test_traced]
558    fn test_get_nonexistent() {
559        let runner = deterministic::Runner::timed(Duration::from_secs(5));
560        runner.start(|context| async move {
561            let (peers, mut registrations, oracle) =
562                initialize_simulation(context.child("network"), 2, 1.0).await;
563            let mailboxes =
564                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
565
566            // Request nonexistent message from two nodes
567            let message = TestMessage::shared(b"future message");
568            let digest = message.digest();
569            let mailbox1 = mailboxes.get(&peers[0]).unwrap().clone();
570            let mailbox2 = mailboxes.get(&peers[1]).unwrap().clone();
571            let receiver = mailbox1.subscribe(digest);
572
573            // Create two other requests which are dropped
574            let dummy1 = mailbox1.subscribe(digest);
575            let dummy2 = mailbox2.subscribe(digest);
576            drop(dummy1);
577            drop(dummy2);
578
579            // Broadcast the message
580            assert!(mailbox1
581                .broadcast(Recipients::All, message.clone())
582                .accepted());
583
584            // Wait for propagation
585            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
586
587            // Check receiver1 gets the message, receiver2 was dropped
588            let received = receiver.await.expect("receiver1 should get message");
589            assert_eq!(received, message);
590        });
591    }
592
593    #[test_traced]
594    fn test_cache_eviction_single_peer() {
595        let runner = deterministic::Runner::timed(Duration::from_secs(5));
596        runner.start(|context| async move {
597            let (peers, mut registrations, oracle) =
598                initialize_simulation(context.child("network"), 2, 1.0).await;
599            let mailboxes =
600                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
601
602            // Broadcast messages exceeding cache size
603            let mailbox = mailboxes.get(&peers[0]).unwrap().clone();
604            let mut messages = vec![];
605            for i in 0..CACHE_SIZE + 1 {
606                messages.push(TestMessage::shared(format!("message {i}").as_bytes()));
607            }
608            for message in messages.iter() {
609                assert!(mailbox
610                    .broadcast(Recipients::All, message.clone())
611                    .accepted());
612            }
613
614            // Wait for propagation
615            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
616
617            // Check all other messages exist
618            let peer_mailbox = mailboxes.get(&peers[1]).unwrap().clone();
619            for msg in messages.iter().skip(1) {
620                let result = peer_mailbox.subscribe(msg.digest()).await.unwrap();
621                assert_eq!(result, msg.clone());
622            }
623
624            // Check first message times out
625            let receiver = peer_mailbox.subscribe(messages[0].digest());
626            match context.timeout(A_JIFFY, receiver).await {
627                Ok(_) => panic!("receiver should have failed"),
628                Err(Error::Timeout) => {} // Expected timeout
629                Err(e) => panic!("unexpected error: {e:?}"),
630            }
631        });
632    }
633
634    #[test_traced]
635    fn test_cache_eviction_multi_peer() {
636        let runner = deterministic::Runner::timed(Duration::from_secs(10));
637        runner.start(|context| async move {
638            // Initialize simulation with 3 peers
639            let (peers, mut registrations, oracle) =
640                initialize_simulation(context.child("network"), 3, 1.0).await;
641            let mailboxes =
642                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
643
644            // Assign mailboxes for peers A, B, C
645            let mailbox_a = mailboxes.get(&peers[0]).unwrap().clone();
646            let mailbox_b = mailboxes.get(&peers[1]).unwrap().clone();
647            let mailbox_c = mailboxes.get(&peers[2]).unwrap().clone();
648
649            // Create and broadcast message M1 from A
650            let m1 = TestMessage::shared(b"message M1");
651            let digest_m1 = m1.digest();
652            assert!(mailbox_a.broadcast(Recipients::All, m1.clone()).accepted());
653            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
654
655            // Broadcast M1 from C
656            assert!(mailbox_c.broadcast(Recipients::All, m1.clone()).accepted());
657            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
658
659            // M1 is now in A's and C's deques in B's engine
660
661            // Peer A broadcasts 10 new messages to evict M1 from A's deque
662            let mut new_messages_a = Vec::with_capacity(CACHE_SIZE);
663            for i in 0..CACHE_SIZE {
664                new_messages_a.push(TestMessage::shared(format!("A{i}").as_bytes()));
665            }
666            for msg in &new_messages_a {
667                assert!(mailbox_a.broadcast(Recipients::All, msg.clone()).accepted());
668            }
669            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
670
671            // Verify B can still get M1 (in C's deque)
672            let receiver = mailbox_b.subscribe(digest_m1);
673            let received = receiver.await.expect("M1 should be retrievable");
674            assert_eq!(received, m1);
675
676            // Peer C broadcasts 10 new messages to evict M1 from C's deque
677            let mut new_messages_c = Vec::with_capacity(CACHE_SIZE);
678            for i in 0..CACHE_SIZE {
679                new_messages_c.push(TestMessage::shared(format!("C{i}").as_bytes()));
680            }
681            for msg in &new_messages_c {
682                assert!(mailbox_c.broadcast(Recipients::All, msg.clone()).accepted());
683            }
684            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
685
686            // Verify B cannot get M1 (evicted from all deques)
687            let receiver = mailbox_b.subscribe(digest_m1);
688            match context.timeout(A_JIFFY, receiver).await {
689                Ok(_) => panic!("M1 should not be retrievable"),
690                Err(Error::Timeout) => {} // Expected timeout
691                Err(e) => panic!("unexpected error: {e:?}"),
692            }
693        });
694    }
695
696    #[test_traced]
697    fn test_selective_recipients() {
698        let runner = deterministic::Runner::timed(Duration::from_secs(5));
699        runner.start(|context| async move {
700            let (peers, mut registrations, oracle) =
701                initialize_simulation(context.child("network"), 4, 1.0).await;
702
703            let sender_pk = peers[0].clone();
704            let target_peer = peers[1].clone();
705            let non_target_peer = peers[2].clone();
706
707            let mailboxes =
708                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
709            let sender_mb = mailboxes.get(&sender_pk).unwrap().clone();
710
711            let msg = TestMessage::shared(b"selective-broadcast");
712            assert!(sender_mb
713                .broadcast(Recipients::One(target_peer.clone()), msg.clone())
714                .accepted());
715
716            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
717
718            // Only target peer should retrieve the message.
719            let got_target = mailboxes
720                .get(&target_peer)
721                .unwrap()
722                .clone()
723                .get(msg.digest())
724                .await;
725            assert_eq!(got_target, Some(msg.clone()));
726
727            // Non-target peer should not retrieve the message.
728            let got_other = mailboxes
729                .get(&non_target_peer)
730                .unwrap()
731                .clone()
732                .get(msg.digest())
733                .await;
734            assert!(got_other.is_none());
735        });
736    }
737
738    #[test_traced]
739    fn test_ref_count_across_peers() {
740        let runner = deterministic::Runner::timed(Duration::from_secs(10));
741        runner.start(|context| async move {
742            // three peers so we can observe from a third
743            let (peers, mut registrations, oracle) =
744                initialize_simulation(context.child("network"), 3, 1.0).await;
745            let mailboxes =
746                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
747
748            let p0 = peers[0].clone();
749            let p1 = peers[1].clone();
750            let observer = peers[2].clone();
751
752            let mb0 = mailboxes.get(&p0).unwrap().clone();
753            let mb1 = mailboxes.get(&p1).unwrap().clone();
754            let obs = mailboxes.get(&observer).unwrap().clone();
755
756            // the message duplicated by p0 and p1
757            let dup = TestMessage::shared(b"dup");
758            let digest = dup.digest();
759
760            // broadcast from both senders
761            assert!(mb0.broadcast(Recipients::All, dup.clone()).accepted());
762            assert!(mb1.broadcast(Recipients::All, dup.clone()).accepted());
763            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
764
765            // observer must get it now
766            assert_eq!(obs.get(digest).await, Some(dup.clone()));
767
768            // Evict from p0's deque only
769            for i in 0..CACHE_SIZE {
770                let spam = TestMessage::shared(format!("p0-{i}").into_bytes());
771                assert!(mb0.broadcast(Recipients::All, spam).accepted());
772            }
773            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
774            assert_eq!(obs.get(digest).await, Some(dup.clone()));
775
776            // Evict from p1's deque as well
777            for i in 0..CACHE_SIZE {
778                let spam = TestMessage::shared(format!("p1-{i}").into_bytes());
779                assert!(mb1.broadcast(Recipients::All, spam).accepted());
780            }
781            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
782            assert!(obs.get(digest).await.is_none());
783        });
784    }
785
786    #[test_traced]
787    fn test_deterministic_retrieval() {
788        let run = |seed: u64| {
789            let config = deterministic::Config::new()
790                .with_seed(seed)
791                .with_timeout(Some(Duration::from_secs(5)));
792            let runner = deterministic::Runner::new(config);
793            runner.start(|context| async move {
794                let (peers, mut registrations, oracle) =
795                    initialize_simulation(context.child("network"), 1, 1.0).await;
796                let mailboxes =
797                    spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
798
799                let sender1 = peers[0].clone();
800                let mb1 = mailboxes.get(&sender1).unwrap().clone();
801
802                // Three messages with distinct digests.
803                let m1 = TestMessage::shared(b"content-1");
804                let m2 = TestMessage::shared(b"content-2");
805                let m3 = TestMessage::shared(b"content-3");
806                assert!(mb1.broadcast(Recipients::All, m1.clone()).accepted());
807                assert!(mb1.broadcast(Recipients::All, m2.clone()).accepted());
808                assert!(mb1.broadcast(Recipients::All, m3.clone()).accepted());
809
810                let mut hasher = Sha256::default();
811                for msg in [&m1, &m2, &m3] {
812                    if let Some(value) = mb1.get(msg.digest()).await {
813                        hasher.update(&value.content);
814                    }
815                }
816                hasher.finalize()
817            })
818        };
819
820        for seed in 0..10 {
821            let h1 = run(seed);
822            let h2 = run(seed);
823
824            assert_eq!(h1, h2, "Messages returned in different order for {seed}");
825        }
826    }
827
828    #[test_traced]
829    fn test_malformed_network_payload_does_not_break_valid_traffic() {
830        let runner = deterministic::Runner::timed(Duration::from_secs(10));
831        runner.start(|context| async move {
832            let (peers, mut registrations, oracle) =
833                initialize_simulation(context.child("network"), 3, 1.0).await;
834
835            let attacker = peers[0].clone();
836            let honest = peers[1].clone();
837            let victim = peers[2].clone();
838
839            let (mut attacker_sender, _) = registrations.remove(&attacker).unwrap();
840            let mailboxes =
841                spawn_peer_engines(context.child("peers"), &oracle, &mut registrations).await;
842            let honest_mailbox = mailboxes.get(&honest).unwrap().clone();
843            let victim_mailbox = mailboxes.get(&victim).unwrap().clone();
844
845            // Send malformed bytes that cannot decode into `TestMessage`.
846            let sent = attacker_sender.send(
847                Recipients::One(victim.clone()),
848                IoBuf::from(vec![0xFF]),
849                false,
850            );
851            assert_eq!(sent, vec![victim.clone()]);
852            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
853
854            // The victim should still process later valid traffic.
855            let message = TestMessage::shared(b"valid-after-malformed");
856            assert!(honest_mailbox
857                .broadcast(Recipients::One(victim.clone()), message.clone())
858                .accepted());
859            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
860
861            let received = victim_mailbox
862                .subscribe(message.digest())
863                .await
864                .expect("victim should receive valid message after malformed payload");
865            assert_eq!(received, message);
866        });
867    }
868
869    #[test_traced]
870    fn test_dropped_waiters_for_missing_digest_are_cleaned_up() {
871        let runner = deterministic::Runner::timed(Duration::from_secs(10));
872        runner.start(|context| async move {
873            let (peers, mut registrations, oracle) =
874                initialize_simulation(context.child("network"), 1, 1.0).await;
875            let peer = peers[0].clone();
876            let (sender, receiver) = registrations.remove(&peer).unwrap();
877
878            let engine_context = context.child("waiter_cleanup");
879            let config = Config {
880                public_key: peer,
881                mailbox_size: NZUsize!(1024),
882                deque_size: CACHE_SIZE,
883                priority: false,
884                codec_config: RangeCfg::from(..),
885                peer_provider: oracle.manager(),
886            };
887            let (engine, mailbox) =
888                Engine::<_, PublicKey, TestMessage, _>::new(engine_context, config);
889            engine.start((sender, receiver));
890
891            let missing = TestMessage::shared(b"never-arrives");
892            let missing_digest = missing.digest();
893            let rx1 = mailbox.subscribe(missing_digest);
894            let rx2 = mailbox.subscribe(missing_digest);
895
896            // Ensure subscriptions are processed and waiters are reflected in metrics.
897            let _ = mailbox
898                .get(TestMessage::shared(b"before-cleanup").digest())
899                .await;
900            context.sleep(A_JIFFY).await;
901            let metrics_before = context.encode();
902            let waiter_values_before: Vec<f64> = metrics_before
903                .lines()
904                .filter(|line| {
905                    line.starts_with("waiters")
906                        || (line.contains("_waiters")
907                            && !line.starts_with("# HELP")
908                            && !line.starts_with("# TYPE"))
909                })
910                .filter_map(|line| line.split_whitespace().last())
911                .filter_map(|value| value.parse::<f64>().ok())
912                .collect();
913            assert!(
914                !waiter_values_before.is_empty(),
915                "waiters metric not found in output:\n{metrics_before}"
916            );
917            assert!(
918                waiter_values_before.iter().any(|value| *value > 0.0),
919                "expected positive waiters before cleanup, got:\n{metrics_before}"
920            );
921
922            drop(rx1);
923            drop(rx2);
924
925            // Trigger another mailbox event and give the run loop time to clean closed waiters.
926            let _ = mailbox
927                .get(TestMessage::shared(b"after-cleanup").digest())
928                .await;
929            context.sleep(A_JIFFY).await;
930
931            let metrics_after = context.encode();
932            let waiter_values_after: Vec<f64> = metrics_after
933                .lines()
934                .filter(|line| {
935                    line.starts_with("waiters")
936                        || (line.contains("_waiters")
937                            && !line.starts_with("# HELP")
938                            && !line.starts_with("# TYPE"))
939                })
940                .filter_map(|line| line.split_whitespace().last())
941                .filter_map(|value| value.parse::<f64>().ok())
942                .collect();
943            assert!(
944                !waiter_values_after.is_empty(),
945                "waiters metric not found in output:\n{metrics_after}"
946            );
947            assert!(
948                waiter_values_after.iter().all(|value| *value == 0.0),
949                "expected zero retained waiters, got:\n{metrics_after}"
950            );
951        });
952    }
953
954    #[allow(clippy::type_complexity)]
955    async fn spawn_peer_engines_with_handles(
956        context: deterministic::Context,
957        oracle: &Oracle<PublicKey, deterministic::Context>,
958        registrations: &mut Registrations,
959    ) -> (
960        BTreeMap<PublicKey, Mailbox<PublicKey, TestMessage>>,
961        Vec<commonware_runtime::Handle<()>>,
962    ) {
963        let mut mailboxes = BTreeMap::new();
964        let mut handles = Vec::new();
965        while let Some((peer, network)) = registrations.pop_first() {
966            let ctx = context.child("peer").with_attribute("public_key", &peer);
967            let config = Config {
968                public_key: peer.clone(),
969                mailbox_size: NZUsize!(1024),
970                deque_size: CACHE_SIZE,
971                priority: false,
972                codec_config: RangeCfg::from(..),
973                peer_provider: oracle.manager(),
974            };
975            let (engine, engine_mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
976            mailboxes.insert(peer.clone(), engine_mailbox);
977            handles.push(engine.start(network));
978        }
979
980        context.sleep(A_JIFFY).await;
981        (mailboxes, handles)
982    }
983
984    #[test_traced]
985    fn test_operations_after_shutdown_do_not_panic() {
986        let runner = deterministic::Runner::timed(Duration::from_secs(5));
987        runner.start(|context| async move {
988            let (peers, mut registrations, oracle) =
989                initialize_simulation(context.child("network"), 2, 1.0).await;
990            let (mut mailboxes, handles) = spawn_peer_engines_with_handles(
991                context.child("peers"),
992                &oracle,
993                &mut registrations,
994            )
995            .await;
996
997            // Broadcast a message to verify network is functional
998            let message = TestMessage::shared(b"test message");
999            let mailbox = mailboxes.remove(&peers[0]).unwrap();
1000            assert!(
1001                mailbox
1002                    .broadcast(Recipients::All, message.clone())
1003                    .accepted(),
1004                "broadcast should succeed before shutdown"
1005            );
1006
1007            // Abort all engine handles
1008            for handle in handles {
1009                handle.abort();
1010            }
1011            context.sleep(Duration::from_millis(100)).await;
1012
1013            // All operations should not panic after shutdown
1014
1015            // Broadcast should not panic
1016            assert_eq!(
1017                mailbox.broadcast(Recipients::All, message.clone()),
1018                Feedback::Closed,
1019                "broadcast after shutdown should return Closed"
1020            );
1021
1022            // Subscribe should not panic (returns Canceled since engine is down)
1023            let digest = message.digest();
1024            let receiver = mailbox.subscribe(digest);
1025            let result = receiver.await;
1026            assert!(
1027                result.is_err(),
1028                "subscribe after shutdown should return Canceled"
1029            );
1030
1031            // Get should not panic
1032            let result = mailbox.get(digest).await;
1033            assert!(result.is_none(), "get after shutdown should return None");
1034        });
1035    }
1036
1037    fn clean_shutdown(seed: u64) {
1038        let cfg = deterministic::Config::new()
1039            .with_seed(seed)
1040            .with_timeout(Some(Duration::from_secs(30)));
1041        let runner = deterministic::Runner::new(cfg);
1042        runner.start(|context| async move {
1043            let (peers, mut registrations, oracle) =
1044                initialize_simulation(context.child("network"), 2, 1.0).await;
1045
1046            let (mailboxes, handles) = spawn_peer_engines_with_handles(
1047                context.child("peers"),
1048                &oracle,
1049                &mut registrations,
1050            )
1051            .await;
1052
1053            // Allow tasks to start
1054            context.sleep(Duration::from_millis(100)).await;
1055
1056            // Count running tasks under the peers prefix
1057            let running_before = count_running_tasks(&context, "peers");
1058            assert!(
1059                running_before > 0,
1060                "at least one peer engine task should be running"
1061            );
1062
1063            // Verify network is functional
1064            let message = TestMessage::shared(b"test message");
1065            let mailbox = mailboxes.get(&peers[0]).unwrap().clone();
1066            assert!(
1067                mailbox
1068                    .broadcast(Recipients::All, message.clone())
1069                    .accepted(),
1070                "broadcast should succeed"
1071            );
1072
1073            // Wait for propagation
1074            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1075
1076            // Verify message received
1077            let peer_mailbox = mailboxes.get(&peers[1]).unwrap().clone();
1078            let received = peer_mailbox.get(message.digest()).await;
1079            assert_eq!(received, Some(message));
1080
1081            // Abort all engine handles
1082            for handle in handles {
1083                handle.abort();
1084            }
1085            context.sleep(Duration::from_millis(100)).await;
1086
1087            // Verify all peer engine tasks are stopped
1088            let running_after = count_running_tasks(&context, "peers");
1089            assert_eq!(
1090                running_after, 0,
1091                "all peer engine tasks should be stopped, but {running_after} still running"
1092            );
1093        });
1094    }
1095
1096    #[test]
1097    fn test_clean_shutdown() {
1098        for seed in 0..25 {
1099            clean_shutdown(seed);
1100        }
1101    }
1102
1103    #[test_traced]
1104    fn test_peer_set_update_evicts_disconnected_peer_buffers() {
1105        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1106        runner.start(|context| async move {
1107            let (peers, mut registrations, oracle) =
1108                initialize_simulation(context.child("network"), 3, 1.0).await;
1109
1110            let peer_a = peers[0].clone();
1111            let peer_b = peers[1].clone();
1112            let peer_c = peers[2].clone();
1113
1114            // Spawn peer B's engine with its own manager.
1115            let network_b = registrations.remove(&peer_b).unwrap();
1116            let config_b = Config {
1117                public_key: peer_b.clone(),
1118                mailbox_size: NZUsize!(1024),
1119                deque_size: CACHE_SIZE,
1120                priority: false,
1121                codec_config: RangeCfg::from(..),
1122                peer_provider: oracle.manager(),
1123            };
1124            let (engine_b, mailbox_b) =
1125                Engine::<_, PublicKey, TestMessage, _>::new(context.child("peer_b"), config_b);
1126            engine_b.start(network_b);
1127
1128            // Spawn remaining peer engines.
1129            let mut mailboxes = BTreeMap::new();
1130            mailboxes.insert(peer_b.clone(), mailbox_b);
1131            for (peer, network) in registrations {
1132                let ctx = context.child("peer").with_attribute("public_key", &peer);
1133                let config = Config {
1134                    public_key: peer.clone(),
1135                    mailbox_size: NZUsize!(1024),
1136                    deque_size: CACHE_SIZE,
1137                    priority: false,
1138                    codec_config: RangeCfg::from(..),
1139                    peer_provider: oracle.manager(),
1140                };
1141                let (engine, mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
1142                mailboxes.insert(peer, mailbox);
1143                engine.start(network);
1144            }
1145            context.sleep(A_JIFFY).await;
1146
1147            // Peer A broadcasts a message.
1148            let msg = TestMessage::shared(b"eviction-test");
1149            let mailbox_a = mailboxes.get(&peer_a).unwrap().clone();
1150            assert!(mailbox_a.broadcast(Recipients::All, msg.clone()).accepted());
1151            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1152
1153            // Peer B should have cached the message (received from A).
1154            let mailbox_b = mailboxes.get(&peer_b).unwrap().clone();
1155            assert_eq!(
1156                mailbox_b.get(msg.digest()).await,
1157                Some(msg.clone()),
1158                "peer B should have the message before eviction"
1159            );
1160
1161            // Send a peer set update excluding peer A.
1162            let remaining = commonware_utils::ordered::Set::from_iter_dedup(vec![peer_b, peer_c]);
1163            oracle.manager().track(1, remaining);
1164            context.sleep(A_JIFFY).await;
1165
1166            // Peer A's deque was evicted; the message should be gone.
1167            assert!(
1168                mailbox_b.get(msg.digest()).await.is_none(),
1169                "message should be evicted after peer A left the peer set"
1170            );
1171        });
1172    }
1173
1174    #[test_traced]
1175    fn test_peer_set_update_evicts_peers_not_in_latest_set_even_if_still_in_overlap() {
1176        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1177        runner.start(|context| async move {
1178            // Use tracked_peer_sets=2 so old sets are retained in the window.
1179            let (network, oracle) = Network::<deterministic::Context, PublicKey>::new(
1180                context.child("network"),
1181                commonware_p2p::simulated::Config {
1182                    max_size: 1024 * 1024,
1183                    disconnect_on_block: true,
1184                    tracked_peer_sets: NZUsize!(2),
1185                },
1186            );
1187            network.start();
1188
1189            let mut schemes = (0..3)
1190                .map(|i| PrivateKey::from_seed(i as u64))
1191                .collect::<Vec<_>>();
1192            schemes.sort_by_key(|s| s.public_key());
1193            let peers: Vec<PublicKey> = schemes.iter().map(|c| c.public_key()).collect();
1194            let peer_a = peers[0].clone();
1195            let peer_b = peers[1].clone();
1196            let peer_c = peers[2].clone();
1197
1198            let mut registrations: Registrations = BTreeMap::new();
1199            for peer in peers.iter() {
1200                let (sender, receiver) = oracle
1201                    .control(peer.clone())
1202                    .register(0, TEST_QUOTA)
1203                    .await
1204                    .unwrap();
1205                registrations.insert(peer.clone(), (sender, receiver));
1206            }
1207            let link = Link {
1208                latency: NETWORK_SPEED,
1209                jitter: Duration::ZERO,
1210                success_rate: 1.0,
1211            };
1212            for p1 in peers.iter() {
1213                for p2 in peers.iter() {
1214                    if p2 != p1 {
1215                        oracle
1216                            .add_link(p1.clone(), p2.clone(), link.clone())
1217                            .await
1218                            .unwrap();
1219                    }
1220                }
1221            }
1222
1223            // Track all three peers in set 0.
1224            let all = commonware_utils::ordered::Set::from_iter_dedup(peers.clone());
1225            oracle.manager().track(0, all);
1226
1227            // Spawn engines for B (with its own manager) and the rest.
1228            let network_b = registrations.remove(&peer_b).unwrap();
1229            let config_b = Config {
1230                public_key: peer_b.clone(),
1231                mailbox_size: NZUsize!(1024),
1232                deque_size: CACHE_SIZE,
1233                priority: false,
1234                codec_config: RangeCfg::from(..),
1235                peer_provider: oracle.manager(),
1236            };
1237            let (engine_b, mailbox_b) =
1238                Engine::<_, PublicKey, TestMessage, _>::new(context.child("peer_b"), config_b);
1239            engine_b.start(network_b);
1240
1241            let mut mailboxes = BTreeMap::new();
1242            mailboxes.insert(peer_b.clone(), mailbox_b);
1243            for (peer, network) in registrations {
1244                let ctx = context.child("peer").with_attribute("public_key", &peer);
1245                let config = Config {
1246                    public_key: peer.clone(),
1247                    mailbox_size: NZUsize!(1024),
1248                    deque_size: CACHE_SIZE,
1249                    priority: false,
1250                    codec_config: RangeCfg::from(..),
1251                    peer_provider: oracle.manager(),
1252                };
1253                let (engine, mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
1254                mailboxes.insert(peer, mailbox);
1255                engine.start(network);
1256            }
1257            context.sleep(A_JIFFY).await;
1258
1259            // Peer A broadcasts a message. B caches it.
1260            let msg = TestMessage::shared(b"eviction-latest-test");
1261            let mailbox_a = mailboxes.get(&peer_a).unwrap().clone();
1262            assert!(mailbox_a.broadcast(Recipients::All, msg.clone()).accepted());
1263            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1264
1265            let mailbox_b = mailboxes.get(&peer_b).unwrap().clone();
1266            assert_eq!(
1267                mailbox_b.get(msg.digest()).await,
1268                Some(msg.clone()),
1269                "peer B should have the message before eviction"
1270            );
1271
1272            // Track set 1 with only [B, C]. With tracked_peer_sets=2, both
1273            // sets 0 and 1 are retained, so A is still in `all.primary`. Buffered caches follow
1274            // `latest.primary`, though, so A's deque should be evicted immediately.
1275            let remaining = commonware_utils::ordered::Set::from_iter_dedup(vec![
1276                peer_b.clone(),
1277                peer_c.clone(),
1278            ]);
1279            oracle.manager().track(1, remaining);
1280            context.sleep(A_JIFFY).await;
1281
1282            assert!(
1283                mailbox_b.get(msg.digest()).await.is_none(),
1284                "message should be evicted: peer A is not in the latest peer set"
1285            );
1286
1287            // Peer A is no longer in `latest.primary`, so A does not buffer; send still runs.
1288            let fresh = TestMessage::shared(b"post-eviction-latest-test");
1289            assert!(mailbox_a
1290                .broadcast(Recipients::All, fresh.clone())
1291                .accepted());
1292            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1293
1294            assert!(
1295                mailbox_b.get(fresh.digest()).await.is_none(),
1296                "message should not be rebuffered after peer A left latest.primary"
1297            );
1298        });
1299    }
1300
1301    #[test_traced]
1302    fn test_initial_latest_peer_set_blocks_sender_not_in_latest_primary() {
1303        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1304        runner.start(|context| async move {
1305            let (network, oracle) = Network::<deterministic::Context, PublicKey>::new(
1306                context.child("network"),
1307                commonware_p2p::simulated::Config {
1308                    max_size: 1024 * 1024,
1309                    disconnect_on_block: true,
1310                    tracked_peer_sets: NZUsize!(1),
1311                },
1312            );
1313            network.start();
1314
1315            let mut schemes = (0..3)
1316                .map(|i| PrivateKey::from_seed(i as u64))
1317                .collect::<Vec<_>>();
1318            schemes.sort_by_key(|s| s.public_key());
1319            let peers: Vec<PublicKey> = schemes.iter().map(|c| c.public_key()).collect();
1320            let peer_a = peers[0].clone();
1321            let peer_b = peers[1].clone();
1322            let peer_c = peers[2].clone();
1323
1324            let mut registrations: Registrations = BTreeMap::new();
1325            for peer in &peers {
1326                let (sender, receiver) = oracle
1327                    .control(peer.clone())
1328                    .register(0, TEST_QUOTA)
1329                    .await
1330                    .unwrap();
1331                registrations.insert(peer.clone(), (sender, receiver));
1332            }
1333            let link = Link {
1334                latency: NETWORK_SPEED,
1335                jitter: Duration::ZERO,
1336                success_rate: 1.0,
1337            };
1338            for p1 in &peers {
1339                for p2 in &peers {
1340                    if p1 != p2 {
1341                        oracle
1342                            .add_link(p1.clone(), p2.clone(), link.clone())
1343                            .await
1344                            .unwrap();
1345                    }
1346                }
1347            }
1348
1349            let latest_primary = commonware_utils::ordered::Set::from_iter_dedup(vec![
1350                peer_b.clone(),
1351                peer_c.clone(),
1352            ]);
1353            let latest_secondary =
1354                commonware_utils::ordered::Set::from_iter_dedup(vec![peer_a.clone()]);
1355            oracle
1356                .manager()
1357                .track(0, TrackedPeers::new(latest_primary, latest_secondary));
1358
1359            let mut mailboxes = BTreeMap::new();
1360            for (peer, network) in registrations {
1361                let ctx = context.child("peer").with_attribute("public_key", &peer);
1362                let config = Config {
1363                    public_key: peer.clone(),
1364                    mailbox_size: NZUsize!(1024),
1365                    deque_size: CACHE_SIZE,
1366                    priority: false,
1367                    codec_config: RangeCfg::from(..),
1368                    peer_provider: oracle.manager(),
1369                };
1370                let (engine, mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
1371                mailboxes.insert(peer, mailbox);
1372                engine.start(network);
1373            }
1374            context.sleep(A_JIFFY).await;
1375
1376            let mailbox_a = mailboxes.get(&peer_a).unwrap().clone();
1377            let mailbox_b = mailboxes.get(&peer_b).unwrap().clone();
1378            let msg = TestMessage::shared(b"startup-latest-primary-only");
1379            assert!(
1380                mailbox_a
1381                    .broadcast(Recipients::All, msg.clone())
1382                    .accepted(),
1383                "Recipients::All is accepted locally; cache policy is separate"
1384            );
1385            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1386
1387            assert_eq!(
1388                mailbox_a.get(msg.digest()).await,
1389                None,
1390                "sender not in latest.primary should not buffer, including own broadcasts"
1391            );
1392            assert!(
1393                mailbox_b.get(msg.digest()).await.is_none(),
1394                "peer B should not cache messages from a sender excluded by the initial latest.primary set"
1395            );
1396        });
1397    }
1398
1399    /// Local `broadcast` queued before the engine run loop starts must still be cached when the
1400    /// peer is already in `latest.primary` (regression for biased handling of `peer_set_subscription`
1401    /// vs mailbox).
1402    #[test_traced]
1403    fn test_broadcast_queued_before_start_respects_initial_latest_primary() {
1404        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1405        runner.start(|context| async move {
1406            // Add a sole peer (self) to the network
1407            let (peers, mut registrations, oracle) =
1408                initialize_simulation(context.child("network"), 1, 1.0).await;
1409            let peer = peers[0].clone();
1410            let network = registrations.remove(&peer).unwrap();
1411            let config = Config {
1412                public_key: peer.clone(),
1413                mailbox_size: NZUsize!(1024),
1414                deque_size: CACHE_SIZE,
1415                priority: false,
1416                codec_config: RangeCfg::from(..),
1417                peer_provider: oracle.manager(),
1418            };
1419            let (engine, mailbox) =
1420                Engine::<_, PublicKey, TestMessage, _>::new(context.child("peer"), config);
1421
1422            // Enqueue a broadcast while the engine task is not running yet (only the mailbox channel)
1423            let msg = TestMessage::shared(b"queued-before-start");
1424            assert!(mailbox
1425                .broadcast(Recipients::All, msg.clone())
1426                .accepted());
1427
1428            // Start the engine (now that a message is enqueued)
1429            engine.start(network);
1430
1431            assert_eq!(
1432                mailbox.get(msg.digest()).await,
1433                Some(msg),
1434                "sender is already in the initial latest.primary set, so its local broadcast should be cached"
1435            );
1436        });
1437    }
1438
1439    #[test_traced]
1440    fn test_engine_starts_before_initial_peer_set_and_delivers_after_tracking() {
1441        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1442        runner.start(|context| async move {
1443            let (network, oracle) = Network::<deterministic::Context, PublicKey>::new(
1444                context.child("network"),
1445                commonware_p2p::simulated::Config {
1446                    max_size: 1024 * 1024,
1447                    disconnect_on_block: true,
1448                    tracked_peer_sets: NZUsize!(1),
1449                },
1450            );
1451            network.start();
1452
1453            let mut schemes = (0..2)
1454                .map(|i| PrivateKey::from_seed(i as u64))
1455                .collect::<Vec<_>>();
1456            schemes.sort_by_key(|s| s.public_key());
1457            let peers: Vec<PublicKey> = schemes.iter().map(|c| c.public_key()).collect();
1458            let peer_a = peers[0].clone();
1459            let peer_b = peers[1].clone();
1460
1461            let mut registrations: Registrations = BTreeMap::new();
1462            for peer in &peers {
1463                let (sender, receiver) = oracle
1464                    .control(peer.clone())
1465                    .register(0, TEST_QUOTA)
1466                    .await
1467                    .unwrap();
1468                registrations.insert(peer.clone(), (sender, receiver));
1469            }
1470
1471            let link = Link {
1472                latency: NETWORK_SPEED,
1473                jitter: Duration::ZERO,
1474                success_rate: 1.0,
1475            };
1476            for p1 in &peers {
1477                for p2 in &peers {
1478                    if p1 != p2 {
1479                        oracle
1480                            .add_link(p1.clone(), p2.clone(), link.clone())
1481                            .await
1482                            .unwrap();
1483                    }
1484                }
1485            }
1486
1487            let mut mailboxes = BTreeMap::new();
1488            for (peer, network) in registrations {
1489                let ctx = context.child("peer").with_attribute("public_key", &peer);
1490                let config = Config {
1491                    public_key: peer.clone(),
1492                    mailbox_size: NZUsize!(1024),
1493                    deque_size: CACHE_SIZE,
1494                    priority: false,
1495                    codec_config: RangeCfg::from(..),
1496                    peer_provider: oracle.manager(),
1497                };
1498                let (engine, mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
1499                mailboxes.insert(peer, mailbox);
1500                engine.start(network);
1501            }
1502
1503            let mailbox_a = mailboxes.get(&peer_a).unwrap().clone();
1504            let mailbox_b = mailboxes.get(&peer_b).unwrap().clone();
1505
1506            let before = TestMessage::shared(b"before-tracking");
1507            assert!(
1508                mailbox_a
1509                    .broadcast(Recipients::All, before.clone())
1510                    .accepted(),
1511                "broadcast request should be accepted before a peer set is tracked"
1512            );
1513            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1514
1515            assert_eq!(
1516                mailbox_a.get(before.digest()).await,
1517                None,
1518                "without latest.primary, local broadcasts are not buffered"
1519            );
1520            assert!(
1521                mailbox_b.get(before.digest()).await.is_none(),
1522                "without latest.primary, remote peers do not cache inbound messages"
1523            );
1524
1525            oracle.manager().track(
1526                0,
1527                commonware_utils::ordered::Set::from_iter_dedup(peers.clone()),
1528            );
1529            context.sleep(A_JIFFY).await;
1530
1531            let after = TestMessage::shared(b"after-tracking");
1532            assert!(mailbox_a
1533                .broadcast(Recipients::All, after.clone())
1534                .accepted());
1535            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1536
1537            assert_eq!(mailbox_b.get(after.digest()).await, Some(after));
1538        });
1539    }
1540
1541    #[test_traced]
1542    fn test_peer_set_update_preserves_shared_messages() {
1543        let runner = deterministic::Runner::timed(Duration::from_secs(5));
1544        runner.start(|context| async move {
1545            let (peers, mut registrations, oracle) =
1546                initialize_simulation(context.child("network"), 3, 1.0).await;
1547
1548            let peer_a = peers[0].clone();
1549            let peer_b = peers[1].clone();
1550            let peer_c = peers[2].clone();
1551
1552            // Spawn peer B with its own manager.
1553            let network_b = registrations.remove(&peer_b).unwrap();
1554            let config_b = Config {
1555                public_key: peer_b.clone(),
1556                mailbox_size: NZUsize!(1024),
1557                deque_size: CACHE_SIZE,
1558                priority: false,
1559                codec_config: RangeCfg::from(..),
1560                peer_provider: oracle.manager(),
1561            };
1562            let (engine_b, mailbox_b) =
1563                Engine::<_, PublicKey, TestMessage, _>::new(context.child("peer_b"), config_b);
1564            engine_b.start(network_b);
1565
1566            // Spawn remaining peer engines.
1567            let mut mailboxes = BTreeMap::new();
1568            mailboxes.insert(peer_b.clone(), mailbox_b);
1569            for (peer, network) in registrations {
1570                let ctx = context.child("peer").with_attribute("public_key", &peer);
1571                let config = Config {
1572                    public_key: peer.clone(),
1573                    mailbox_size: NZUsize!(1024),
1574                    deque_size: CACHE_SIZE,
1575                    priority: false,
1576                    codec_config: RangeCfg::from(..),
1577                    peer_provider: oracle.manager(),
1578                };
1579                let (engine, mailbox) = Engine::<_, PublicKey, TestMessage, _>::new(ctx, config);
1580                mailboxes.insert(peer, mailbox);
1581                engine.start(network);
1582            }
1583            context.sleep(A_JIFFY).await;
1584
1585            // Both A and C broadcast the same message.
1586            let msg = TestMessage::shared(b"shared-msg");
1587            let mailbox_a = mailboxes.get(&peer_a).unwrap().clone();
1588            let mailbox_c = mailboxes.get(&peer_c).unwrap().clone();
1589            assert!(mailbox_a.broadcast(Recipients::All, msg.clone()).accepted());
1590            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1591            assert!(mailbox_c.broadcast(Recipients::All, msg.clone()).accepted());
1592            context.sleep(NETWORK_SPEED_WITH_BUFFER).await;
1593
1594            // B has the message in both A's and C's deques (ref count = 2).
1595            let mailbox_b = mailboxes.get(&peer_b).unwrap().clone();
1596            assert_eq!(mailbox_b.get(msg.digest()).await, Some(msg.clone()));
1597
1598            // Evict peer A only; C is still in the latest primary set.
1599            let remaining = commonware_utils::ordered::Set::from_iter_dedup(vec![peer_b, peer_c]);
1600            oracle.manager().track(1, remaining);
1601            context.sleep(A_JIFFY).await;
1602
1603            // Message should still be available (C's deque still holds it).
1604            assert_eq!(
1605                mailbox_b.get(msg.digest()).await,
1606                Some(msg.clone()),
1607                "message should survive when another peer in the primary set still references it"
1608            );
1609        });
1610    }
1611}