1
1
//! Utilities to assist in the initial sync required to initialize or reload Rust-Lightning objects
2
2
//! from disk.
3
3
4
- use crate :: { BlockSource , BlockSourceResult , Cache , ChainNotifier } ;
4
+ use crate :: { BlockSource , BlockSourceError , BlockSourceResult , Cache , ChainNotifier } ;
5
5
use crate :: poll:: { ChainPoller , Validate , ValidatedBlockHeader } ;
6
6
7
7
use bitcoin:: blockdata:: block:: BlockHeader ;
8
8
use bitcoin:: hash_types:: BlockHash ;
9
9
use bitcoin:: network:: constants:: Network ;
10
10
11
- use lightning:: chain;
11
+ use lightning:: chain:: { self , BestBlock } ;
12
12
13
13
use std:: ops:: Deref ;
14
14
@@ -26,6 +26,47 @@ BlockSourceResult<ValidatedBlockHeader> where B::Target: BlockSource {
26
26
. validate ( best_block_hash)
27
27
}
28
28
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
+
29
70
/// Performs a one-time sync of chain listeners using a single *trusted* block source, bringing each
30
71
/// listener's view of the chain from its paired block hash to `block_source`'s best chain tip.
31
72
///
0 commit comments