Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Refactor `BroadcasterInterface` to include `TransactionType` by tnull · Pull Request #4353 · lightningdevkit/rust-lightning · GitHub
Skip to content

Refactor BroadcasterInterface to include TransactionType - #4353

Merged
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor
Feb 5, 2026
Merged

Refactor BroadcasterInterface to include TransactionType#4353
TheBlueMatt merged 3 commits into
lightningdevkit:mainfrom
tnull:2026-01-broadcast-type-refactor

Conversation

@tnull

@tnulltnull commented Jan 27, 2026

Copy link
Copy Markdown
Contributor

Fixes#3566.

Add a `BroadcastType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `BroadcastType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A transaction for force-close
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000

and:

We add the `ChannelId` as context to the just-added `BroadcastType`
enum.
Co-Authored-By: HAL 9000

@ldk-reviews-bot

ldk-reviews-bot commented Jan 27, 2026

Copy link
Copy Markdown

👋 Thanks for assigning @TheBlueMatt as a reviewer!
I'll wait for their review and will help manage the review process.
Once they submit their review, I'll check if a second reviewer would be helpful.

Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 4f6a8a4 to be02cecCompareJanuary 27, 2026 13:24

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs need a lot of love

/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,
},
/// A cooperative close transaction mutually agreed upon by both parties.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean all transactions are mutually agreed upon by both parties? Maybe describe what a coop close tx means

@tnulltnullJan 27, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, changed it up a bit, but let me know what exactly is missing for you.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from be02cec to 4f6a8a4CompareJanuary 27, 2026 13:30
Comment threadlightning/src/chain/onchaintx.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 4f6a8a4 to fb8378cCompareJanuary 27, 2026 13:53
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from fb8378c to 54b52f3CompareJanuary 27, 2026 14:05
@codecov

codecovBot commented Jan 27, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.09091% with 28 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.99%. Comparing base (8679d8d) to head (0715f4a).
⚠️ Report is 39 commits behind head on main.

Files with missing linesPatch %Lines
lightning/src/util/sweep.rs79.59%6 Missing and 4 partials ⚠️
lightning/src/ln/channelmanager.rs72.72%8 Missing and 1 partial ⚠️
lightning/src/ln/channel.rs46.15%6 Missing and 1 partial ⚠️
lightning-liquidity/src/lsps2/service.rs85.71%0 Missing and 1 partial ⚠️
lightning/src/chain/onchaintx.rs94.11%0 Missing and 1 partial ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #4353 +/- ##
==========================================
+ Coverage 85.98% 85.99% +0.01% 
==========================================
Files 156 156 Lines 102641 102734 +93 Branches 102641 102734 +93 ==========================================
+ Hits 88258 88349 +91 - Misses 11873 11875 +2 
Partials 2510 2510 
FlagCoverage Δ
tests85.99% <84.09%> (+0.01%)⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
pub enum BroadcastType {
/// A funding transaction establishing a new channel.
Funding,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Splice transactions should have their own variant, no?

@tnulltnullJan 28, 2026

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, hence the question above regarding which variants we want. So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, post #4261 we'll now three variants (SpliceIn/SpliceOut/SpliceInAndOut)?

If we want more splicing context we should include the splice metadata in the splice variant rather than having a separate variant for each splice init logic. This feels like a followup though.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To clarify a bit - the differentiation between "splice out" and "splice in" at the top-level API is a bug that we're fixing - there is only a "splice" which can have constituent parts that are in + out. Its a useful differentiation when building splicing instructions but after that it should dissapear.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And AFAICT we need to track the TransactionType across the entire flow (i.e., inititally set in SpliceContribution, track in SpliceInstructions, PendingFunding, and then return via FundingTxSigned to hand it to broadcast_interactive_funding? Or do you see a way to shortcut or re-derive the type of splice contribution at the last step somehow?

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw transaction is already available since we're broadcasting it so they can inspect its inputs and outputs if they want to distinguish between splice in/out.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, but for the user it still makes a fundamental difference, no? So in the actual API we still want to discern in/out, right?

Sure at the constructor level we have utilities that allow you to only do one, but the right API definitely isn't a tri-state where the third state is "both". Rather, where we want to expose it it should be a "does this splice have inputs from me" and "does this splice have outputs I added" methods.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this also work going forward with dual funding, given that then we might reuse the same broadcast_interactive_funding path? Or would we get wrong classifications then, if we don't track the 'intent' from the beginning?

Dual-funding should keep the Funding type and we can just return that along with the transaction since the ChannelManager doesn't have enough context to determine the correct one.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed offline: for now, just add a Splice variant. While we want to add more context (in/out etc) to the Splice variant soon, for now we just need to return and hand through the TransactionType together with the Transaction from its origin.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now updated accordingly.

Comment threadlightning/src/chain/chaininterface.rs
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 54b52f3 to 5912fd4CompareJanuary 28, 2026 10:09
@tnull

Copy link
Copy Markdown
ContributorAuthor

FWIW, I also now pushed a fixup renaming to TransactionType which seemed like a slightly better naming, let me know if you object.

@tnulltnull self-assigned this Jan 28, 2026
@tnulltnull changed the title Refactor BroadcasterInterface to include BroadcastTypeRefactor BroadcasterInterface to include TransactionTypeJan 28, 2026
@tnulltnull moved this to Goal: Merge in Weekly GoalsJan 28, 2026
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from a499b27 to 06377a0CompareJanuary 30, 2026 13:40
@wpaulino

Copy link
Copy Markdown
Contributor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch 2 times, most recently from 9ab7f14 to 302599dCompareFebruary 2, 2026 14:42
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

This needs a rebase now, feel free to squash. There's one pending comment from Matt left that still needs to be addressed.

Rebased and also added a commit that adds some test coverage for the TransactionType::Splice case.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

few comments on the docs, otherwise feel free to squash.

Comment threadlightning/src/chain/chaininterface.rs Outdated
Comment threadlightning/src/chain/chaininterface.rs Outdated
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 302599d to 5c5d180CompareFebruary 2, 2026 17:22
@tnull

tnull commented Feb 2, 2026

Copy link
Copy Markdown
ContributorAuthor

few comments on the docs, otherwise feel free to squash.

Squashed with the following changes:

diff --git a/lightning/src/chain/chaininterface.rs b/lightning/src/chain/chaininterface.rs
index cbac84aaf..90f4aa13e 100644
--- a/lightning/src/chain/chaininterface.rs+++ b/lightning/src/chain/chaininterface.rs@@ -41,5 +41,6 @@ pub enum TransactionType {
/// A transaction cooperatively closing a channel.
///
-	/// A transaction of this type will be broadcast when cooperatively closing a channel via [`ChannelManager::close_channel`].+	/// A transaction of this type will be broadcast when cooperatively closing a channel via+	/// [`ChannelManager::close_channel`] or if the counterparty closes the channel.
///
/// [`ChannelManager::close_channel`]: crate::ln::channelmanager::ChannelManager::close_channel
@@ -50,5 +51,7 @@ pub enum TransactionType {
/// A transaction being broadcast to force-close the channel.
///
-	/// A transaction of this type will be broadcast when unilaterally closing a channel via [`ChannelManager::force_close_broadcasting_latest_txn`].+	/// A transaction of this type will be broadcast when unilaterally closing a channel via+	/// [`ChannelManager::force_close_broadcasting_latest_txn`] or if the counterparty force-closes+	/// the channel..
///
/// [`ChannelManager::force_close_broadcasting_latest_txn`]: crate::ln::channelmanager::ChannelManager::force_close_broadcasting_latest_txn
@@ -67,5 +70,15 @@ pub enum TransactionType {
channel_id: ChannelId,
},
-	/// A transaction claiming outputs from a commitment transaction (HTLC claims, penalty/justice).+	/// A transaction which is resolving an output spendable by both us and our counterparty.+	///+	/// When a channel closes via the unilateral close path, there may be transaction outputs which+	/// are spendable by either our counterparty or us and represent some lightning state. In order+	/// to resolve that state, the [`ChannelMonitor`] will spend any such outputs, ensuring funds+	/// are only available to us prior to generating an [`Event::SpendableOutputs`]. This+	/// transaction is one such transaction - resolving in-flight HTLCs or punishing our+	/// counterparty if they broadcasted an outdated state.+	///+	/// [`ChannelMonitor`]: crate::chain::ChannelMonitor+	/// [`Event::SpendableOutputs`]: crate::events::Event::SpendableOutputs
Claim {
/// The ID of the channel from which outputs are being claimed.

Add a `TransactionType` enum to provide context about the type of
transaction being broadcast. This information can be useful for
logging, filtering, or prioritization purposes.
The `TransactionType` variants are:
- `Funding`: A funding transaction establishing a new channel
- `CooperativeClose`: A cooperative close transaction
- `UnilateralClose`: A force-close transaction
- `AnchorBump`: An anchor transaction for CPFP fee-bumping
- `Claim`: A transaction claiming outputs from commitment tx
- `Sweep`: A transaction sweeping spendable outputs to wallet
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Add parallel `txn_types` vector to `TestBroadcaster` to track
`TransactionType` alongside broadcast transactions. Existing
`txn_broadcast()` API remains unchanged for backward compatibility.
New `txn_broadcast_with_types()` API allows tests to verify transaction
types.
Also add a `clear()` helper method and update test files to use it
instead of directly manipulating `txn_broadcasted`, ensuring the two
vectors stay in sync.
Update splice tests to use the new API and verify that splice
transactions are broadcast with the correct `TransactionType`.
Co-Authored-By: HAL 9000
Signed-off-by: Elias Rohrer <dev@tnull.de>
Co-Authored-By: HAL 9000
@tnull
tnullforce-pushed the 2026-01-broadcast-type-refactor branch from 5c5d180 to 0715f4aCompareFebruary 2, 2026 17:24
@ldk-reviews-bot

Copy link
Copy Markdown

🔔 1st Reminder

Hey @TheBlueMatt@wpaulino! This PR has been waiting for your review.
Please take a look when you have a chance. If you're unable to review, please let us know so we can find another reviewer.

@TheBlueMattTheBlueMatt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gonna just land this so the bulk of the code is out of the way, but we really need counterparty node ids if we're gonna use channel ids.

/// The IDs of the channels being funded.
///
/// A single funding transaction may establish multiple channels when using batch funding.
channel_ids: Vec<ChannelId>,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oops, note that because we're still not living in a funding-v2-required world ChannelIds aren't the right unique indicator of a specific channel. We need the counterparty node id as well. We should also (obviously) provide the user_channel_id here.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, good point regarding the counterparty_node_id, though it seems we then first need it to add to a few other places. For example, we don't track it in the SpendableOutputs event (only channel_id) and therefore we also don't track it in OutputSweeper.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in #4393

@TheBlueMatt
TheBlueMatt merged commit bbb5ed5 into lightningdevkit:mainFeb 5, 2026
19 of 21 checks passed
@github-project-automationgithub-project-automationBot moved this from Goal: Merge to Done in Weekly GoalsFeb 5, 2026
@jkczyzjkczyz mentioned this pull request Mar 19, 2026
50 tasks
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

Add APIs to classify channel-related transaction types

4 participants

@tnull@ldk-reviews-bot@wpaulino@TheBlueMatt