Skip to content

Commit 17f7858

Browse files
authored
Merge pull request #4109 from martinsaposnic/track-funding-tx-channelmonitor
Track funding tx channelmonitor
2 parents c11d1a5 + ea95a15 commit 17f7858

File tree

4 files changed

+362
-21
lines changed

4 files changed

+362
-21
lines changed

lightning/src/chain/channelmonitor.rs

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,6 +1202,19 @@ pub(crate) struct ChannelMonitorImpl<Signer: EcdsaChannelSigner> {
12021202
funding: FundingScope,
12031203
pending_funding: Vec<FundingScope>,
12041204

1205+
/// True if this channel was configured for manual funding broadcasts. Monitors written by
1206+
/// versions prior to LDK 0.2 load with `false` until a new update persists it.
1207+
is_manual_broadcast: bool,
1208+
/// True once we've observed either funding transaction on-chain. Older monitors prior to LDK 0.2
1209+
/// assume this is `true` when absent during upgrade so holder broadcasts aren't gated unexpectedly.
1210+
/// In manual-broadcast channels we also use this to trigger deferred holder
1211+
/// broadcasts once the funding transaction finally appears on-chain.
1212+
///
1213+
/// Note: This tracks whether the funding transaction was ever broadcast, not whether it is
1214+
/// currently confirmed. It is never reset, even if the funding transaction is unconfirmed due
1215+
/// to a reorg.
1216+
funding_seen_onchain: bool,
1217+
12051218
latest_update_id: u64,
12061219
commitment_transaction_number_obscure_factor: u64,
12071220

@@ -1740,6 +1753,8 @@ pub(crate) fn write_chanmon_internal<Signer: EcdsaChannelSigner, W: Writer>(
17401753
(32, channel_monitor.pending_funding, optional_vec),
17411754
(33, channel_monitor.htlcs_resolved_to_user, required),
17421755
(34, channel_monitor.alternative_funding_confirmed, option),
1756+
(35, channel_monitor.is_manual_broadcast, required),
1757+
(37, channel_monitor.funding_seen_onchain, required),
17431758
});
17441759

17451760
Ok(())
@@ -1868,6 +1883,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
18681883
commitment_transaction_number_obscure_factor: u64,
18691884
initial_holder_commitment_tx: HolderCommitmentTransaction, best_block: BestBlock,
18701885
counterparty_node_id: PublicKey, channel_id: ChannelId,
1886+
is_manual_broadcast: bool,
18711887
) -> ChannelMonitor<Signer> {
18721888

18731889
assert!(commitment_transaction_number_obscure_factor <= (1 << 48));
@@ -1914,6 +1930,9 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
19141930
},
19151931
pending_funding: vec![],
19161932

1933+
is_manual_broadcast,
1934+
funding_seen_onchain: false,
1935+
19171936
latest_update_id: 0,
19181937
commitment_transaction_number_obscure_factor,
19191938

@@ -2327,19 +2346,33 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
23272346
/// close channel with their commitment transaction after a substantial amount of time. Best
23282347
/// may be to contact the other node operator out-of-band to coordinate other options available
23292348
/// to you.
2330-
#[rustfmt::skip]
2349+
///
2350+
/// Note: For channels using manual funding broadcast (see
2351+
/// [`crate::ln::channelmanager::ChannelManager::funding_transaction_generated_manual_broadcast`]),
2352+
/// automatic broadcasts are suppressed until the funding transaction has been observed on-chain.
2353+
/// Calling this method overrides that suppression and queues the latest holder commitment
2354+
/// transaction for broadcast even if the funding has not yet been seen on-chain. This may result
2355+
/// in unconfirmable transactions being broadcast or [`Event::BumpTransaction`] notifications for
2356+
/// transactions that cannot be confirmed until the funding transaction is visible.
2357+
///
2358+
/// [`Event::BumpTransaction`]: crate::events::Event::BumpTransaction
23312359
pub fn broadcast_latest_holder_commitment_txn<B: Deref, F: Deref, L: Deref>(
2332-
&self, broadcaster: &B, fee_estimator: &F, logger: &L
2333-
)
2334-
where
2360+
&self, broadcaster: &B, fee_estimator: &F, logger: &L,
2361+
) where
23352362
B::Target: BroadcasterInterface,
23362363
F::Target: FeeEstimator,
2337-
L::Target: Logger
2364+
L::Target: Logger,
23382365
{
23392366
let mut inner = self.inner.lock().unwrap();
23402367
let fee_estimator = LowerBoundedFeeEstimator::new(&**fee_estimator);
23412368
let logger = WithChannelMonitor::from_impl(logger, &*inner, None);
2342-
inner.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &fee_estimator, &logger);
2369+
2370+
inner.queue_latest_holder_commitment_txn_for_broadcast(
2371+
broadcaster,
2372+
&fee_estimator,
2373+
&logger,
2374+
false,
2375+
);
23432376
}
23442377

23452378
/// Unsafe test-only version of `broadcast_latest_holder_commitment_txn` used by our test framework
@@ -3952,12 +3985,26 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39523985
}
39533986
claimable_outpoints.append(&mut new_outpoints);
39543987
}
3955-
(claimable_outpoints, watch_outputs)
3988+
// In manual-broadcast mode, if we have not yet observed the funding transaction on-chain,
3989+
// return empty vectors.
3990+
if self.is_manual_broadcast && !self.funding_seen_onchain {
3991+
return (Vec::new(), Vec::new());
3992+
} else {
3993+
(claimable_outpoints, watch_outputs)
3994+
}
39563995
}
39573996

39583997
#[rustfmt::skip]
3998+
/// Note: For channels where the funding transaction is being manually managed (see
3999+
/// [`crate::ln::channelmanager::ChannelManager::funding_transaction_generated_manual_broadcast`]),
4000+
/// this method returns without queuing any transactions until the funding transaction has been
4001+
/// observed on-chain, unless `require_funding_seen` is `false`. This prevents attempting to
4002+
/// broadcast unconfirmable holder commitment transactions before the funding is visible.
4003+
/// See also [`ChannelMonitor::broadcast_latest_holder_commitment_txn`].
4004+
///
4005+
/// [`ChannelMonitor::broadcast_latest_holder_commitment_txn`]: crate::chain::channelmonitor::ChannelMonitor::broadcast_latest_holder_commitment_txn
39594006
pub(crate) fn queue_latest_holder_commitment_txn_for_broadcast<B: Deref, F: Deref, L: Deref>(
3960-
&mut self, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &WithChannelMonitor<L>
4007+
&mut self, broadcaster: &B, fee_estimator: &LowerBoundedFeeEstimator<F>, logger: &WithChannelMonitor<L>, require_funding_seen: bool,
39614008
)
39624009
where
39634010
B::Target: BroadcasterInterface,
@@ -3969,6 +4016,12 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
39694016
message: "ChannelMonitor-initiated commitment transaction broadcast".to_owned(),
39704017
};
39714018
let (claimable_outpoints, _) = self.generate_claimable_outpoints_and_watch_outputs(Some(reason));
4019+
// In manual-broadcast mode, if `require_funding_seen` is true and we have not yet observed
4020+
// the funding transaction on-chain, do not queue any transactions.
4021+
if require_funding_seen && self.is_manual_broadcast && !self.funding_seen_onchain {
4022+
log_info!(logger, "Not broadcasting holder commitment for manual-broadcast channel before funding appears on-chain");
4023+
return;
4024+
}
39724025
let conf_target = self.closure_conf_target();
39734026
self.onchain_tx_handler.update_claims_view_from_requests(
39744027
claimable_outpoints, self.best_block.height, self.best_block.height, broadcaster,
@@ -4291,7 +4344,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
42914344
log_trace!(logger, "Avoiding commitment broadcast, already detected confirmed spend onchain");
42924345
continue;
42934346
}
4294-
self.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &bounded_fee_estimator, logger);
4347+
self.queue_latest_holder_commitment_txn_for_broadcast(broadcaster, &bounded_fee_estimator, logger, true);
42954348
} else if !self.holder_tx_signed {
42964349
log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
42974350
log_error!(logger, " in channel monitor for channel {}!", &self.channel_id());
@@ -5310,7 +5363,21 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
53105363
F::Target: FeeEstimator,
53115364
L::Target: Logger,
53125365
{
5366+
let funding_seen_before = self.funding_seen_onchain;
53135367
let txn_matched = self.filter_block(txdata);
5368+
5369+
if !self.funding_seen_onchain {
5370+
for &(_, tx) in txdata.iter() {
5371+
let txid = tx.compute_txid();
5372+
if txid == self.funding.funding_txid() ||
5373+
self.pending_funding.iter().any(|f| f.funding_txid() == txid)
5374+
{
5375+
self.funding_seen_onchain = true;
5376+
break;
5377+
}
5378+
}
5379+
}
5380+
53145381
for tx in &txn_matched {
53155382
let mut output_val = Amount::ZERO;
53165383
for out in tx.output.iter() {
@@ -5331,6 +5398,11 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
53315398

53325399
let mut watch_outputs = Vec::new();
53335400
let mut claimable_outpoints = Vec::new();
5401+
5402+
if self.is_manual_broadcast && !funding_seen_before && self.funding_seen_onchain && self.holder_tx_signed
5403+
{
5404+
should_broadcast_commitment = true;
5405+
}
53345406
'tx_iter: for tx in &txn_matched {
53355407
let txid = tx.compute_txid();
53365408
log_trace!(logger, "Transaction {} confirmed in block {}", txid , block_hash);
@@ -5582,13 +5654,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
55825654
log_trace!(logger, "Processing {} matched transactions for block at height {}.", txn_matched.len(), conf_height);
55835655
debug_assert!(self.best_block.height >= conf_height);
55845656

5585-
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
5586-
if let Some(payment_hash) = should_broadcast {
5587-
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
5588-
let (mut new_outpoints, mut new_outputs) =
5589-
self.generate_claimable_outpoints_and_watch_outputs(Some(reason));
5590-
claimable_outpoints.append(&mut new_outpoints);
5591-
watch_outputs.append(&mut new_outputs);
5657+
// Only generate claims if we haven't already done so (e.g., in transactions_confirmed).
5658+
if claimable_outpoints.is_empty() {
5659+
let should_broadcast = self.should_broadcast_holder_commitment_txn(logger);
5660+
if let Some(payment_hash) = should_broadcast {
5661+
let reason = ClosureReason::HTLCsTimedOut { payment_hash: Some(payment_hash) };
5662+
let (mut new_outpoints, mut new_outputs) =
5663+
self.generate_claimable_outpoints_and_watch_outputs(Some(reason));
5664+
claimable_outpoints.append(&mut new_outpoints);
5665+
watch_outputs.append(&mut new_outputs);
5666+
}
55925667
}
55935668

55945669
// Find which on-chain events have reached their confirmation threshold.
@@ -5826,7 +5901,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
58265901
// Only attempt to broadcast the new commitment after the `block_disconnected` call above so that
58275902
// it doesn't get removed from the set of pending claims.
58285903
if should_broadcast_commitment {
5829-
self.queue_latest_holder_commitment_txn_for_broadcast(&broadcaster, &bounded_fee_estimator, logger);
5904+
self.queue_latest_holder_commitment_txn_for_broadcast(&broadcaster, &bounded_fee_estimator, logger, true);
58305905
}
58315906

58325907
self.best_block = fork_point;
@@ -5887,14 +5962,14 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
58875962
// Only attempt to broadcast the new commitment after the `transaction_unconfirmed` call above so
58885963
// that it doesn't get removed from the set of pending claims.
58895964
if should_broadcast_commitment {
5890-
self.queue_latest_holder_commitment_txn_for_broadcast(&broadcaster, fee_estimator, logger);
5965+
self.queue_latest_holder_commitment_txn_for_broadcast(&broadcaster, fee_estimator, logger, true);
58915966
}
58925967
}
58935968

58945969
/// Filters a block's `txdata` for transactions spending watched outputs or for any child
58955970
/// transactions thereof.
58965971
#[rustfmt::skip]
5897-
fn filter_block<'a>(&self, txdata: &TransactionData<'a>) -> Vec<&'a Transaction> {
5972+
fn filter_block<'a>(&mut self, txdata: &TransactionData<'a>) -> Vec<&'a Transaction> {
58985973
let mut matched_txn = new_hash_set();
58995974
txdata.iter().filter(|&&(_, tx)| {
59005975
let mut matches = self.spends_watched_output(tx);
@@ -6560,6 +6635,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
65606635
let mut channel_parameters = None;
65616636
let mut pending_funding = None;
65626637
let mut alternative_funding_confirmed = None;
6638+
let mut is_manual_broadcast = RequiredWrapper(None);
6639+
let mut funding_seen_onchain = RequiredWrapper(None);
65636640
read_tlv_fields!(reader, {
65646641
(1, funding_spend_confirmed, option),
65656642
(3, htlcs_resolved_on_chain, optional_vec),
@@ -6580,6 +6657,8 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
65806657
(32, pending_funding, optional_vec),
65816658
(33, htlcs_resolved_to_user, option),
65826659
(34, alternative_funding_confirmed, option),
6660+
(35, is_manual_broadcast, (default_value, false)),
6661+
(37, funding_seen_onchain, (default_value, true)),
65836662
});
65846663
// Note that `payment_preimages_with_info` was added (and is always written) in LDK 0.1, so
65856664
// we can use it to determine if this monitor was last written by LDK 0.1 or later.
@@ -6693,6 +6772,10 @@ impl<'a, 'b, ES: EntropySource, SP: SignerProvider> ReadableArgs<(&'a ES, &'b SP
66936772
prev_holder_commitment_tx,
66946773
},
66956774
pending_funding: pending_funding.unwrap_or(vec![]),
6775+
is_manual_broadcast: is_manual_broadcast.0.unwrap(),
6776+
// Older monitors prior to LDK 0.2 assume this is `true` when absent
6777+
// during upgrade so holder broadcasts aren't gated unexpectedly.
6778+
funding_seen_onchain: funding_seen_onchain.0.unwrap(),
66966779

66976780
latest_update_id,
66986781
commitment_transaction_number_obscure_factor,
@@ -7029,7 +7112,7 @@ mod tests {
70297112
let monitor = ChannelMonitor::new(
70307113
Secp256k1::new(), keys, Some(shutdown_script.into_inner()), 0, &ScriptBuf::new(),
70317114
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, funding_outpoint, Vec::new()),
7032-
best_block, dummy_key, channel_id,
7115+
best_block, dummy_key, channel_id, false,
70337116
);
70347117

70357118
let nondust_htlcs = preimages_slice_to_htlcs!(preimages[0..10]);
@@ -7290,7 +7373,7 @@ mod tests {
72907373
let monitor = ChannelMonitor::new(
72917374
Secp256k1::new(), keys, Some(shutdown_script.into_inner()), 0, &ScriptBuf::new(),
72927375
&channel_parameters, true, 0, HolderCommitmentTransaction::dummy(0, funding_outpoint, Vec::new()),
7293-
best_block, dummy_key, channel_id,
7376+
best_block, dummy_key, channel_id, false,
72947377
);
72957378

72967379
let chan_id = monitor.inner.lock().unwrap().channel_id();

lightning/src/ln/channel.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3196,6 +3196,7 @@ where
31963196
funding.get_holder_selected_contest_delay(), &context.destination_script,
31973197
&funding.channel_transaction_parameters, funding.is_outbound(), obscure_factor,
31983198
holder_commitment_tx, best_block, context.counterparty_node_id, context.channel_id(),
3199+
context.is_manual_broadcast,
31993200
);
32003201
channel_monitor.provide_initial_counterparty_commitment_tx(
32013202
counterparty_initial_commitment_tx.clone(),

lightning/src/ln/functional_test_utils.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1804,6 +1804,66 @@ pub fn create_chan_between_nodes_with_value_a<'a, 'b, 'c: 'd, 'd>(
18041804
(msgs, chan_id, tx)
18051805
}
18061806

1807+
pub fn create_channel_manual_funding<'a, 'b, 'c: 'd, 'd>(
1808+
nodes: &'a Vec<Node<'b, 'c, 'd>>, initiator: usize, counterparty: usize, channel_value: u64,
1809+
push_msat: u64,
1810+
) -> (ChannelId, Transaction, OutPoint) {
1811+
let node_a = &nodes[initiator];
1812+
let node_b = &nodes[counterparty];
1813+
let node_a_id = node_a.node.get_our_node_id();
1814+
let node_b_id = node_b.node.get_our_node_id();
1815+
1816+
let temp_channel_id = exchange_open_accept_chan(node_a, node_b, channel_value, push_msat);
1817+
1818+
let (funding_temp_id, funding_tx, funding_outpoint) =
1819+
create_funding_transaction(node_a, &node_b_id, channel_value, 42);
1820+
assert_eq!(temp_channel_id, funding_temp_id);
1821+
1822+
node_a
1823+
.node
1824+
.funding_transaction_generated_manual_broadcast(
1825+
funding_temp_id,
1826+
node_b_id,
1827+
funding_tx.clone(),
1828+
)
1829+
.unwrap();
1830+
check_added_monitors!(node_a, 0);
1831+
1832+
let funding_created = get_event_msg!(node_a, MessageSendEvent::SendFundingCreated, node_b_id);
1833+
node_b.node.handle_funding_created(node_a_id, &funding_created);
1834+
check_added_monitors!(node_b, 1);
1835+
let channel_id_b = expect_channel_pending_event(node_b, &node_a_id);
1836+
1837+
let funding_signed = get_event_msg!(node_b, MessageSendEvent::SendFundingSigned, node_a_id);
1838+
node_a.node.handle_funding_signed(node_b_id, &funding_signed);
1839+
check_added_monitors!(node_a, 1);
1840+
1841+
let events = node_a.node.get_and_clear_pending_events();
1842+
assert_eq!(events.len(), 2);
1843+
let funding_txid = funding_tx.compute_txid();
1844+
let mut channel_id = None;
1845+
for event in events {
1846+
match event {
1847+
Event::FundingTxBroadcastSafe { funding_txo, counterparty_node_id, .. } => {
1848+
assert_eq!(counterparty_node_id, node_b_id);
1849+
assert_eq!(funding_txo.txid, funding_txid);
1850+
assert_eq!(funding_txo.vout, u32::from(funding_outpoint.index));
1851+
},
1852+
Event::ChannelPending { channel_id: pending_id, counterparty_node_id, .. } => {
1853+
assert_eq!(counterparty_node_id, node_b_id);
1854+
channel_id = Some(pending_id);
1855+
},
1856+
_ => panic!("Unexpected event"),
1857+
}
1858+
}
1859+
let channel_id = channel_id.expect("channel pending event missing");
1860+
assert_eq!(channel_id, channel_id_b);
1861+
1862+
assert!(node_a.tx_broadcaster.txn_broadcasted.lock().unwrap().is_empty());
1863+
1864+
(channel_id, funding_tx, funding_outpoint)
1865+
}
1866+
18071867
pub fn create_chan_between_nodes_with_value_b<'a, 'b, 'c>(
18081868
node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>,
18091869
as_funding_msgs: &(msgs::ChannelReady, msgs::AnnouncementSignatures),

0 commit comments

Comments
 (0)