alto_chain/application/
ingress.rs

1use alto_types::Block;
2use commonware_consensus::{
3    threshold_simplex::types::{Context, View},
4    Automaton, Relay, Reporter,
5};
6use commonware_cryptography::sha256::Digest;
7use futures::{
8    channel::{mpsc, oneshot},
9    SinkExt,
10};
11
12/// Messages sent to the application.
13pub enum Message {
14    Genesis {
15        response: oneshot::Sender<Digest>,
16    },
17    Propose {
18        view: View,
19        parent: (View, Digest),
20        response: oneshot::Sender<Digest>,
21    },
22    Broadcast {
23        payload: Digest,
24    },
25    Verify {
26        view: View,
27        parent: (View, Digest),
28        payload: Digest,
29        response: oneshot::Sender<bool>,
30    },
31    Finalized {
32        block: Block,
33    },
34}
35
36/// Mailbox for the application.
37#[derive(Clone)]
38pub struct Mailbox {
39    sender: mpsc::Sender<Message>,
40}
41
42impl Mailbox {
43    pub(super) fn new(sender: mpsc::Sender<Message>) -> Self {
44        Self { sender }
45    }
46}
47
48impl Automaton for Mailbox {
49    type Digest = Digest;
50    type Context = Context<Self::Digest>;
51
52    async fn genesis(&mut self) -> Self::Digest {
53        let (response, receiver) = oneshot::channel();
54        self.sender
55            .send(Message::Genesis { response })
56            .await
57            .expect("Failed to send genesis");
58        receiver.await.expect("Failed to receive genesis")
59    }
60
61    async fn propose(&mut self, context: Context<Self::Digest>) -> oneshot::Receiver<Self::Digest> {
62        // If we linked payloads to their parent, we would include
63        // the parent in the `Context` in the payload.
64        let (response, receiver) = oneshot::channel();
65        self.sender
66            .send(Message::Propose {
67                view: context.view,
68                parent: context.parent,
69                response,
70            })
71            .await
72            .expect("Failed to send propose");
73        receiver
74    }
75
76    async fn verify(
77        &mut self,
78        context: Context<Self::Digest>,
79        payload: Self::Digest,
80    ) -> oneshot::Receiver<bool> {
81        // If we linked payloads to their parent, we would verify
82        // the parent included in the payload matches the provided `Context`.
83        let (response, receiver) = oneshot::channel();
84        self.sender
85            .send(Message::Verify {
86                view: context.view,
87                parent: context.parent,
88                payload,
89                response,
90            })
91            .await
92            .expect("Failed to send verify");
93        receiver
94    }
95}
96
97impl Relay for Mailbox {
98    type Digest = Digest;
99
100    async fn broadcast(&mut self, digest: Self::Digest) {
101        self.sender
102            .send(Message::Broadcast { payload: digest })
103            .await
104            .expect("Failed to send broadcast");
105    }
106}
107
108impl Reporter for Mailbox {
109    type Activity = Block;
110
111    async fn report(&mut self, block: Self::Activity) {
112        self.sender
113            .send(Message::Finalized { block })
114            .await
115            .expect("Failed to send finalized");
116    }
117}