Skip to content

Commit c406072

Browse files
committed
Make the ChannelManager::block_connected API more electrum-friendly
See the similar commit that operates on `Channel`'s internal API for more details on the reasoning.
1 parent 4170bba commit c406072

File tree

2 files changed

+51
-18
lines changed

2 files changed

+51
-18
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3293,8 +3293,13 @@ where
32933293
L::Target: Logger,
32943294
{
32953295
fn block_connected(&self, block: &Block, height: u32) {
3296+
assert_eq!(*self.last_block_hash.read().unwrap(), block.header.prev_blockhash,
3297+
"Blocks must be connected in chain-order - the connected header must build on the last connected header");
3298+
assert_eq!(self.latest_block_height.load(Ordering::Acquire) as u64, height as u64 - 1,
3299+
"Blocks must be connected in chain-order - the connected header must build on the last connected header");
32963300
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
3297-
ChannelManager::block_connected(self, &block.header, &txdata, height);
3301+
self.transactions_confirmed(&block.header, height, &txdata);
3302+
self.update_best_block(&block.header, height);
32983303
}
32993304

33003305
fn block_disconnected(&self, header: &BlockHeader, _height: u32) {
@@ -3309,22 +3314,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33093314
F::Target: FeeEstimator,
33103315
L::Target: Logger,
33113316
{
3312-
/// Updates channel state based on transactions seen in a connected block.
3313-
pub fn block_connected(&self, header: &BlockHeader, txdata: &TransactionData, height: u32) {
3317+
fn do_chain_event<FN: Fn(&mut Channel<Signer>) -> Result<(Option<msgs::FundingLocked>, Vec<(HTLCSource, PaymentHash)>), msgs::ErrorMessage>>
3318+
(&self, height: u32, f: FN) {
33143319
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
33153320
// during initialization prior to the chain_monitor being fully configured in some cases.
33163321
// See the docs for `ChannelManagerReadArgs` for more.
3317-
let block_hash = header.block_hash();
3318-
log_trace!(self.logger, "Block {} at height {} connected", block_hash, height);
3319-
3320-
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3321-
3322-
assert_eq!(*self.last_block_hash.read().unwrap(), header.prev_blockhash,
3323-
"Blocks must be connected in chain-order - the connected header must build on the last connected header");
3324-
assert_eq!(self.latest_block_height.load(Ordering::Acquire) as u64, height as u64 - 1,
3325-
"Blocks must be connected in chain-order - the connected header must build on the last connected header");
3326-
self.latest_block_height.store(height as usize, Ordering::Release);
3327-
*self.last_block_hash.write().unwrap() = block_hash;
33283322

33293323
let mut failed_channels = Vec::new();
33303324
let mut timed_out_htlcs = Vec::new();
@@ -3334,8 +3328,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
33343328
let short_to_id = &mut channel_state.short_to_id;
33353329
let pending_msg_events = &mut channel_state.pending_msg_events;
33363330
channel_state.by_id.retain(|_, channel| {
3337-
let res = channel.transactions_confirmed(&block_hash, height, txdata, &self.logger)
3338-
.and_then(|_| channel.update_best_block(height, header.time));
3331+
let res = f(channel);
33393332
if let Ok((chan_res, mut timed_out_pending_htlcs)) = res {
33403333
for (source, payment_hash) in timed_out_pending_htlcs.drain(..) {
33413334
let chan_update = self.get_channel_update(&channel).map(|u| u.encode_with_len()).unwrap(); // Cannot add/recv HTLCs before we have a short_id so unwrap is safe
@@ -3405,6 +3398,46 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34053398
for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
34063399
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
34073400
}
3401+
}
3402+
3403+
/// Updates channel state to take note of transactions which were confirmed in the given block
3404+
/// at the given height.
3405+
///
3406+
/// Note that you must still call update_best_block with the block information here.
3407+
///
3408+
/// XXX: Note that in the case that a transaction which was provided via this method is
3409+
/// reorganized out of the best chain, the only current way to correctly handle the any
3410+
/// associated channel force-closure is to walk the chain back from the current tip with
3411+
/// repeated `block_disconnected` calls, followed by an `update_best_block` call.
3412+
pub fn transactions_confirmed(&self, header: &BlockHeader, height: u32, txdata: &TransactionData) {
3413+
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
3414+
// during initialization prior to the chain_monitor being fully configured in some cases.
3415+
// See the docs for `ChannelManagerReadArgs` for more.
3416+
3417+
let block_hash = header.block_hash();
3418+
log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
3419+
3420+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3421+
self.do_chain_event(height, |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|a| (a, Vec::new())));
3422+
}
3423+
3424+
/// Updates channel state with the current best blockchain tip. You should attempt to call this
3425+
/// quickly after a new block becomes available, however it does not need to be called for each
3426+
/// new block.
3427+
pub fn update_best_block(&self, header: &BlockHeader, height: u32) {
3428+
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
3429+
// during initialization prior to the chain_monitor being fully configured in some cases.
3430+
// See the docs for `ChannelManagerReadArgs` for more.
3431+
3432+
let block_hash = header.block_hash();
3433+
log_trace!(self.logger, "Block {} at height {} connected", block_hash, height);
3434+
3435+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3436+
3437+
self.latest_block_height.store(height as usize, Ordering::Release);
3438+
*self.last_block_hash.write().unwrap() = block_hash;
3439+
3440+
self.do_chain_event(height, |channel| channel.update_best_block(height, header.time));
34083441

34093442
loop {
34103443
// Update last_node_announcement_serial to be the max of its current value and the

lightning/src/ln/functional_test_utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
//! A bunch of useful utilities for building networks of nodes and exchanging messages between
1111
//! nodes for functional tests.
1212
13-
use chain::Watch;
13+
use chain::{Listen, Watch};
1414
use chain::channelmonitor::ChannelMonitor;
1515
use chain::transaction::OutPoint;
1616
use ln::channelmanager::{ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentPreimage, PaymentHash, PaymentSecret, PaymentSendFailure};
@@ -102,7 +102,7 @@ pub fn connect_block<'a, 'b, 'c, 'd>(node: &'a Node<'b, 'c, 'd>, block: &Block)
102102
let txdata: Vec<_> = block.txdata.iter().enumerate().collect();
103103
let height = node.best_block_info().1 + 1;
104104
node.chain_monitor.chain_monitor.block_connected(&block.header, &txdata, height);
105-
node.node.block_connected(&block.header, &txdata, height);
105+
node.node.block_connected(&block, height);
106106
node.node.test_process_background_events();
107107
node.blocks.borrow_mut().push((block.header, height));
108108
}

0 commit comments

Comments
 (0)