Skip to content

Commit eb300b6

Browse files
authored
Merge pull request #3876 from TheBlueMatt/2025-06-disconnect-less-info
Drop the need for fork headers when calling Listen's disconnect
2 parents 457d2bd + a5b745a commit eb300b6

File tree

14 files changed

+182
-154
lines changed

14 files changed

+182
-154
lines changed

fuzz/src/full_stack.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,9 @@ impl<'a> MoneyLossDetector<'a> {
343343
self.header_hashes[self.height - 1].0,
344344
self.header_hashes[self.height].1,
345345
);
346-
self.manager.block_disconnected(&header, self.height as u32);
347-
self.monitor.block_disconnected(&header, self.height as u32);
346+
let best_block = BestBlock::new(header.prev_blockhash, self.height as u32 - 1);
347+
self.manager.blocks_disconnected(best_block);
348+
self.monitor.blocks_disconnected(best_block);
348349
self.height -= 1;
349350
let removal_height = self.height;
350351
self.txids_confirmed.retain(|_, height| removal_height != *height);

lightning-block-sync/src/init.rs

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use bitcoin::hash_types::BlockHash;
99
use bitcoin::network::Network;
1010

1111
use lightning::chain;
12+
use lightning::chain::BestBlock;
1213

1314
use std::ops::Deref;
1415

@@ -230,8 +231,8 @@ impl<'a, L: chain::Listen + ?Sized> chain::Listen for DynamicChainListener<'a, L
230231
unreachable!()
231232
}
232233

233-
fn block_disconnected(&self, header: &Header, height: u32) {
234-
self.0.block_disconnected(header, height)
234+
fn blocks_disconnected(&self, fork_point: BestBlock) {
235+
self.0.blocks_disconnected(fork_point)
235236
}
236237
}
237238

@@ -257,7 +258,7 @@ impl<'a, L: chain::Listen + ?Sized> chain::Listen for ChainListenerSet<'a, L> {
257258
}
258259
}
259260

260-
fn block_disconnected(&self, _header: &Header, _height: u32) {
261+
fn blocks_disconnected(&self, _fork_point: BestBlock) {
261262
unreachable!()
262263
}
263264
}
@@ -300,19 +301,16 @@ mod tests {
300301
let fork_chain_3 = main_chain.fork_at_height(3);
301302

302303
let listener_1 = MockChainListener::new()
303-
.expect_block_disconnected(*fork_chain_1.at_height(4))
304-
.expect_block_disconnected(*fork_chain_1.at_height(3))
305-
.expect_block_disconnected(*fork_chain_1.at_height(2))
304+
.expect_blocks_disconnected(*fork_chain_1.at_height(1))
306305
.expect_block_connected(*main_chain.at_height(2))
307306
.expect_block_connected(*main_chain.at_height(3))
308307
.expect_block_connected(*main_chain.at_height(4));
309308
let listener_2 = MockChainListener::new()
310-
.expect_block_disconnected(*fork_chain_2.at_height(4))
311-
.expect_block_disconnected(*fork_chain_2.at_height(3))
309+
.expect_blocks_disconnected(*fork_chain_2.at_height(2))
312310
.expect_block_connected(*main_chain.at_height(3))
313311
.expect_block_connected(*main_chain.at_height(4));
314312
let listener_3 = MockChainListener::new()
315-
.expect_block_disconnected(*fork_chain_3.at_height(4))
313+
.expect_blocks_disconnected(*fork_chain_3.at_height(3))
316314
.expect_block_connected(*main_chain.at_height(4));
317315

318316
let listeners = vec![
@@ -337,23 +335,17 @@ mod tests {
337335
let fork_chain_3 = fork_chain_2.fork_at_height(3);
338336

339337
let listener_1 = MockChainListener::new()
340-
.expect_block_disconnected(*fork_chain_1.at_height(4))
341-
.expect_block_disconnected(*fork_chain_1.at_height(3))
342-
.expect_block_disconnected(*fork_chain_1.at_height(2))
338+
.expect_blocks_disconnected(*fork_chain_1.at_height(1))
343339
.expect_block_connected(*main_chain.at_height(2))
344340
.expect_block_connected(*main_chain.at_height(3))
345341
.expect_block_connected(*main_chain.at_height(4));
346342
let listener_2 = MockChainListener::new()
347-
.expect_block_disconnected(*fork_chain_2.at_height(4))
348-
.expect_block_disconnected(*fork_chain_2.at_height(3))
349-
.expect_block_disconnected(*fork_chain_2.at_height(2))
343+
.expect_blocks_disconnected(*fork_chain_2.at_height(1))
350344
.expect_block_connected(*main_chain.at_height(2))
351345
.expect_block_connected(*main_chain.at_height(3))
352346
.expect_block_connected(*main_chain.at_height(4));
353347
let listener_3 = MockChainListener::new()
354-
.expect_block_disconnected(*fork_chain_3.at_height(4))
355-
.expect_block_disconnected(*fork_chain_3.at_height(3))
356-
.expect_block_disconnected(*fork_chain_3.at_height(2))
348+
.expect_blocks_disconnected(*fork_chain_3.at_height(1))
357349
.expect_block_connected(*main_chain.at_height(2))
358350
.expect_block_connected(*main_chain.at_height(3))
359351
.expect_block_connected(*main_chain.at_height(4));
@@ -380,7 +372,7 @@ mod tests {
380372
let old_tip = fork_chain.tip();
381373

382374
let listener = MockChainListener::new()
383-
.expect_block_disconnected(*old_tip)
375+
.expect_blocks_disconnected(*fork_chain.at_height(1))
384376
.expect_block_connected(*new_tip);
385377

386378
let listeners = vec![(old_tip.block_hash, &listener as &dyn chain::Listen)];

lightning-block-sync/src/lib.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ use bitcoin::hash_types::BlockHash;
4949
use bitcoin::pow::Work;
5050

5151
use lightning::chain;
52-
use lightning::chain::Listen;
52+
use lightning::chain::{BestBlock, Listen};
5353

5454
use std::future::Future;
5555
use std::ops::Deref;
@@ -398,12 +398,15 @@ where
398398
}
399399

400400
/// Notifies the chain listeners of disconnected blocks.
401-
fn disconnect_blocks(&mut self, mut disconnected_blocks: Vec<ValidatedBlockHeader>) {
402-
for header in disconnected_blocks.drain(..) {
401+
fn disconnect_blocks(&mut self, disconnected_blocks: Vec<ValidatedBlockHeader>) {
402+
for header in disconnected_blocks.iter() {
403403
if let Some(cached_header) = self.header_cache.block_disconnected(&header.block_hash) {
404-
assert_eq!(cached_header, header);
404+
assert_eq!(cached_header, *header);
405405
}
406-
self.chain_listener.block_disconnected(&header.header, header.height);
406+
}
407+
if let Some(block) = disconnected_blocks.last() {
408+
let fork_point = BestBlock::new(block.header.prev_blockhash, block.height - 1);
409+
self.chain_listener.blocks_disconnected(fork_point);
407410
}
408411
}
409412

@@ -615,7 +618,7 @@ mod chain_notifier_tests {
615618
let new_tip = fork_chain.tip();
616619
let old_tip = main_chain.tip();
617620
let chain_listener = &MockChainListener::new()
618-
.expect_block_disconnected(*old_tip)
621+
.expect_blocks_disconnected(*fork_chain.at_height(1))
619622
.expect_block_connected(*new_tip);
620623
let mut notifier =
621624
ChainNotifier { header_cache: &mut main_chain.header_cache(0..=2), chain_listener };
@@ -635,8 +638,7 @@ mod chain_notifier_tests {
635638
let new_tip = fork_chain.tip();
636639
let old_tip = main_chain.tip();
637640
let chain_listener = &MockChainListener::new()
638-
.expect_block_disconnected(*old_tip)
639-
.expect_block_disconnected(*main_chain.at_height(2))
641+
.expect_blocks_disconnected(*main_chain.at_height(1))
640642
.expect_block_connected(*new_tip);
641643
let mut notifier =
642644
ChainNotifier { header_cache: &mut main_chain.header_cache(0..=3), chain_listener };
@@ -656,7 +658,7 @@ mod chain_notifier_tests {
656658
let new_tip = fork_chain.tip();
657659
let old_tip = main_chain.tip();
658660
let chain_listener = &MockChainListener::new()
659-
.expect_block_disconnected(*old_tip)
661+
.expect_blocks_disconnected(*fork_chain.at_height(1))
660662
.expect_block_connected(*fork_chain.at_height(2))
661663
.expect_block_connected(*new_tip);
662664
let mut notifier =

lightning-block-sync/src/test_utils.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use bitcoin::transaction;
1313
use bitcoin::Transaction;
1414

1515
use lightning::chain;
16+
use lightning::chain::BestBlock;
1617

1718
use std::cell::RefCell;
1819
use std::collections::VecDeque;
@@ -203,7 +204,7 @@ impl chain::Listen for NullChainListener {
203204
&self, _header: &Header, _txdata: &chain::transaction::TransactionData, _height: u32,
204205
) {
205206
}
206-
fn block_disconnected(&self, _header: &Header, _height: u32) {}
207+
fn blocks_disconnected(&self, _fork_point: BestBlock) {}
207208
}
208209

209210
pub struct MockChainListener {
@@ -231,8 +232,8 @@ impl MockChainListener {
231232
self
232233
}
233234

234-
pub fn expect_block_disconnected(self, block: BlockHeaderData) -> Self {
235-
self.expected_blocks_disconnected.borrow_mut().push_back(block);
235+
pub fn expect_blocks_disconnected(self, fork_point: BlockHeaderData) -> Self {
236+
self.expected_blocks_disconnected.borrow_mut().push_back(fork_point);
236237
self
237238
}
238239
}
@@ -264,14 +265,17 @@ impl chain::Listen for MockChainListener {
264265
}
265266
}
266267

267-
fn block_disconnected(&self, header: &Header, height: u32) {
268+
fn blocks_disconnected(&self, fork_point: BestBlock) {
268269
match self.expected_blocks_disconnected.borrow_mut().pop_front() {
269270
None => {
270-
panic!("Unexpected block disconnected: {:?}", header.block_hash());
271+
panic!(
272+
"Unexpected block(s) disconnected {} at height {}",
273+
fork_point.block_hash, fork_point.height,
274+
);
271275
},
272-
Some(expected_block) => {
273-
assert_eq!(header.block_hash(), expected_block.header.block_hash());
274-
assert_eq!(height, expected_block.height);
276+
Some(expected) => {
277+
assert_eq!(fork_point.block_hash, expected.header.block_hash());
278+
assert_eq!(fork_point.height, expected.height);
275279
},
276280
}
277281
}

lightning-liquidity/src/manager.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -790,14 +790,11 @@ where
790790
self.best_block_updated(header, height);
791791
}
792792

793-
fn block_disconnected(&self, header: &bitcoin::block::Header, height: u32) {
794-
let new_height = height - 1;
793+
fn blocks_disconnected(&self, fork_point: BestBlock) {
795794
if let Some(best_block) = self.best_block.write().unwrap().as_mut() {
796-
assert_eq!(best_block.block_hash, header.block_hash(),
797-
"Blocks must be disconnected in chain-order - the disconnected header must be the last connected header");
798-
assert_eq!(best_block.height, height,
799-
"Blocks must be disconnected in chain-order - the disconnected block must have the correct height");
800-
*best_block = BestBlock::new(header.prev_blockhash, new_height)
795+
assert!(best_block.height > fork_point.height,
796+
"Blocks disconnected must indicate disconnection from the current best height, i.e. the new chain tip must be lower than the previous best height");
797+
*best_block = fork_point;
801798
}
802799

803800
// TODO: Call block_disconnected on all sub-modules that require it, e.g., LSPS1MessageHandler.

lightning/src/chain/chainmonitor.rs

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::chain::channelmonitor::{
3535
WithChannelMonitor,
3636
};
3737
use crate::chain::transaction::{OutPoint, TransactionData};
38-
use crate::chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput};
38+
use crate::chain::{BestBlock, ChannelMonitorUpdateStatus, Filter, WatchedOutput};
3939
use crate::events::{self, Event, EventHandler, ReplayEvent};
4040
use crate::ln::channel_state::ChannelDetails;
4141
#[cfg(peer_storage)]
@@ -1055,18 +1055,17 @@ where
10551055
self.event_notifier.notify();
10561056
}
10571057

1058-
fn block_disconnected(&self, header: &Header, height: u32) {
1058+
fn blocks_disconnected(&self, fork_point: BestBlock) {
10591059
let monitor_states = self.monitors.read().unwrap();
10601060
log_debug!(
10611061
self.logger,
1062-
"Latest block {} at height {} removed via block_disconnected",
1063-
header.block_hash(),
1064-
height
1062+
"Block(s) removed to height {} via blocks_disconnected. New best block is {}",
1063+
fork_point.height,
1064+
fork_point.block_hash,
10651065
);
10661066
for monitor_state in monitor_states.values() {
1067-
monitor_state.monitor.block_disconnected(
1068-
header,
1069-
height,
1067+
monitor_state.monitor.blocks_disconnected(
1068+
fork_point,
10701069
&*self.broadcaster,
10711070
&*self.fee_estimator,
10721071
&self.logger,

lightning/src/chain/channelmonitor.rs

Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2308,23 +2308,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
23082308

23092309
/// Determines if the disconnected block contained any transactions of interest and updates
23102310
/// appropriately.
2311-
#[rustfmt::skip]
2312-
pub fn block_disconnected<B: Deref, F: Deref, L: Deref>(
2313-
&self,
2314-
header: &Header,
2315-
height: u32,
2316-
broadcaster: B,
2317-
fee_estimator: F,
2318-
logger: &L,
2311+
pub fn blocks_disconnected<B: Deref, F: Deref, L: Deref>(
2312+
&self, fork_point: BestBlock, broadcaster: B, fee_estimator: F, logger: &L,
23192313
) where
23202314
B::Target: BroadcasterInterface,
23212315
F::Target: FeeEstimator,
23222316
L::Target: Logger,
23232317
{
23242318
let mut inner = self.inner.lock().unwrap();
23252319
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
2326-
inner.block_disconnected(
2327-
header, height, broadcaster, fee_estimator, &logger)
2320+
inner.blocks_disconnected(fork_point, broadcaster, fee_estimator, &logger)
23282321
}
23292322

23302323
/// Processes transactions confirmed in a block with the given header and height, returning new
@@ -2358,10 +2351,10 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
23582351

23592352
/// Processes a transaction that was reorganized out of the chain.
23602353
///
2361-
/// Used instead of [`block_disconnected`] by clients that are notified of transactions rather
2354+
/// Used instead of [`blocks_disconnected`] by clients that are notified of transactions rather
23622355
/// than blocks. See [`chain::Confirm`] for calling expectations.
23632356
///
2364-
/// [`block_disconnected`]: Self::block_disconnected
2357+
/// [`blocks_disconnected`]: Self::blocks_disconnected
23652358
#[rustfmt::skip]
23662359
pub fn transaction_unconfirmed<B: Deref, F: Deref, L: Deref>(
23672360
&self,
@@ -5124,8 +5117,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
51245117
log_trace!(logger, "Best block re-orged, replaced with new block {} at height {}", block_hash, height);
51255118
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= height);
51265119
let conf_target = self.closure_conf_target();
5127-
self.onchain_tx_handler.block_disconnected(
5128-
height + 1, &broadcaster, conf_target, &self.destination_script, fee_estimator, logger,
5120+
self.onchain_tx_handler.blocks_disconnected(
5121+
height, &broadcaster, conf_target, &self.destination_script, fee_estimator, logger,
51295122
);
51305123
Vec::new()
51315124
} else { Vec::new() }
@@ -5452,12 +5445,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
54525445
!unmatured_htlcs.contains(&source),
54535446
"An unmature HTLC transaction conflicts with a maturing one; failed to \
54545447
call either transaction_unconfirmed for the conflicting transaction \
5455-
or block_disconnected for a block containing it.");
5448+
or blocks_disconnected for a block before it.");
54565449
debug_assert!(
54575450
!matured_htlcs.contains(&source),
54585451
"A matured HTLC transaction conflicts with a maturing one; failed to \
54595452
call either transaction_unconfirmed for the conflicting transaction \
5460-
or block_disconnected for a block containing it.");
5453+
or blocks_disconnected for a block before it.");
54615454
matured_htlcs.push(source.clone());
54625455
}
54635456

@@ -5605,23 +5598,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
56055598
}
56065599

56075600
#[rustfmt::skip]
5608-
fn block_disconnected<B: Deref, F: Deref, L: Deref>(
5609-
&mut self, header: &Header, height: u32, broadcaster: B, fee_estimator: F, logger: &WithChannelMonitor<L>
5601+
fn blocks_disconnected<B: Deref, F: Deref, L: Deref>(
5602+
&mut self, fork_point: BestBlock, broadcaster: B, fee_estimator: F, logger: &WithChannelMonitor<L>
56105603
) where B::Target: BroadcasterInterface,
56115604
F::Target: FeeEstimator,
56125605
L::Target: Logger,
56135606
{
5614-
log_trace!(logger, "Block {} at height {} disconnected", header.block_hash(), height);
5607+
let new_height = fork_point.height;
5608+
log_trace!(logger, "Block(s) disconnected to height {}", new_height);
5609+
assert!(self.best_block.height > fork_point.height,
5610+
"Blocks disconnected must indicate disconnection from the current best height, i.e. the new chain tip must be lower than the previous best height");
56155611

56165612
//We may discard:
56175613
//- htlc update there as failure-trigger tx (revoked commitment tx, non-revoked commitment tx, HTLC-timeout tx) has been disconnected
56185614
//- maturing spendable output has transaction paying us has been disconnected
5619-
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height < height);
5615+
self.onchain_events_awaiting_threshold_conf.retain(|ref entry| entry.height <= new_height);
56205616

56215617
// TODO: Replace with `take_if` once our MSRV is >= 1.80.
56225618
let mut should_broadcast_commitment = false;
56235619
if let Some((_, conf_height)) = self.alternative_funding_confirmed.as_ref() {
5624-
if *conf_height == height {
5620+
if *conf_height > new_height {
56255621
self.alternative_funding_confirmed.take();
56265622
if self.holder_tx_signed || self.funding_spend_seen {
56275623
// Cancel any previous claims that are no longer valid as they stemmed from a
@@ -5637,8 +5633,8 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
56375633

56385634
let bounded_fee_estimator = LowerBoundedFeeEstimator::new(fee_estimator);
56395635
let conf_target = self.closure_conf_target();
5640-
self.onchain_tx_handler.block_disconnected(
5641-
height, &broadcaster, conf_target, &self.destination_script, &bounded_fee_estimator, logger
5636+
self.onchain_tx_handler.blocks_disconnected(
5637+
new_height, &broadcaster, conf_target, &self.destination_script, &bounded_fee_estimator, logger
56425638
);
56435639

56445640
// Only attempt to broadcast the new commitment after the `block_disconnected` call above so that
@@ -5647,7 +5643,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
56475643
self.queue_latest_holder_commitment_txn_for_broadcast(&broadcaster, &bounded_fee_estimator, logger);
56485644
}
56495645

5650-
self.best_block = BestBlock::new(header.prev_blockhash, height - 1);
5646+
self.best_block = fork_point;
56515647
}
56525648

56535649
#[rustfmt::skip]
@@ -6121,8 +6117,8 @@ where
61216117
self.0.block_connected(header, txdata, height, &*self.1, &*self.2, &self.3);
61226118
}
61236119

6124-
fn block_disconnected(&self, header: &Header, height: u32) {
6125-
self.0.block_disconnected(header, height, &*self.1, &*self.2, &self.3);
6120+
fn blocks_disconnected(&self, fork_point: BestBlock) {
6121+
self.0.blocks_disconnected(fork_point, &*self.1, &*self.2, &self.3);
61266122
}
61276123
}
61286124

0 commit comments

Comments
 (0)