Skip to content

Commit a15c854

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 60b962a commit a15c854

File tree

4 files changed

+74
-21
lines changed

4 files changed

+74
-21
lines changed

fuzz/src/chanmon_consistency.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,10 +435,11 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
435435
let chain_hash = genesis_block(Network::Bitcoin).block_hash();
436436
let mut header = BlockHeader { version: 0x20000000, prev_blockhash: chain_hash, merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
437437
let txdata: Vec<_> = channel_txn.iter().enumerate().map(|(i, tx)| (i + 1, tx)).collect();
438-
$node.block_connected(&header, &txdata, 1);
438+
$node.transactions_confirmed(&header, 1, &txdata);
439+
$node.update_best_block(&header, 1);
439440
for i in 2..100 {
440441
header = BlockHeader { version: 0x20000000, prev_blockhash: header.block_hash(), merkle_root: Default::default(), time: 42, bits: 42, nonce: 42 };
441-
$node.block_connected(&header, &[], i);
442+
$node.update_best_block(&header, i);
442443
}
443444
} }
444445
}

fuzz/src/full_stack.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ impl<'a> MoneyLossDetector<'a> {
202202
self.blocks_connected += 1;
203203
let header = BlockHeader { version: 0x20000000, prev_blockhash: self.header_hashes[self.height].0, merkle_root: Default::default(), time: self.blocks_connected, bits: 42, nonce: 42 };
204204
self.height += 1;
205-
self.manager.block_connected(&header, &txdata, self.height as u32);
205+
self.manager.transactions_confirmed(&header, self.height as u32, &txdata);
206+
self.manager.update_best_block(&header, self.height as u32);
206207
(*self.monitor).block_connected(&header, &txdata, self.height as u32);
207208
if self.header_hashes.len() > self.height {
208209
self.header_hashes[self.height] = (header.block_hash(), self.blocks_connected);

lightning/src/ln/channelmanager.rs

Lines changed: 67 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 block height must be one greater than the previous height");
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
@@ -3406,6 +3399,64 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
34063399
for (source, payment_hash, reason) in timed_out_htlcs.drain(..) {
34073400
self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), source, &payment_hash, reason);
34083401
}
3402+
}
3403+
3404+
/// Updates channel state to take note of transactions which were confirmed in the given block
3405+
/// at the given height.
3406+
///
3407+
/// Note that you must still call (or have called) [`update_best_block`] with the block
3408+
/// information which is included here.
3409+
///
3410+
/// This method may be called before or after [`update_best_block`] for a given block's
3411+
/// transaction data and may be called multiple times with additional transaction data for a
3412+
/// given block.
3413+
///
3414+
/// This method may be called for a previous block after an [`update_best_block`] call has
3415+
/// been made for a later block, however it must *not* be called with transaction data from a
3416+
/// block which is no longer in the best chain (ie where [`update_best_block`] has already
3417+
/// been informed about a blockchain reorganization which no longer includes the block which
3418+
/// corresponds to `header`).
3419+
///
3420+
/// [`update_best_block`]: `Self::update_best_block`
3421+
pub fn transactions_confirmed(&self, header: &BlockHeader, height: u32, txdata: &TransactionData) {
3422+
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
3423+
// during initialization prior to the chain_monitor being fully configured in some cases.
3424+
// See the docs for `ChannelManagerReadArgs` for more.
3425+
3426+
let block_hash = header.block_hash();
3427+
log_trace!(self.logger, "{} transactions included in block {} at height {} provided", txdata.len(), block_hash, height);
3428+
3429+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3430+
self.do_chain_event(height, |channel| channel.transactions_confirmed(&block_hash, height, txdata, &self.logger).map(|_| (None, Vec::new())));
3431+
}
3432+
3433+
/// Updates channel state with the current best blockchain tip. You should attempt to call this
3434+
/// quickly after a new block becomes available, however if multiple new blocks become
3435+
/// available at the same time, only a single `update_best_block()` call needs to be made.
3436+
///
3437+
/// This method should also be called immediately after any block disconnections, once at the
3438+
/// reorganization fork point, and once with the new chain tip. Calling this method at the
3439+
/// blockchain reorganization fork point ensures we learn when a funding transaction which was
3440+
/// previously confirmed is reorganized out of the blockchain, ensuring we do not continue to
3441+
/// accept payments which cannot be enforced on-chain.
3442+
///
3443+
/// In both the block-connection and block-disconnection case, this method may be called either
3444+
/// once per block connected or disconnected, or simply at the fork point and new tip(s),
3445+
/// skipping any intermediary blocks.
3446+
pub fn update_best_block(&self, header: &BlockHeader, height: u32) {
3447+
// Note that we MUST NOT end up calling methods on self.chain_monitor here - we're called
3448+
// during initialization prior to the chain_monitor being fully configured in some cases.
3449+
// See the docs for `ChannelManagerReadArgs` for more.
3450+
3451+
let block_hash = header.block_hash();
3452+
log_trace!(self.logger, "New best block: {} at height {}", block_hash, height);
3453+
3454+
let _persistence_guard = PersistenceNotifierGuard::new(&self.total_consistency_lock, &self.persistence_notifier);
3455+
3456+
self.latest_block_height.store(height as usize, Ordering::Release);
3457+
*self.last_block_hash.write().unwrap() = block_hash;
3458+
3459+
self.do_chain_event(height, |channel| channel.update_best_block(height, header.time));
34093460

34103461
loop {
34113462
// 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)