@@ -382,7 +382,7 @@ where
382
382
output_spender : O , change_destination_source : D , kv_store : K , logger : L ,
383
383
) -> Self {
384
384
let outputs = Vec :: new ( ) ;
385
- let sweeper_state = Mutex :: new ( SweeperState { outputs, best_block } ) ;
385
+ let sweeper_state = Mutex :: new ( SweeperState { outputs, best_block, dirty : false } ) ;
386
386
Self {
387
387
sweeper_state,
388
388
pending_sweep : AtomicBool :: new ( false ) ,
@@ -446,7 +446,10 @@ where
446
446
}
447
447
self . persist_state ( & * state_lock) . map_err ( |e| {
448
448
log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
449
- } )
449
+ } ) ?;
450
+ state_lock. dirty = false ;
451
+
452
+ Ok ( ( ) )
450
453
}
451
454
452
455
/// Returns a list of the currently tracked spendable outputs.
@@ -503,11 +506,19 @@ where
503
506
504
507
// See if there is anything to sweep before requesting a change address.
505
508
{
506
- let sweeper_state = self . sweeper_state . lock ( ) . unwrap ( ) ;
509
+ let mut sweeper_state = self . sweeper_state . lock ( ) . unwrap ( ) ;
507
510
508
511
let cur_height = sweeper_state. best_block . height ;
509
512
let has_respends = sweeper_state. outputs . iter ( ) . any ( |o| filter_fn ( o, cur_height) ) ;
510
513
if !has_respends {
514
+ // If there is nothing to sweep, we still persist the state if it is dirty.
515
+ if sweeper_state. dirty {
516
+ self . persist_state ( & sweeper_state) . map_err ( |e| {
517
+ log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
518
+ } ) ?;
519
+ sweeper_state. dirty = false ;
520
+ }
521
+
511
522
return Ok ( ( ) ) ;
512
523
}
513
524
}
@@ -531,7 +542,8 @@ where
531
542
. collect ( ) ;
532
543
533
544
if respend_descriptors. is_empty ( ) {
534
- // It could be that a tx confirmed and there is now nothing to sweep anymore.
545
+ // It could be that a tx confirmed and there is now nothing to sweep anymore. If there is dirty state,
546
+ // we'll persist it in the next cycle.
535
547
return Ok ( ( ) ) ;
536
548
}
537
549
@@ -563,6 +575,7 @@ where
563
575
self . persist_state ( & sweeper_state) . map_err ( |e| {
564
576
log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
565
577
} ) ?;
578
+ sweeper_state. dirty = false ;
566
579
567
580
self . broadcaster . broadcast_transactions ( & [ & spending_tx] ) ;
568
581
}
@@ -588,6 +601,8 @@ where
588
601
}
589
602
true
590
603
} ) ;
604
+
605
+ sweeper_state. dirty = true ;
591
606
}
592
607
593
608
fn persist_state ( & self , sweeper_state : & SweeperState ) -> Result < ( ) , io:: Error > {
@@ -641,13 +656,17 @@ where
641
656
}
642
657
}
643
658
}
659
+
660
+ sweeper_state. dirty = true ;
644
661
}
645
662
646
663
fn best_block_updated_internal (
647
664
& self , sweeper_state : & mut SweeperState , header : & Header , height : u32 ,
648
665
) {
649
666
sweeper_state. best_block = BestBlock :: new ( header. block_hash ( ) , height) ;
650
667
self . prune_confirmed_outputs ( sweeper_state) ;
668
+
669
+ sweeper_state. dirty = true ;
651
670
}
652
671
}
653
672
@@ -671,12 +690,8 @@ where
671
690
assert_eq ! ( state_lock. best_block. height, height - 1 ,
672
691
"Blocks must be connected in chain-order - the connected block height must be one greater than the previous height" ) ;
673
692
674
- self . transactions_confirmed_internal ( & mut * state_lock, header, txdata, height) ;
675
- self . best_block_updated_internal ( & mut * state_lock, header, height) ;
676
-
677
- let _ = self . persist_state ( & * state_lock) . map_err ( |e| {
678
- log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
679
- } ) ;
693
+ self . transactions_confirmed_internal ( & mut state_lock, header, txdata, height) ;
694
+ self . best_block_updated_internal ( & mut state_lock, header, height) ;
680
695
}
681
696
682
697
fn block_disconnected ( & self , header : & Header , height : u32 ) {
@@ -698,9 +713,7 @@ where
698
713
}
699
714
}
700
715
701
- self . persist_state ( & * state_lock) . unwrap_or_else ( |e| {
702
- log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
703
- } ) ;
716
+ state_lock. dirty = true ;
704
717
}
705
718
}
706
719
@@ -720,9 +733,6 @@ where
720
733
) {
721
734
let mut state_lock = self . sweeper_state . lock ( ) . unwrap ( ) ;
722
735
self . transactions_confirmed_internal ( & mut * state_lock, header, txdata, height) ;
723
- self . persist_state ( & * state_lock) . unwrap_or_else ( |e| {
724
- log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
725
- } ) ;
726
736
}
727
737
728
738
fn transaction_unconfirmed ( & self , txid : & Txid ) {
@@ -743,18 +753,13 @@ where
743
753
. filter ( |o| o. status . confirmation_height ( ) >= Some ( unconf_height) )
744
754
. for_each ( |o| o. status . unconfirmed ( ) ) ;
745
755
746
- self . persist_state ( & * state_lock) . unwrap_or_else ( |e| {
747
- log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
748
- } ) ;
756
+ state_lock. dirty = true ;
749
757
}
750
758
}
751
759
752
760
fn best_block_updated ( & self , header : & Header , height : u32 ) {
753
761
let mut state_lock = self . sweeper_state . lock ( ) . unwrap ( ) ;
754
- self . best_block_updated_internal ( & mut * state_lock, header, height) ;
755
- let _ = self . persist_state ( & * state_lock) . map_err ( |e| {
756
- log_error ! ( self . logger, "Error persisting OutputSweeper: {:?}" , e) ;
757
- } ) ;
762
+ self . best_block_updated_internal ( & mut state_lock, header, height) ;
758
763
}
759
764
760
765
fn get_relevant_txids ( & self ) -> Vec < ( Txid , u32 , Option < BlockHash > ) > {
@@ -783,11 +788,13 @@ where
783
788
struct SweeperState {
784
789
outputs : Vec < TrackedSpendableOutput > ,
785
790
best_block : BestBlock ,
791
+ dirty : bool ,
786
792
}
787
793
788
794
impl_writeable_tlv_based ! ( SweeperState , {
789
795
( 0 , outputs, required_vec) ,
790
796
( 2 , best_block, required) ,
797
+ ( _unused, dirty, ( static_value, false ) ) ,
791
798
} ) ;
792
799
793
800
/// A `enum` signalling to the [`OutputSweeper`] that it should delay spending an output until a
0 commit comments