22//! from disk.
33
44use crate :: poll:: { ChainPoller , Validate , ValidatedBlockHeader } ;
5- use crate :: { BlockSource , BlockSourceResult , Cache , ChainNotifier } ;
5+ use crate :: { BlockSource , BlockSourceResult , Cache , ChainNotifier , UnboundedCache } ;
66
77use bitcoin:: block:: Header ;
88use bitcoin:: hash_types:: BlockHash ;
3232/// Performs a one-time sync of chain listeners using a single *trusted* block source, bringing each
3333/// listener's view of the chain from its paired block hash to `block_source`'s best chain tip.
3434///
35- /// Upon success, the returned header can be used to initialize [`SpvClient`]. In the case of
36- /// failure, each listener may be left at a different block hash than the one it was originally
37- /// paired with.
35+ /// Upon success, the returned header and header cache can be used to initialize [`SpvClient`]. In
36+ /// the case of failure, each listener may be left at a different block hash than the one it was
37+ /// originally paired with.
3838///
3939/// Useful during startup to bring the [`ChannelManager`] and each [`ChannelMonitor`] in sync before
4040/// switching to [`SpvClient`]. For example:
@@ -114,14 +114,13 @@ where
114114/// };
115115///
116116/// // Synchronize any channel monitors and the channel manager to be on the best block.
117- /// let mut cache = UnboundedCache::new();
118117/// let mut monitor_listener = (monitor, &*tx_broadcaster, &*fee_estimator, &*logger);
119118/// let listeners = vec![
120119/// (monitor_best_block, &monitor_listener as &dyn chain::Listen),
121120/// (manager_best_block, &manager as &dyn chain::Listen),
122121/// ];
123- /// let chain_tip = init::synchronize_listeners(
124- /// block_source, Network::Bitcoin, &mut cache, listeners).await.unwrap();
122+ /// let (chain_cache, chain_tip) = init::synchronize_listeners(
123+ /// block_source, Network::Bitcoin, listeners).await.unwrap();
125124///
126125/// // Allow the chain monitor to watch any channels.
127126/// let monitor = monitor_listener.0;
@@ -130,7 +129,7 @@ where
130129/// // Create an SPV client to notify the chain monitor and channel manager of block events.
131130/// let chain_poller = poll::ChainPoller::new(block_source, Network::Bitcoin);
132131/// let mut chain_listener = (chain_monitor, &manager);
133- /// let spv_client = SpvClient::new(chain_tip, chain_poller, &mut cache , &chain_listener);
132+ /// let spv_client = SpvClient::new(chain_tip, chain_poller, chain_cache , &chain_listener);
134133/// }
135134/// ```
136135///
@@ -139,12 +138,11 @@ where
139138/// [`ChannelMonitor`]: lightning::chain::channelmonitor::ChannelMonitor
140139pub async fn synchronize_listeners <
141140 B : Deref + Sized + Send + Sync ,
142- C : Cache ,
143141 L : chain:: Listen + ?Sized ,
144142> (
145- block_source : B , network : Network , header_cache : & mut C ,
143+ block_source : B , network : Network ,
146144 mut chain_listeners : Vec < ( BestBlock , & L ) > ,
147- ) -> BlockSourceResult < ValidatedBlockHeader >
145+ ) -> BlockSourceResult < ( UnboundedCache , ValidatedBlockHeader ) >
148146where
149147 B :: Target : BlockSource ,
150148{
@@ -155,12 +153,12 @@ where
155153 let mut chain_listeners_at_height = Vec :: new ( ) ;
156154 let mut most_common_ancestor = None ;
157155 let mut most_connected_blocks = Vec :: new ( ) ;
156+ let mut header_cache = UnboundedCache :: new ( ) ;
158157 for ( old_best_block, chain_listener) in chain_listeners. drain ( ..) {
159158 // Disconnect any stale blocks, but keep them in the cache for the next iteration.
160- let header_cache = & mut ReadOnlyCache ( header_cache) ;
161159 let ( common_ancestor, connected_blocks) = {
162160 let chain_listener = & DynamicChainListener ( chain_listener) ;
163- let mut chain_notifier = ChainNotifier { header_cache, chain_listener } ;
161+ let mut chain_notifier = ChainNotifier { header_cache : & mut header_cache , chain_listener } ;
164162 let difference =
165163 chain_notifier. find_difference_from_best_block ( best_header, old_best_block, & mut chain_poller) . await ?;
166164 if difference. common_ancestor . block_hash != old_best_block. block_hash {
@@ -180,32 +178,14 @@ where
180178 // Connect new blocks for all listeners at once to avoid re-fetching blocks.
181179 if let Some ( common_ancestor) = most_common_ancestor {
182180 let chain_listener = & ChainListenerSet ( chain_listeners_at_height) ;
183- let mut chain_notifier = ChainNotifier { header_cache, chain_listener } ;
181+ let mut chain_notifier = ChainNotifier { header_cache : & mut header_cache , chain_listener } ;
184182 chain_notifier
185183 . connect_blocks ( common_ancestor, most_connected_blocks, & mut chain_poller)
186184 . await
187185 . map_err ( |( e, _) | e) ?;
188186 }
189187
190- Ok ( best_header)
191- }
192-
193- /// A wrapper to make a cache read-only.
194- ///
195- /// Used to prevent losing headers that may be needed to disconnect blocks common to more than one
196- /// listener.
197- struct ReadOnlyCache < ' a , C : Cache > ( & ' a mut C ) ;
198-
199- impl < ' a , C : Cache > Cache for ReadOnlyCache < ' a , C > {
200- fn look_up ( & self , block_hash : & BlockHash ) -> Option < & ValidatedBlockHeader > {
201- self . 0 . look_up ( block_hash)
202- }
203-
204- fn block_connected ( & mut self , _block_hash : BlockHash , _block_header : ValidatedBlockHeader ) {
205- unreachable ! ( )
206- }
207-
208- fn blocks_disconnected ( & mut self , _fork_point : & ValidatedBlockHeader ) { }
188+ Ok ( ( header_cache, best_header) )
209189}
210190
211191/// Wrapper for supporting dynamically sized chain listeners.
@@ -273,9 +253,8 @@ mod tests {
273253 ( chain. best_block_at_height( 2 ) , & listener_2 as & dyn chain:: Listen ) ,
274254 ( chain. best_block_at_height( 3 ) , & listener_3 as & dyn chain:: Listen ) ,
275255 ] ;
276- let mut cache = chain. header_cache ( 0 ..=4 ) ;
277- match synchronize_listeners ( & chain, Network :: Bitcoin , & mut cache, listeners) . await {
278- Ok ( header) => assert_eq ! ( header, chain. tip( ) ) ,
256+ match synchronize_listeners ( & chain, Network :: Bitcoin , listeners) . await {
257+ Ok ( ( _, header) ) => assert_eq ! ( header, chain. tip( ) ) ,
279258 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
280259 }
281260 }
@@ -305,11 +284,8 @@ mod tests {
305284 ( fork_chain_2. best_block( ) , & listener_2 as & dyn chain:: Listen ) ,
306285 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
307286 ] ;
308- let mut cache = fork_chain_1. header_cache ( 2 ..=4 ) ;
309- cache. extend ( fork_chain_2. header_cache ( 3 ..=4 ) ) ;
310- cache. extend ( fork_chain_3. header_cache ( 4 ..=4 ) ) ;
311- match synchronize_listeners ( & main_chain, Network :: Bitcoin , & mut cache, listeners) . await {
312- Ok ( header) => assert_eq ! ( header, main_chain. tip( ) ) ,
287+ match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
288+ Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
313289 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
314290 }
315291 }
@@ -342,33 +318,8 @@ mod tests {
342318 ( fork_chain_2. best_block( ) , & listener_2 as & dyn chain:: Listen ) ,
343319 ( fork_chain_3. best_block( ) , & listener_3 as & dyn chain:: Listen ) ,
344320 ] ;
345- let mut cache = fork_chain_1. header_cache ( 2 ..=4 ) ;
346- cache. extend ( fork_chain_2. header_cache ( 3 ..=4 ) ) ;
347- cache. extend ( fork_chain_3. header_cache ( 4 ..=4 ) ) ;
348- match synchronize_listeners ( & main_chain, Network :: Bitcoin , & mut cache, listeners) . await {
349- Ok ( header) => assert_eq ! ( header, main_chain. tip( ) ) ,
350- Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
351- }
352- }
353-
354- #[ tokio:: test]
355- async fn cache_connected_and_keep_disconnected_blocks ( ) {
356- let main_chain = Blockchain :: default ( ) . with_height ( 2 ) ;
357- let fork_chain = main_chain. fork_at_height ( 1 ) ;
358- let new_tip = main_chain. tip ( ) ;
359- let old_best_block = fork_chain. best_block ( ) ;
360-
361- let listener = MockChainListener :: new ( )
362- . expect_blocks_disconnected ( * fork_chain. at_height ( 1 ) )
363- . expect_block_connected ( * new_tip) ;
364-
365- let listeners = vec ! [ ( old_best_block, & listener as & dyn chain:: Listen ) ] ;
366- let mut cache = fork_chain. header_cache ( 2 ..=2 ) ;
367- match synchronize_listeners ( & main_chain, Network :: Bitcoin , & mut cache, listeners) . await {
368- Ok ( _) => {
369- assert ! ( cache. contains_key( & new_tip. block_hash) ) ;
370- assert ! ( cache. contains_key( & old_best_block. block_hash) ) ;
371- } ,
321+ match synchronize_listeners ( & main_chain, Network :: Bitcoin , listeners) . await {
322+ Ok ( ( _, header) ) => assert_eq ! ( header, main_chain. tip( ) ) ,
372323 Err ( e) => panic ! ( "Unexpected error: {:?}" , e) ,
373324 }
374325 }
0 commit comments