Skip to content

Commit 2ab34e3

Browse files
committed
Retain bitcoind SPV client
Retain the cache populated during initial listener synchronization so subsequent polls can find headers for stale forks when REST no longer serves them. Use weak listener handles to avoid creating an ownership cycle through the chain source. Co-Authored-By: HAL 9000
1 parent 66d48d2 commit 2ab34e3

1 file changed

Lines changed: 93 additions & 30 deletions

File tree

src/chain/bitcoind.rs

Lines changed: 93 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,12 @@ use crate::{Error, PersistedNodeMetrics};
4949
const CHAIN_POLLING_INTERVAL_SECS: u64 = 2;
5050
const CHAIN_POLLING_TIMEOUT_SECS: u64 = 10;
5151

52+
type BitcoindSpvClient =
53+
SpvClient<ChainPoller<Arc<BitcoindClient>, BitcoindClient>, Arc<ChainListener>>;
54+
5255
pub(super) struct BitcoindChainSource {
5356
api_client: Arc<BitcoindClient>,
57+
spv_client: tokio::sync::Mutex<Option<BitcoindSpvClient>>,
5458
latest_chain_tip: RwLock<Option<ValidatedBlockHeader>>,
5559
wallet_polling_status: Mutex<WalletSyncStatus>,
5660
fee_estimator: Arc<OnchainFeeEstimator>,
@@ -74,9 +78,11 @@ impl BitcoindChainSource {
7478
));
7579

7680
let latest_chain_tip = RwLock::new(None);
81+
let spv_client = tokio::sync::Mutex::new(None);
7782
let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed);
7883
Self {
7984
api_client,
85+
spv_client,
8086
latest_chain_tip,
8187
wallet_polling_status,
8288
fee_estimator,
@@ -103,10 +109,12 @@ impl BitcoindChainSource {
103109
));
104110

105111
let latest_chain_tip = RwLock::new(None);
112+
let spv_client = tokio::sync::Mutex::new(None);
106113
let wallet_polling_status = Mutex::new(WalletSyncStatus::Completed);
107114

108115
Self {
109116
api_client,
117+
spv_client,
110118
latest_chain_tip,
111119
wallet_polling_status,
112120
fee_estimator,
@@ -210,7 +218,16 @@ impl BitcoindChainSource {
210218
)
211219
.await
212220
{
213-
Ok((_header_cache, chain_tip)) => {
221+
Ok((header_cache, chain_tip)) => {
222+
let spv_client = self.new_spv_client(
223+
chain_tip,
224+
header_cache,
225+
Arc::clone(&onchain_wallet),
226+
Arc::clone(&channel_manager),
227+
Arc::clone(&chain_monitor),
228+
Arc::clone(&output_sweeper),
229+
);
230+
*self.spv_client.lock().await = Some(spv_client);
214231
{
215232
let elapsed_ms = now.elapsed().map(|d| d.as_millis()).unwrap_or(0);
216233
log_info!(
@@ -415,19 +432,24 @@ impl BitcoindChainSource {
415432
&self, onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
416433
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
417434
) -> Result<(), Error> {
418-
let latest_chain_tip_opt = self.latest_chain_tip.read().expect("lock").clone();
419-
let chain_tip =
420-
if let Some(tip) = latest_chain_tip_opt { tip } else { self.poll_chain_tip().await? };
421-
422-
let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network);
423-
let chain_listener = ChainListener {
424-
onchain_wallet: Arc::clone(&onchain_wallet),
425-
channel_manager: Arc::clone(&channel_manager),
426-
chain_monitor: Arc::clone(&chain_monitor),
427-
output_sweeper,
428-
};
429-
let mut spv_client =
430-
SpvClient::new(chain_tip, chain_poller, HeaderCache::new(), &chain_listener);
435+
let mut spv_client_lock = self.spv_client.lock().await;
436+
if spv_client_lock.is_none() {
437+
let latest_chain_tip_opt = self.latest_chain_tip.read().expect("lock").clone();
438+
let chain_tip = if let Some(tip) = latest_chain_tip_opt {
439+
tip
440+
} else {
441+
self.poll_chain_tip().await?
442+
};
443+
*spv_client_lock = Some(self.new_spv_client(
444+
chain_tip,
445+
HeaderCache::new(),
446+
Arc::clone(&onchain_wallet),
447+
Arc::clone(&channel_manager),
448+
chain_monitor,
449+
output_sweeper,
450+
));
451+
}
452+
let spv_client = spv_client_lock.as_mut().expect("initialized above");
431453

432454
let now = SystemTime::now();
433455
match spv_client.poll_best_tip().await {
@@ -442,6 +464,7 @@ impl BitcoindChainSource {
442464
return Err(Error::TxSyncFailed);
443465
},
444466
}
467+
drop(spv_client_lock);
445468

446469
let cur_height = channel_manager.current_best_block().height;
447470

@@ -485,6 +508,21 @@ impl BitcoindChainSource {
485508
Ok(())
486509
}
487510

511+
fn new_spv_client(
512+
&self, chain_tip: ValidatedBlockHeader, header_cache: HeaderCache,
513+
onchain_wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>,
514+
chain_monitor: Arc<ChainMonitor>, output_sweeper: Arc<Sweeper>,
515+
) -> BitcoindSpvClient {
516+
let chain_poller = ChainPoller::new(Arc::clone(&self.api_client), self.config.network);
517+
let chain_listener = Arc::new(ChainListener {
518+
onchain_wallet: Arc::downgrade(&onchain_wallet),
519+
channel_manager: Arc::downgrade(&channel_manager),
520+
chain_monitor: Arc::downgrade(&chain_monitor),
521+
output_sweeper: Arc::downgrade(&output_sweeper),
522+
});
523+
SpvClient::new(chain_tip, chain_poller, header_cache, chain_listener)
524+
}
525+
488526
pub(super) async fn update_fee_rate_estimates(&self) -> Result<(), Error> {
489527
macro_rules! get_fee_rate_update {
490528
($estimation_fut:expr) => {{
@@ -1467,34 +1505,59 @@ pub(crate) enum FeeRateEstimationMode {
14671505
}
14681506

14691507
pub(crate) struct ChainListener {
1470-
pub(crate) onchain_wallet: Arc<Wallet>,
1471-
pub(crate) channel_manager: Arc<ChannelManager>,
1472-
pub(crate) chain_monitor: Arc<ChainMonitor>,
1473-
pub(crate) output_sweeper: Arc<Sweeper>,
1508+
pub(crate) onchain_wallet: std::sync::Weak<Wallet>,
1509+
pub(crate) channel_manager: std::sync::Weak<ChannelManager>,
1510+
pub(crate) chain_monitor: std::sync::Weak<ChainMonitor>,
1511+
pub(crate) output_sweeper: std::sync::Weak<Sweeper>,
1512+
}
1513+
1514+
impl ChainListener {
1515+
fn upgrade(
1516+
&self,
1517+
) -> Option<(Arc<Wallet>, Arc<ChannelManager>, Arc<ChainMonitor>, Arc<Sweeper>)> {
1518+
Some((
1519+
self.onchain_wallet.upgrade()?,
1520+
self.channel_manager.upgrade()?,
1521+
self.chain_monitor.upgrade()?,
1522+
self.output_sweeper.upgrade()?,
1523+
))
1524+
}
14741525
}
14751526

14761527
impl Listen for ChainListener {
14771528
fn filtered_block_connected(
14781529
&self, header: &bitcoin::block::Header,
14791530
txdata: &lightning::chain::transaction::TransactionData, height: u32,
14801531
) {
1481-
self.onchain_wallet.filtered_block_connected(header, txdata, height);
1482-
self.channel_manager.filtered_block_connected(header, txdata, height);
1483-
self.chain_monitor.filtered_block_connected(header, txdata, height);
1484-
self.output_sweeper.filtered_block_connected(header, txdata, height);
1532+
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
1533+
self.upgrade()
1534+
{
1535+
onchain_wallet.filtered_block_connected(header, txdata, height);
1536+
channel_manager.filtered_block_connected(header, txdata, height);
1537+
chain_monitor.filtered_block_connected(header, txdata, height);
1538+
output_sweeper.filtered_block_connected(header, txdata, height);
1539+
}
14851540
}
14861541
fn block_connected(&self, block: &bitcoin::Block, height: u32) {
1487-
self.onchain_wallet.block_connected(block, height);
1488-
self.channel_manager.block_connected(block, height);
1489-
self.chain_monitor.block_connected(block, height);
1490-
self.output_sweeper.block_connected(block, height);
1542+
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
1543+
self.upgrade()
1544+
{
1545+
onchain_wallet.block_connected(block, height);
1546+
channel_manager.block_connected(block, height);
1547+
chain_monitor.block_connected(block, height);
1548+
output_sweeper.block_connected(block, height);
1549+
}
14911550
}
14921551

14931552
fn blocks_disconnected(&self, fork_point_block: lightning::chain::BlockLocator) {
1494-
self.onchain_wallet.blocks_disconnected(fork_point_block);
1495-
self.channel_manager.blocks_disconnected(fork_point_block);
1496-
self.chain_monitor.blocks_disconnected(fork_point_block);
1497-
self.output_sweeper.blocks_disconnected(fork_point_block);
1553+
if let Some((onchain_wallet, channel_manager, chain_monitor, output_sweeper)) =
1554+
self.upgrade()
1555+
{
1556+
onchain_wallet.blocks_disconnected(fork_point_block);
1557+
channel_manager.blocks_disconnected(fork_point_block);
1558+
chain_monitor.blocks_disconnected(fork_point_block);
1559+
output_sweeper.blocks_disconnected(fork_point_block);
1560+
}
14981561
}
14991562
}
15001563

0 commit comments

Comments
 (0)