Skip to content

Conversation

@t-bast
Copy link
Collaborator

@t-bast t-bast commented Feb 14, 2025

We introduce a new channel_type that leverages v3 (TRUC) transactions, pay-to-anchor outputs and ephemeral dust. With this change, commitment transactions don't pay any mining fee (in most cases), which gets rid of update_fee and all of the related channel reserve issues. It also gets rid of the undesired channel force-closes that happen when the mempool feerate spikes and channel participants disagree on what feerate to use, which has been a major source of wasted on-chain space.

It also offers better protection against pinning attacks (thanks to package relay) and reduces the on-chain footprint compared to anchor output channels.

We use a single anchor output whose amount is the sum of all trimmed outputs (outputs below the dust_limit, which are thus not included in the commitment transaction) and all millisatoshi amounts that have been rounded down to satoshis, capped at 240 sats (and may thus be 0 sat when there are no trimmed outputs or rounded down millisatoshi amounts). Note that when the sum of trimmed outputs and millisatoshi rounding exceeds 240 sats, the commitment transaction won't by 0-fees anymore: but the fees aren't deduced from any of the commitment transaction's outputs.

This anchor output is unkeyed: it simply uses the standard P2A output introduced in bitcoin/bitcoin#30352.

We remove the 1-block relative delay used by anchor output channels: this allows using our channel outputs (main balance or pending HTLCs) to CPFP a remote commitment transaction (no need to add external inputs, which simplifies wallet management and liquidity requirements).

Note that v3 transactions and pay-to-anchor outputs have been standard since the release of Bitcoin Core v28.0. Ephemeral dust has become standard in the Bitcoin Core v29.0 release. All of this is thus ready to use on the network now!

@saubyk
Copy link

saubyk commented Feb 17, 2025

We use a single anchor output whose amount is the sum of all trimmed outputs (and may thus be 0 sat).

Hi @t-bast can you elaborate this a bit?

@saubyk
Copy link

saubyk commented Feb 17, 2025

We use a single anchor output whose amount is the sum of all trimmed outputs (and may thus be 0 sat).

Hi @t-bast can you elaborate this a bit?

Never mind. This delving post has the details, makes for a good supplemental reading:
https://delvingbitcoin.org/t/which-ephemeral-anchor-script-should-lightning-use/1412

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 19, 2025

Hi @t-bast can you elaborate this a bit?

This will become more obvious when I add the test vectors! It is also already defined in Bolt 3, if the paragraph for this is unclear please put a comment on it with a suggestion on how I could make it clearer.

Copy link
Contributor

@morehouse morehouse left a comment

Choose a reason for hiding this comment

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

Approach ACK.

Really eager to see this get implemented and used across the network. Also hope we can follow up soon with the changes needed to fix HTLC pinning.

Copy link
Collaborator

@TheBlueMatt TheBlueMatt left a comment

Choose a reason for hiding this comment

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

This was actually a good bit easier to implement than I thought.

@tnull
Copy link
Contributor

tnull commented May 6, 2025

Just want to node that it was discussed in yesterday's spec call that as part of this work we'll probably also want to make option_simple_close transactions (optionally) v3, i.e., require v3 close transactions for v3 channels.

@Roasbeef
Copy link
Collaborator

Roasbeef commented May 7, 2025

Just want to node that it was discussed in yesterday's spec call that as part of this work we'll probably also want to make option_simple_close transactions (optionally) v3, i.e., require v3 close transactions for v3 channels.

Compared to the HTLC case, are there any pinning concerns when it comes to coop close? The channel is no longer active, and the only outputs on the coop close transaction send funds directly to either party.

I point this out as the TRUC constraints are passed on to all unconfirmed children:

Any TRUC transaction's unconfirmed ancestors must all be TRUC

As a result, if the coop close transaction is v3, then a user wouldn't be able to CPFP with a non-v3 transaction to bump the fee (imagine the peer is just no longer offline). Another scenario that would be prevented is a non-v3 aware wallet spending that unconfirmed change to create a normal transaction, or fund a new channel.

@t-bast
Copy link
Collaborator Author

t-bast commented May 12, 2025

Compared to the HTLC case, are there any pinning concerns when it comes to coop close?

I don't think there are any, once we start using v3 for the commit tx and mutual close tx, the mutual close tx should be protected against pinning.

@sble
Copy link

sble commented Oct 21, 2025

When do you expect zero-fee commitments to be released out?

And, which ephemeral anchor options are likely to be implemented? (https://delvingbitcoin.org/t/which-ephemeral-anchor-script-should-lightning-use/1412?utm_source=chatgpt.com)

@t-bast t-bast force-pushed the zero-fee-commitments branch from c3e6be1 to 6a832c5 Compare October 23, 2025 15:54
@t-bast
Copy link
Collaborator Author

t-bast commented Oct 23, 2025

I have rebased to fix the merge conflicts, and squashed into a single commit. I have also:

  • changed the explanation of the 240 sats cap in Bolt 3
  • added a warning in Bolt 5 about batching HTLCs transactions and the 10kvB limit

I'm working on adding a set of Bolt 3 test vectors.

@t-bast t-bast marked this pull request as ready for review October 23, 2025 15:57
@t-bast
Copy link
Collaborator Author

t-bast commented Oct 23, 2025

When do you expect zero-fee commitments to be released out?

We cannot provide any estimate on timing.

And, which ephemeral anchor options are likely to be implemented? (https://delvingbitcoin.org/t/which-ephemeral-anchor-script-should-lightning-use/1412?utm_source=chatgpt.com)

This is explained in this PR, and in the description. We use the unkeyed version.

t-bast added a commit to ACINQ/eclair that referenced this pull request Oct 24, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.
t-bast added a commit to ACINQ/eclair that referenced this pull request Oct 27, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.
t-bast added a commit to ACINQ/eclair that referenced this pull request Oct 27, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.

In this commit, we simply introduce the commitment format and create
the corresponding transactions.
@t-bast
Copy link
Collaborator Author

t-bast commented Oct 28, 2025

@carlaKC I've addressed the remaining comments, rebased and added test vectors for transaction construction (in 9fa506e), let me know if they work for you and if I should clarify the different fields of the test vector to help implementations use them.

Once those test vectors are validated, we can move forward with cross-compat tests between LDK and eclair 🚀

t-bast added a commit to ACINQ/eclair that referenced this pull request Nov 3, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.

In this commit, we simply introduce the commitment format and create
the corresponding transactions.
t-bast added a commit to ACINQ/eclair that referenced this pull request Nov 10, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.

In this commit, we simply introduce the commitment format and create
the corresponding transactions.
t-bast added a commit to ACINQ/eclair that referenced this pull request Nov 12, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.

In this commit, we simply introduce the commitment format and create
the corresponding transactions.
@t-bast
Copy link
Collaborator Author

t-bast commented Nov 18, 2025

@carlaKC @tankyleo I've tested cross-compatibility between eclair (ACINQ/eclair#3192) and LDK (lightningdevkit/ldk-server#75) and everything is working like a charm:

  • I'm able to open and close v3 channels
  • I'm able to make payments in both directions
  • Dust is correctly allocated to the anchor output, until it reaches 240 sat

That was simpler than I thought, good job!

I've added a test vector in ACINQ/eclair@8b2e2e3, because I actually had a bug in eclair, where I was incorrectly using a Set for HTLCs and thus ignoring dust HTLCs that have the same amount. I thought it could be useful to others as well (even though LDK already handles this correctly).

@tankyleo mentioned during the spec meeting that propagation of v3 force-close isn't satisfying yet, so this may not be ready to use safely on mainnet, but it looks like code and spec are ready to go 🚀 ⚡ 🔥

Copy link
Contributor

@carlaKC carlaKC left a comment

Choose a reason for hiding this comment

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

everything is working like a charm

🔥

LGTM! Last test vector passes in LDK, just some nits and a request for a general "beware V3 gremlins" warning 🙏

t-bast added a commit to ACINQ/eclair that referenced this pull request Nov 19, 2025
We add support for the zero-fee commitment format specified in
lightning/bolts#1228.

Channels using this commitment format benefit from better protection
against pinning attacks (thanks to TRUC/v3 transactions), don't need
the `update_fee` mechanism, have less dust exposure risk, and use an
overall simpler state machine.

In this commit, we simply introduce the commitment format and create
the corresponding transactions.
We introduce a new `channel_type` that leverages v3 transactions,
pay-to-anchor outputs and ephemeral dust. With this change, commitment
transactions don't pay any mining fee, which gets rid of `update_fee`
and all of the related channel reserve issues. It also gets rid of the
undesired channel force-closes that happen when the mempool feerate
spikes and channel participants disagree on what feerate to use, which
has been a major source of wasted on-chain space.

It also offers better protection against pinning attacks and reduces the
on-chain footprint compared to anchor output channels. We use a single
anchor output whose amount is the sum of all trimmed outputs and rounded
down millisatoshi amounts (and may thus be `0 sat`), capped at 240 sats.
When the sum of trimmed outputs and rounded down millisatoshi amounts
exceeds 240 sats, the remaining amount directly goes to on-chain fees
(and in that case, the commitment transactions does pay some on-chain
fees on its own). We do this to ensure that only miners can collect
the excess from trimmed outputs, while respecting standardness rules.

We remove the 1-block relative delay used by anchor output channels,
because we don't need the CPFP carve-out rule when using v3 txs. This
allows using our channel outputs (main balance or pending HTLCs) to
CPFP a remote commitment transaction (no need to add external wallet
inputs, which greatly simplifies liquidity management).

v3 transactions and pay-to-anchor outputs have been standard since the
release of Bitcoin Core v28.0. Ephemeral dust has been standard since
the Bitcoin Core v29.0 release.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This is still the case, why remove this section?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I can't see which section you're referring to here, github doesn't link that comment to any code change...

Before the commitment transaction outputs are determined:
- the base fee MUST be subtracted from the `to_local` or `to_remote` output,
as specified in [Fee Calculation](#fee-calculation).
- if `option_anchors` applies:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should this actually be zero_fee_commitments? Don't understand this portion of the diff.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, this isn't for zero_fee_commitments, this is for existing anchor output channels. The spec here was missing this part, which was in other sections but should have been in this one as well. The introduction of the shared anchor forced me to "refactor" a bit this file to properly distinguish the shared anchor case from the local/remote anchor case.

- MUST be generated as specified in [`to_local` Output](#to_local-output).
- if the amount of the commitment transaction `to_remote` output would be
less than `dust_limit_satoshis` set by the transaction owner:
less than `dust_limit_satoshis` set by the transaction owner:
Copy link
Collaborator

Choose a reason for hiding this comment

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

White space/format changes like this littered all over the PR adds noise, and makes the diff as a whole harder to review.

I sincerely hope that this is the last PR written in the style of an ever expanding document which specifies All Things. The extension BOLT format is a superior way to make spec changes, as the documents are self contained, carrying nearly all the context needed for review.

- If `zero_fee_commitments` applies:
- MUST NOT exceed the 10kvB limit of v3 transactions, otherwise the
transaction may not reach miners (as explained in the section
about [v3 limitations](#limitations-of-v3-transactions) below).
Copy link
Collaborator

Choose a reason for hiding this comment

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

IIUC, this doesn't apply if the transaction has already been confirmed before a sweep is attempted. AFAIK, we all currently wait for confirmation before attempting to sweep a channel's output.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I'm not sure I understand your comment here. HTLC transactions are using v3, so if you batch a bunch of HTLC transactions together (using the fact that their input uses SIGHASH_SINGLE | SIGHASH_ANYONECANPAY), the resulting transaction is a batched HTLC transaction that is using v3. So regardless of whether the commitment transaction is confirmed or not, the batched HTLC transaction cannot exceed 10kvB. Does that make sense?

A node which broadcasts an HTLC-success or HTLC-timeout transaction for a
commitment transaction:
- if `option_anchors` applies:
- if `SIGHASH_SINGLE|SIGHASH_ANYONECANPAY` is used:
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be more precise to just enumerate the channel types here so option_anchors and zero_fee_commitments. Or in the glossary make a new entry for anchor_channels or something like that, and ref as necessary.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I disagree, I think it makes more sense to state the condition that makes adding another input possible (it's only possible because of those sighash flags on the input). Also, it's more future-proof because as we add more channel types that also use SIGHASH_SINGLE | SIGHASH_ANYONECANPAY, we don't have to edit all the places where we list channel types, the requirements are automatically inherited by the fact that we specify what should happen for SIGHASH_SINGLE | SIGHASH_ANYONECANPAY inputs.

- Note: watching for mempool transactions should result in lower latency
HTLC redemptions.

## Limitations of v3 transactions
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's say a user has a zero conf channel, the funding transaction is currently unconfirmed and a v3 transaction. Are they able to do a coop close with a v2 transaction, or will the bitcoind logic reject that as its considered an ancestor of the funding transaction?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

It will be rejected since its parent transaction is an unconfirmed v3 transaction. That's one of the reasons we use "high" feerates for 0-conf transactions in Phoenix, especially when there are no change outputs available to CPFP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.