commonware_glue/stateful/probe/mailbox.rs
1use commonware_actor::mailbox::{Policy, Sender};
2use commonware_consensus::{
3 marshal::core::{Mailbox as MarshalMailbox, Variant},
4 simplex::types::Finalization,
5};
6use commonware_cryptography::certificate::Scheme;
7use commonware_utils::channel::oneshot;
8use std::collections::VecDeque;
9
10/// A message that can be sent to the [`Probe`](super::Probe).
11pub(crate) enum Message<S, V>
12where
13 S: Scheme,
14 V: Variant,
15{
16 /// Subscribe for the receipt of the floor finalization from peers.
17 Subscribe {
18 /// The response channel to send the finalization to.
19 response: oneshot::Sender<Finalization<S, V::Commitment>>,
20 },
21 /// Attach a marshal mailbox, moving the actor from discovery to service once any
22 /// discovered floor has been consumed. Service answers peers' `Request` from the
23 /// attached marshal and never issues outbound requests.
24 Attach {
25 /// The marshal mailbox to serve the latest finalization from.
26 marshal: MarshalMailbox<S, V>,
27 },
28}
29
30impl<S, V> Policy for Message<S, V>
31where
32 S: Scheme,
33 V: Variant,
34{
35 type Overflow = VecDeque<Self>;
36
37 fn handle(overflow: &mut Self::Overflow, message: Self) {
38 overflow.push_back(message);
39 }
40}
41
42/// Handle to the mailbox of the [`Probe`](super::Probe).
43#[derive(Clone)]
44pub struct Mailbox<S, V>
45where
46 S: Scheme,
47 V: Variant,
48{
49 sender: Sender<Message<S, V>>,
50}
51
52impl<S, V> Mailbox<S, V>
53where
54 S: Scheme,
55 V: Variant,
56{
57 pub(crate) const fn new(sender: Sender<Message<S, V>>) -> Self {
58 Self { sender }
59 }
60
61 /// Open a subscription to the receipt of the floor finalization from peers.
62 ///
63 /// While the actor is still discovering, this requests discovery if no floor has been selected
64 /// yet. Dropping the receiver cancels this subscription; if all subscribers are dropped before
65 /// a floor is selected, discovery may be abandoned. If marshal is later attached, the actor
66 /// transitions to service without a cached floor and later subscriptions will not restart
67 /// discovery.
68 ///
69 /// Callers that need a floor must keep the receiver alive until it resolves and should attach
70 /// only after consuming that floor.
71 ///
72 /// If a floor has already been selected, the receiver resolves immediately.
73 pub fn subscribe(&self) -> oneshot::Receiver<Finalization<S, V::Commitment>> {
74 let (tx, rx) = oneshot::channel();
75 let _ = self.sender.enqueue(Message::Subscribe { response: tx });
76 rx
77 }
78
79 /// Attach a marshal mailbox so the actor can serve the latest finalization to peers.
80 ///
81 /// This moves the actor from discovery to service. It is applied only after any
82 /// discovered floor has been delivered to its subscribers. If no floor was ever requested, or
83 /// every pending subscriber was dropped before a floor was selected, the actor serves without a
84 /// cached floor.
85 pub fn attach(&self, marshal: MarshalMailbox<S, V>) {
86 let _ = self.sender.enqueue(Message::Attach { marshal });
87 }
88}