11//! Utilities to assist in the initial sync required to initialize or reload Rust-Lightning objects
22//! from disk.
33
4- use crate :: { BlockSource , BlockSourceResult , Cache , ChainNotifier } ;
4+ use crate :: { BlockSource , BlockSourceError , BlockSourceResult , Cache , ChainNotifier } ;
55use crate :: poll:: { ChainPoller , Validate , ValidatedBlockHeader } ;
66
77use bitcoin:: blockdata:: block:: BlockHeader ;
88use bitcoin:: hash_types:: BlockHash ;
99use bitcoin:: network:: constants:: Network ;
1010
11- use lightning:: chain;
11+ use lightning:: chain:: { self , BestBlock } ;
1212
1313use std:: ops:: Deref ;
1414
@@ -26,6 +26,47 @@ BlockSourceResult<ValidatedBlockHeader> where B::Target: BlockSource {
2626 . validate ( best_block_hash)
2727}
2828
29+ /// Polls the block source, returning a validated block header and [`BestBlock`]
30+ /// corresponding to the block source's best chain tip.
31+ ///
32+ /// Upon success, the returned header can be used to initialize [`SpvClient`],
33+ /// and the returned [`BestBlock`] can be passed into [`ChannelManager::new`]
34+ /// as part of its [`ChainParameters`]. Initializing the channel manager and spv
35+ /// client with the outputs of this function ensures that the channel manager
36+ /// and [`SpvClient`] are synced to the same block during a fresh start.
37+ ///
38+ /// [`SpvClient`]: crate::SpvClient
39+ /// [`ChainParameters`]: lightning::ln::channelmanager::ChainParameters
40+ /// [`ChannelManager::new`]: lightning::ln::channelmanager::ChannelManager::new
41+ // This prevents a possible race where an intermediate block is mined in between
42+ // when the channel manager and SpvClient are initialized, causing them to be
43+ // out of sync. When the SpvClient detects the next block, it feeds this new
44+ // block into the channel manager, but the channel manager is actually expecting
45+ // to hear about the intermediate block, thereby panicking with the message
46+ // "Blocks must be connected in chain-order - the connected header must build on
47+ // the last connected header."
48+ pub async fn validate_best_block_header_and_best_block < B : Deref > ( block_source : B )
49+ -> BlockSourceResult < ( ValidatedBlockHeader , BestBlock ) >
50+ where
51+ B :: Target : BlockSource
52+ {
53+ let ( polled_best_block_hash, maybe_best_block_height) = block_source
54+ . get_best_block ( )
55+ . await ?;
56+ let best_block_header_data = block_source
57+ . get_header ( & polled_best_block_hash, maybe_best_block_height)
58+ . await ?;
59+ let best_block_height = maybe_best_block_height. ok_or_else ( ||
60+ BlockSourceError :: persistent ( "block height missing" )
61+ ) ?;
62+ let polled_best_block =
63+ BestBlock :: new ( polled_best_block_hash, best_block_height) ;
64+ let polled_chain_tip = best_block_header_data
65+ . validate ( polled_best_block_hash) ?;
66+
67+ Ok ( ( polled_chain_tip, polled_best_block) )
68+ }
69+
2970/// Performs a one-time sync of chain listeners using a single *trusted* block source, bringing each
3071/// listener's view of the chain from its paired block hash to `block_source`'s best chain tip.
3172///
0 commit comments