1
1
//! Block heartbeat and pending transaction watcher.
2
2
3
- use crate :: { Provider , RootProvider } ;
3
+ use crate :: { blocks :: Paused , Provider , RootProvider } ;
4
4
use alloy_consensus:: BlockHeader ;
5
5
use alloy_json_rpc:: RpcError ;
6
6
use alloy_network:: { BlockResponse , Network } ;
@@ -14,6 +14,7 @@ use std::{
14
14
collections:: { BTreeMap , VecDeque } ,
15
15
fmt,
16
16
future:: Future ,
17
+ sync:: Arc ,
17
18
time:: Duration ,
18
19
} ;
19
20
use tokio:: {
@@ -463,18 +464,22 @@ pub(crate) struct Heartbeat<N, S> {
463
464
/// Ordered map of transactions to reap at a certain time.
464
465
reap_at : BTreeMap < Instant , B256 > ,
465
466
467
+ /// Whether the heartbeat is currently paused.
468
+ paused : Arc < Paused > ,
469
+
466
470
_network : std:: marker:: PhantomData < N > ,
467
471
}
468
472
469
473
impl < N : Network , S : Stream < Item = N :: BlockResponse > + Unpin + ' static > Heartbeat < N , S > {
470
474
/// Create a new heartbeat task.
471
- pub ( crate ) fn new ( stream : S ) -> Self {
475
+ pub ( crate ) fn new ( stream : S , is_paused : Arc < Paused > ) -> Self {
472
476
Self {
473
477
stream : stream. fuse ( ) ,
474
478
past_blocks : Default :: default ( ) ,
475
479
unconfirmed : Default :: default ( ) ,
476
480
waiting_confs : Default :: default ( ) ,
477
481
reap_at : Default :: default ( ) ,
482
+ paused : is_paused,
478
483
_network : Default :: default ( ) ,
479
484
}
480
485
}
@@ -531,6 +536,20 @@ impl<N: Network, S: Stream<Item = N::BlockResponse> + Unpin + 'static> Heartbeat
531
536
}
532
537
}
533
538
539
+ /// Check if we have any pending transactions.
540
+ fn has_pending_transactions ( & self ) -> bool {
541
+ !self . unconfirmed . is_empty ( ) || !self . waiting_confs . is_empty ( )
542
+ }
543
+
544
+ /// Update the pause state based on whether we have pending transactions.
545
+ fn update_pause_state ( & mut self ) {
546
+ let should_pause = !self . has_pending_transactions ( ) ;
547
+ if self . paused . is_paused ( ) != should_pause {
548
+ debug ! ( paused = should_pause, "updating heartbeat pause state" ) ;
549
+ self . paused . set_paused ( should_pause) ;
550
+ }
551
+ }
552
+
534
553
/// Handle a watch instruction by adding it to the watch list, and
535
554
/// potentially adding it to our `reap_at` list.
536
555
fn handle_watch_ix ( & mut self , to_watch : TxWatcher ) {
@@ -597,7 +616,8 @@ impl<N: Network, S: Stream<Item = N::BlockResponse> + Unpin + 'static> Heartbeat
597
616
// Check that the chain is continuous.
598
617
if * last_height + 1 != block_height {
599
618
// Move all the transactions that were reset by the reorg to the unconfirmed list.
600
- warn ! ( %block_height, last_height, "reorg detected" ) ;
619
+ // This can also happen if we unpaused the heartbeat after some time.
620
+ debug ! ( block_height, last_height, "reorg/unpause detected" ) ;
601
621
self . move_reorg_to_unconfirmed ( block_height) ;
602
622
// Remove past blocks that are now invalid.
603
623
self . past_blocks . retain ( |( h, _) | * h < block_height) ;
@@ -663,6 +683,8 @@ impl<N: Network, S: Stream<Item = N::BlockResponse> + Unpin + 'static> Heartbeat
663
683
async fn into_future ( mut self , mut ixns : mpsc:: Receiver < TxWatcher > ) {
664
684
' shutdown: loop {
665
685
{
686
+ self . update_pause_state ( ) ;
687
+
666
688
let next_reap = self . next_reap ( ) ;
667
689
let sleep = std:: pin:: pin!( sleep_until( next_reap. into( ) ) ) ;
668
690
0 commit comments