Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

blip-0033: commit fees channel flag #33

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

t-bast
Copy link
Contributor

@t-bast t-bast commented Jul 2, 2024

Standard lightning channels require the channel opener to pay the mining fees for the commitment transaction and mutual close transaction. This requirement forces the channel opener to contribute to the funding transaction and makes it impossible to open channels by only purchasing inbound liquidity from a remote node.

We want to allow nodes to opt into paying the commitment transaction fees even though they're not the channel opener.

@t-bast t-bast changed the title blip-00xx: commit fees channel flag blip-0033: commit fees channel flag Jul 2, 2024
@t-bast t-bast force-pushed the non-initiator-pays-commit-tx-fees branch from 7e1ef8a to 3b7b625 Compare July 2, 2024 12:20
Standard lightning channels require the channel opener to pay the
mining fees for the commitment transaction and mutual close transaction.
This requirement forces the channel opener to contribute to the funding
transaction and makes it impossible to open channels by only purchasing
inbound liquidity from a remote node.

We want to allow nodes to opt into paying the commitment transaction
fees even though they're not the channel opener.
Copy link
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

I understand that supporting non_initiator_pays_commit_fees is not an universal feature and could be negotiated between the two channel parties. However, given that we require that (s)ome messages that should be sent first by the channel opener are instead sent first by the node paying the commitment fees, it seems that this is not a purely additive feature, but could interfere with other protocols/bLIPs.

Given this is a rather fundamental change regarding a major assumption of the Lightning protocol, I wonder if it would be reasonable to add this as an optional feature to the BOLTs directly rather than making it a bLIP?

@t-bast
Copy link
Contributor Author

t-bast commented Jul 4, 2024

it seems that this is not a purely additive feature, but could interfere with other protocols/bLIPs.

That's true in theory, but in practice the risk of that should be pretty low, especially given that this bLIP is a temporary measure that won't be necessary anymore once we move to 0-fee commit txs. We can also just keep this bLIP updated whenever a feature is added to the BOLT that interferes with this bLIP, but there are none pending right now, so we're probably ok.

Given this is a rather fundamental change regarding a major assumption of the Lightning protocol, I wonder if it would be reasonable to add this as an optional feature to the BOLTs directly rather than making it a bLIP?

I'd like to avoid that since I hope we can instead switch to 0-fee commit txs and then remove this bLIP!

@tnull
Copy link
Contributor

tnull commented Jul 4, 2024

I'd like to avoid that since I hope we can instead switch to 0-fee commit txs and then remove this bLIP!

I think I'm a bit more skeptical regarding the zero-fee commitment transaction timeline. Yes, first steps towards package relay will ship in Bitcoin Core 0.28, but it will be quite some time (as in multiple years, no?) until we will be able to really lean on it and actually ship, let alone require zero-fee commit txs?

So, I'm not so sure how 'temporary' this change will be? And given how fundamental the change in the implementations' channel state machine/logic would be, it 'feels' to me a bit unsuited for a bLIP, but I might be wrong.

@t-bast
Copy link
Contributor Author

t-bast commented Jul 4, 2024

I'd like to avoid cluttering the BOLTs with something that we know will be temporary (even if temporary means a couple of years), but if others also feel like this should be in the BOLTs, I'll move it there!

@TheBlueMatt
Copy link
Contributor

This requirement forces the channel opener to contribute to the funding transaction and makes it impossible to open channels by only purchasing inbound liquidity from a remote node.

Not sure I understand the motivation here - if you want to buy inbound liquidity, you should have the inbound-liquidity-seller initiate the channel open from the lightning PoV. I assume that that liquidity seller is also the one who will want to pay the fees.

@tnull
Copy link
Contributor

tnull commented Jul 8, 2024

Not sure I understand the motivation here - if you want to buy inbound liquidity, you should have the inbound-liquidity-seller initiate the channel open from the lightning PoV. I assume that that liquidity seller is also the one who will want to pay the fees.

IIUC, this is necessary as we want to build on Liquidity Ads in which the buyer adds a request_funding TLV to the open_channel2 message, i.e., the channel opening is the liquidity request. FWIW, while it's indeed a bit weird for the on-the-fly flow, it is a bit more streamlined/efficient and as we don't need to spec additional messages/message formats and it's also nice that it saves us another RTT.

@t-bast
Copy link
Contributor Author

t-bast commented Jul 8, 2024

Agreed with @tnull here, that's one of the reasons for it: in the liquidity ads flow, it's the initiator who is buying liquidity, doing it the other way around is clunky: you cannot send request_funding when accepting a channel, because the other peer has already announced their funding_amount in open_channel. So you'd need a pre-open message to tell the LSP to open/splice.

But that's actually what we initially tried for Phoenix: current Phoenix wallets send a please_open_channel message with details about the liquidity being bought and let the LSP send open_channel2. That requires more state tracking on both sides and forces us to pass custom TLV fields back and forth to keep track of the funding context. Having implemented both options (and having maintained one of them in production), I'm much happier with the one that relies on non_initiator_pays_commit_fees!

@TheBlueMatt
Copy link
Contributor

I'm very, very, very much not a fan of touching the channel state machine just to avoid a round-trip when opening a non-JIT channel. Further, for JIT channels we need some kind of please_open_channel_when_i_get_a_payment message anyway, and splitting the JIT and non-JIT flows into two totally separate channel types and inverse negotiation flows also seems weird.

That requires more state tracking on both sides and forces us to pass custom TLV fields back and forth to keep track of the funding context. Having implemented both options (and having maintained one of them in production), I'm much happier with the one that relies on non_initiator_pays_commit_fees!

Yea, its definitely more code to add a new place to put state while claiming a channel, but we need that for JIT flows anyway. Given that code will already exist, why not use it for the non-JIT flow and avoid the need for channel changes?

@t-bast
Copy link
Contributor Author

t-bast commented Jul 11, 2024

I'm very, very, very much not a fan of touching the channel state machine just to avoid a round-trip when opening a non-JIT channel.

The only thing it's changing in the channel state machine is that instead of gating operations based on whether the current node is the channel opener, you simply gate them on a different boolean that is defined immediately after exchanging open/accept (and should be stored in the static channel parameters). This is very straightforward, as the eclair PR shows!

Using some kind of please_open_channel message to make the liquidity seller initiate the open/splice requires much more changes to the channel funding state machine. It is quite inconsistent with the standard liquidity ads flow because it forces you to revert everything (provide_funding sent in open_channel2 instead of accept_channel2, which doesn't make any sense without a pre-open message).

Further, for JIT channels we need some kind of please_open_channel_when_i_get_a_payment message anyway, and splitting the JIT and non-JIT flows into two totally separate channel types and inverse negotiation flows also seems weird.

It doesn't have to be that way though once we start relying on liquidity ads, which contains all the negotiation we need? That was only true when there was no dual-funding nor liquidity ads protocol available (and is why we also initially shipped with a message like this)?

@TheBlueMatt
Copy link
Contributor

The only thing it's changing in the channel state machine is that instead of gating operations based on whether the current node is the channel opener, you simply gate them on a different boolean that is defined immediately after exchanging open/accept (and should be stored in the static channel parameters). This is very straightforward, as the eclair PR shows!

I'm quite confident it'll be similarly simple code in LDK, though not quite as trivial since we have to pipe that bool through to multiple different systems (ie off and on-chain enforcement) and serialize it everywhere, but...

It doesn't have to be that way though once we start relying on liquidity ads, which contains all the negotiation we need? That was only true when there was no dual-funding nor liquidity ads protocol available (and is why we also initially shipped with a message like this)?

Hmm? Even with liquidity ads if I want to receive a JIT channel I need to exchange some message with the LSP, telling them I want to take advantage of their liquidity offer, track the fee I committed to pay, make sure I connect to this node even though I don't have a channel with them, etc, etc. I don't see how that changes this?

@t-bast
Copy link
Contributor Author

t-bast commented Jul 17, 2024

Hmm? Even with liquidity ads if I want to receive a JIT channel I need to exchange some message with the LSP, telling them I want to take advantage of their liquidity offer, track the fee I committed to pay, make sure I connect to this node even though I don't have a channel with them, etc, etc. I don't see how that changes this?

What I mean is that you don't need any custom message for all of those points outside of the official BOLT messages:

  • the LSP forwards will_add_htlc messages to you so you can decide whether you will accept that payment or not if you had enough inbound liquidity to receive the corresponding HTLC
  • you know the LSP's funding rates from their node announcement and init message
  • you can thus decide how much additional liquidity you want to purchase and how much it will cost you
  • if the resulting funding fee is acceptable, you simply send open_channel2 or splice_init to the LSP with the request_funding TLV included, and in the case of open_channel2, the non_initiator_pays_commit_fees flag
  • if the resulting funding fee is too high, you simply don't do initiate open/splice

That uses the standard liquidity ads flow and doesn't require additional changes to the channel state machine. Note that this is because liquidity purchases are always driven by the user (you could also design a different scheme where liquidity decisions are driven by the LSP, but I think that only works in a model where the user pays a % fee from every HTLC they receive - which could be an interesting model, but it's not the one we chose to experiment with).

@dzdidi
Copy link

dzdidi commented Jul 22, 2024

@niftynei , @vincenzopalazzo told me that you might be the right person to give a feedback from the perspective of Core-Lightning

@TheBlueMatt
Copy link
Contributor

After discussion at the summit we concluded that we can avoid this if we move to zero-fee commitment txn, which we agreed loosely to do.

@t-bast
Copy link
Contributor Author

t-bast commented Oct 24, 2024

We will indeed be able to get rid of this with 0-fee commitment transactions. But since this is what we're currently using for Phoenix, I think it makes sense to keep the PR open so that it is specified somewhere (but no need to merge it). I'll close it when we're able to migrate to 0-fee commitment transactions.

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.

4 participants