1use super::{Processed, 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::{Digested, 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 GetProcessed {
68 span: Span,
70 response: oneshot::Sender<Option<Processed>>,
72 },
73 GetAnchor {
75 span: Span,
77 response: oneshot::Sender<Option<(Processed, V::Block)>>,
79 },
80 HintFinalized {
95 span: Span,
97 height: Height,
99 targets: NonEmptyVec<S::PublicKey>,
101 },
102 SubscribeByDigest {
104 span: Span,
106 digest: <V::Block as Digestible>::Digest,
108 fallback: DigestFallback,
110 response: oneshot::Sender<V::Block>,
112 },
113 SubscribeByCommitment {
115 span: Span,
117 commitment: V::Commitment,
119 fallback: CommitmentFallback,
121 response: oneshot::Sender<V::Block>,
123 },
124 HintNotarized {
129 span: Span,
131 round: Round,
133 commitment: V::Commitment,
135 },
136 GetVerified {
138 span: Span,
140 round: Round,
142 response: oneshot::Sender<Option<V::Block>>,
144 },
145 Forward {
147 span: Span,
149 round: Round,
151 commitment: V::Commitment,
153 recipients: Recipients<S::PublicKey>,
155 },
156 Proposed {
158 span: Span,
160 round: Round,
162 block: V::Block,
164 recipients: Recipients<S::PublicKey>,
166 ack: oneshot::Sender<Handle<()>>,
168 },
169 Prepared {
171 span: Span,
173 round: Round,
175 block: V::Block,
177 recipients: Recipients<S::PublicKey>,
179 },
180 Verified {
183 span: Span,
185 round: Round,
187 block: V::Block,
189 ack: oneshot::Sender<Handle<()>>,
191 },
192 Certified {
195 span: Span,
197 round: Round,
199 block: V::Block,
201 ack: oneshot::Sender<Handle<()>>,
204 },
205 SetFloor {
215 span: Span,
217 finalization: Finalization<S, V::Commitment>,
219 },
220 Prune {
228 span: Span,
230 height: Height,
232 },
233 Notarization {
235 span: Span,
237 notarization: Notarization<S, V::Commitment>,
239 },
240 Finalization {
242 span: Span,
244 finalization: Finalization<S, V::Commitment>,
246 },
247 Certification {
249 span: Span,
251 notarization: Notarization<S, V::Commitment>,
253 },
254}
255
256#[derive(Clone, Copy, Debug, Eq, PartialEq)]
258pub enum DigestFallback {
259 Wait,
261 FetchByRound { round: Round },
266}
267
268impl From<DigestFallback> for CommitmentFallback {
269 fn from(fallback: DigestFallback) -> Self {
270 match fallback {
271 DigestFallback::Wait => Self::Wait,
272 DigestFallback::FetchByRound { round } => Self::FetchByRound { round },
273 }
274 }
275}
276
277#[derive(Clone, Copy, Debug, Eq, PartialEq)]
279pub enum CommitmentFallback {
280 Wait,
284 FetchByRound { round: Round },
298 FetchByCommitment { height: Height },
311}
312
313impl<S: Scheme, V: Variant> Message<S, V> {
314 pub(crate) const fn span(&self) -> &Span {
316 match self {
317 Self::GetInfo { span, .. }
318 | Self::GetBlock { span, .. }
319 | Self::GetFinalization { span, .. }
320 | Self::GetVerified { span, .. }
321 | Self::SubscribeByDigest { span, .. }
322 | Self::SubscribeByCommitment { span, .. }
323 | Self::Forward { span, .. }
324 | Self::Proposed { span, .. }
325 | Self::Prepared { span, .. }
326 | Self::Verified { span, .. }
327 | Self::Certified { span, .. }
328 | Self::Notarization { span, .. }
329 | Self::Finalization { span, .. }
330 | Self::Certification { span, .. }
331 | Self::GetProcessed { span, .. }
332 | Self::GetAnchor { span, .. }
333 | Self::HintFinalized { span, .. }
334 | Self::HintNotarized { span, .. }
335 | Self::SetFloor { span, .. }
336 | Self::Prune { span, .. } => span,
337 }
338 }
339
340 pub(crate) const fn name(&self) -> &'static str {
342 match self {
343 Self::GetInfo { .. } => "get_info",
344 Self::GetBlock { .. } => "get_block",
345 Self::GetFinalization { .. } => "get_finalization",
346 Self::GetProcessed { .. } => "get_processed",
347 Self::GetAnchor { .. } => "get_anchor",
348 Self::HintFinalized { .. } => "hint_finalized",
349 Self::SubscribeByDigest { .. } => "subscribe_by_digest",
350 Self::SubscribeByCommitment { .. } => "subscribe_by_commitment",
351 Self::HintNotarized { .. } => "hint_notarized",
352 Self::GetVerified { .. } => "get_verified",
353 Self::Forward { .. } => "forward",
354 Self::Proposed { .. } => "proposed",
355 Self::Prepared { .. } => "prepared",
356 Self::Verified { .. } => "verified",
357 Self::Certified { .. } => "certified",
358 Self::SetFloor { .. } => "set_floor",
359 Self::Prune { .. } => "prune",
360 Self::Notarization { .. } => "notarization",
361 Self::Finalization { .. } => "finalization",
362 Self::Certification { .. } => "certification",
363 }
364 }
365
366 fn stale(&self, current: Option<Height>) -> bool {
367 match self {
368 Self::GetInfo {
370 identifier: Identifier::Height(height),
371 ..
372 }
373 | Self::GetBlock {
374 identifier: Identifier::Height(height),
375 ..
376 }
377 | Self::GetFinalization { height, .. } => Some(*height) < current,
378 Self::HintFinalized { height, .. } => Some(*height) <= current,
380 Self::Proposed { .. } | Self::Verified { .. } | Self::Certified { .. } => false,
382 Self::GetBlock {
384 identifier: Identifier::Digest(_) | Identifier::Latest,
385 ..
386 }
387 | Self::GetInfo {
388 identifier: Identifier::Digest(_) | Identifier::Latest,
389 ..
390 }
391 | Self::GetProcessed { .. }
392 | Self::GetAnchor { .. } => false,
393 Self::HintNotarized { .. } => false,
394 Self::SubscribeByDigest { .. }
395 | Self::SubscribeByCommitment { .. }
396 | Self::GetVerified { .. }
397 | Self::Forward { .. }
398 | Self::Prepared { .. }
399 | Self::SetFloor { .. }
400 | Self::Prune { .. }
401 | Self::Notarization { .. }
402 | Self::Finalization { .. }
403 | Self::Certification { .. } => false,
404 }
405 }
406
407 pub(crate) fn response_closed(&self) -> bool {
408 match self {
409 Self::GetInfo { response, .. } => response.is_closed(),
410 Self::GetBlock { response, .. } | Self::GetVerified { response, .. } => {
411 response.is_closed()
412 }
413 Self::GetFinalization { response, .. } => response.is_closed(),
414 Self::GetProcessed { response, .. } => response.is_closed(),
415 Self::GetAnchor { response, .. } => response.is_closed(),
416 Self::SubscribeByDigest { response, .. }
417 | Self::SubscribeByCommitment { response, .. } => response.is_closed(),
418 Self::HintNotarized { .. } => false,
419 Self::HintFinalized { .. }
420 | Self::Forward { .. }
421 | Self::Proposed { .. }
422 | Self::Prepared { .. }
423 | Self::Verified { .. }
424 | Self::Certified { .. }
425 | Self::SetFloor { .. }
426 | Self::Prune { .. }
427 | Self::Notarization { .. }
428 | Self::Finalization { .. }
429 | Self::Certification { .. } => false,
430 }
431 }
432}
433
434pub(crate) struct Pending<S: Scheme, V: Variant> {
435 floor: Option<(Span, Finalization<S, V::Commitment>)>,
436 prune: Option<(Span, Height)>,
437 hints: BTreeMap<Height, (Span, NonEmptyVec<S::PublicKey>)>,
438 messages: VecDeque<PendingMessage<S, V>>,
439}
440
441enum PendingMessage<S: Scheme, V: Variant> {
442 Message(Message<S, V>),
443 HintFinalized(Height),
444}
445
446impl<S: Scheme, V: Variant> Default for Pending<S, V> {
447 fn default() -> Self {
448 Self {
449 floor: None,
450 prune: None,
451 hints: BTreeMap::new(),
452 messages: VecDeque::new(),
453 }
454 }
455}
456
457impl<S: Scheme, V: Variant> Pending<S, V> {
458 fn height(&self) -> Option<Height> {
461 self.prune.as_ref().map(|(_, height)| *height)
462 }
463
464 fn retain(&mut self) {
465 let current = self.height();
466 self.hints.retain(|height, _| Some(*height) > current);
467
468 let hints = &self.hints;
469 self.messages.retain(|message| match message {
470 PendingMessage::Message(message) => {
471 !message.response_closed() && !message.stale(current)
472 }
473 PendingMessage::HintFinalized(height) => hints.contains_key(height),
474 });
475 }
476
477 fn set_floor(&mut self, span: Span, finalization: Finalization<S, V::Commitment>) {
478 let round = finalization.round();
479 if self
480 .floor
481 .as_ref()
482 .is_some_and(|(_, floor)| floor.round() >= round)
483 {
484 return;
485 }
486
487 self.floor = Some((span, finalization));
488 }
489
490 fn prune(&mut self, span: Span, height: Height) {
491 let current = self.height();
492 if current >= Some(height) {
493 return;
494 }
495
496 self.prune = Some((span, height));
497 self.retain();
498 }
499
500 fn extend_hint_targets(
501 pending: &mut NonEmptyVec<S::PublicKey>,
502 targets: NonEmptyVec<S::PublicKey>,
503 ) {
504 for target in targets {
505 if !pending.contains(&target) {
506 pending.push(target);
507 }
508 }
509 }
510
511 fn hint_finalized(&mut self, span: Span, height: Height, targets: NonEmptyVec<S::PublicKey>) {
512 let current = self.height();
514 if current.is_some_and(|current| height <= current) {
515 return;
516 }
517
518 match self.hints.entry(height) {
519 Entry::Vacant(entry) => {
520 entry.insert((span, targets));
521 self.messages
522 .push_back(PendingMessage::HintFinalized(height));
523 }
524 Entry::Occupied(mut entry) => {
525 Self::extend_hint_targets(&mut entry.get_mut().1, targets);
526 }
527 }
528 }
529
530 fn restore_hint(&mut self, span: Span, height: Height, targets: NonEmptyVec<S::PublicKey>) {
531 match self.hints.entry(height) {
532 Entry::Vacant(entry) => {
533 entry.insert((span, targets));
534 }
535 Entry::Occupied(mut entry) => {
536 Self::extend_hint_targets(&mut entry.get_mut().1, targets);
537 }
538 }
539 self.messages
540 .push_front(PendingMessage::HintFinalized(height));
541 }
542
543 fn drain_one<F>(&mut self, message: Message<S, V>, push: &mut F) -> bool
544 where
545 F: FnMut(Message<S, V>) -> Option<Message<S, V>>,
546 {
547 let Some(message) = push(message) else {
549 return true;
550 };
551
552 match message {
554 Message::SetFloor { span, finalization } => self.set_floor(span, finalization),
555 Message::Prune { span, height } => self.prune(span, height),
556 Message::HintFinalized {
557 span,
558 height,
559 targets,
560 } => self.restore_hint(span, height, targets),
561 message => self.messages.push_front(PendingMessage::Message(message)),
562 }
563 false
564 }
565}
566
567impl<S: Scheme, V: Variant> Overflow<Message<S, V>> for Pending<S, V> {
568 fn is_empty(&self) -> bool {
569 self.floor.is_none()
570 && self.prune.is_none()
571 && self.hints.is_empty()
572 && self.messages.is_empty()
573 }
574
575 fn drain<F>(&mut self, mut push: F)
576 where
577 F: FnMut(Message<S, V>) -> Option<Message<S, V>>,
578 {
579 if let Some((span, finalization)) = self.floor.take()
582 && !self.drain_one(Message::SetFloor { span, finalization }, &mut push)
583 {
584 return;
585 }
586 if let Some((span, height)) = self.prune.take()
587 && !self.drain_one(Message::Prune { span, height }, &mut push)
588 {
589 return;
590 }
591
592 while let Some(pending) = self.messages.pop_front() {
594 match pending {
595 PendingMessage::Message(message) => {
596 if message.response_closed() {
597 continue;
598 }
599 if !self.drain_one(message, &mut push) {
600 break;
601 }
602 }
603 PendingMessage::HintFinalized(hint_height) => {
604 let Some((span, targets)) = self.hints.remove(&hint_height) else {
605 continue;
606 };
607 let message = Message::HintFinalized {
608 span,
609 height: hint_height,
610 targets,
611 };
612 if !self.drain_one(message, &mut push) {
613 break;
614 }
615 }
616 }
617 }
618 }
619}
620
621impl<S: Scheme, V: Variant> Policy for Message<S, V> {
624 type Overflow = Pending<S, V>;
625
626 fn handle(overflow: &mut Self::Overflow, message: Self) {
627 if message.response_closed() {
629 return;
630 }
631 match message {
632 Self::HintFinalized {
634 span,
635 height,
636 targets,
637 } => {
638 overflow.hint_finalized(span, height, targets);
639 }
640 Self::SetFloor { span, finalization } => {
643 overflow.set_floor(span, finalization);
644 }
645 Self::Prune { span, height } => {
646 overflow.prune(span, height);
647 }
648 message => {
649 if message.stale(overflow.height()) {
650 return;
651 }
652 overflow
653 .messages
654 .push_back(PendingMessage::Message(message));
655 }
656 }
657 }
658}
659
660#[derive(Clone)]
662pub struct Mailbox<S: Scheme, V: Variant> {
663 sender: Sender<Message<S, V>>,
664 max_pending_acks: usize,
665}
666
667impl<S: Scheme, V: Variant> Mailbox<S, V> {
668 pub(crate) const fn new(sender: Sender<Message<S, V>>, max_pending_acks: NonZeroUsize) -> Self {
670 Self {
671 sender,
672 max_pending_acks: max_pending_acks.get(),
673 }
674 }
675
676 pub const fn max_pending_acks(&self) -> usize {
679 self.max_pending_acks
680 }
681
682 pub(crate) fn ancestor_stream<I, C>(
691 &self,
692 clock: Arc<C>,
693 initial: I,
694 fetch_duration: Timed,
695 ) -> impl Ancestry<V::ApplicationBlock> + use<S, V, I, C>
696 where
697 Self: BlockProvider<Block = V::ApplicationBlock>,
698 I: IntoIterator<Item = Digested<V::ApplicationBlock>>,
699 C: Clock,
700 {
701 AncestorStream::new(clock, self.clone(), initial, fetch_duration)
702 }
703
704 pub async fn get_info(
706 &self,
707 identifier: impl Into<Identifier<<V::Block as Digestible>::Digest>>,
708 ) -> Option<(Height, <V::Block as Digestible>::Digest)> {
709 let identifier = identifier.into();
710 let (response, receiver) = oneshot::channel();
711 let _ = self.sender.enqueue(Message::GetInfo {
712 span: info_span!("marshal.mailbox.get_info"),
713 identifier,
714 response,
715 });
716 receiver.await.ok().flatten()
717 }
718
719 pub async fn get_block(
722 &self,
723 identifier: impl Into<Identifier<<V::Block as Digestible>::Digest>>,
724 ) -> Option<V::Block> {
725 let identifier = identifier.into();
726 let (response, receiver) = oneshot::channel();
727 let _ = self.sender.enqueue(Message::GetBlock {
728 span: info_span!("marshal.mailbox.get_block"),
729 identifier,
730 response,
731 });
732 receiver.await.ok().flatten()
733 }
734
735 pub async fn get_finalization(&self, height: Height) -> Option<Finalization<S, V::Commitment>> {
738 let (response, receiver) = oneshot::channel();
739 let _ = self.sender.enqueue(Message::GetFinalization {
740 span: info_span!("marshal.mailbox.get_finalization", height = height.traced()),
741 height,
742 response,
743 });
744 receiver.await.ok().flatten()
745 }
746
747 pub async fn get_processed(&self) -> Option<Processed> {
751 let (response, receiver) = oneshot::channel();
752 let _ = self.sender.enqueue(Message::GetProcessed {
753 span: info_span!("marshal.mailbox.get_processed"),
754 response,
755 });
756 receiver.await.ok().flatten()
757 }
758
759 pub async fn get_anchor(&self) -> Option<(Processed, V::Block)> {
765 let (response, receiver) = oneshot::channel();
766 let _ = self.sender.enqueue(Message::GetAnchor {
767 span: info_span!("marshal.mailbox.get_anchor"),
768 response,
769 });
770 receiver.await.ok().flatten()
771 }
772
773 pub fn hint_finalized(&self, height: Height, targets: NonEmptyVec<S::PublicKey>) {
793 let _ = self.sender.enqueue(Message::HintFinalized {
794 span: info_span!("marshal.mailbox.hint_finalized", height = height.traced()),
795 height,
796 targets,
797 });
798 }
799
800 pub fn subscribe_by_digest(
821 &self,
822 digest: <V::Block as Digestible>::Digest,
823 fallback: DigestFallback,
824 ) -> oneshot::Receiver<V::Block> {
825 let (tx, rx) = oneshot::channel();
826 let _ = self.sender.enqueue(Message::SubscribeByDigest {
827 span: info_span!("marshal.mailbox.subscribe_by_digest", digest = %digest),
828 digest,
829 fallback,
830 response: tx,
831 });
832 rx
833 }
834
835 pub fn subscribe_by_commitment(
855 &self,
856 commitment: V::Commitment,
857 fallback: CommitmentFallback,
858 ) -> oneshot::Receiver<V::Block> {
859 let (tx, rx) = oneshot::channel();
860 let _ = self.sender.enqueue(Message::SubscribeByCommitment {
861 span: info_span!("marshal.mailbox.subscribe_by_commitment", commitment = %commitment),
862 fallback,
863 commitment,
864 response: tx,
865 });
866 rx
867 }
868
869 pub fn hint_notarized(&self, round: Round, commitment: V::Commitment) {
878 let _ = self.sender.enqueue(Message::HintNotarized {
879 span: info_span!(
880 "marshal.mailbox.hint_notarized",
881 round = %round,
882 commitment = %commitment
883 ),
884 round,
885 commitment,
886 });
887 }
888
889 pub async fn ancestry<C>(
897 &self,
898 clock: Arc<C>,
899 (fallback, start_digest): (DigestFallback, <V::Block as Digestible>::Digest),
900 fetch_duration: Timed,
901 ) -> Option<impl Ancestry<V::ApplicationBlock> + use<S, V, C>>
902 where
903 Self: BlockProvider<Block = V::ApplicationBlock>,
904 C: Clock,
905 {
906 let receiver = self.subscribe_by_digest(start_digest, fallback);
907 receiver.await.ok().map(|block| {
908 let block = V::into_shared(block);
909 self.ancestor_stream(clock, [block], fetch_duration)
910 })
911 }
912
913 pub async fn get_verified(&self, round: Round) -> Option<V::Block> {
921 let (response, receiver) = oneshot::channel();
922 let _ = self.sender.enqueue(Message::GetVerified {
923 span: info_span!("marshal.mailbox.get_verified", round = %round),
924 round,
925 response,
926 });
927 receiver.await.ok().flatten()
928 }
929
930 pub fn proposed(
945 &self,
946 round: Round,
947 block: impl Into<V::Block>,
948 recipients: Recipients<S::PublicKey>,
949 ack: oneshot::Sender<Handle<()>>,
950 ) -> Feedback {
951 self.sender.enqueue(Message::Proposed {
952 span: info_span!("marshal.mailbox.proposed", round = %round),
953 round,
954 block: block.into(),
955 recipients,
956 ack,
957 })
958 }
959
960 pub fn prepared(
966 &self,
967 round: Round,
968 block: impl Into<V::Block>,
969 recipients: Recipients<S::PublicKey>,
970 ) -> Feedback {
971 self.sender.enqueue(Message::Prepared {
972 span: info_span!("marshal.mailbox.prepared", round = %round),
973 round,
974 block: block.into(),
975 recipients,
976 })
977 }
978
979 pub fn verified_deferred(
987 &self,
988 round: Round,
989 block: impl Into<V::Block>,
990 ack: oneshot::Sender<Handle<()>>,
991 ) {
992 let _ = self.sender.enqueue(Message::Verified {
993 span: info_span!("marshal.mailbox.verified", round = %round),
994 round,
995 block: block.into(),
996 ack,
997 });
998 }
999
1000 #[must_use = "callers must consider block durability before proceeding"]
1006 pub async fn verified(&self, round: Round, block: impl Into<V::Block>) -> bool {
1007 let (ack, receiver) = oneshot::channel();
1008 self.verified_deferred(round, block, ack);
1009 let Ok(handle) = receiver.await else {
1010 return false;
1011 };
1012 handle.durable(round, "verified").await
1013 }
1014
1015 #[must_use = "callers must consider block durability before proceeding"]
1019 pub async fn certified(&self, round: Round, block: impl Into<V::Block>) -> bool {
1020 let (ack, receiver) = oneshot::channel();
1021 let _ = self.sender.enqueue(Message::Certified {
1022 span: info_span!("marshal.mailbox.certified", round = %round),
1023 round,
1024 block: block.into(),
1025 ack,
1026 });
1027 let Ok(handle) = receiver.await else {
1028 return false;
1029 };
1030 handle.durable(round, "certified").await
1031 }
1032
1033 pub fn set_floor(&self, finalization: Finalization<S, V::Commitment>) {
1048 let _ = self.sender.enqueue(Message::SetFloor {
1049 span: info_span!("marshal.mailbox.set_floor", round = %finalization.round()),
1050 finalization,
1051 });
1052 }
1053
1054 pub fn prune(&self, height: Height) {
1062 let _ = self.sender.enqueue(Message::Prune {
1063 span: info_span!("marshal.mailbox.prune", height = height.traced()),
1064 height,
1065 });
1066 }
1067
1068 pub fn forward(
1070 &self,
1071 round: Round,
1072 commitment: V::Commitment,
1073 recipients: Recipients<S::PublicKey>,
1074 ) -> Feedback {
1075 self.sender.enqueue(Message::Forward {
1076 span: info_span!("marshal.mailbox.forward", round = %round, commitment = %commitment),
1077 round,
1078 commitment,
1079 recipients,
1080 })
1081 }
1082}
1083
1084impl<S: Scheme, V: Variant> Reporter for Mailbox<S, V> {
1085 type Activity = Activity<S, V::Commitment>;
1086
1087 fn report(&mut self, activity: Self::Activity) -> Feedback {
1088 let message = match activity {
1089 Activity::Notarization(notarization) => Message::Notarization {
1090 span: info_span!("marshal.mailbox.notarization", round = %notarization.round()),
1091 notarization,
1092 },
1093 Activity::Finalization(finalization) => Message::Finalization {
1094 span: info_span!("marshal.mailbox.finalization", round = %finalization.round()),
1095 finalization,
1096 },
1097 Activity::Certification(notarization) => Message::Certification {
1098 span: info_span!("marshal.mailbox.certification", round = %notarization.round()),
1099 notarization,
1100 },
1101 _ => return Feedback::Ok,
1102 };
1103 self.sender.enqueue(message)
1104 }
1105}
1106
1107#[cfg(test)]
1108mod tests {
1109 use super::*;
1110 use crate::{
1111 Heightable,
1112 marshal::{mocks::harness, standard::Standard},
1113 simplex::{scheme::bls12381_threshold::vrf as bls12381_threshold_vrf, types::Proposal},
1114 types::{Epoch, View},
1115 };
1116 use commonware_cryptography::{
1117 Digest as _, Signer as _, certificate::mocks::Fixture, ed25519::PrivateKey,
1118 };
1119 use commonware_runtime::{Runner as _, deterministic};
1120 use commonware_utils::{NZUsize, TestRng, channel::oneshot::error::TryRecvError};
1121
1122 type TestMessage = Message<harness::S, Standard<harness::B>>;
1123 type TestPending = Pending<harness::S, Standard<harness::B>>;
1124
1125 fn public_key(seed: u64) -> harness::K {
1126 PrivateKey::from_seed(seed).public_key()
1127 }
1128
1129 fn round(height: u64) -> Round {
1130 Round::new(Epoch::zero(), View::new(height))
1131 }
1132
1133 fn block(height: u64) -> Digested<harness::B> {
1134 let block = harness::make_raw_block(harness::D::EMPTY, Height::new(height), height);
1135 let digest = block.digest();
1136 Digested::precomputed(block, digest)
1137 }
1138
1139 fn commitment(height: u64) -> harness::D {
1140 block(height).digest()
1141 }
1142
1143 fn finalization(height: u64) -> Finalization<harness::S, harness::D> {
1144 let mut rng = TestRng::new(height);
1145 let Fixture { schemes, .. } = bls12381_threshold_vrf::fixture::<harness::V, _>(
1146 &mut rng,
1147 harness::NAMESPACE,
1148 harness::NUM_VALIDATORS,
1149 );
1150 let proposal = Proposal::new(round(height), View::zero(), commitment(height));
1151 <harness::StandardHarness as harness::TestHarness>::make_finalization(
1152 proposal,
1153 &schemes,
1154 harness::QUORUM,
1155 )
1156 }
1157
1158 fn get_info(height: u64) -> (TestMessage, oneshot::Receiver<Option<(Height, harness::D)>>) {
1159 let (response, receiver) = oneshot::channel();
1160 (
1161 TestMessage::GetInfo {
1162 span: Span::none(),
1163 identifier: Identifier::Height(Height::new(height)),
1164 response,
1165 },
1166 receiver,
1167 )
1168 }
1169
1170 fn proposed(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1171 let (ack, receiver) = oneshot::channel();
1172 (
1173 TestMessage::Proposed {
1174 span: Span::none(),
1175 round: round(height),
1176 block: block(height),
1177 recipients: Recipients::All,
1178 ack,
1179 },
1180 receiver,
1181 )
1182 }
1183
1184 fn verified(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1185 let (ack, receiver) = oneshot::channel();
1186 (
1187 TestMessage::Verified {
1188 span: Span::none(),
1189 round: round(height),
1190 block: block(height),
1191 ack,
1192 },
1193 receiver,
1194 )
1195 }
1196
1197 fn certified(height: u64) -> (TestMessage, oneshot::Receiver<Handle<()>>) {
1198 let (ack, receiver) = oneshot::channel();
1199 (
1200 TestMessage::Certified {
1201 span: Span::none(),
1202 round: round(height),
1203 block: block(height),
1204 ack,
1205 },
1206 receiver,
1207 )
1208 }
1209
1210 fn get_block(height: u64) -> (TestMessage, oneshot::Receiver<Option<Digested<harness::B>>>) {
1211 let (response, receiver) = oneshot::channel();
1212 (
1213 TestMessage::GetBlock {
1214 span: Span::none(),
1215 identifier: Identifier::Height(Height::new(height)),
1216 response,
1217 },
1218 receiver,
1219 )
1220 }
1221
1222 fn get_finalization(
1223 height: u64,
1224 ) -> (
1225 TestMessage,
1226 oneshot::Receiver<Option<Finalization<harness::S, harness::D>>>,
1227 ) {
1228 let (response, receiver) = oneshot::channel();
1229 (
1230 TestMessage::GetFinalization {
1231 span: Span::none(),
1232 height: Height::new(height),
1233 response,
1234 },
1235 receiver,
1236 )
1237 }
1238
1239 fn subscribe_by_digest(height: u64) -> (TestMessage, oneshot::Receiver<Digested<harness::B>>) {
1240 let (response, receiver) = oneshot::channel();
1241 (
1242 TestMessage::SubscribeByDigest {
1243 span: Span::none(),
1244 digest: block(height).digest(),
1245 fallback: DigestFallback::FetchByRound {
1246 round: round(height),
1247 },
1248 response,
1249 },
1250 receiver,
1251 )
1252 }
1253
1254 fn subscribe_by_commitment_message(
1255 height: u64,
1256 fallback: CommitmentFallback,
1257 ) -> (TestMessage, oneshot::Receiver<Digested<harness::B>>) {
1258 let (response, receiver) = oneshot::channel();
1259 (
1260 TestMessage::SubscribeByCommitment {
1261 span: Span::none(),
1262 commitment: commitment(height),
1263 fallback,
1264 response,
1265 },
1266 receiver,
1267 )
1268 }
1269
1270 fn hint_finalized(height: u64, target: harness::K) -> TestMessage {
1271 TestMessage::HintFinalized {
1272 span: Span::none(),
1273 height: Height::new(height),
1274 targets: NonEmptyVec::new(target),
1275 }
1276 }
1277
1278 fn hint_notarized(height: u64) -> TestMessage {
1279 TestMessage::HintNotarized {
1280 span: Span::none(),
1281 round: round(height),
1282 commitment: commitment(height),
1283 }
1284 }
1285
1286 fn set_floor(height: u64) -> TestMessage {
1287 TestMessage::SetFloor {
1288 span: Span::none(),
1289 finalization: finalization(height),
1290 }
1291 }
1292
1293 fn prune(height: u64) -> TestMessage {
1294 TestMessage::Prune {
1295 span: Span::none(),
1296 height: Height::new(height),
1297 }
1298 }
1299
1300 fn pending() -> TestPending {
1301 TestPending::default()
1302 }
1303
1304 fn drain(overflow: &mut TestPending) -> VecDeque<TestMessage> {
1305 let mut drained = VecDeque::new();
1306 overflow.drain(|message| {
1307 drained.push_back(message);
1308 None
1309 });
1310 drained
1311 }
1312
1313 fn has_get_info(overflow: &TestPending, height: u64) -> bool {
1314 overflow.messages.iter().any(|message| {
1315 matches!(
1316 message,
1317 PendingMessage::Message(TestMessage::GetInfo {
1318 identifier: Identifier::Height(found),
1319 response,
1320 ..
1321 }) if *found == Height::new(height) && !response.is_closed()
1322 )
1323 })
1324 }
1325
1326 fn has_get_block(overflow: &TestPending, height: u64) -> bool {
1327 overflow.messages.iter().any(|message| {
1328 matches!(
1329 message,
1330 PendingMessage::Message(TestMessage::GetBlock {
1331 identifier: Identifier::Height(found),
1332 response,
1333 ..
1334 }) if *found == Height::new(height) && !response.is_closed()
1335 )
1336 })
1337 }
1338
1339 fn has_get_finalization(overflow: &TestPending, height: u64) -> bool {
1340 overflow.messages.iter().any(|message| {
1341 matches!(
1342 message,
1343 PendingMessage::Message(TestMessage::GetFinalization {
1344 height: found,
1345 response,
1346 ..
1347 }) if *found == Height::new(height) && !response.is_closed()
1348 )
1349 })
1350 }
1351
1352 fn hint_targets(overflow: &TestPending, height: u64) -> Option<&NonEmptyVec<harness::K>> {
1353 overflow
1354 .hints
1355 .get(&Height::new(height))
1356 .map(|(_, targets)| targets)
1357 }
1358
1359 fn has_block_message(overflow: &TestPending, height: u64) -> bool {
1360 overflow.messages.iter().any(|message| {
1361 matches!(
1362 message,
1363 PendingMessage::Message(
1364 TestMessage::Proposed { block, .. }
1365 | TestMessage::Verified { block, .. }
1366 | TestMessage::Certified { block, .. }
1367 )
1368 if block.height() == Height::new(height)
1369 )
1370 })
1371 }
1372
1373 fn has_prune(overflow: &TestPending, height: u64) -> bool {
1374 overflow.prune.as_ref().map(|(_, height)| *height) == Some(Height::new(height))
1375 }
1376
1377 fn has_subscription(overflow: &TestPending, height: u64) -> bool {
1378 let expected_digest = block(height).digest();
1379 let expected_commitment = commitment(height);
1380 overflow.messages.iter().any(|message| {
1381 matches!(
1382 message,
1383 PendingMessage::Message(TestMessage::SubscribeByDigest { digest, response, .. })
1384 if *digest == expected_digest && !response.is_closed()
1385 ) || matches!(
1386 message,
1387 PendingMessage::Message(TestMessage::SubscribeByCommitment {
1388 commitment,
1389 response,
1390 ..
1391 }) if *commitment == expected_commitment && !response.is_closed()
1392 )
1393 })
1394 }
1395
1396 #[test]
1397 fn durable_methods_report_failure_when_mailbox_closed() {
1398 let runner = deterministic::Runner::default();
1399 runner.start(|context| async move {
1400 let (sender, receiver) =
1401 commonware_actor::mailbox::new::<TestMessage>(context, NZUsize!(1));
1402 let mailbox = Mailbox::<harness::S, Standard<harness::B>>::new(sender, NZUsize!(1));
1403 drop(receiver);
1404
1405 let (ack, receiver) = oneshot::channel();
1406 let _ = mailbox.proposed(round(1), block(1), Recipients::All, ack);
1407 assert!(receiver.await.is_err());
1408 assert!(!mailbox.verified(round(2), block(2)).await);
1409 assert!(!mailbox.certified(round(3), block(3)).await);
1410 });
1411 }
1412
1413 #[test]
1414 fn policy_coalesces_hint_targets() {
1415 let mut overflow = pending();
1416 let first = public_key(1);
1417 let second = public_key(2);
1418
1419 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1420 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1421 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, second.clone()));
1422
1423 assert_eq!(overflow.messages.len(), 1);
1424 let targets = hint_targets(&overflow, 10).expect("expected hint");
1425 assert_eq!(targets.len().get(), 2);
1426 assert!(targets.contains(&first));
1427 assert!(targets.contains(&second));
1428 }
1429
1430 #[test]
1431 fn policy_preserves_commitment_subscription_fallbacks() {
1432 let mut overflow = pending();
1433
1434 let (wait, _wait_rx) = subscribe_by_commitment_message(1, CommitmentFallback::Wait);
1435 let (by_round, _by_round_rx) = subscribe_by_commitment_message(
1436 2,
1437 CommitmentFallback::FetchByRound { round: round(2) },
1438 );
1439 let (by_commitment, _by_commitment_rx) = subscribe_by_commitment_message(
1440 3,
1441 CommitmentFallback::FetchByCommitment {
1442 height: Height::new(3),
1443 },
1444 );
1445
1446 <TestMessage as Policy>::handle(&mut overflow, wait);
1447 <TestMessage as Policy>::handle(&mut overflow, by_round);
1448 <TestMessage as Policy>::handle(&mut overflow, by_commitment);
1449
1450 let drained = drain(&mut overflow);
1451 assert_eq!(drained.len(), 3);
1452 assert!(matches!(
1453 &drained[0],
1454 TestMessage::SubscribeByCommitment {
1455 fallback: CommitmentFallback::Wait,
1456 ..
1457 }
1458 ));
1459 assert!(matches!(
1460 &drained[1],
1461 TestMessage::SubscribeByCommitment {
1462 fallback: CommitmentFallback::FetchByRound { round: found },
1463 ..
1464 } if *found == round(2)
1465 ));
1466 assert!(matches!(
1467 &drained[2],
1468 TestMessage::SubscribeByCommitment {
1469 fallback: CommitmentFallback::FetchByCommitment { height },
1470 ..
1471 } if *height == Height::new(3)
1472 ));
1473 }
1474
1475 #[test]
1476 fn policy_handles_closed_subscriptions() {
1477 let mut overflow = pending();
1478
1479 let (pending_closed, pending_closed_rx) = subscribe_by_digest(1);
1480 drop(pending_closed_rx);
1481 overflow
1482 .messages
1483 .push_back(PendingMessage::Message(pending_closed));
1484
1485 let (pending_open, mut pending_open_rx) = subscribe_by_commitment_message(
1486 2,
1487 CommitmentFallback::FetchByRound { round: round(2) },
1488 );
1489 overflow
1490 .messages
1491 .push_back(PendingMessage::Message(pending_open));
1492
1493 let (current_closed, current_closed_rx) = subscribe_by_digest(3);
1494 drop(current_closed_rx);
1495 <TestMessage as Policy>::handle(&mut overflow, current_closed);
1496
1497 assert!(!has_subscription(&overflow, 1));
1498 assert!(has_subscription(&overflow, 2));
1499 assert!(!has_subscription(&overflow, 3));
1500 assert!(matches!(
1501 pending_open_rx.try_recv(),
1502 Err(TryRecvError::Empty)
1503 ));
1504 }
1505
1506 #[test]
1507 fn policy_handles_closed_responses() {
1508 let mut overflow = pending();
1509
1510 let (pending_closed, pending_closed_rx) = get_block(1);
1511 drop(pending_closed_rx);
1512 overflow
1513 .messages
1514 .push_back(PendingMessage::Message(pending_closed));
1515
1516 let (pending_open, mut pending_open_rx) = get_info(2);
1517 overflow
1518 .messages
1519 .push_back(PendingMessage::Message(pending_open));
1520
1521 let (current_closed, current_closed_rx) = get_finalization(3);
1522 drop(current_closed_rx);
1523 <TestMessage as Policy>::handle(&mut overflow, current_closed);
1524
1525 assert!(!has_get_block(&overflow, 1));
1526 assert!(has_get_info(&overflow, 2));
1527 assert!(!has_get_finalization(&overflow, 3));
1528 assert!(matches!(
1529 pending_open_rx.try_recv(),
1530 Err(TryRecvError::Empty)
1531 ));
1532 }
1533
1534 #[test]
1535 fn policy_drain_stops_after_returned_response_closes() {
1536 let mut overflow = pending();
1537 let (first, first_rx) = get_block(1);
1538 let (second, mut second_rx) = get_info(2);
1539 overflow.messages.push_back(PendingMessage::Message(first));
1540 overflow.messages.push_back(PendingMessage::Message(second));
1541
1542 let mut first_rx = Some(first_rx);
1543 let mut attempts = 0;
1544 overflow.drain(|message| {
1545 attempts += 1;
1546 drop(first_rx.take());
1547 Some(message)
1548 });
1549 assert_eq!(attempts, 1);
1550
1551 let drained = drain(&mut overflow);
1552 assert_eq!(drained.len(), 1);
1553 assert!(matches!(
1554 &drained[0],
1555 TestMessage::GetInfo {
1556 identifier: Identifier::Height(height),
1557 response,
1558 ..
1559 } if *height == Height::new(2) && !response.is_closed()
1560 ));
1561 assert!(matches!(second_rx.try_recv(), Err(TryRecvError::Empty)));
1562 }
1563
1564 #[test]
1565 fn policy_drains_fifo() {
1566 let mut overflow = pending();
1567 let first = public_key(1);
1568 let second = public_key(2);
1569 let (response, _subscribe_rx) = oneshot::channel();
1570 let subscribe = TestMessage::SubscribeByDigest {
1571 span: Span::none(),
1572 digest: block(1).digest(),
1573 fallback: DigestFallback::Wait,
1574 response,
1575 };
1576 let (response, _processed_rx) = oneshot::channel();
1577 let processed = TestMessage::GetProcessed {
1578 span: Span::none(),
1579 response,
1580 };
1581
1582 <TestMessage as Policy>::handle(&mut overflow, subscribe);
1583 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, first.clone()));
1584 <TestMessage as Policy>::handle(&mut overflow, hint_notarized(1));
1585 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(10, second.clone()));
1586 <TestMessage as Policy>::handle(&mut overflow, processed);
1587
1588 let drained = drain(&mut overflow);
1589 assert_eq!(drained.len(), 4);
1590 assert!(matches!(
1591 &drained[0],
1592 TestMessage::SubscribeByDigest {
1593 digest,
1594 fallback: DigestFallback::Wait,
1595 ..
1596 } if *digest == block(1).digest()
1597 ));
1598 let TestMessage::HintFinalized {
1599 height, targets, ..
1600 } = &drained[1]
1601 else {
1602 panic!("expected hint");
1603 };
1604 assert_eq!(*height, Height::new(10));
1605 assert_eq!(targets.len().get(), 2);
1606 assert!(targets.contains(&first));
1607 assert!(targets.contains(&second));
1608 assert!(matches!(
1609 &drained[2],
1610 TestMessage::HintNotarized { round: hinted, .. } if *hinted == round(1)
1611 ));
1612 assert!(matches!(&drained[3], TestMessage::GetProcessed { .. }));
1613 }
1614
1615 #[test]
1616 fn policy_keeps_highest_floor_and_prune() {
1617 let mut overflow = pending();
1618
1619 <TestMessage as Policy>::handle(&mut overflow, set_floor(5));
1620 <TestMessage as Policy>::handle(&mut overflow, set_floor(3));
1621 <TestMessage as Policy>::handle(&mut overflow, set_floor(8));
1622 <TestMessage as Policy>::handle(&mut overflow, prune(4));
1623 <TestMessage as Policy>::handle(&mut overflow, prune(2));
1624 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1625
1626 assert_eq!(
1627 overflow.floor.as_ref().map(|(_, floor)| floor.round()),
1628 Some(round(8))
1629 );
1630 assert_eq!(
1631 overflow.prune.as_ref().map(|(_, height)| *height),
1632 Some(Height::new(7))
1633 );
1634 assert!(overflow.messages.is_empty());
1635
1636 let drained = drain(&mut overflow);
1637 assert_eq!(drained.len(), 2);
1638 assert!(matches!(
1639 &drained[0],
1640 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(8)
1641 ));
1642 assert!(matches!(
1643 &drained[1],
1644 TestMessage::Prune { height, .. } if *height == Height::new(7)
1645 ));
1646 }
1647
1648 #[test]
1649 fn policy_replaces_floor_and_prune_and_drops_stale_pending_on_drain() {
1650 let mut overflow = pending();
1651
1652 overflow.floor = Some((Span::none(), finalization(5)));
1653 let (get_info_4, _get_info_4_rx) = get_info(4);
1654 let (get_block_7, _get_block_7_rx) = get_block(7);
1655 let (get_block_8, _get_block_8_rx) = get_block(8);
1656 overflow
1657 .messages
1658 .push_back(PendingMessage::Message(get_info_4));
1659 overflow
1660 .messages
1661 .push_back(PendingMessage::Message(get_block_7));
1662 overflow.hint_finalized(
1663 Span::none(),
1664 Height::new(8),
1665 NonEmptyVec::new(public_key(1)),
1666 );
1667 overflow
1668 .messages
1669 .push_back(PendingMessage::Message(get_block_8));
1670 <TestMessage as Policy>::handle(&mut overflow, set_floor(8));
1671 <TestMessage as Policy>::handle(&mut overflow, prune(8));
1672 assert_eq!(
1673 overflow.floor.as_ref().map(|(_, floor)| floor.round()),
1674 Some(round(8))
1675 );
1676 assert_eq!(overflow.messages.len(), 1);
1677 assert!(!has_get_info(&overflow, 4));
1678 assert!(!has_get_block(&overflow, 7));
1679 assert!(has_get_block(&overflow, 8));
1680 assert!(hint_targets(&overflow, 8).is_none());
1681 let drained = drain(&mut overflow);
1682 assert_eq!(drained.len(), 3);
1683 assert!(matches!(
1684 &drained[0],
1685 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(8)
1686 ));
1687 assert!(matches!(
1688 &drained[1],
1689 TestMessage::Prune { height, .. } if *height == Height::new(8)
1690 ));
1691 assert!(matches!(
1692 &drained[2],
1693 TestMessage::GetBlock {
1694 identifier: Identifier::Height(height),
1695 ..
1696 } if *height == Height::new(8)
1697 ));
1698
1699 let mut overflow = pending();
1700 overflow.prune = Some((Span::none(), Height::new(5)));
1701 let (get_finalization_4, _get_finalization_4_rx) = get_finalization(4);
1702 let (get_block_6, _get_block_6_rx) = get_block(6);
1703 let (get_block_7, _get_block_7_rx) = get_block(7);
1704 overflow
1705 .messages
1706 .push_back(PendingMessage::Message(get_finalization_4));
1707 overflow
1708 .messages
1709 .push_back(PendingMessage::Message(get_block_6));
1710 overflow.hint_finalized(
1711 Span::none(),
1712 Height::new(6),
1713 NonEmptyVec::new(public_key(2)),
1714 );
1715 overflow
1716 .messages
1717 .push_back(PendingMessage::Message(get_block_7));
1718 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1719 assert_eq!(
1720 overflow.prune.as_ref().map(|(_, height)| *height),
1721 Some(Height::new(7))
1722 );
1723 assert_eq!(overflow.messages.len(), 1);
1724 assert!(!has_get_finalization(&overflow, 4));
1725 assert!(!has_get_block(&overflow, 6));
1726 assert!(has_get_block(&overflow, 7));
1727 assert!(hint_targets(&overflow, 6).is_none());
1728 let drained = drain(&mut overflow);
1729 assert_eq!(drained.len(), 2);
1730 assert!(matches!(
1731 &drained[0],
1732 TestMessage::Prune { height, .. } if *height == Height::new(7)
1733 ));
1734 assert!(matches!(
1735 &drained[1],
1736 TestMessage::GetBlock {
1737 identifier: Identifier::Height(height),
1738 ..
1739 } if *height == Height::new(7)
1740 ));
1741 }
1742
1743 #[test]
1744 fn policy_prune_drops_closed_pending() {
1745 let mut overflow = pending();
1746 let (closed_message, closed_rx) = get_block(8);
1747 drop(closed_rx);
1748 let (open_message, mut open_rx) = get_block(8);
1749
1750 overflow
1751 .messages
1752 .push_back(PendingMessage::Message(closed_message));
1753 overflow
1754 .messages
1755 .push_back(PendingMessage::Message(open_message));
1756
1757 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1758 assert_eq!(overflow.messages.len(), 1);
1759 assert!(has_get_block(&overflow, 8));
1760 assert!(matches!(open_rx.try_recv(), Err(TryRecvError::Empty)));
1761
1762 let mut overflow = pending();
1763 let (closed_message, closed_rx) = get_finalization(8);
1764 drop(closed_rx);
1765 let (open_message, mut open_rx) = get_finalization(8);
1766
1767 overflow
1768 .messages
1769 .push_back(PendingMessage::Message(closed_message));
1770 overflow
1771 .messages
1772 .push_back(PendingMessage::Message(open_message));
1773
1774 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1775 assert_eq!(overflow.messages.len(), 1);
1776 assert!(has_get_finalization(&overflow, 8));
1777 assert!(matches!(open_rx.try_recv(), Err(TryRecvError::Empty)));
1778 }
1779
1780 #[test]
1781 fn policy_skips_retain_when_prune_height_does_not_increase() {
1782 let mut overflow = pending();
1783 <TestMessage as Policy>::handle(&mut overflow, prune(10));
1784
1785 let (closed_message, closed_rx) = get_block(11);
1786 drop(closed_rx);
1787 overflow
1788 .messages
1789 .push_back(PendingMessage::Message(closed_message));
1790
1791 <TestMessage as Policy>::handle(&mut overflow, set_floor(9));
1792 assert_eq!(overflow.messages.len(), 1);
1793
1794 <TestMessage as Policy>::handle(&mut overflow, prune(9));
1795 assert_eq!(overflow.messages.len(), 1);
1796
1797 <TestMessage as Policy>::handle(&mut overflow, prune(12));
1798 assert!(overflow.messages.is_empty());
1799 }
1800
1801 #[test]
1802 fn policy_drops_stale_requests_against_pending_floor_and_prune() {
1803 let mut overflow = pending();
1804 let (get_info_4, _get_info_4_rx) = get_info(4);
1805 let (get_info_5, _get_info_5_rx) = get_info(5);
1806 let (get_info_6, _get_info_6_rx) = get_info(6);
1807 let (get_info_7, _get_info_7_rx) = get_info(7);
1808 let (get_block_4, _get_block_4_rx) = get_block(4);
1809 let (get_block_5, _get_block_5_rx) = get_block(5);
1810 let (get_block_6, _get_block_6_rx) = get_block(6);
1811 let (get_block_7, _get_block_7_rx) = get_block(7);
1812 let (get_finalization_4, _get_finalization_4_rx) = get_finalization(4);
1813 let (get_finalization_6, _get_finalization_6_rx) = get_finalization(6);
1814
1815 <TestMessage as Policy>::handle(&mut overflow, set_floor(5));
1816 <TestMessage as Policy>::handle(&mut overflow, get_info_4);
1817 <TestMessage as Policy>::handle(&mut overflow, get_info_5);
1818 <TestMessage as Policy>::handle(&mut overflow, get_block_4);
1819 <TestMessage as Policy>::handle(&mut overflow, get_block_5);
1820 <TestMessage as Policy>::handle(&mut overflow, get_finalization_4);
1821 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(5, public_key(1)));
1822 <TestMessage as Policy>::handle(&mut overflow, hint_finalized(6, public_key(2)));
1823
1824 <TestMessage as Policy>::handle(&mut overflow, prune(7));
1825 assert!(has_prune(&overflow, 7));
1826 <TestMessage as Policy>::handle(&mut overflow, get_info_6);
1827 <TestMessage as Policy>::handle(&mut overflow, get_finalization_6);
1828 assert!(!has_get_finalization(&overflow, 6));
1829 <TestMessage as Policy>::handle(&mut overflow, get_block_6);
1830 <TestMessage as Policy>::handle(&mut overflow, get_info_7);
1831 assert!(has_get_info(&overflow, 7));
1832 <TestMessage as Policy>::handle(&mut overflow, get_block_7);
1833 assert!(has_get_block(&overflow, 7));
1834
1835 let drained = drain(&mut overflow);
1836 assert_eq!(drained.len(), 4);
1837 assert!(matches!(
1838 &drained[0],
1839 TestMessage::SetFloor { finalization, .. } if finalization.round() == round(5)
1840 ));
1841 assert!(matches!(
1842 &drained[1],
1843 TestMessage::Prune { height, .. } if *height == Height::new(7)
1844 ));
1845 assert!(matches!(
1846 &drained[2],
1847 TestMessage::GetInfo {
1848 identifier: Identifier::Height(height),
1849 ..
1850 } if *height == Height::new(7)
1851 ));
1852 assert!(matches!(
1853 &drained[3],
1854 TestMessage::GetBlock {
1855 identifier: Identifier::Height(height),
1856 ..
1857 } if *height == Height::new(7)
1858 ));
1859 }
1860
1861 #[test]
1862 fn policy_keeps_block_messages_and_waiters() {
1863 let mut overflow = pending();
1864
1865 let (proposed_message, mut proposed_ack) = proposed(4);
1866 let (verified_message, mut verified_ack) = verified(6);
1867 let (certified_message, mut certified_ack) = certified(8);
1868 overflow
1869 .messages
1870 .push_back(PendingMessage::Message(proposed_message));
1871 overflow
1872 .messages
1873 .push_back(PendingMessage::Message(verified_message));
1874 overflow
1875 .messages
1876 .push_back(PendingMessage::Message(certified_message));
1877
1878 <TestMessage as Policy>::handle(&mut overflow, set_floor(7));
1879 assert!(has_block_message(&overflow, 4));
1880 assert!(has_block_message(&overflow, 6));
1881 assert!(has_block_message(&overflow, 8));
1882 assert!(matches!(proposed_ack.try_recv(), Err(TryRecvError::Empty)));
1883 assert!(matches!(verified_ack.try_recv(), Err(TryRecvError::Empty)));
1884 assert!(matches!(certified_ack.try_recv(), Err(TryRecvError::Empty)));
1885
1886 <TestMessage as Policy>::handle(&mut overflow, prune(9));
1887 assert!(has_block_message(&overflow, 8));
1888 assert!(matches!(certified_ack.try_recv(), Err(TryRecvError::Empty)));
1889
1890 let (stale, mut stale_ack) = proposed(8);
1891 <TestMessage as Policy>::handle(&mut overflow, stale);
1892 assert!(has_block_message(&overflow, 8));
1893 assert!(matches!(stale_ack.try_recv(), Err(TryRecvError::Empty)));
1894
1895 let (current, mut current_ack) = verified(9);
1896 <TestMessage as Policy>::handle(&mut overflow, current);
1897 assert!(has_block_message(&overflow, 9));
1898 assert!(matches!(current_ack.try_recv(), Err(TryRecvError::Empty)));
1899
1900 let drained = drain(&mut overflow);
1901 assert!(matches!(drained[0], TestMessage::SetFloor { .. }));
1902 assert!(matches!(drained[1], TestMessage::Prune { .. }));
1903 }
1904}