Skip to content

Commit b6fce3d

Browse files
authored
Merge pull request #1796 from tnull/2022-10-track-confirmation-block-hash
Track confirmation block hash and return via `Confirm::get_relevant_txids`
2 parents 97a6a6b + 9685d6c commit b6fce3d

File tree

7 files changed

+129
-60
lines changed

7 files changed

+129
-60
lines changed

lightning/src/chain/chainmonitor.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
//! servicing [`ChannelMonitor`] updates from the client.
2525
2626
use bitcoin::blockdata::block::BlockHeader;
27-
use bitcoin::hash_types::Txid;
27+
use bitcoin::hash_types::{Txid, BlockHash};
2828

2929
use crate::chain;
3030
use crate::chain::{ChannelMonitorUpdateStatus, Filter, WatchedOutput};
@@ -561,7 +561,7 @@ where
561561
});
562562
}
563563

564-
fn get_relevant_txids(&self) -> Vec<Txid> {
564+
fn get_relevant_txids(&self) -> Vec<(Txid, Option<BlockHash>)> {
565565
let mut txids = Vec::new();
566566
let monitor_states = self.monitors.read().unwrap();
567567
for monitor_state in monitor_states.values() {

lightning/src/chain/channelmonitor.rs

+45-32
Large diffs are not rendered by default.

lightning/src/chain/mod.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ pub trait Confirm {
171171
/// if they become available at the same time.
172172
fn best_block_updated(&self, header: &BlockHeader, height: u32);
173173

174-
/// Returns transactions that should be monitored for reorganization out of the chain.
174+
/// Returns transactions that should be monitored for reorganization out of the chain along
175+
/// with the hash of the block as part of which had been previously confirmed.
175176
///
176177
/// Will include any transactions passed to [`transactions_confirmed`] that have insufficient
177178
/// confirmations to be safe from a chain reorganization. Will not include any transactions
@@ -180,11 +181,13 @@ pub trait Confirm {
180181
/// May be called to determine the subset of transactions that must still be monitored for
181182
/// reorganization. Will be idempotent between calls but may change as a result of calls to the
182183
/// other interface methods. Thus, this is useful to determine which transactions may need to be
183-
/// given to [`transaction_unconfirmed`].
184+
/// given to [`transaction_unconfirmed`]. If any of the returned transactions are confirmed in
185+
/// a block other than the one with the given hash, they need to be unconfirmed and reconfirmed
186+
/// via [`transaction_unconfirmed`] and [`transactions_confirmed`], respectively.
184187
///
185188
/// [`transactions_confirmed`]: Self::transactions_confirmed
186189
/// [`transaction_unconfirmed`]: Self::transaction_unconfirmed
187-
fn get_relevant_txids(&self) -> Vec<Txid>;
190+
fn get_relevant_txids(&self) -> Vec<(Txid, Option<BlockHash>)>;
188191
}
189192

190193
/// An enum representing the status of a channel monitor update persistence.

lightning/src/chain/onchaintx.rs

+45-16
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use bitcoin::blockdata::transaction::Transaction;
1616
use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
1717
use bitcoin::blockdata::script::Script;
1818

19-
use bitcoin::hash_types::Txid;
19+
use bitcoin::hash_types::{Txid, BlockHash};
2020

2121
use bitcoin::secp256k1::{Secp256k1, ecdsa::Signature};
2222
use bitcoin::secp256k1;
@@ -58,6 +58,7 @@ const MAX_ALLOC_SIZE: usize = 64*1024;
5858
struct OnchainEventEntry {
5959
txid: Txid,
6060
height: u32,
61+
block_hash: Option<BlockHash>, // Added as optional, will be filled in for any entry generated on 0.0.113 or after
6162
event: OnchainEvent,
6263
}
6364

@@ -92,6 +93,7 @@ impl Writeable for OnchainEventEntry {
9293
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
9394
write_tlv_fields!(writer, {
9495
(0, self.txid, required),
96+
(1, self.block_hash, option),
9597
(2, self.height, required),
9698
(4, self.event, required),
9799
});
@@ -103,14 +105,16 @@ impl MaybeReadable for OnchainEventEntry {
103105
fn read<R: io::Read>(reader: &mut R) -> Result<Option<Self>, DecodeError> {
104106
let mut txid = Txid::all_zeros();
105107
let mut height = 0;
108+
let mut block_hash = None;
106109
let mut event = None;
107110
read_tlv_fields!(reader, {
108111
(0, txid, required),
112+
(1, block_hash, option),
109113
(2, height, required),
110114
(4, event, ignorable),
111115
});
112116
if let Some(ev) = event {
113-
Ok(Some(Self { txid, height, event: ev }))
117+
Ok(Some(Self { txid, height, block_hash, event: ev }))
114118
} else {
115119
Ok(None)
116120
}
@@ -543,17 +547,22 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
543547

544548
/// Upon channelmonitor.block_connected(..) or upon provision of a preimage on the forward link
545549
/// for this channel, provide new relevant on-chain transactions and/or new claim requests.
546-
/// Formerly this was named `block_connected`, but it is now also used for claiming an HTLC output
547-
/// if we receive a preimage after force-close.
548-
/// `conf_height` represents the height at which the transactions in `txn_matched` were
549-
/// confirmed. This does not need to equal the current blockchain tip height, which should be
550-
/// provided via `cur_height`, however it must never be higher than `cur_height`.
551-
pub(crate) fn update_claims_view<B: Deref, F: Deref, L: Deref>(&mut self, txn_matched: &[&Transaction], requests: Vec<PackageTemplate>, conf_height: u32, cur_height: u32, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L)
552-
where B::Target: BroadcasterInterface,
553-
F::Target: FeeEstimator,
554-
L::Target: Logger,
550+
/// Together with `update_claims_view_from_matched_txn` this used to be named
551+
/// `block_connected`, but it is now also used for claiming an HTLC output if we receive a
552+
/// preimage after force-close.
553+
///
554+
/// `conf_height` represents the height at which the request was generated. This
555+
/// does not need to equal the current blockchain tip height, which should be provided via
556+
/// `cur_height`, however it must never be higher than `cur_height`.
557+
pub(crate) fn update_claims_view_from_requests<B: Deref, F: Deref, L: Deref>(
558+
&mut self, requests: Vec<PackageTemplate>, conf_height: u32, cur_height: u32,
559+
broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
560+
) where
561+
B::Target: BroadcasterInterface,
562+
F::Target: FeeEstimator,
563+
L::Target: Logger,
555564
{
556-
log_debug!(logger, "Updating claims view at height {} with {} matched transactions in block {} and {} claim requests", cur_height, txn_matched.len(), conf_height, requests.len());
565+
log_debug!(logger, "Updating claims view at height {} with {} claim requests", cur_height, requests.len());
557566
let mut preprocessed_requests = Vec::with_capacity(requests.len());
558567
let mut aggregated_request = None;
559568

@@ -633,7 +642,25 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
633642
self.pending_claim_requests.insert(txid, req);
634643
}
635644
}
645+
}
636646

647+
/// Upon channelmonitor.block_connected(..) or upon provision of a preimage on the forward link
648+
/// for this channel, provide new relevant on-chain transactions and/or new claim requests.
649+
/// Together with `update_claims_view_from_requests` this used to be named `block_connected`,
650+
/// but it is now also used for claiming an HTLC output if we receive a preimage after force-close.
651+
///
652+
/// `conf_height` represents the height at which the transactions in `txn_matched` were
653+
/// confirmed. This does not need to equal the current blockchain tip height, which should be
654+
/// provided via `cur_height`, however it must never be higher than `cur_height`.
655+
pub(crate) fn update_claims_view_from_matched_txn<B: Deref, F: Deref, L: Deref>(
656+
&mut self, txn_matched: &[&Transaction], conf_height: u32, conf_hash: BlockHash,
657+
cur_height: u32, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &L
658+
) where
659+
B::Target: BroadcasterInterface,
660+
F::Target: FeeEstimator,
661+
L::Target: Logger,
662+
{
663+
log_debug!(logger, "Updating claims view at height {} with {} matched transactions in block {}", cur_height, txn_matched.len(), conf_height);
637664
let mut bump_candidates = HashMap::new();
638665
for tx in txn_matched {
639666
// Scan all input to verify is one of the outpoint spent is of interest for us
@@ -661,6 +688,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
661688
let entry = OnchainEventEntry {
662689
txid: tx.txid(),
663690
height: conf_height,
691+
block_hash: Some(conf_hash),
664692
event: OnchainEvent::Claim { claim_request: first_claim_txid_height.0.clone() }
665693
};
666694
if !self.onchain_events_awaiting_threshold_conf.contains(&entry) {
@@ -701,6 +729,7 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
701729
let entry = OnchainEventEntry {
702730
txid: tx.txid(),
703731
height: conf_height,
732+
block_hash: Some(conf_hash),
704733
event: OnchainEvent::ContentiousOutpoint { package },
705734
};
706735
if !self.onchain_events_awaiting_threshold_conf.contains(&entry) {
@@ -860,12 +889,12 @@ impl<ChannelSigner: Sign> OnchainTxHandler<ChannelSigner> {
860889
self.claimable_outpoints.get(outpoint).is_some()
861890
}
862891

863-
pub(crate) fn get_relevant_txids(&self) -> Vec<Txid> {
864-
let mut txids: Vec<Txid> = self.onchain_events_awaiting_threshold_conf
892+
pub(crate) fn get_relevant_txids(&self) -> Vec<(Txid, Option<BlockHash>)> {
893+
let mut txids: Vec<(Txid, Option<BlockHash>)> = self.onchain_events_awaiting_threshold_conf
865894
.iter()
866-
.map(|entry| entry.txid)
895+
.map(|entry| (entry.txid, entry.block_hash))
867896
.collect();
868-
txids.sort_unstable();
897+
txids.sort_unstable_by_key(|(txid, _)| *txid);
869898
txids.dedup();
870899
txids
871900
}

lightning/src/ln/channel.rs

+5
Original file line numberDiff line numberDiff line change
@@ -4520,6 +4520,11 @@ impl<Signer: Sign> Channel<Signer> {
45204520
self.channel_transaction_parameters.funding_outpoint
45214521
}
45224522

4523+
/// Returns the block hash in which our funding transaction was confirmed.
4524+
pub fn get_funding_tx_confirmed_in(&self) -> Option<BlockHash> {
4525+
self.funding_tx_confirmed_in
4526+
}
4527+
45234528
fn get_holder_selected_contest_delay(&self) -> u16 {
45244529
self.channel_transaction_parameters.holder_selected_contest_delay
45254530
}

lightning/src/ln/channelmanager.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -5906,12 +5906,12 @@ where
59065906
});
59075907
}
59085908

5909-
fn get_relevant_txids(&self) -> Vec<Txid> {
5909+
fn get_relevant_txids(&self) -> Vec<(Txid, Option<BlockHash>)> {
59105910
let channel_state = self.channel_state.lock().unwrap();
59115911
let mut res = Vec::with_capacity(channel_state.by_id.len());
59125912
for chan in channel_state.by_id.values() {
5913-
if let Some(funding_txo) = chan.get_funding_txo() {
5914-
res.push(funding_txo.txid);
5913+
if let (Some(funding_txo), block_hash) = (chan.get_funding_txo(), chan.get_funding_tx_confirmed_in()) {
5914+
res.push((funding_txo.txid, block_hash));
59155915
}
59165916
}
59175917
res

lightning/src/ln/reorg_tests.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
271271
let mut nodes = create_network(2, &node_cfgs, &node_chanmgrs);
272272
*nodes[0].connect_style.borrow_mut() = connect_style;
273273

274+
let chan_conf_height = core::cmp::max(nodes[0].best_block_info().1 + 1, nodes[1].best_block_info().1 + 1);
274275
let chan = create_announced_chan_between_nodes(&nodes, 0, 1, channelmanager::provided_init_features(), channelmanager::provided_init_features());
275276

276277
let channel_state = nodes[0].node.channel_state.lock().unwrap();
@@ -281,15 +282,24 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
281282
if !reorg_after_reload {
282283
if use_funding_unconfirmed {
283284
let relevant_txids = nodes[0].node.get_relevant_txids();
284-
assert_eq!(&relevant_txids[..], &[chan.3.txid()]);
285-
nodes[0].node.transaction_unconfirmed(&relevant_txids[0]);
285+
assert_eq!(relevant_txids.len(), 1);
286+
let block_hash_opt = relevant_txids[0].1;
287+
let expected_hash = nodes[0].get_block_header(chan_conf_height).block_hash();
288+
assert_eq!(block_hash_opt, Some(expected_hash));
289+
let txid = relevant_txids[0].0;
290+
assert_eq!(txid, chan.3.txid());
291+
nodes[0].node.transaction_unconfirmed(&txid);
286292
} else if connect_style == ConnectStyle::FullBlockViaListen {
287293
disconnect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH - 1);
288294
assert_eq!(nodes[0].node.list_usable_channels().len(), 1);
289295
disconnect_blocks(&nodes[0], 1);
290296
} else {
291297
disconnect_all_blocks(&nodes[0]);
292298
}
299+
300+
let relevant_txids = nodes[0].node.get_relevant_txids();
301+
assert_eq!(relevant_txids.len(), 0);
302+
293303
handle_announce_close_broadcast_events(&nodes, 0, 1, true, "Channel closed because of an exception: Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.");
294304
check_added_monitors!(nodes[1], 1);
295305
{
@@ -350,15 +360,24 @@ fn do_test_unconf_chan(reload_node: bool, reorg_after_reload: bool, use_funding_
350360
if reorg_after_reload {
351361
if use_funding_unconfirmed {
352362
let relevant_txids = nodes[0].node.get_relevant_txids();
353-
assert_eq!(&relevant_txids[..], &[chan.3.txid()]);
354-
nodes[0].node.transaction_unconfirmed(&relevant_txids[0]);
363+
assert_eq!(relevant_txids.len(), 1);
364+
let block_hash_opt = relevant_txids[0].1;
365+
let expected_hash = nodes[0].get_block_header(chan_conf_height).block_hash();
366+
assert_eq!(block_hash_opt, Some(expected_hash));
367+
let txid = relevant_txids[0].0;
368+
assert_eq!(txid, chan.3.txid());
369+
nodes[0].node.transaction_unconfirmed(&txid);
355370
} else if connect_style == ConnectStyle::FullBlockViaListen {
356371
disconnect_blocks(&nodes[0], CHAN_CONFIRM_DEPTH - 1);
357372
assert_eq!(nodes[0].node.list_channels().len(), 1);
358373
disconnect_blocks(&nodes[0], 1);
359374
} else {
360375
disconnect_all_blocks(&nodes[0]);
361376
}
377+
378+
let relevant_txids = nodes[0].node.get_relevant_txids();
379+
assert_eq!(relevant_txids.len(), 0);
380+
362381
handle_announce_close_broadcast_events(&nodes, 0, 1, true, "Channel closed because of an exception: Funding transaction was un-confirmed. Locked at 6 confs, now have 0 confs.");
363382
check_added_monitors!(nodes[1], 1);
364383
{

0 commit comments

Comments
 (0)