reth_transaction_pool/pool/
listener.rs1use crate::{
4 pool::{
5 events::{FullTransactionEvent, NewTransactionEvent, TransactionEvent},
6 QueuedReason,
7 },
8 traits::{NewBlobSidecar, PropagateKind},
9 PoolTransaction, ValidPoolTransaction,
10};
11use alloy_primitives::{
12 map::{hash_map::Entry, B256Map},
13 TxHash, B256,
14};
15use futures_util::Stream;
16use std::{
17 pin::Pin,
18 sync::Arc,
19 task::{Context, Poll},
20};
21use tokio::sync::mpsc::{
22 self as mpsc, error::TrySendError, Receiver, Sender, UnboundedReceiver, UnboundedSender,
23};
24use tracing::debug;
25
26const TX_POOL_EVENT_CHANNEL_SIZE: usize = 1024;
28
29#[derive(Debug)]
31#[must_use = "streams do nothing unless polled"]
32pub struct TransactionEvents {
33 hash: TxHash,
34 events: UnboundedReceiver<TransactionEvent>,
35}
36
37impl TransactionEvents {
38 pub const fn new(hash: TxHash, events: UnboundedReceiver<TransactionEvent>) -> Self {
40 Self { hash, events }
41 }
42
43 pub const fn hash(&self) -> TxHash {
45 self.hash
46 }
47}
48
49impl Stream for TransactionEvents {
50 type Item = TransactionEvent;
51
52 fn poll_next(
53 self: std::pin::Pin<&mut Self>,
54 cx: &mut std::task::Context<'_>,
55 ) -> std::task::Poll<Option<Self::Item>> {
56 self.get_mut().events.poll_recv(cx)
57 }
58}
59
60#[derive(Debug)]
62#[must_use = "streams do nothing unless polled"]
63pub struct AllTransactionsEvents<T: PoolTransaction> {
64 pub(crate) events: Receiver<FullTransactionEvent<T>>,
65}
66
67impl<T: PoolTransaction> AllTransactionsEvents<T> {
68 pub const fn new(events: Receiver<FullTransactionEvent<T>>) -> Self {
70 Self { events }
71 }
72}
73
74impl<T: PoolTransaction> Stream for AllTransactionsEvents<T> {
75 type Item = FullTransactionEvent<T>;
76
77 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
78 self.get_mut().events.poll_recv(cx)
79 }
80}
81
82#[derive(Debug)]
87pub struct PoolEventBroadcast<T: PoolTransaction> {
88 all_events_broadcaster: AllPoolEventsBroadcaster<T>,
90 broadcasters_by_hash: B256Map<PoolEventBroadcaster>,
92}
93
94impl<T: PoolTransaction> Default for PoolEventBroadcast<T> {
95 fn default() -> Self {
96 Self {
97 all_events_broadcaster: AllPoolEventsBroadcaster::default(),
98 broadcasters_by_hash: B256Map::default(),
99 }
100 }
101}
102
103impl<T: PoolTransaction> PoolEventBroadcast<T> {
104 fn broadcast_event(
106 &mut self,
107 hash: &TxHash,
108 event: TransactionEvent,
109 pool_event: FullTransactionEvent<T>,
110 ) {
111 if let Entry::Occupied(mut sink) = self.broadcasters_by_hash.entry(*hash) {
113 sink.get_mut().broadcast(event.clone());
114
115 if sink.get().is_empty() || event.is_final() {
116 sink.remove();
117 }
118 }
119
120 self.all_events_broadcaster.broadcast(pool_event);
122 }
123
124 #[inline]
126 pub fn is_empty(&self) -> bool {
127 self.all_events_broadcaster.is_empty() && self.broadcasters_by_hash.is_empty()
128 }
129
130 pub fn subscribe(&mut self, tx_hash: TxHash) -> TransactionEvents {
132 let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
133
134 match self.broadcasters_by_hash.entry(tx_hash) {
135 Entry::Occupied(mut entry) => {
136 entry.get_mut().senders.push(tx);
137 }
138 Entry::Vacant(entry) => {
139 entry.insert(PoolEventBroadcaster { senders: vec![tx] });
140 }
141 };
142 TransactionEvents { hash: tx_hash, events: rx }
143 }
144
145 pub fn subscribe_all(&mut self) -> AllTransactionsEvents<T> {
147 let (tx, rx) = tokio::sync::mpsc::channel(TX_POOL_EVENT_CHANNEL_SIZE);
148 self.all_events_broadcaster.senders.push(tx);
149 AllTransactionsEvents::new(rx)
150 }
151
152 pub fn pending(&mut self, tx: &TxHash, replaced: Option<Arc<ValidPoolTransaction<T>>>) {
154 self.broadcast_event(tx, TransactionEvent::Pending, FullTransactionEvent::Pending(*tx));
155
156 if let Some(replaced) = replaced {
157 self.replaced(replaced, *tx);
159 }
160 }
161
162 pub fn replaced(&mut self, tx: Arc<ValidPoolTransaction<T>>, replaced_by: TxHash) {
164 let transaction = Arc::clone(&tx);
165 self.broadcast_event(
166 tx.hash(),
167 TransactionEvent::Replaced(replaced_by),
168 FullTransactionEvent::Replaced { transaction, replaced_by },
169 );
170 }
171
172 pub fn queued(&mut self, tx: &TxHash, reason: Option<QueuedReason>) {
174 self.broadcast_event(
175 tx,
176 TransactionEvent::Queued,
177 FullTransactionEvent::Queued(*tx, reason),
178 );
179 }
180
181 pub fn propagated(&mut self, tx: &TxHash, peers: Vec<PropagateKind>) {
183 let peers = Arc::new(peers);
184 self.broadcast_event(
185 tx,
186 TransactionEvent::Propagated(Arc::clone(&peers)),
187 FullTransactionEvent::Propagated(peers),
188 );
189 }
190
191 #[inline]
193 pub fn discarded_many(&mut self, discarded: &[Arc<ValidPoolTransaction<T>>]) {
194 if self.is_empty() {
195 return
196 }
197 for tx in discarded {
198 self.discarded(tx.hash());
199 }
200 }
201
202 pub fn discarded(&mut self, tx: &TxHash) {
204 self.broadcast_event(tx, TransactionEvent::Discarded, FullTransactionEvent::Discarded(*tx));
205 }
206
207 pub fn invalid(&mut self, tx: &TxHash) {
209 self.broadcast_event(tx, TransactionEvent::Invalid, FullTransactionEvent::Invalid(*tx));
210 }
211
212 pub fn mined(&mut self, tx: &TxHash, block_hash: B256) {
214 self.broadcast_event(
215 tx,
216 TransactionEvent::Mined(block_hash),
217 FullTransactionEvent::Mined { tx_hash: *tx, block_hash },
218 );
219 }
220}
221
222#[derive(Debug)]
226struct AllPoolEventsBroadcaster<T: PoolTransaction> {
227 senders: Vec<Sender<FullTransactionEvent<T>>>,
229}
230
231impl<T: PoolTransaction> Default for AllPoolEventsBroadcaster<T> {
232 fn default() -> Self {
233 Self { senders: Vec::new() }
234 }
235}
236
237impl<T: PoolTransaction> AllPoolEventsBroadcaster<T> {
238 fn broadcast(&mut self, event: FullTransactionEvent<T>) {
240 self.senders.retain(|sender| match sender.try_send(event.clone()) {
241 Ok(_) | Err(TrySendError::Full(_)) => true,
242 Err(TrySendError::Closed(_)) => false,
243 })
244 }
245
246 #[inline]
248 const fn is_empty(&self) -> bool {
249 self.senders.is_empty()
250 }
251}
252
253#[derive(Default, Debug)]
257struct PoolEventBroadcaster {
258 senders: Vec<UnboundedSender<TransactionEvent>>,
260}
261
262impl PoolEventBroadcaster {
263 const fn is_empty(&self) -> bool {
265 self.senders.is_empty()
266 }
267
268 fn broadcast(&mut self, event: TransactionEvent) {
270 self.senders.retain(|sender| sender.send(event.clone()).is_ok())
271 }
272}
273
274#[derive(Debug)]
276pub struct PendingTransactionHashListener {
277 pub sender: mpsc::Sender<TxHash>,
279 pub kind: TransactionListenerKind,
281}
282
283impl PendingTransactionHashListener {
284 pub fn send_all(&self, hashes: impl IntoIterator<Item = TxHash>) -> bool {
288 for tx_hash in hashes {
289 match self.sender.try_send(tx_hash) {
290 Ok(()) => {}
291 Err(err) => {
292 return if matches!(err, mpsc::error::TrySendError::Full(_)) {
293 debug!(
294 target: "txpool",
295 "[{:?}] failed to send pending tx; channel full",
296 tx_hash,
297 );
298 true
299 } else {
300 false
301 }
302 }
303 }
304 }
305 true
306 }
307}
308
309#[derive(Debug)]
311pub struct TransactionListener<T: PoolTransaction> {
312 pub sender: mpsc::Sender<NewTransactionEvent<T>>,
314 pub kind: TransactionListenerKind,
316}
317
318impl<T: PoolTransaction> TransactionListener<T> {
319 pub fn send(&self, event: NewTransactionEvent<T>) -> bool {
323 self.send_all(std::iter::once(event))
324 }
325
326 pub fn send_all(&self, events: impl IntoIterator<Item = NewTransactionEvent<T>>) -> bool {
330 for event in events {
331 match self.sender.try_send(event) {
332 Ok(()) => {}
333 Err(err) => {
334 return if let mpsc::error::TrySendError::Full(event) = err {
335 debug!(
336 target: "txpool",
337 "[{:?}] failed to send pending tx; channel full",
338 event.transaction.hash(),
339 );
340 true
341 } else {
342 false
343 }
344 }
345 }
346 }
347 true
348 }
349}
350
351#[derive(Debug)]
353pub(crate) struct BlobTransactionSidecarListener {
354 pub(crate) sender: mpsc::Sender<NewBlobSidecar>,
355}
356
357#[derive(Debug, Copy, Clone, PartialEq, Eq)]
361pub enum TransactionListenerKind {
362 All,
364 PropagateOnly,
368}
369
370impl TransactionListenerKind {
371 #[inline]
373 pub const fn is_propagate_only(&self) -> bool {
374 matches!(self, Self::PropagateOnly)
375 }
376}