hotshot_events_service/
events_source.rs1use std::{marker::PhantomData, sync::Arc};
2
3use async_broadcast::{InactiveReceiver, Sender as BroadcastSender, broadcast};
4use async_trait::async_trait;
5use futures::{
6 future::BoxFuture,
7 stream::{BoxStream, Stream, StreamExt},
8};
9use hotshot_types::{
10 PeerConfig,
11 event::{Event, EventType, LegacyEvent},
12 traits::node_implementation::NodeType,
13};
14use serde::{Deserialize, Serialize};
15use tide_disco::method::ReadState;
16const RETAINED_EVENTS_COUNT: usize = 4096;
17
18#[async_trait]
19pub trait EventsSource<Types>
20where
21 Types: NodeType,
22{
23 type EventStream: Stream<Item = Arc<Event<Types>>> + Unpin + Send + 'static;
24 type LegacyEventStream: Stream<Item = Arc<LegacyEvent<Types>>> + Unpin + Send + 'static;
25 async fn get_event_stream(&self, filter: Option<EventFilterSet<Types>>) -> Self::EventStream;
26 async fn get_legacy_event_stream(
27 &self,
28 filter: Option<EventFilterSet<Types>>,
29 ) -> Self::LegacyEventStream;
30 async fn get_startup_info(&self) -> StartupInfo<Types>;
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
34#[serde(bound = "Types::SignatureKey: for<'a> Deserialize<'a>")]
35pub struct StartupInfo<Types: NodeType> {
36 pub known_node_with_stake: Vec<PeerConfig<Types>>,
37 pub non_staked_node_count: usize,
38}
39
40#[async_trait]
41pub trait EventConsumer<Types>
42where
43 Types: NodeType,
44{
45 async fn handle_event(&mut self, event: Event<Types>);
46}
47
48#[derive(Debug)]
49pub struct EventsStreamer<Types: NodeType> {
50 inactive_to_subscribe_clone_recv: InactiveReceiver<Arc<Event<Types>>>,
52 subscriber_send_channel: BroadcastSender<Arc<Event<Types>>>,
53
54 known_nodes_with_stake: Vec<PeerConfig<Types>>,
56 non_staked_node_count: usize,
57}
58
59impl<Types: NodeType> EventsStreamer<Types> {
60 pub fn known_node_with_stake(&self) -> Vec<PeerConfig<Types>> {
61 self.known_nodes_with_stake.clone()
62 }
63
64 pub fn non_staked_node_count(&self) -> usize {
65 self.non_staked_node_count
66 }
67
68 pub fn subscriber_count(&self) -> usize {
72 self.subscriber_send_channel.receiver_count()
73 }
74}
75
76#[async_trait]
77impl<Types: NodeType> EventConsumer<Types> for EventsStreamer<Types> {
78 async fn handle_event(&mut self, event: Event<Types>) {
79 if let Err(e) = self.subscriber_send_channel.broadcast(event.into()).await {
80 tracing::debug!("Error broadcasting the event: {e:?}");
81 }
82 }
83}
84
85#[derive(Clone, Debug)]
87pub struct EventFilterSet<Types: NodeType>(pub(crate) Vec<EventFilter<Types>>);
88
89impl<Types: NodeType> From<Vec<EventFilter<Types>>> for EventFilterSet<Types> {
91 fn from(filters: Vec<EventFilter<Types>>) -> Self {
92 EventFilterSet(filters)
93 }
94}
95
96impl<Types: NodeType> From<EventFilter<Types>> for EventFilterSet<Types> {
98 fn from(filter: EventFilter<Types>) -> Self {
99 EventFilterSet(vec![filter])
100 }
101}
102
103impl<Types: NodeType> EventFilterSet<Types> {
104 pub(crate) fn should_broadcast(&self, hotshot_event: &EventType<Types>) -> bool {
108 let filter = &self.0;
109
110 match hotshot_event {
111 EventType::Error { .. } => filter.contains(&EventFilter::Error),
112 EventType::Decide { .. } => filter.contains(&EventFilter::Decide),
113 EventType::ReplicaViewTimeout { .. } => {
114 filter.contains(&EventFilter::ReplicaViewTimeout)
115 },
116 EventType::ViewFinished { .. } => filter.contains(&EventFilter::ViewFinished),
117 EventType::ViewTimeout { .. } => filter.contains(&EventFilter::ViewTimeout),
118 EventType::Transactions { .. } => filter.contains(&EventFilter::Transactions),
119 EventType::DaProposal { .. } => filter.contains(&EventFilter::DaProposal),
120 EventType::QuorumProposal { .. } => filter.contains(&EventFilter::QuorumProposal),
121 EventType::UpgradeProposal { .. } => filter.contains(&EventFilter::UpgradeProposal),
122 _ => false,
123 }
124 }
125}
126
127#[derive(Clone, Debug, PartialEq)]
130pub enum EventFilter<Types: NodeType> {
131 Error,
132 Decide,
133 ReplicaViewTimeout,
134 ViewFinished,
135 ViewTimeout,
136 Transactions,
137 DaProposal,
138 QuorumProposal,
139 UpgradeProposal,
140 Pd(PhantomData<Types>),
141}
142
143#[async_trait]
144impl<Types: NodeType> EventsSource<Types> for EventsStreamer<Types> {
145 type EventStream = BoxStream<'static, Arc<Event<Types>>>;
146 type LegacyEventStream = BoxStream<'static, Arc<LegacyEvent<Types>>>;
147
148 async fn get_event_stream(&self, filter: Option<EventFilterSet<Types>>) -> Self::EventStream {
149 let receiver = self.inactive_to_subscribe_clone_recv.activate_cloned();
150
151 if let Some(filter) = filter {
152 receiver
153 .filter(move |event| {
154 futures::future::ready(filter.should_broadcast(&event.as_ref().event))
155 })
156 .boxed()
157 } else {
158 receiver.boxed()
159 }
160 }
161
162 async fn get_legacy_event_stream(
163 &self,
164 filter: Option<EventFilterSet<Types>>,
165 ) -> Self::LegacyEventStream {
166 let receiver = self.inactive_to_subscribe_clone_recv.activate_cloned();
167
168 if let Some(filter) = filter {
169 receiver
170 .filter(move |event| {
171 futures::future::ready(filter.should_broadcast(&event.as_ref().event))
172 })
173 .filter_map(|a| {
174 futures::future::ready(Event::to_legacy(a.as_ref().clone()).ok().map(Arc::new))
175 })
176 .boxed()
177 } else {
178 receiver
179 .filter_map(|a| {
180 futures::future::ready(Event::to_legacy(a.as_ref().clone()).ok().map(Arc::new))
181 })
182 .boxed()
183 }
184 }
185
186 async fn get_startup_info(&self) -> StartupInfo<Types> {
187 StartupInfo {
188 known_node_with_stake: self.known_node_with_stake(),
189 non_staked_node_count: self.non_staked_node_count(),
190 }
191 }
192}
193
194impl<Types: NodeType> EventsStreamer<Types> {
195 pub fn new(
196 known_nodes_with_stake: Vec<PeerConfig<Types>>,
197 non_staked_node_count: usize,
198 ) -> Self {
199 let (mut subscriber_send_channel, to_subscribe_clone_recv) =
200 broadcast::<Arc<Event<Types>>>(RETAINED_EVENTS_COUNT);
201 subscriber_send_channel.set_overflow(true);
203 subscriber_send_channel.set_await_active(false);
205 let inactive_to_subscribe_clone_recv = to_subscribe_clone_recv.deactivate();
206
207 EventsStreamer {
208 subscriber_send_channel,
209 inactive_to_subscribe_clone_recv,
210 known_nodes_with_stake,
211 non_staked_node_count,
212 }
213 }
214}
215
216#[async_trait]
217impl<Types: NodeType> ReadState for EventsStreamer<Types> {
218 type State = Self;
219
220 async fn read<T>(
221 &self,
222 op: impl Send + for<'a> FnOnce(&'a Self::State) -> BoxFuture<'a, T> + 'async_trait,
223 ) -> T {
224 op(self).await
225 }
226}