1use super::{Variant, durability::Durable as _};
2use crate::{
3 Reporter,
4 marshal::{
5 Identifier,
6 ancestry::{AncestorStream, Ancestry, BlockProvider},
7 },
8 simplex::types::{Activity, Finalization, Notarization},
9 types::{Height, Round},
10};
11use commonware_actor::{
12 Feedback,
13 mailbox::{Overflow, Policy, Sender},
14};
15use commonware_cryptography::{Digestible, certificate::Scheme};
16use commonware_p2p::Recipients;
17use commonware_runtime::{
18 Clock, Handle,
19 telemetry::{metrics::histogram::Timed, traces::TracedExt as _},
20};
21use commonware_utils::{channel::oneshot, vec::NonEmptyVec};
22use std::{
23 collections::{BTreeMap, VecDeque, btree_map::Entry},
24 num::NonZeroUsize,
25 sync::Arc,
26};
27use tracing::{Span, info_span};
28
29pub(crate) enum Message<S: Scheme, V: Variant> {
34 GetInfo {
37 span: Span,
39 identifier: Identifier<<V::Block as Digestible>::Digest>,
41 response: oneshot::Sender<Option<(Height, <V::Block as Digestible>::Digest)>>,
43 },
44 GetBlock {
50 span: Span,
52 identifier: Identifier<<V::Block as Digestible>::Digest>,
54 response: oneshot::Sender<Option<V::Block>>,
56 },
57 GetFinalization {
59 span: Span,
61 height: Height,
63 response: oneshot::Sender<Option<Finalization<S, V::Commitment>>>,
65 },
66 GetProcessedHeight {
68 span: Span,
70 response: oneshot::Sender<Option<Height>>,
72 },
73 HintFinalized {
88 span: Span,
90 height: Height,
92 targets: NonEmptyVec<S::PublicKey>,
94 },
95 SubscribeByDigest {
97 span: Span,
99 digest: <V::Block as Digestible>::Digest,
101 fallback: DigestFallback,
103 response: oneshot::Sender<Arc<V::Block>>,
105 },
106 SubscribeByCommitment {
108 span: Span,
110 commitment: V::Commitment,
112 fallback: CommitmentFallback,
114 response: oneshot::Sender<Arc<V::Block>>,
116 },
117 HintNotarized {
122 span: Span,
124 round: Round,
126 commitment: V::Commitment,
128 },
129 GetVerified {
131 span: Span,
133 round: Round,
135 response: oneshot::Sender<Option<V::Block>>,
137 },
138 Forward {
140 span: Span,
142 round: Round,
144 commitment: V::Commitment,
146 recipients: Recipients<S::PublicKey>,
148 },
149 Proposed {
151 span: Span,
153 round: Round,
155 block: Arc<V::Block>,
157 recipients: Recipients<S::PublicKey>,
159 ack: oneshot::Sender<Handle<()>>,
161 },
162 Verified {
165 span: Span,
167 round: Round,
169 block: Arc<V::Block>,
171 ack: oneshot::Sender<Handle<()>>,
173 },
174 Certified {
177 span: Span,
179 round: Round,
181 block: Arc<V::Block>,
183 ack: oneshot::Sender<Handle<()>>,
186 },
187 SetFloor {
196 span: Span,
198 finalization: Finalization<S, V::Commitment>,
200 },
201 Prune {
206 span: Span,
208 height: Height,
210 },
211 Notarization {
213 span: Span,
215 notarization: Notarization<S, V::Commitment>,
217 },
218 Finalization {
220 span: Span,
222 finalization: Finalization<S, V::Commitment>,
224 },
225}
226
227#[derive(Clone, Copy, Debug, Eq, PartialEq)]
229pub enum DigestFallback {
230 Wait,
232 FetchByRound { round: Round },
237}
238
239impl From<DigestFallback> for CommitmentFallback {
240 fn from(fallback: DigestFallback) -> Self {
241 match fallback {
242 DigestFallback::Wait => Self::Wait,
243 DigestFallback::FetchByRound { round } => Self::FetchByRound { round },
244 }
245 }
246}
247
248#[derive(Clone, Copy, Debug, Eq, PartialEq)]
250pub enum CommitmentFallback {
251 Wait,
255 FetchByRound { round: Round },
267 FetchByCommitment { height: Height },
280}
281
282impl<S: Scheme, V: Variant> Message<S, V> {
283 pub(crate) const fn span(&self) -> &Span {
285 match self {
286 Self::GetInfo { span, .. }
287 | Self::GetBlock { span, .. }
288 | Self::GetFinalization { span, .. }
289 | Self::GetVerified { span, .. }
290 | Self::SubscribeByDigest { span, .. }
291 | Self::SubscribeByCommitment { span, .. }
292 | Self::Forward { span, .. }
293 | Self::Proposed { span, .. }
294 | Self::Verified { span, .. }
295 | Self::Certified { span, .. }
296 | Self::Notarization { span, .. }
297 | Self::Finalization { span, .. }
298 | Self::GetProcessedHeight { span, .. }
299 | Self::HintFinalized { span, .. }
300 | Self::HintNotarized { span, .. }
301 | Self::SetFloor { span, .. }
302 | Self::Prune { span, .. } => span,
303 }
304 }
305
306 pub(crate) const fn name(&self) -> &'static str {
308 match self {
309 Self::GetInfo { .. } => "get_info",
310 Self::GetBlock { .. } => "get_block",
311 Self::GetFinalization { .. } => "get_finalization",
312 Self::GetProcessedHeight { .. } => "get_processed_height",
313 Self::HintFinalized { .. } => "hint_finalized",
314 Self::SubscribeByDigest { .. } => "subscribe_by_digest",
315 Self::SubscribeByCommitment { .. } => "subscribe_by_commitment",
316 Self::HintNotarized { .. } => "hint_notarized",
317 Self::GetVerified { .. } => "get_verified",
318 Self::Forward { .. } => "forward",
319 Self::Proposed { .. } => "proposed",
320 Self::Verified { .. } => "verified",
321 Self::Certified { .. } => "certified",
322 Self::SetFloor { .. } => "set_floor",
323 Self::Prune { .. } => "prune",
324 Self::Notarization { .. } => "notarization",
325 Self::Finalization { .. } => "finalization",
326 }
327 }
328
329 fn stale(&self, current: Option<Height>) -> bool {
330 match self {
331 Self::GetInfo {
333 identifier: Identifier::Height(height),
334 ..
335 }
336 | Self::GetBlock {
337 identifier: Identifier::Height(height),
338 ..
339 }
340 | Self::GetFinalization { height, .. } => Some(*height) < current,
341 Self::HintFinalized { height, .. } => Some(*height) <= current,
343 Self::Proposed { .. } | Self::Verified { .. } | Self::Certified { .. } => false,
345 Self::GetBlock {
347 identifier: Identifier::Digest(_) | Identifier::Latest,
348 ..
349 }
350 | Self::GetInfo {
351 identifier: Identifier::Digest(_) | Identifier::Latest,
352 ..
353 }
354 | Self::GetProcessedHeight { .. } => false,
355 Self::HintNotarized { .. } => false,
356 Self::SubscribeByDigest { .. }
357 | Self::SubscribeByCommitment { .. }
358 | Self::GetVerified { .. }
359 | Self::Forward { .. }
360 | Self::SetFloor { .. }
361 | Self::Prune { .. }
362 | Self::Notarization { .. }
363 | Self::Finalization { .. } => false,
364 }
365 }
366
367 pub(crate) fn response_closed(&self) -> bool {
368 match self {
369 Self::GetInfo { response, .. } => response.is_closed(),
370 Self::GetBlock { response, .. } | Self::GetVerified { response, .. } => {
371 response.is_closed()
372 }
373 Self::GetFinalization { response, .. } => response.is_closed(),
374 Self::GetProcessedHeight { response, .. } => response.is_closed(),
375 Self::SubscribeByDigest { response, .. }
376 | Self::SubscribeByCommitment { response, .. } => response.is_closed(),
377 Self::HintNotarized { .. } => false,
378 Self::HintFinalized { .. }
379 | Self::Forward { .. }
380 | Self::Proposed { .. }
381 | Self::Verified { .. }
382 | Self::Certified { .. }
383 | Self::SetFloor { .. }
384 | Self::Prune { .. }
385 | Self::Notarization { .. }
386 | Self::Finalization { .. } => false,
387 }
388 }
389}
390
391pub(crate) struct Pending<S: Scheme, V: Variant> {
392 floor: Option<(Span, Finalization<S, V::Commitment>)>,
393 prune: Option<(Span, Height)>,
394 hints: BTreeMap<Height, (Span, NonEmptyVec<S::PublicKey>)>,
395 messages: VecDeque<PendingMessage<S, V>>,
396}
397
398enum PendingMessage<S: Scheme, V: Variant> {
399 Message(Message<S, V>),
400 HintFinalized(Height),
401}
402
403impl<S: Scheme, V: Variant> Default for Pending<S, V> {
404 fn default() -> Self {
405 Self {
406 floor: None,
407 prune: None,
408 hints: BTreeMap::new(),
409 messages: VecDeque::new(),
410 }
411 }
412}
413
414impl<S: Scheme, V: Variant> Pending<S, V> {
415 fn height(&self) -> Option<Height> {
418 self.prune.as_ref().map(|(_, height)| *height)
419 }
420
421 fn retain(&mut self) {
422 let current = self.height();
423 self.hints.retain(|height, _| Some(*height) > current);
424
425 let hints = &self.hints;
426 self.messages.retain(|message| match message {
427 PendingMessage::Message(message) => {
428 !message.response_closed() && !message.stale(current)
429 }
430 PendingMessage::HintFinalized(height) => hints.contains_key(height),
431 });
432 }
433
434 fn set_floor(&mut self, span: Span, finalization: Finalization<S, V::Commitment>) {
435 let round = finalization.round();
436 if self
437 .floor
438 .as_ref()
439 .is_some_and(|(_, floor)| floor.round() >= round)
440 {
441 return;
442 }
443
444 self.floor = Some((span, finalization));
445 }
446
447 fn prune(&mut self, span: Span, height: Height) {
448 let current = self.height();
449 if current >= Some(height) {
450 return;
451 }
452
453 self.prune = Some((span, height));
454 self.retain();
455 }
456
457 fn extend_hint_targets(
458 pending: &mut NonEmptyVec<S::PublicKey>,
459 targets: NonEmptyVec<S::PublicKey>,
460 ) {
461 for target in targets {
462 if !pending.contains(&target) {
463 pending.push(target);
464 }
465 }
466 }
467
468 fn hint_finalized(&mut self, span: Span, height: Height, targets: NonEmptyVec<S::PublicKey>) {
469 let current = self.height();
471 if current.is_some_and(|current| height <= current) {
472 return;
473 }
474
475 match self.hints.entry(height) {
476 Entry::Vacant(entry) => {
477 entry.insert((span, targets));
478 self.messages
479 .push_back(PendingMessage::HintFinalized(height));
480 }
481 Entry::Occupied(mut entry) => {
482 Self::extend_hint_targets(&mut entry.get_mut().1, targets);
483 }
484 }
485 }
486
487 fn restore_hint(&mut self, span: Span, height: Height, targets: NonEmptyVec<S::PublicKey>) {
488 match self.hints.entry(height) {
489 Entry::Vacant(entry) => {
490 entry.insert((span, targets));
491 }
492 Entry::Occupied(mut entry) => {
493 Self::extend_hint_targets(&mut entry.get_mut().1, targets);
494 }
495 }
496 self.messages
497 .push_front(PendingMessage::HintFinalized(height));
498 }
499
500 fn drain_one<F>(&mut self, message: Message<S, V>, push: &mut F) -> bool
501 where
502 F: FnMut(Message<S, V>) -> Option<Message<S, V>>,
503 {
504 let Some(message) = push(message) else {
506 return true;
507 };
508
509 match message {
511 Message::SetFloor { span, finalization } => self.set_floor(span, finalization),
512 Message::Prune { span, height } => self.prune(span, height),
513 Message::HintFinalized {
514 span,
515 height,
516 targets,
517 } => self.restore_hint(span, height, targets),
518 message => self.messages.push_front(PendingMessage::Message(message)),
519 }
520 false
521 }
522}
523
524impl<S: Scheme, V: Variant> Overflow<Message<S, V>> for Pending<S, V> {
525 fn is_empty(&self) -> bool {
526 self.floor.is_none()
527 && self.prune.is_none()
528 && self.hints.is_empty()
529 && self.messages.is_empty()
530 }
531
532 fn drain<F>(&mut self, mut push: F)
533 where
534 F: FnMut(Message<S, V>) -> Option<Message<S, V>>,
535 {
536 if let Some((span, finalization)) = self.floor.take()
539 && !self.drain_one(Message::SetFloor { span, finalization }, &mut push)
540 {
541 return;
542 }
543 if let Some((span, height)) = self.prune.take()
544 && !self.drain_one(Message::Prune { span, height }, &mut push)
545 {
546 return;
547 }
548
549 while let Some(pending) = self.messages.pop_front() {
551 match pending {
552 PendingMessage::Message(message) => {
553 if message.response_closed() {
554 continue;
555 }
556 if !self.drain_one(message, &mut push) {
557 break;
558 }
559 }
560 PendingMessage::HintFinalized(hint_height) => {
561 let Some((span, targets)) = self.hints.remove(&hint_height) else {
562 continue;
563 };
564 let message = Message::HintFinalized {
565 span,
566 height: hint_height,
567 targets,
568 };
569 if !self.drain_one(message, &mut push) {
570 break;
571 }
572 }
573 }
574 }
575 }
576}
577
578impl<S: Scheme, V: Variant> Policy for Message<S, V> {
581 type Overflow = Pending<S, V>;
582
583 fn handle(overflow: &mut Self::Overflow, message: Self) {
584 if message.response_closed() {
586 return;
587 }
588 match message {
589 Self::HintFinalized {
591 span,
592 height,
593 targets,
594 } => {
595 overflow.hint_finalized(span, height, targets);
596 }
597 Self::SetFloor { span, finalization } => {
600 overflow.set_floor(span, finalization);
601 }
602 Self::Prune { span, height } => {
603 overflow.prune(span, height);
604 }
605 message => {
606 if message.stale(overflow.height()) {
607 return;
608 }
609 overflow
610 .messages
611 .push_back(PendingMessage::Message(message));
612 }
613 }
614 }
615}
616
617#[derive(Clone)]
619pub struct Mailbox<S: Scheme, V: Variant> {
620 sender: Sender<Message<S, V>>,
621 max_pending_acks: usize,
622}
623
624impl<S: Scheme, V: Variant> Mailbox<S, V> {
625 pub(crate) const fn new(sender: Sender<Message<S, V>>, max_pending_acks: NonZeroUsize) -> Self {
627 Self {
628 sender,
629 max_pending_acks: max_pending_acks.get(),
630 }
631 }
632
633 pub const fn max_pending_acks(&self) -> usize {
636 self.max_pending_acks
637 }
638
639 pub(crate) fn ancestor_stream<I, C>(
648 &self,
649 clock: Arc<C>,
650 initial: I,
651 fetch_duration: Timed,
652 ) -> impl Ancestry<V::ApplicationBlock> + use<S, V, I, C>
653 where
654 Self: BlockProvider<Block = V::ApplicationBlock>,
655 I: IntoIterator<Item = Arc<V::ApplicationBlock>>,
656 C: Clock,
657 {
658 AncestorStream::new(clock, self.clone(), initial, fetch_duration)
659 }
660
661 pub async fn get_info(
663 &self,
664 identifier: impl Into<Identifier<<V::Block as Digestible>::Digest>>,
665 ) -> Option<(Height, <V::Block as Digestible>::Digest)> {
666 let identifier = identifier.into();
667 let (response, receiver) = oneshot::channel();
668 let _ = self.sender.enqueue(Message::GetInfo {
669 span: info_span!("marshal.mailbox.get_info"),
670 identifier,
671 response,
672 });
673 receiver.await.ok().flatten()
674 }
675
676 pub async fn get_block(
679 &self,
680 identifier: impl Into<Identifier<<V::Block as Digestible>::Digest>>,
681 ) -> Option<V::Block> {
682 let identifier = identifier.into();
683 let (response, receiver) = oneshot::channel();
684 let _ = self.sender.enqueue(Message::GetBlock {
685 span: info_span!("marshal.mailbox.get_block"),
686 identifier,
687 response,
688 });
689 receiver.await.ok().flatten()
690 }
691
692 pub async fn get_finalization(&self, height: Height) -> Option<Finalization<S, V::Commitment>> {
695 let (response, receiver) = oneshot::channel();
696 let _ = self.sender.enqueue(Message::GetFinalization {
697 span: info_span!("marshal.mailbox.get_finalization", height = height.traced()),
698 height,
699 response,
700 });
701 receiver.await.ok().flatten()
702 }
703
704 pub async fn get_processed_height(&self) -> Option<Height> {
706 let (response, receiver) = oneshot::channel();
707 let _ = self.sender.enqueue(Message::GetProcessedHeight {
708 span: info_span!("marshal.mailbox.get_processed_height"),
709 response,
710 });
711 receiver.await.ok().flatten()
712 }
713
714 pub fn hint_finalized(&self, height: Height, targets: NonEmptyVec<S::PublicKey>) {
734 let _ = self.sender.enqueue(Message::HintFinalized {
735 span: info_span!("marshal.mailbox.hint_finalized", height = height.traced()),
736 height,
737 targets,
738 });
739 }
740
741 pub fn subscribe_by_digest(
762 &self,
763 digest: <V::Block as Digestible>::Digest,
764 fallback: DigestFallback,
765 ) -> oneshot::Receiver<Arc<V::Block>> {
766 let (tx, rx) = oneshot::channel();
767 let _ = self.sender.enqueue(Message::SubscribeByDigest {
768 span: info_span!("marshal.mailbox.subscribe_by_digest", digest = %digest),
769 digest,
770 fallback,
771 response: tx,
772 });
773 rx
774 }
775
776 pub fn subscribe_by_commitment(
796 &self,
797 commitment: V::Commitment,
798 fallback: CommitmentFallback,
799 ) -> oneshot::Receiver<Arc<V::Block>> {
800 let (tx, rx) = oneshot::channel();
801 let _ = self.sender.enqueue(Message::SubscribeByCommitment {
802 span: info_span!("marshal.mailbox.subscribe_by_commitment", commitment = %commitment),
803 fallback,
804 commitment,
805 response: tx,
806 });
807 rx
808 }
809
810 pub fn hint_notarized(&self, round: Round, commitment: V::Commitment) {
819 let _ = self.sender.enqueue(Message::HintNotarized {
820 span: info_span!(
821 "marshal.mailbox.hint_notarized",
822 round = %round,
823 commitment = %commitment
824 ),
825 round,
826 commitment,
827 });
828 }
829
830 pub async fn ancestry<C>(
838 &self,
839 clock: Arc<C>,
840 (fallback, start_digest): (DigestFallback, <V::Block as Digestible>::Digest),
841 fetch_duration: Timed,
842 ) -> Option<impl Ancestry<V::ApplicationBlock> + use<S, V, C>>
843 where
844 Self: BlockProvider<Block = V::ApplicationBlock>,
845 C: Clock,
846 {
847 let receiver = self.subscribe_by_digest(start_digest, fallback);
848 receiver.await.ok().map(|block| {
849 let block = V::into_inner_shared(block);
850 self.ancestor_stream(clock, [block], fetch_duration)
851 })
852 }
853
854 pub async fn get_verified(&self, round: Round) -> Option<V::Block> {
861 let (response, receiver) = oneshot::channel();
862 let _ = self.sender.enqueue(Message::GetVerified {
863 span: info_span!("marshal.mailbox.get_verified", round = %round),
864 round,
865 response,
866 });
867 receiver.await.ok().flatten()
868 }
869
870 pub fn proposed(
882 &self,
883 round: Round,
884 block: impl Into<Arc<V::Block>>,
885 recipients: Recipients<S::PublicKey>,
886 ack: oneshot::Sender<Handle<()>>,
887 ) -> Feedback {
888 self.sender.enqueue(Message::Proposed {
889 span: info_span!("marshal.mailbox.proposed", round = %round),
890 round,
891 block: block.into(),
892 recipients,
893 ack,
894 })
895 }
896
897 pub fn verified_deferred(
904 &self,
905 round: Round,
906 block: impl Into<Arc<V::Block>>,
907 ack: oneshot::Sender<Handle<()>>,
908 ) {
909 let _ = self.sender.enqueue(Message::Verified {
910 span: info_span!("marshal.mailbox.verified", round = %round),
911 round,
912 block: block.into(),
913 ack,
914 });
915 }
916
917 #[must_use = "callers must consider block durability before proceeding"]
923 pub async fn verified(&self, round: Round, block: impl Into<Arc<V::Block>>) -> bool {
924 let (ack, receiver) = oneshot::channel();
925 self.verified_deferred(round, block, ack);
926 let Ok(handle) = receiver.await else {
927 return false;
928 };
929 handle.durable(round, "verified").await
930 }
931
932 #[must_use = "callers must consider block durability before proceeding"]
936 pub async fn certified(&self, round: Round, block: impl Into<Arc<V::Block>>) -> bool {
937 let (ack, receiver) = oneshot::channel();
938 let _ = self.sender.enqueue(Message::Certified {
939 span: info_span!("marshal.mailbox.certified", round = %round),
940 round,
941 block: block.into(),
942 ack,
943 });
944 let Ok(handle) = receiver.await else {
945 return false;
946 };
947 handle.durable(round, "certified").await
948 }
949
950 pub fn set_floor(&self, finalization: Finalization<S, V::Commitment>) {
960 let _ = self.sender.enqueue(Message::SetFloor {
961 span: info_span!("marshal.mailbox.set_floor", round = %finalization.round()),
962 finalization,
963 });
964 }
965
966 pub fn prune(&self, height: Height) {
971 let _ = self.sender.enqueue(Message::Prune {
972 span: info_span!("marshal.mailbox.prune", height = height.traced()),
973 height,
974 });
975 }
976
977 pub fn forward(
979 &self,
980 round: Round,
981 commitment: V::Commitment,
982 recipients: Recipients<S::PublicKey>,
983 ) -> Feedback {
984 self.sender.enqueue(Message::Forward {
985 span: info_span!("marshal.mailbox.forward", round = %round, commitment = %commitment),
986 round,
987 commitment,
988 recipients,
989 })
990 }
991}
992
993impl<S: Scheme, V: Variant> Reporter for Mailbox<S, V> {
994 type Activity = Activity<S, V::Commitment>;
995
996 fn report(&mut self, activity: Self::Activity) -> Feedback {
997 let message = match activity {
998 Activity::Notarization(notarization) => Message::Notarization {
999 span: info_span!("marshal.mailbox.notarization", round = %notarization.round()),
1000 notarization,
1001 },
1002 Activity::Finalization(finalization) => Message::Finalization {
1003 span: info_span!("marshal.mailbox.finalization", round = %finalization.round()),
1004 finalization,
1005 },
1006 _ => return Feedback::Ok,
1007 };
1008 self.sender.enqueue(message)
1009 }
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014 use super::*;
1015 use crate::{
1016 Heightable,
1017 marshal::{mocks::harness, standard::Standard},
1018 simplex::{scheme::bls12381_threshold::vrf as bls12381_threshold_vrf, types::Proposal},
1019 types::{Epoch, View},
1020 };
1021 use commonware_cryptography::{
1022 Digest as _, Signer as _, certificate::mocks::Fixture, ed25519::PrivateKey,
1023 };
1024 use commonware_runtime::{Runner as _, deterministic};
1025 use commonware_utils::{NZUsize, TestRng, channel::oneshot::error::TryRecvError};
1026
1027 type TestMessage = Message<harness::S, Standard<harness::B>>;
1028 type TestPending = Pending<harness::S, Standard<harness::B>>;
1029
1030 fn public_key(seed: u64) -> harness::K {
1031 PrivateKey::from_seed(seed).public_key()
1032 }
1033
1034 fn round(height: u64) -> Round {
1035 Round::new(Epoch::zero(), View::new(height))
1036 }
1037
1038 fn block(height: u64) -> harness::B {
1039 harness::make_raw_block(harness::D::EMPTY, Height::new(height), height)
1040 }
1041
1042 fn commitment(height: u64) -> harness::D {
1043 <Standard<harness::B> as Variant>::commitment(&block(height))
1044 }
1045
1046 fn finalization(height: u64) -> Finalization<harness::S, harness::D> {
1047 let mut rng = TestRng::new(height);
1048 let Fixture { schemes, .. } = bls12381_threshold_vrf::fixture::<harness::V, _>(
1049 &mut rng,
1050 harness::NAMESPACE,
1051 harness::NUM_VALIDATORS,
1052 );
1053 let proposal = Proposal::new(round(height), View::zero(), commitment(height));
1054 <harness::StandardHarness as harness::TestHarness>::make_finalization(
1055 proposal,
1056 &schemes,
1057 harness::QUORUM,
1058 )
1059 }
1060
1061 fn get_info(height: u64) -> (TestMessage, oneshot::Receiver<Option<(Height, harness::D)>>) {
1062 let (response, receiver) = oneshot::channel();
1063 (
1064 TestMessage::GetInfo {
1065 span: Span::none(),
1066 identifier: Identifier::Height(Height::new(height)),
1067 response,
1068 },
1069 receiver,
1070 )
1071 }
1072
1073 fn proposed(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1074 let (ack, receiver) = oneshot::channel();
1075 (
1076 TestMessage::Proposed {
1077 span: Span::none(),
1078 round: round(height),
1079 block: block(height).into(),
1080 recipients: Recipients::All,
1081 ack,
1082 },
1083 receiver,
1084 )
1085 }
1086
1087 fn verified(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1088 let (ack, receiver) = oneshot::channel();
1089 (
1090 TestMessage::Verified {
1091 span: Span::none(),
1092 round: round(height),
1093 block: block(height).into(),
1094 ack,
1095 },
1096 receiver,
1097 )
1098 }
1099
1100 fn certified(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1101 let (ack, receiver) = oneshot::channel();
1102 (
1103 TestMessage::Certified {
1104 span: Span::none(),
1105 round: round(height),
1106 block: block(height).into(),
1107 ack,
1108 },
1109 receiver,
1110 )
1111 }
1112
1113 fn get_block(height: u64) -> (TestMessage, oneshot::Receiver<Option<harness::B>>) {
1114 let (response, receiver) = oneshot::channel();
1115 (
1116 TestMessage::GetBlock {
1117 span: Span::none(),
1118 identifier: Identifier::Height(Height::new(height)),
1119 response,
1120 },
1121 receiver,
1122 )
1123 }
1124
1125 fn get_finalization(
1126 height: u64,
1127 ) -> (
1128 TestMessage,
1129 oneshot::Receiver<Option<Finalization<harness::S, harness::D>>>,
1130 ) {
1131 let (response, receiver) = oneshot::channel();
1132 (
1133 TestMessage::GetFinalization {
1134 span: Span::none(),
1135 height: Height::new(height),
1136 response,
1137 },
1138 receiver,
1139 )
1140 }
1141
1142 fn subscribe_by_digest(height: u64) -> (TestMessage, oneshot::Receiver<Arc<harness::B>>) {
1143 let (response, receiver) = oneshot::channel();
1144 (
1145 TestMessage::SubscribeByDigest {
1146 span: Span::none(),
1147 digest: block(height).digest(),
1148 fallback: DigestFallback::FetchByRound {
1149 round: round(height),
1150 },
1151 response,
1152 },
1153 receiver,
1154 )
1155 }
1156
1157 fn subscribe_by_commitment_message(
1158 height: u64,
1159 fallback: CommitmentFallback,
1160 ) -> (TestMessage, oneshot::Receiver<Arc<harness::B>>) {
1161 let (response, receiver) = oneshot::channel();
1162 (
1163 TestMessage::SubscribeByCommitment {
1164 span: Span::none(),
1165 commitment: commitment(height),
1166 fallback,
1167 response,
1168 },
1169 receiver,
1170 )
1171 }
1172
1173 fn hint_finalized(height: u64, target: harness::K) -> TestMessage {
1174 TestMessage::HintFinalized {
1175 span: Span::none(),
1176 height: Height::new(height),
1177 targets: NonEmptyVec::new(target),
1178 }
1179 }
1180
1181 fn hint_notarized(height: u64) -> TestMessage {
1182 TestMessage::HintNotarized {
1183 span: Span::none(),
1184 round: round(height),
1185 commitment: commitment(height),
1186 }
1187 }
1188
1189 fn set_floor(height: u64) -> TestMessage {
1190 TestMessage::SetFloor {
1191 span: Span::none(),
1192 finalization: finalization(height),
1193 }
1194 }
1195
1196 fn prune(height: u64) -> TestMessage {
1197 TestMessage::Prune {
1198 span: Span::none(),
1199 height: Height::new(height),
1200 }
1201 }
1202
1203 fn pending() -> TestPending {
1204 TestPending::default()
1205 }
1206
1207 fn drain(overflow: &mut TestPending) -> VecDeque<TestMessage> {
1208 let mut drained = VecDeque::new();
1209 overflow.drain(|message| {
1210 drained.push_back(message);
1211 None
1212 });
1213 drained
1214 }
1215
1216 fn has_get_info(overflow: &TestPending, height: u64) -> bool {
1217 overflow.messages.iter().any(|message| {
1218 matches!(
1219 message,
1220 PendingMessage::Message(TestMessage::GetInfo {
1221 identifier: Identifier::Height(found),
1222 response,
1223 ..
1224 }) if *found == Height::new(height) && !response.is_closed()
1225 )
1226 })
1227 }
1228
1229 fn has_get_block(overflow: &TestPending, height: u64) -> bool {
1230 overflow.messages.iter().any(|message| {
1231 matches!(
1232 message,
1233 PendingMessage::Message(TestMessage::GetBlock {
1234 identifier: Identifier::Height(found),
1235 response,
1236 ..
1237 }) if *found == Height::new(height) && !response.is_closed()
1238 )
1239 })
1240 }
1241
1242 fn has_get_finalization(overflow: &TestPending, height: u64) -> bool {
1243 overflow.messages.iter().any(|message| {
1244 matches!(
1245 message,
1246 PendingMessage::Message(TestMessage::GetFinalization {
1247 height: found,
1248 response,
1249 ..
1250 }) if *found == Height::new(height) && !response.is_closed()
1251 )
1252 })
1253 }
1254
1255 fn hint_targets(overflow: &TestPending, height: u64) -> Option<&NonEmptyVec<harness::K>> {
1256 overflow
1257 .hints
1258 .get(&Height::new(height))
1259 .map(|(_, targets)| targets)
1260 }
1261
1262 fn has_block_message(overflow: &TestPending, height: u64) -> bool {
1263 overflow.messages.iter().any(|message| {
1264 matches!(
1265 message,
1266 PendingMessage::Message(
1267 TestMessage::Proposed { block, .. }
1268 | TestMessage::Verified { block, .. }
1269 | TestMessage::Certified { block, .. }
1270 )
1271 if block.height() == Height::new(height)
1272 )
1273 })
1274 }
1275
1276 fn has_prune(overflow: &TestPending, height: u64) -> bool {
1277 overflow.prune.as_ref().map(|(_, height)| *height) == Some(Height::new(height))
1278 }
1279
1280 fn has_subscription(overflow: &TestPending, height: u64) -> bool {
1281 let expected_digest = block(height).digest();
1282 let expected_commitment = commitment(height);
1283 overflow.messages.iter().any(|message| {
1284 matches!(
1285 message,
1286 PendingMessage::Message(TestMessage::SubscribeByDigest { digest, response, .. })
1287 if *digest == expected_digest && !response.is_closed()
1288 ) || matches!(
1289 message,
1290 PendingMessage::Message(TestMessage::SubscribeByCommitment {
1291 commitment,
1292 response,
1293 ..
1294 }) if *commitment == expected_commitment && !response.is_closed()
1295 )
1296 })
1297 }
1298
1299 #[test]
1300 fn durable_methods_report_failure_when_mailbox_closed() {
1301 let runner = deterministic::Runner::default();
1302 runner.start(|context| async move {
1303 let (sender, receiver) =
1304 commonware_actor::mailbox::new::<TestMessage>(context, NZUsize!(1));
1305 let mailbox = Mailbox::<harness::S, Standard<harness::B>>::new(sender, NZUsize!(1));
1306 drop(receiver);
1307
1308 let (ack, receiver) = oneshot::channel();
1309 let _ = mailbox.proposed(round(1), block(1), Recipients::All, ack);
1310 assert!(receiver.await.is_err());
1311 assert!(!mailbox.verified(round(2), block(2)).await);
1312 assert!(!mailbox.certified(round(3), block(3)).await);
1313 });
1314 }
1315
1316 #[test]
1317 fn policy_coalesces_hint_targets() {
1318 let mut overflow = pending();
1319 let first = public_key(1);
1320 let second = public_key(2);
1321
1322 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1323 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1324 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, second.clone()));
1325
1326 assert_eq!(overflow.messages.len(), 1);
1327 let targets = hint_targets(&overflow, 10).expect("expected hint");
1328 assert_eq!(targets.len().get(), 2);
1329 assert!(targets.contains(&first));
1330 assert!(targets.contains(&second));
1331 }
1332
1333 #[test]
1334 fn policy_preserves_commitment_subscription_fallbacks() {
1335 let mut overflow = pending();
1336
1337 let (wait, _wait_rx) = subscribe_by_commitment_message(1, CommitmentFallback::Wait);
1338 let (by_round, _by_round_rx) = subscribe_by_commitment_message(
1339 2,
1340 CommitmentFallback::FetchByRound { round: round(2) },
1341 );
1342 let (by_commitment, _by_commitment_rx) = subscribe_by_commitment_message(
1343 3,
1344 CommitmentFallback::FetchByCommitment {
1345 height: Height::new(3),
1346 },
1347 );
1348
1349 <TestMessage as Policy>::handle(&mut overflow, wait);
1350 <TestMessage as Policy>::handle(&mut overflow, by_round);
1351 <TestMessage as Policy>::handle(&mut overflow, by_commitment);
1352
1353 let drained = drain(&mut overflow);
1354 assert_eq!(drained.len(), 3);
1355 assert!(matches!(
1356 &drained[0],
1357 TestMessage::SubscribeByCommitment {
1358 fallback: CommitmentFallback::Wait,
1359 ..
1360 }
1361 ));
1362 assert!(matches!(
1363 &drained[1],
1364 TestMessage::SubscribeByCommitment {
1365 fallback: CommitmentFallback::FetchByRound { round: found },
1366 ..
1367 } if *found == round(2)
1368 ));
1369 assert!(matches!(
1370 &drained[2],
1371 TestMessage::SubscribeByCommitment {
1372 fallback: CommitmentFallback::FetchByCommitment { height },
1373 ..
1374 } if *height == Height::new(3)
1375 ));
1376 }
1377
1378 #[test]
1379 fn policy_handles_closed_subscriptions() {
1380 let mut overflow = pending();
1381
1382 let (pending_closed, pending_closed_rx) = subscribe_by_digest(1);
1383 drop(pending_closed_rx);
1384 overflow
1385 .messages
1386 .push_back(PendingMessage::Message(pending_closed));
1387
1388 let (pending_open, mut pending_open_rx) = subscribe_by_commitment_message(
1389 2,
1390 CommitmentFallback::FetchByRound { round: round(2) },
1391 );
1392 overflow
1393 .messages
1394 .push_back(PendingMessage::Message(pending_open));
1395
1396 let (current_closed, current_closed_rx) = subscribe_by_digest(3);
1397 drop(current_closed_rx);
1398 <TestMessage as Policy>::handle(&mut overflow, current_closed);
1399
1400 assert!(!has_subscription(&overflow, 1));
1401 assert!(has_subscription(&overflow, 2));
1402 assert!(!has_subscription(&overflow, 3));
1403 assert!(matches!(
1404 pending_open_rx.try_recv(),
1405 Err(TryRecvError::Empty)
1406 ));
1407 }
1408
1409 #[test]
1410 fn policy_handles_closed_responses() {
1411 let mut overflow = pending();
1412
1413 let (pending_closed, pending_closed_rx) = get_block(1);
1414 drop(pending_closed_rx);
1415 overflow
1416 .messages
1417 .push_back(PendingMessage::Message(pending_closed));
1418
1419 let (pending_open, mut pending_open_rx) = get_info(2);
1420 overflow
1421 .messages
1422 .push_back(PendingMessage::Message(pending_open));
1423
1424 let (current_closed, current_closed_rx) = get_finalization(3);
1425 drop(current_closed_rx);
1426 <TestMessage as Policy>::handle(&mut overflow, current_closed);
1427
1428 assert!(!has_get_block(&overflow, 1));
1429 assert!(has_get_info(&overflow, 2));
1430 assert!(!has_get_finalization(&overflow, 3));
1431 assert!(matches!(
1432 pending_open_rx.try_recv(),
1433 Err(TryRecvError::Empty)
1434 ));
1435 }
1436
1437 #[test]
1438 fn policy_drain_stops_after_returned_response_closes() {
1439 let mut overflow = pending();
1440 let (first, first_rx) = get_block(1);
1441 let (second, mut second_rx) = get_info(2);
1442 overflow.messages.push_back(PendingMessage::Message(first));
1443 overflow.messages.push_back(PendingMessage::Message(second));
1444
1445 let mut first_rx = Some(first_rx);
1446 let mut attempts = 0;
1447 overflow.drain(|message| {
1448 attempts += 1;
1449 drop(first_rx.take());
1450 Some(message)
1451 });
1452 assert_eq!(attempts, 1);
1453
1454 let drained = drain(&mut overflow);
1455 assert_eq!(drained.len(), 1);
1456 assert!(matches!(
1457 &drained[0],
1458 TestMessage::GetInfo {
1459 identifier: Identifier::Height(height),
1460 response,
1461 ..
1462 } if *height == Height::new(2) && !response.is_closed()
1463 ));
1464 assert!(matches!(second_rx.try_recv(), Err(TryRecvError::Empty)));
1465 }
1466
1467 #[test]
1468 fn policy_drains_fifo() {
1469 let mut overflow = pending();
1470 let first = public_key(1);
1471 let second = public_key(2);
1472 let (response, _subscribe_rx) = oneshot::channel();
1473 let subscribe = TestMessage::SubscribeByDigest {
1474 span: Span::none(),
1475 digest: block(1).digest(),
1476 fallback: DigestFallback::Wait,
1477 response,
1478 };
1479 let (response, _processed_rx) = oneshot::channel();
1480 let processed = TestMessage::GetProcessedHeight {
1481 span: Span::none(),
1482 response,
1483 };
1484
1485 <TestMessage as Policy>::handle(&mut overflow, subscribe);
1486 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1487 <TestMessage as Policy>::handle(&mut overflow, hint_notarized(1));
1488 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, second.clone()));
1489 <TestMessage as Policy>::handle(&mut overflow, processed);
1490
1491 let drained = drain(&mut overflow);
1492 assert_eq!(drained.len(), 4);
1493 assert!(matches!(
1494 &drained[0],
1495 TestMessage::SubscribeByDigest {
1496 digest,
1497 fallback: DigestFallback::Wait,
1498 ..
1499 } if *digest == block(1).digest()
1500 ));
1501 let TestMessage::HintFinalized {
1502 height, targets, ..
1503 } = &drained[1]
1504 else {
1505 panic!("expected hint");
1506 };
1507 assert_eq!(*height, Height::new(10));
1508 assert_eq!(targets.len().get(), 2);
1509 assert!(targets.contains(&first));
1510 assert!(targets.contains(&second));
1511 assert!(matches!(
1512 &drained[2],
1513 TestMessage::HintNotarized { round: hinted, .. } if *hinted == round(1)
1514 ));
1515 assert!(matches!(
1516 &drained[3],
1517 TestMessage::GetProcessedHeight { .. }
1518 ));
1519 }
1520
1521 #[test]
1522 fn policy_keeps_highest_floor_and_prune() {
1523 let mut overflow = pending();
1524
1525 <TestMessage as Policy>::handle(&mut overflow, set_floor(5));
1526 <TestMessage as Policy>::handle(&mut overflow, set_floor(3));
1527 <TestMessage as Policy>::handle(&mut overflow, set_floor(8));
1528 <TestMessage as Policy>::handle(&mut overflow, prune(4));
1529 <TestMessage as Policy>::handle(&mut overflow, prune(2));
1530 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1531
1532 assert_eq!(
1533 overflow.floor.as_ref().map(|(_, floor)| floor.round()),
1534 Some(round(8))
1535 );
1536 assert_eq!(
1537 overflow.prune.as_ref().map(|(_, height)| *height),
1538 Some(Height::new(7))
1539 );
1540 assert!(overflow.messages.is_empty());
1541
1542 let drained = drain(&mut overflow);
1543 assert_eq!(drained.len(), 2);
1544 assert!(matches!(
1545 &drained[0],
1546 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(8)
1547 ));
1548 assert!(matches!(
1549 &drained[1],
1550 TestMessage::Prune { height, .. } if *height == Height::new(7)
1551 ));
1552 }
1553
1554 #[test]
1555 fn policy_replaces_floor_and_prune_and_drops_stale_pending_on_drain() {
1556 let mut overflow = pending();
1557
1558 overflow.floor = Some((Span::none(), finalization(5)));
1559 let (get_info_4, _get_info_4_rx) = get_info(4);
1560 let (get_block_7, _get_block_7_rx) = get_block(7);
1561 let (get_block_8, _get_block_8_rx) = get_block(8);
1562 overflow
1563 .messages
1564 .push_back(PendingMessage::Message(get_info_4));
1565 overflow
1566 .messages
1567 .push_back(PendingMessage::Message(get_block_7));
1568 overflow.hint_finalized(
1569 Span::none(),
1570 Height::new(8),
1571 NonEmptyVec::new(public_key(1)),
1572 );
1573 overflow
1574 .messages
1575 .push_back(PendingMessage::Message(get_block_8));
1576 <TestMessage as Policy>::handle(&mut overflow, set_floor(8));
1577 <TestMessage as Policy>::handle(&mut overflow, prune(8));
1578 assert_eq!(
1579 overflow.floor.as_ref().map(|(_, floor)| floor.round()),
1580 Some(round(8))
1581 );
1582 assert_eq!(overflow.messages.len(), 1);
1583 assert!(!has_get_info(&overflow, 4));
1584 assert!(!has_get_block(&overflow, 7));
1585 assert!(has_get_block(&overflow, 8));
1586 assert!(hint_targets(&overflow, 8).is_none());
1587 let drained = drain(&mut overflow);
1588 assert_eq!(drained.len(), 3);
1589 assert!(matches!(
1590 &drained[0],
1591 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(8)
1592 ));
1593 assert!(matches!(
1594 &drained[1],
1595 TestMessage::Prune { height, .. } if *height == Height::new(8)
1596 ));
1597 assert!(matches!(
1598 &drained[2],
1599 TestMessage::GetBlock {
1600 identifier: Identifier::Height(height),
1601 ..
1602 } if *height == Height::new(8)
1603 ));
1604
1605 let mut overflow = pending();
1606 overflow.prune = Some((Span::none(), Height::new(5)));
1607 let (get_finalization_4, _get_finalization_4_rx) = get_finalization(4);
1608 let (get_block_6, _get_block_6_rx) = get_block(6);
1609 let (get_block_7, _get_block_7_rx) = get_block(7);
1610 overflow
1611 .messages
1612 .push_back(PendingMessage::Message(get_finalization_4));
1613 overflow
1614 .messages
1615 .push_back(PendingMessage::Message(get_block_6));
1616 overflow.hint_finalized(
1617 Span::none(),
1618 Height::new(6),
1619 NonEmptyVec::new(public_key(2)),
1620 );
1621 overflow
1622 .messages
1623 .push_back(PendingMessage::Message(get_block_7));
1624 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1625 assert_eq!(
1626 overflow.prune.as_ref().map(|(_, height)| *height),
1627 Some(Height::new(7))
1628 );
1629 assert_eq!(overflow.messages.len(), 1);
1630 assert!(!has_get_finalization(&overflow, 4));
1631 assert!(!has_get_block(&overflow, 6));
1632 assert!(has_get_block(&overflow, 7));
1633 assert!(hint_targets(&overflow, 6).is_none());
1634 let drained = drain(&mut overflow);
1635 assert_eq!(drained.len(), 2);
1636 assert!(matches!(
1637 &drained[0],
1638 TestMessage::Prune { height, .. } if *height == Height::new(7)
1639 ));
1640 assert!(matches!(
1641 &drained[1],
1642 TestMessage::GetBlock {
1643 identifier: Identifier::Height(height),
1644 ..
1645 } if *height == Height::new(7)
1646 ));
1647 }
1648
1649 #[test]
1650 fn policy_prune_drops_closed_pending() {
1651 let mut overflow = pending();
1652 let (closed_message, closed_rx) = get_block(8);
1653 drop(closed_rx);
1654 let (open_message, mut open_rx) = get_block(8);
1655
1656 overflow
1657 .messages
1658 .push_back(PendingMessage::Message(closed_message));
1659 overflow
1660 .messages
1661 .push_back(PendingMessage::Message(open_message));
1662
1663 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1664 assert_eq!(overflow.messages.len(), 1);
1665 assert!(has_get_block(&overflow, 8));
1666 assert!(matches!(open_rx.try_recv(), Err(TryRecvError::Empty)));
1667
1668 let mut overflow = pending();
1669 let (closed_message, closed_rx) = get_finalization(8);
1670 drop(closed_rx);
1671 let (open_message, mut open_rx) = get_finalization(8);
1672
1673 overflow
1674 .messages
1675 .push_back(PendingMessage::Message(closed_message));
1676 overflow
1677 .messages
1678 .push_back(PendingMessage::Message(open_message));
1679
1680 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1681 assert_eq!(overflow.messages.len(), 1);
1682 assert!(has_get_finalization(&overflow, 8));
1683 assert!(matches!(open_rx.try_recv(), Err(TryRecvError::Empty)));
1684 }
1685
1686 #[test]
1687 fn policy_skips_retain_when_prune_height_does_not_increase() {
1688 let mut overflow = pending();
1689 <TestMessage as Policy>::handle(&mut overflow, prune(10));
1690
1691 let (closed_message, closed_rx) = get_block(11);
1692 drop(closed_rx);
1693 overflow
1694 .messages
1695 .push_back(PendingMessage::Message(closed_message));
1696
1697 <TestMessage as Policy>::handle(&mut overflow, set_floor(9));
1698 assert_eq!(overflow.messages.len(), 1);
1699
1700 <TestMessage as Policy>::handle(&mut overflow, prune(9));
1701 assert_eq!(overflow.messages.len(), 1);
1702
1703 <TestMessage as Policy>::handle(&mut overflow, prune(12));
1704 assert!(overflow.messages.is_empty());
1705 }
1706
1707 #[test]
1708 fn policy_drops_stale_requests_against_pending_floor_and_prune() {
1709 let mut overflow = pending();
1710 let (get_info_4, _get_info_4_rx) = get_info(4);
1711 let (get_info_5, _get_info_5_rx) = get_info(5);
1712 let (get_info_6, _get_info_6_rx) = get_info(6);
1713 let (get_info_7, _get_info_7_rx) = get_info(7);
1714 let (get_block_4, _get_block_4_rx) = get_block(4);
1715 let (get_block_5, _get_block_5_rx) = get_block(5);
1716 let (get_block_6, _get_block_6_rx) = get_block(6);
1717 let (get_block_7, _get_block_7_rx) = get_block(7);
1718 let (get_finalization_4, _get_finalization_4_rx) = get_finalization(4);
1719 let (get_finalization_6, _get_finalization_6_rx) = get_finalization(6);
1720
1721 <TestMessage as Policy>::handle(&mut overflow, set_floor(5));
1722 <TestMessage as Policy>::handle(&mut overflow, get_info_4);
1723 <TestMessage as Policy>::handle(&mut overflow, get_info_5);
1724 <TestMessage as Policy>::handle(&mut overflow, get_block_4);
1725 <TestMessage as Policy>::handle(&mut overflow, get_block_5);
1726 <TestMessage as Policy>::handle(&mut overflow, get_finalization_4);
1727 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(5, public_key(1)));
1728 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(6, public_key(2)));
1729
1730 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1731 assert!(has_prune(&overflow, 7));
1732 <TestMessage as Policy>::handle(&mut overflow, get_info_6);
1733 <TestMessage as Policy>::handle(&mut overflow, get_finalization_6);
1734 assert!(!has_get_finalization(&overflow, 6));
1735 <TestMessage as Policy>::handle(&mut overflow, get_block_6);
1736 <TestMessage as Policy>::handle(&mut overflow, get_info_7);
1737 assert!(has_get_info(&overflow, 7));
1738 <TestMessage as Policy>::handle(&mut overflow, get_block_7);
1739 assert!(has_get_block(&overflow, 7));
1740
1741 let drained = drain(&mut overflow);
1742 assert_eq!(drained.len(), 4);
1743 assert!(matches!(
1744 &drained[0],
1745 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(5)
1746 ));
1747 assert!(matches!(
1748 &drained[1],
1749 TestMessage::Prune { height, .. } if *height == Height::new(7)
1750 ));
1751 assert!(matches!(
1752 &drained[2],
1753 TestMessage::GetInfo {
1754 identifier: Identifier::Height(height),
1755 ..
1756 } if *height == Height::new(7)
1757 ));
1758 assert!(matches!(
1759 &drained[3],
1760 TestMessage::GetBlock {
1761 identifier: Identifier::Height(height),
1762 ..
1763 } if *height == Height::new(7)
1764 ));
1765 }
1766
1767 #[test]
1768 fn policy_keeps_block_messages_and_waiters() {
1769 let mut overflow = pending();
1770
1771 let (proposed_message, mut proposed_ack) = proposed(4);
1772 let (verified_message, mut verified_ack) = verified(6);
1773 let (certified_message, mut certified_ack) = certified(8);
1774 overflow
1775 .messages
1776 .push_back(PendingMessage::Message(proposed_message));
1777 overflow
1778 .messages
1779 .push_back(PendingMessage::Message(verified_message));
1780 overflow
1781 .messages
1782 .push_back(PendingMessage::Message(certified_message));
1783
1784 <TestMessage as Policy>::handle(&mut overflow, set_floor(7));
1785 assert!(has_block_message(&overflow, 4));
1786 assert!(has_block_message(&overflow, 6));
1787 assert!(has_block_message(&overflow, 8));
1788 assert!(matches!(proposed_ack.try_recv(), Err(TryRecvError::Empty)));
1789 assert!(matches!(verified_ack.try_recv(), Err(TryRecvError::Empty)));
1790 assert!(matches!(certified_ack.try_recv(), Err(TryRecvError::Empty)));
1791
1792 <TestMessage as Policy>::handle(&mut overflow, prune(9));
1793 assert!(has_block_message(&overflow, 8));
1794 assert!(matches!(certified_ack.try_recv(), Err(TryRecvError::Empty)));
1795
1796 let (stale, mut stale_ack) = proposed(8);
1797 <TestMessage as Policy>::handle(&mut overflow, stale);
1798 assert!(has_block_message(&overflow, 8));
1799 assert!(matches!(stale_ack.try_recv(), Err(TryRecvError::Empty)));
1800
1801 let (current, mut current_ack) = verified(9);
1802 <TestMessage as Policy>::handle(&mut overflow, current);
1803 assert!(has_block_message(&overflow, 9));
1804 assert!(matches!(current_ack.try_recv(), Err(TryRecvError::Empty)));
1805
1806 let drained = drain(&mut overflow);
1807 assert!(matches!(drained[0], TestMessage::SetFloor { .. }));
1808 assert!(matches!(drained[1], TestMessage::Prune { .. }));
1809 }
1810}