Skip to content

Commit a384bb1

Browse files
committed
Implement validate_best_block_header_and_best_block
1 parent 4ae65e8 commit a384bb1

File tree

1 file changed

+43
-2
lines changed

1 file changed

+43
-2
lines changed

lightning-block-sync/src/init.rs

+43-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
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};
55
use crate::poll::{ChainPoller, Validate, ValidatedBlockHeader};
66

77
use bitcoin::blockdata::block::BlockHeader;
88
use bitcoin::hash_types::BlockHash;
99
use bitcoin::network::constants::Network;
1010

11-
use lightning::chain;
11+
use lightning::chain::{self, BestBlock};
1212

1313
use 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

Comments
 (0)