@@ -427,14 +427,14 @@ pub(crate) type HeaderCache = std::collections::HashMap<BlockHash, ValidatedBloc
427
427
/// This prevents one block source from being able to orphan us on a fork of its own creation by
428
428
/// not responding to requests for old headers on that fork. However, if one block source is
429
429
/// unreachable this may result in our memory usage growing in accordance with the chain.
430
- pub struct MicroSPVClient < P : Poll > {
430
+ pub struct MicroSPVClient < P : Poll , CL : ChainListener > {
431
431
chain_tip : ValidatedBlockHeader ,
432
432
chain_poller : P ,
433
433
chain_notifier : ChainNotifier ,
434
+ chain_listener : CL ,
434
435
}
435
436
436
- impl < P : Poll > MicroSPVClient < P > {
437
-
437
+ impl < P : Poll , CL : ChainListener > MicroSPVClient < P , CL > {
438
438
/// Creates a new `MicroSPVClient` with a chain poller for polling one or more block sources and
439
439
/// a chain listener for receiving updates of the new chain tip.
440
440
///
@@ -447,15 +447,15 @@ impl<P: Poll> MicroSPVClient<P> {
447
447
/// useful when you have a block source which is more censorship-resistant than others but
448
448
/// which only provides headers. In this case, we can use such source(s) to learn of a censorship
449
449
/// attack without giving up privacy by querying a privacy-losing block sources.
450
- pub fn init ( chain_tip : ValidatedBlockHeader , chain_poller : P ) -> Self {
450
+ pub fn init ( chain_tip : ValidatedBlockHeader , chain_poller : P , chain_listener : CL ) -> Self {
451
451
let header_cache = HeaderCache :: new ( ) ;
452
452
let chain_notifier = ChainNotifier { header_cache } ;
453
- Self { chain_tip, chain_poller, chain_notifier }
453
+ Self { chain_tip, chain_poller, chain_notifier, chain_listener }
454
454
}
455
455
456
456
/// Check each source for a new best tip and update the chain listener accordingly.
457
457
/// Returns true if some blocks were [dis]connected, false otherwise.
458
- pub async fn poll_best_tip < CL : ChainListener > ( & mut self , chain_listener : & mut CL ) ->
458
+ pub async fn poll_best_tip ( & mut self ) ->
459
459
BlockSourceResult < ( ChainTip , bool ) >
460
460
{
461
461
let chain_tip = self . chain_poller . poll_chain_tip ( self . chain_tip ) . await ?;
@@ -464,7 +464,7 @@ impl<P: Poll> MicroSPVClient<P> {
464
464
ChainTip :: Better ( chain_tip) => {
465
465
debug_assert_ne ! ( chain_tip. block_hash, self . chain_tip. block_hash) ;
466
466
debug_assert ! ( chain_tip. chainwork > self . chain_tip. chainwork) ;
467
- self . update_chain_tip ( chain_tip, chain_listener ) . await
467
+ self . update_chain_tip ( chain_tip) . await
468
468
} ,
469
469
ChainTip :: Worse ( chain_tip) => {
470
470
debug_assert_ne ! ( chain_tip. block_hash, self . chain_tip. block_hash) ;
@@ -477,8 +477,8 @@ impl<P: Poll> MicroSPVClient<P> {
477
477
478
478
/// Updates the chain tip, syncing the chain listener with any connected or disconnected
479
479
/// blocks. Returns whether there were any such blocks.
480
- async fn update_chain_tip < CL : ChainListener > ( & mut self , best_chain_tip : ValidatedBlockHeader , chain_listener : & mut CL ) -> bool {
481
- match self . chain_notifier . sync_listener ( best_chain_tip, & self . chain_tip , & mut self . chain_poller , chain_listener) . await {
480
+ async fn update_chain_tip ( & mut self , best_chain_tip : ValidatedBlockHeader ) -> bool {
481
+ match self . chain_notifier . sync_listener ( best_chain_tip, & self . chain_tip , & mut self . chain_poller , & mut self . chain_listener ) . await {
482
482
Ok ( _) => {
483
483
self . chain_tip = best_chain_tip;
484
484
true
@@ -643,13 +643,13 @@ mod tests {
643
643
use bitcoin:: blockdata:: block:: { Block , BlockHeader } ;
644
644
use bitcoin:: util:: uint:: Uint256 ;
645
645
use std:: collections:: HashMap ;
646
- use std:: sync:: Mutex ;
646
+ use std:: sync:: { Arc , Mutex } ;
647
647
648
648
struct TestChainListener {
649
649
blocks_connected : Mutex < Vec < ( BlockHash , u32 ) > > ,
650
650
blocks_disconnected : Mutex < Vec < ( BlockHash , u32 ) > > ,
651
651
}
652
- impl ChainListener for TestChainListener {
652
+ impl ChainListener for Arc < TestChainListener > {
653
653
fn block_connected ( & mut self , block : & Block , height : u32 ) {
654
654
self . blocks_connected . lock ( ) . unwrap ( ) . push ( ( block. header . block_hash ( ) , height) ) ;
655
655
}
@@ -882,9 +882,9 @@ mod tests {
882
882
} ;
883
883
884
884
// Stand up a client at block_1a with all four sources:
885
- let mut chain_listener = TestChainListener {
885
+ let chain_listener = Arc :: new ( TestChainListener {
886
886
blocks_connected : Mutex :: new ( Vec :: new ( ) ) , blocks_disconnected : Mutex :: new ( Vec :: new ( ) )
887
- } ;
887
+ } ) ;
888
888
let mut source_one = & chain_one;
889
889
let mut source_two = & chain_two;
890
890
let mut source_three = & header_chain;
@@ -894,10 +894,11 @@ mod tests {
894
894
poller:: ChainMultiplexer :: new (
895
895
vec ! [ & mut source_one as & mut dyn BlockSource , & mut source_two as & mut dyn BlockSource , & mut source_three as & mut dyn BlockSource ] ,
896
896
vec ! [ & mut source_four as & mut dyn BlockSource ] ,
897
- Network :: Bitcoin ) ) ;
897
+ Network :: Bitcoin ) ,
898
+ Arc :: clone ( & chain_listener) ) ;
898
899
899
900
// Test that we will reorg onto 2b because chain_one knows about 1b + 2b
900
- match client. poll_best_tip ( & mut chain_listener ) . await {
901
+ match client. poll_best_tip ( ) . await {
901
902
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
902
903
assert_eq ! ( chain_tip. block_hash, block_2b_hash) ;
903
904
assert ! ( blocks_connected) ;
@@ -919,7 +920,7 @@ mod tests {
919
920
chain_listener. blocks_disconnected . lock ( ) . unwrap ( ) . clear ( ) ;
920
921
921
922
// First test that nothing happens if nothing changes:
922
- match client. poll_best_tip ( & mut chain_listener ) . await {
923
+ match client. poll_best_tip ( ) . await {
923
924
Ok ( ( ChainTip :: Common , blocks_connected) ) => {
924
925
assert ! ( !blocks_connected) ;
925
926
} ,
@@ -933,7 +934,7 @@ mod tests {
933
934
chain_two. blocks . lock ( ) . unwrap ( ) . insert ( block_3a_hash, block_3a. clone ( ) ) ;
934
935
* chain_two. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
935
936
936
- match client. poll_best_tip ( & mut chain_listener ) . await {
937
+ match client. poll_best_tip ( ) . await {
937
938
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
938
939
assert_eq ! ( chain_tip. block_hash, block_3a_hash) ;
939
940
assert ! ( blocks_connected) ;
@@ -957,7 +958,7 @@ mod tests {
957
958
// the block header cache.
958
959
* chain_one. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
959
960
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
960
- match client. poll_best_tip ( & mut chain_listener ) . await {
961
+ match client. poll_best_tip ( ) . await {
961
962
Ok ( ( ChainTip :: Common , blocks_connected) ) => {
962
963
assert ! ( !blocks_connected) ;
963
964
} ,
@@ -976,7 +977,7 @@ mod tests {
976
977
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
977
978
* backup_chain. disallowed . lock ( ) . unwrap ( ) = false ;
978
979
979
- match client. poll_best_tip ( & mut chain_listener ) . await {
980
+ match client. poll_best_tip ( ) . await {
980
981
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
981
982
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
982
983
assert ! ( !blocks_connected) ;
@@ -991,7 +992,7 @@ mod tests {
991
992
backup_chain. blocks . lock ( ) . unwrap ( ) . insert ( block_4a_hash, block_4a) ;
992
993
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
993
994
994
- match client. poll_best_tip ( & mut chain_listener ) . await {
995
+ match client. poll_best_tip ( ) . await {
995
996
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
996
997
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
997
998
assert ! ( blocks_connected) ;
@@ -1019,7 +1020,7 @@ mod tests {
1019
1020
// We'll check the backup chain last, so don't give it 4a, as otherwise we'll connect it:
1020
1021
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
1021
1022
1022
- match client. poll_best_tip ( & mut chain_listener ) . await {
1023
+ match client. poll_best_tip ( ) . await {
1023
1024
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_disconnected) ) => {
1024
1025
assert_eq ! ( chain_tip. block_hash, block_5c_hash) ;
1025
1026
assert ! ( blocks_disconnected) ;
@@ -1034,7 +1035,7 @@ mod tests {
1034
1035
// Now reset the headers chain to 4a and test that we end up back there.
1035
1036
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
1036
1037
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
1037
- match client. poll_best_tip ( & mut chain_listener ) . await {
1038
+ match client. poll_best_tip ( ) . await {
1038
1039
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
1039
1040
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
1040
1041
assert ! ( blocks_connected) ;
0 commit comments