@@ -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,24 +447,22 @@ 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 ) ->
459
- BlockSourceResult < ( ChainTip , bool ) >
460
- {
458
+ pub async fn poll_best_tip ( & mut self ) -> BlockSourceResult < ( ChainTip , bool ) > {
461
459
let chain_tip = self . chain_poller . poll_chain_tip ( self . chain_tip ) . await ?;
462
460
let blocks_connected = match chain_tip {
463
461
ChainTip :: Common => false ,
464
462
ChainTip :: Better ( chain_tip) => {
465
463
debug_assert_ne ! ( chain_tip. block_hash, self . chain_tip. block_hash) ;
466
464
debug_assert ! ( chain_tip. chainwork > self . chain_tip. chainwork) ;
467
- self . update_chain_tip ( chain_tip, chain_listener ) . await
465
+ self . update_chain_tip ( chain_tip) . await
468
466
} ,
469
467
ChainTip :: Worse ( chain_tip) => {
470
468
debug_assert_ne ! ( chain_tip. block_hash, self . chain_tip. block_hash) ;
@@ -477,8 +475,8 @@ impl<P: Poll> MicroSPVClient<P> {
477
475
478
476
/// Updates the chain tip, syncing the chain listener with any connected or disconnected
479
477
/// 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 {
478
+ async fn update_chain_tip ( & mut self , best_chain_tip : ValidatedBlockHeader ) -> bool {
479
+ match self . chain_notifier . sync_listener ( best_chain_tip, & self . chain_tip , & mut self . chain_poller , & mut self . chain_listener ) . await {
482
480
Ok ( _) => {
483
481
self . chain_tip = best_chain_tip;
484
482
true
@@ -643,13 +641,13 @@ mod tests {
643
641
use bitcoin:: blockdata:: block:: { Block , BlockHeader } ;
644
642
use bitcoin:: util:: uint:: Uint256 ;
645
643
use std:: collections:: HashMap ;
646
- use std:: sync:: Mutex ;
644
+ use std:: sync:: { Arc , Mutex } ;
647
645
648
646
struct TestChainListener {
649
647
blocks_connected : Mutex < Vec < ( BlockHash , u32 ) > > ,
650
648
blocks_disconnected : Mutex < Vec < ( BlockHash , u32 ) > > ,
651
649
}
652
- impl ChainListener for TestChainListener {
650
+ impl ChainListener for Arc < TestChainListener > {
653
651
fn block_connected ( & mut self , block : & Block , height : u32 ) {
654
652
self . blocks_connected . lock ( ) . unwrap ( ) . push ( ( block. header . block_hash ( ) , height) ) ;
655
653
}
@@ -882,9 +880,9 @@ mod tests {
882
880
} ;
883
881
884
882
// Stand up a client at block_1a with all four sources:
885
- let mut chain_listener = TestChainListener {
883
+ let chain_listener = Arc :: new ( TestChainListener {
886
884
blocks_connected : Mutex :: new ( Vec :: new ( ) ) , blocks_disconnected : Mutex :: new ( Vec :: new ( ) )
887
- } ;
885
+ } ) ;
888
886
let mut source_one = & chain_one;
889
887
let mut source_two = & chain_two;
890
888
let mut source_three = & header_chain;
@@ -894,10 +892,11 @@ mod tests {
894
892
poller:: ChainMultiplexer :: new (
895
893
vec ! [ & mut source_one as & mut dyn BlockSource , & mut source_two as & mut dyn BlockSource , & mut source_three as & mut dyn BlockSource ] ,
896
894
vec ! [ & mut source_four as & mut dyn BlockSource ] ,
897
- Network :: Bitcoin ) ) ;
895
+ Network :: Bitcoin ) ,
896
+ Arc :: clone ( & chain_listener) ) ;
898
897
899
898
// Test that we will reorg onto 2b because chain_one knows about 1b + 2b
900
- match client. poll_best_tip ( & mut chain_listener ) . await {
899
+ match client. poll_best_tip ( ) . await {
901
900
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
902
901
assert_eq ! ( chain_tip. block_hash, block_2b_hash) ;
903
902
assert ! ( blocks_connected) ;
@@ -919,7 +918,7 @@ mod tests {
919
918
chain_listener. blocks_disconnected . lock ( ) . unwrap ( ) . clear ( ) ;
920
919
921
920
// First test that nothing happens if nothing changes:
922
- match client. poll_best_tip ( & mut chain_listener ) . await {
921
+ match client. poll_best_tip ( ) . await {
923
922
Ok ( ( ChainTip :: Common , blocks_connected) ) => {
924
923
assert ! ( !blocks_connected) ;
925
924
} ,
@@ -933,7 +932,7 @@ mod tests {
933
932
chain_two. blocks . lock ( ) . unwrap ( ) . insert ( block_3a_hash, block_3a. clone ( ) ) ;
934
933
* chain_two. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
935
934
936
- match client. poll_best_tip ( & mut chain_listener ) . await {
935
+ match client. poll_best_tip ( ) . await {
937
936
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
938
937
assert_eq ! ( chain_tip. block_hash, block_3a_hash) ;
939
938
assert ! ( blocks_connected) ;
@@ -957,7 +956,7 @@ mod tests {
957
956
// the block header cache.
958
957
* chain_one. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
959
958
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
960
- match client. poll_best_tip ( & mut chain_listener ) . await {
959
+ match client. poll_best_tip ( ) . await {
961
960
Ok ( ( ChainTip :: Common , blocks_connected) ) => {
962
961
assert ! ( !blocks_connected) ;
963
962
} ,
@@ -976,7 +975,7 @@ mod tests {
976
975
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
977
976
* backup_chain. disallowed . lock ( ) . unwrap ( ) = false ;
978
977
979
- match client. poll_best_tip ( & mut chain_listener ) . await {
978
+ match client. poll_best_tip ( ) . await {
980
979
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
981
980
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
982
981
assert ! ( !blocks_connected) ;
@@ -991,7 +990,7 @@ mod tests {
991
990
backup_chain. blocks . lock ( ) . unwrap ( ) . insert ( block_4a_hash, block_4a) ;
992
991
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
993
992
994
- match client. poll_best_tip ( & mut chain_listener ) . await {
993
+ match client. poll_best_tip ( ) . await {
995
994
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
996
995
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
997
996
assert ! ( blocks_connected) ;
@@ -1019,7 +1018,7 @@ mod tests {
1019
1018
// We'll check the backup chain last, so don't give it 4a, as otherwise we'll connect it:
1020
1019
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_3a_hash, Some ( 3 ) ) ;
1021
1020
1022
- match client. poll_best_tip ( & mut chain_listener ) . await {
1021
+ match client. poll_best_tip ( ) . await {
1023
1022
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_disconnected) ) => {
1024
1023
assert_eq ! ( chain_tip. block_hash, block_5c_hash) ;
1025
1024
assert ! ( blocks_disconnected) ;
@@ -1034,7 +1033,7 @@ mod tests {
1034
1033
// Now reset the headers chain to 4a and test that we end up back there.
1035
1034
* backup_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
1036
1035
* header_chain. best_block . lock ( ) . unwrap ( ) = ( block_4a_hash, Some ( 4 ) ) ;
1037
- match client. poll_best_tip ( & mut chain_listener ) . await {
1036
+ match client. poll_best_tip ( ) . await {
1038
1037
Ok ( ( ChainTip :: Better ( chain_tip) , blocks_connected) ) => {
1039
1038
assert_eq ! ( chain_tip. block_hash, block_4a_hash) ;
1040
1039
assert ! ( blocks_connected) ;
0 commit comments