alto_chain/application/
ingress.rs

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