1use std::sync::Arc;
4
5use anyhow::{Context, Result, bail};
6use either::Either;
7use espresso_types::{PubKey, SeqTypes, v0::traits::SequencerPersistence};
8use hotshot::types::Message;
9use hotshot_new_protocol::client::ClientApi;
10use hotshot_types::{
11 message::MessageKind,
12 traits::network::{BroadcastDelay, ConnectedNetwork, Topic, ViewMessage},
13};
14use request_response::network::Bytes;
15use serde::{Deserialize, Serialize};
16use tokio::sync::mpsc::{Receiver, Sender, error::TrySendError};
17use vbs::{BinarySerializer, bincode_serializer::BincodeSerializer, version::StaticVersion};
18
19use crate::{
20 consensus_handle::ConsensusHandle,
21 context::{ConsensusNode, TaskList},
22};
23
24#[derive(Debug, Serialize, Deserialize, Clone)]
26pub enum ExternalMessage {
27 RequestResponse(#[serde(with = "serde_bytes")] Vec<u8>),
28}
29
30#[derive(Clone)]
32pub struct ExternalEventHandler {
33 request_response_sender: Sender<Bytes>,
35}
36
37#[derive(Debug)]
39#[allow(dead_code)]
40pub enum OutboundMessage {
41 Direct(MessageKind<SeqTypes>, PubKey),
42 Broadcast(MessageKind<SeqTypes>),
43}
44
45impl ExternalEventHandler {
46 pub async fn new<N, P>(
48 tasks: &mut TaskList,
49 request_response_sender: Sender<Bytes>,
50 outbound_message_receiver: Receiver<OutboundMessage>,
51 consensus_handle: Arc<ConsensusHandle<SeqTypes, ConsensusNode<N, P>>>,
52 network: Arc<N>,
53 public_key: PubKey,
54 ) -> Result<Self>
55 where
56 N: ConnectedNetwork<PubKey>,
57 P: SequencerPersistence,
58 {
59 tasks.spawn(
61 "ExternalEventHandler",
62 Self::outbound_message_loop(
63 outbound_message_receiver,
64 consensus_handle,
65 network,
66 public_key,
67 ),
68 );
69
70 Ok(Self {
71 request_response_sender,
72 })
73 }
74
75 pub async fn handle_event(&self, external_message_bytes: &[u8]) -> Result<()> {
80 let external_message = bincode::deserialize(external_message_bytes)
82 .with_context(|| "Failed to deserialize external message")?;
83
84 match external_message {
86 ExternalMessage::RequestResponse(request_response) => {
87 match self
88 .request_response_sender
89 .try_send(request_response.into())
90 {
91 Ok(()) => Ok(()),
92 Err(TrySendError::Full(..)) => bail!("request-response channel full"),
93 Err(TrySendError::Closed(..)) => bail!("request-response channel closed"),
94 }
95 },
96 }
97 }
98
99 async fn outbound_message_loop<N, P>(
101 mut receiver: Receiver<OutboundMessage>,
102 consensus_handle: Arc<ConsensusHandle<SeqTypes, ConsensusNode<N, P>>>,
103 network: Arc<N>,
104 public_key: PubKey,
105 ) where
106 N: ConnectedNetwork<PubKey>,
107 P: SequencerPersistence,
108 {
109 let mut network = Either::Left(network);
110
111 while let Some(message) = receiver.recv().await {
112 if network.is_left()
117 && let Some(client_api) = consensus_handle.client_api().await
118 {
119 network = Either::Right(client_api);
120 }
121 let network = match &network {
122 Either::Right(client_api) => {
123 Self::send_via_coordinator(client_api, message, public_key).await;
124 continue;
125 },
126 Either::Left(network) => network,
127 };
128
129 match message {
131 OutboundMessage::Direct(message, recipient) => {
132 let view = message.view_number();
133 let message_inner = Message {
135 sender: public_key,
136 kind: message,
137 };
138
139 let message_bytes =
141 match BincodeSerializer::<StaticVersion<0, 0>>::serialize(&message_inner) {
142 Ok(message_bytes) => message_bytes,
143 Err(err) => {
144 tracing::warn!("Failed to serialize direct message: {}", err);
145 continue;
146 },
147 };
148
149 let network = Arc::clone(network);
151 tokio::spawn(async move {
152 if let Err(err) =
153 network.direct_message(view, message_bytes, recipient).await
154 {
155 tracing::warn!("Failed to send message: {:?}", err);
156 }
157 });
158 },
159
160 OutboundMessage::Broadcast(message) => {
161 let view = message.view_number();
162 let message_inner = Message {
164 sender: public_key,
165 kind: message,
166 };
167
168 let message_bytes =
170 match BincodeSerializer::<StaticVersion<0, 0>>::serialize(&message_inner) {
171 Ok(message_bytes) => message_bytes,
172 Err(err) => {
173 tracing::warn!("Failed to serialize broadcast message: {}", err);
174 continue;
175 },
176 };
177
178 if let Err(err) = network
180 .broadcast_message(view, message_bytes, Topic::Global, BroadcastDelay::None)
181 .await
182 {
183 tracing::error!("Failed to broadcast message: {:?}", err);
184 };
185 },
186 }
187 }
188 }
189
190 async fn send_via_coordinator(
197 client_api: &ClientApi<SeqTypes>,
198 message: OutboundMessage,
199 public_key: PubKey,
200 ) {
201 match message {
202 OutboundMessage::Direct(kind @ MessageKind::External(_), recipient) => {
203 let message = Message {
204 sender: public_key,
205 kind,
206 };
207 let message_bytes =
208 match BincodeSerializer::<StaticVersion<0, 0>>::serialize(&message) {
209 Ok(message_bytes) => message_bytes,
210 Err(err) => {
211 tracing::warn!("Failed to serialize direct message: {}", err);
212 return;
213 },
214 };
215 if let Err(err) = client_api
216 .send_external_message(message_bytes, recipient)
217 .await
218 {
219 tracing::warn!(%err, "failed to send external message via coordinator");
220 }
221 },
222 other => {
226 tracing::warn!(
227 message = ?other,
228 "dropping unsupported external message after cutover"
229 );
230 },
231 }
232 }
233}