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