Immediately archive ChannelMonitors for inbound unfuned channels#4081
Merged
wpaulino merged 1 commit intolightningdevkit:mainfrom Sep 18, 2025
Merged
Conversation
|
👋 I see @tankyleo was un-assigned. |
Collaborator
Author
|
Tagged this "backport 0.1" cause it seems like an important bugfix, but I'm open to feedback from reviewers on that. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4081 +/- ##
==========================================
+ Coverage 88.33% 88.60% +0.26%
==========================================
Files 177 176 -1
Lines 131896 132097 +201
Branches 131896 132097 +201
==========================================
+ Hits 116512 117045 +533
+ Misses 12728 12387 -341
- Partials 2656 2665 +9
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
tnull
reviewed
Sep 18, 2025
d0018e3 to
f7d3296
Compare
Collaborator
Author
$ git diff-tree -U3 278aaa1fc 744664e88
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index 0237e653db..c17cd87d49 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -2571,12 +2571,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
let current_height = self.current_best_block().height;
let mut inner = self.inner.lock().unwrap();
- let mut commitment_not_advanced =
- inner.current_counterparty_commitment_number == INITIAL_COMMITMENT_NUMBER;
- commitment_not_advanced &=
- inner.current_holder_commitment_number == INITIAL_COMMITMENT_NUMBER;
- if (inner.holder_tx_signed || inner.lockdown_from_offchain)
- && commitment_not_advanced
+ if inner.is_closed_without_updates()
&& is_all_funds_claimed
&& !inner.funding_spend_seen
{
@@ -3079,12 +3074,7 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitor<Signer> {
// Avoiding including a `Balance` if none of these are true allows us to prune monitors
// for chanels that were opened inbound to us but where the funding transaction never
// confirmed at all.
- let mut commitment_not_advanced =
- us.current_counterparty_commitment_number == INITIAL_COMMITMENT_NUMBER;
- commitment_not_advanced &=
- us.current_holder_commitment_number == INITIAL_COMMITMENT_NUMBER;
- if (!us.holder_tx_signed && !us.lockdown_from_offchain)
- || !commitment_not_advanced
+ if !us.is_closed_without_updates()
|| balance_candidates.iter().any(|bal| bal.amount_satoshis != 0)
{
res.push(Balance::ClaimableOnChannelClose {
@@ -4383,6 +4373,16 @@ impl<Signer: EcdsaChannelSigner> ChannelMonitorImpl<Signer> {
} else { ret }
}
+ /// Returns true if the channel has been closed (i.e. no further updates are allowed) and no
+ /// commitment state updates ever happened.
+ fn is_closed_without_updates(&self) -> bool {
+ let mut commitment_not_advanced =
+ self.current_counterparty_commitment_number == INITIAL_COMMITMENT_NUMBER;
+ commitment_not_advanced &=
+ self.current_holder_commitment_number == INITIAL_COMMITMENT_NUMBER;
+ (self.holder_tx_signed || self.lockdown_from_offchain) && commitment_not_advanced
+ }
+
fn no_further_updates_allowed(&self) -> bool {
self.funding_spend_seen || self.lockdown_from_offchain || self.holder_tx_signed
}
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 46ff741a54..bc089d495b 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -6635,6 +6635,10 @@ pub fn test_channel_conf_timeout() {
let funding_tx =
create_chan_between_nodes_with_value_init(&nodes[0], &nodes[1], 1_000_000, 100_000);
+ // Inbound channels which haven't advanced state at all and never were funded will generate
+ // claimable `Balance`s until they're closed.
+ assert!(!nodes[1].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty());
+
// The outbound node should wait forever for confirmation:
// This matches `channel::FUNDING_CONF_DEADLINE_BLOCKS` and BOLT 2's suggested timeout, thus is
// copied here instead of directly referencing the constant.
@@ -6648,6 +6652,7 @@ pub fn test_channel_conf_timeout() {
nodes[1].chain_monitor.chain_monitor.archive_fully_resolved_channel_monitors();
assert_eq!(nodes[1].chain_monitor.chain_monitor.list_monitors().len(), 1);
+ assert!(!nodes[1].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty());
connect_blocks(&nodes[1], 1);
check_added_monitors(&nodes[1], 1);
@@ -6668,9 +6673,14 @@ pub fn test_channel_conf_timeout() {
_ => panic!("Unexpected event"),
}
+ // Once an inbound never-confirmed channel is closed, it will no longer generate any claimable
+ // `Balance`s.
+ assert!(nodes[1].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty());
+
// Once the funding times out the monitor should be immediately archived.
nodes[1].chain_monitor.chain_monitor.archive_fully_resolved_channel_monitors();
assert_eq!(nodes[1].chain_monitor.chain_monitor.list_monitors().len(), 0);
+ assert!(nodes[1].chain_monitor.chain_monitor.get_claimable_balances(&[]).is_empty());
// Remove the corresponding outputs and transactions the chain source is
// watching. This is to make sure the `Drop` function assertions pass. |
tnull
previously approved these changes
Sep 18, 2025
If a peer opens a channel to us, but never actually broadcasts the funding transaction, we'll still keep a `ChannelMonitor` around for the channel. While we maybe shouldn't do this either, when the channel ultimately times out 2016 blocks later, we should at least immediately archive the `ChannelMonitor`, which we do here. Fixes lightningdevkit#3384
f7d3296 to
744664e
Compare
Collaborator
Author
|
Oops sorry test was wrong. |
wpaulino
approved these changes
Sep 18, 2025
Collaborator
Author
|
Backported in #4143 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
If a peer opens a channel to us, but never actually broadcasts the funding transaction, we'll still keep a
ChannelMonitoraround for the channel. While we maybe shouldn't do this either, when the channel ultimately times out 2016 blocks later, we should at least immediately archive theChannelMonitor, which we do here.Fixes #3384