espresso_node/
external_event_handler.rs1use std::sync::Arc;
4
5use anyhow::{Context, Result, bail};
6use espresso_types::{PubKey, SeqTypes, v0::traits::SequencerPersistence};
7use hotshot_new_protocol::client::ClientApi;
8use hotshot_types::{
9 message::{Message, MessageKind},
10 traits::metrics::Counter,
11};
12use request_response::network::Bytes;
13use serde::{Deserialize, Serialize};
14use tokio::sync::mpsc::{Receiver, Sender, error::TrySendError};
15use vbs::{BinarySerializer, bincode_serializer::BincodeSerializer, version::StaticVersion};
16
17use crate::{consensus_handle::ConsensusHandle, context::TaskList};
18
19#[derive(Debug, Serialize, Deserialize, Clone)]
21pub enum ExternalMessage {
22 RequestResponse(#[serde(with = "serde_bytes")] Vec<u8>),
23}
24
25#[derive(Clone)]
27pub struct ExternalEventHandler {
28 request_response_sender: Sender<Bytes>,
30
31 dropped_messages: Arc<dyn Counter>,
33}
34
35#[derive(Debug)]
36pub enum OutboundMessage {
37 Direct(MessageKind<SeqTypes>, PubKey),
38}
39
40impl ExternalEventHandler {
41 pub async fn new<P>(
42 tasks: &mut TaskList,
43 request_response_sender: Sender<Bytes>,
44 outbound_message_receiver: Receiver<OutboundMessage>,
45 consensus_handle: Arc<ConsensusHandle<SeqTypes, Arc<P>>>,
46 public_key: PubKey,
47 dropped_messages: Arc<dyn Counter>,
48 ) -> Result<Self>
49 where
50 P: SequencerPersistence,
51 {
52 tasks.spawn(
54 "ExternalEventHandler",
55 Self::outbound_message_loop(outbound_message_receiver, consensus_handle, public_key),
56 );
57
58 Ok(Self {
59 request_response_sender,
60 dropped_messages,
61 })
62 }
63
64 pub async fn handle_event(&self, external_message_bytes: &[u8]) -> Result<()> {
69 let external_message = bincode::deserialize(external_message_bytes)
71 .with_context(|| "Failed to deserialize external message")?;
72
73 match external_message {
75 ExternalMessage::RequestResponse(request_response) => {
76 match self
77 .request_response_sender
78 .try_send(request_response.into())
79 {
80 Ok(()) => Ok(()),
81 Err(TrySendError::Full(..)) => {
82 self.dropped_messages.add(1);
83 bail!("request-response channel full")
84 },
85 Err(TrySendError::Closed(..)) => bail!("request-response channel closed"),
86 }
87 },
88 }
89 }
90
91 async fn outbound_message_loop<P>(
93 mut receiver: Receiver<OutboundMessage>,
94 consensus_handle: Arc<ConsensusHandle<SeqTypes, Arc<P>>>,
95 public_key: PubKey,
96 ) where
97 P: SequencerPersistence,
98 {
99 while let Some(message) = receiver.recv().await {
100 let Some(client_api) = consensus_handle.client_api().await else {
101 tracing::warn!("dropping an outbound message: consensus has shut down");
102 continue;
103 };
104 Self::send_via_coordinator(&client_api, message, public_key).await;
105 }
106 }
107
108 async fn send_via_coordinator(
115 client_api: &ClientApi<SeqTypes>,
116 message: OutboundMessage,
117 public_key: PubKey,
118 ) {
119 match message {
120 OutboundMessage::Direct(kind @ MessageKind::External(_), recipient) => {
121 let message = Message {
122 sender: public_key,
123 kind,
124 };
125 let message_bytes =
126 match BincodeSerializer::<StaticVersion<0, 0>>::serialize(&message) {
127 Ok(message_bytes) => message_bytes,
128 Err(err) => {
129 tracing::warn!("Failed to serialize direct message: {}", err);
130 return;
131 },
132 };
133 if let Err(err) = client_api
134 .send_external_message(message_bytes, recipient)
135 .await
136 {
137 tracing::warn!(%err, "failed to send external message via coordinator");
138 }
139 },
140 other => {
141 tracing::warn!(message = ?other, "dropping a non-external outbound message");
142 },
143 }
144 }
145}