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

Additional inputs for HTLC txs RBF considered harmful #845

Open
t-bast opened this issue Feb 15, 2021 · 16 comments
Open

Additional inputs for HTLC txs RBF considered harmful #845

t-bast opened this issue Feb 15, 2021 · 16 comments

Comments

@t-bast
Copy link
Collaborator

t-bast commented Feb 15, 2021

With anchor outputs, we depend on RBF (adding additional inputs) to ensure HTLC transactions can get confirmed in time.
The more I think about it, the more I find it very sad and unsatisfactory, for the following reasons:

  1. The value of the HTLC is entirely contained in the HTLC transaction, so we shouldn't need additional inputs
  2. It introduces a strong coupling between layer 1 and layer 2, with quite a lot of complexity at scale (routing nodes with a lot of channels will need to reserve/produce utxos, thus locking on-chain capacity for no good reason and potentially paying a lot of on-chain fees to manage their utxo pool if they want to guarantee perfect funds safety)
  3. It forces HTLC transactions to be bigger (at least one more input) and thus costs more fees

It would be a lot better if we could set the feerate of an HTLC transaction by simply updating the output amount at broadcast time (and changing it again if necessary to bump the fees).

Would it be completely unreasonable to devise a sighash flag that allows this?
It feels to me that this could be generally useful for offchain contracts and easily "safe".

There are details to iron out, and it would take a lot of time to get it accepted in bitcoin, so my question right now is: "is this completely unreasonable or short-sighted or does it make sense to explore this seriously?".

I'm interested in your thoughts @ariard @TheBlueMatt @rustyrussell @cdecker @halseth @joostjager @Roasbeef (and of course anyone else who can spare time thinking about this issue).

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 15, 2021

To be clear, my proposal for that sighash flag would be some form of "don't sign the output amount".

@cdecker
Copy link
Collaborator

cdecker commented Feb 15, 2021

I don't see how this could be implemented, or would be better than the status quo: if the signature doesn't cover the output then anyone in the network can adjust the output value to whatever they want, including a dust + \eps amount that'd result in almost all funds going to the miner. Miners would love this of course, but I don't think that's the intention here :-)

I seem to be missing one detail: what would be the advantage over the claiming party just adjusting the amounts and re-signing (I'm assuming this concerns the settle and timeout txs not the commitment txs creating the htlc outputs)?

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 15, 2021

I don't see how this could be implemented, or would be better than the status quo: if the signature doesn't cover the output then anyone in the network can adjust the output value to whatever they want

Please bear in mind that I'm only talking about the remote signature, the local signature will still be a SIGHASH_ALL.
I want the peer who publishes his commit tx to be able to change the output amount without requiring a new signature from the remote peer.

And indeed, it's only for the HTLC transactions (2nd-stage transactions for a local commit).

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 15, 2021

The flow I'd like to enable is:

  • I publish my local commit
  • The commit tx confirms, so it's now time to publish my HTLC txs
  • I check the current on-chain feerate and decide what feerate to apply to my HTLC txs
  • I simply update the output amount on these txs to match the target feerate (I don't add any additional input) and sign with SIGHASH_ALL
  • This operation didn't invalidate the remote signature and only allowed me to change the feerate, not cheat in any way
  • If the feerate rises and my HTLC txs don't confirm, I lower even more their output amount and re-sign (still with SIGHASH_ALL) to RBF them (still not adding any additional input)

Does that make sense? This flow feels to me vastly superior to having to add additional inputs.

@t-bast t-bast changed the title RBF for HTLC txs considered harmful RBF for HTLC txs with additional inputs considered harmful Feb 15, 2021
@t-bast t-bast changed the title RBF for HTLC txs with additional inputs considered harmful Additional inputs for HTLC txs RBF considered harmful Feb 15, 2021
@ariard
Copy link
Contributor

ariard commented Feb 15, 2021

Already thought a lot about a potential SIGHASH_ANYAMOUNT to do just-in-time fee management for off-chain contracts. And thus spare us the pitfalls around useless locked liquidity you're mentioning.

I've never proposed it on the list because AFAICT it doesn't fit Lightning security model. A counterparty will offer a signature not committing to the amount of a revokeable output, opening the door to yet-another fee siphoning attack. Just drain out the whole fee from the amount and capture it with a new output, your honest counterparty won't be able to punish you.

Of course, your smarter sighash flag could commit to the output index to prevent fee-siphoning-output addition by your malicious counterparty. But doesn't prevent to act in cooperation with a miner to get confirmed the commitment and HTLC txn and thus bypass the punishment. Note, I'm not saying a coalition of miner, just at least one miner, who is free to generate such malicious block anytime during channel lifetime.

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 15, 2021

Good catch, the main issue with this proposal is indeed a fee siphoning attack via a revoked commit tx (with a miner's collaboration). For other readers, here is how the attack would work:

  • the attacker fills the commit tx with HTLCs
  • then fulfills/fail them and spends funds from the channel (spend all of his balance)
  • he sends the revoked commit tx filled with HTLCs to a miner friend, who will try to include it in a block (without propagating it on the network)
  • once that revoked commit tx is included in a block, the attacker can publish HTLC txs with a 0-amount output (all funds go to miners) and the honest participant has nothing to penalty-claim on the htlc txs and lost all the channel funds

The only way to prevent this kind of attack while allowing malleability on the output amount would be to use a bigger CSV than 1 on HTLC txs, to ensure the honest participant can claim the outputs of the revoked commit tx directly from the commit tx before the attacker can get his HTLC txs confirmed.

@Roasbeef
Copy link
Collaborator

"Considered harmful" suffixes to an argument are to be "considered harmful" ;)

The more I think about it, the more I find it very sad and unsatisfactory, for the following reasons:
The value of the HTLC is entirely contained in the HTLC transaction, so we shouldn't need additional inputs

One other benefit of the base HTLC having zero second layer fees as that nodes are acutally able to utilize more of their avaliable channels bandwidth. Consider that before this change each HTLC required the sender to commit both the HTLC amount, as well as the fees for the second-layer transaction. With this change, they only commit the HTLC amount itself, leaving the rest of the channel available for other forwarding/payment/receiving attempts.

routing nodes with a lot of channels will need to reserve/produce utxos

In the ideal case, assuming that force closes aren't correlated with each other, they only actually need a single "well sized" UTXO. Ofc, figuring out what the proper size is for your node doesn't have a very straightforward solution.

It forces HTLC transactions to be bigger (at least one more input) and thus costs more fees

On the contrary, it can actually let a node reduce the total number of transactions they do on chain given they can now aggregate all time-lock compatible HTLC second level transaction together into a single transaction. These transactions can also further be aggregated with any other trnasactions the node may be making at the time (attach them to a funding transaction as an example).

With that said, it seems implementations have 3 options:

  1. Implement and utilize the current fee bumping mechanisms we put into place over the past year or so, which are now increasingly critical for routing nodes given the persistent higher fee rates.
  2. Do nothing.
  3. Wait ??? years to maybe propose a new sighash that may solves the issue at hand in a "cleaner" way and maybe doesn't introduce any new issues along the way.

From a risk management perspective, it's clear to me that option #1 is the way to go. Particularly for routing nodes that accept larger HTLC amounts (via the max_htlc) settings, as if they're routing such HTLCs without the super duper anchor transactions, they can't bump their fees at all, and my find themselves on the wrong side of a Bitcoin price spike/dump while forwarding HTLCs, which as we've seen typically causes a flurry of mempool activity which drives up near confirmation fee rates.

Independent of this proposal, I'm all for more granular sighash flags tho. IMO the ideal solution would be flexible enough to accomodate this use case and also allow for additional innovation using the set of more flexible sighash flags. Various flavoers of covenents would also help here.

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 17, 2021

One other benefit of the base HTLC having zero second layer fees as that nodes are acutally able to utilize more of their avaliable channels bandwidth. Consider that before this change each HTLC required the sender to commit both the HTLC amount, as well as the fees for the second-layer transaction. With this change, they only commit the HTLC amount itself, leaving the rest of the channel available for other forwarding/payment/receiving attempts.

You're mistaking me, I think having 0-fee HTLC txs is great during the channel lifetime.
But I'd like the closing party to be able to change the output amount to pay the fee at closing time, instead of relying on an additional input (that wouldn't impact what happens during the channel lifetime, where you would allocate 0 fee for the HTLC tx). But as ariard pointed out, the fee siphoning attack via a revoked commit makes this a no-go...

From a risk management perspective, it's clear to me that option #1 is the way to go.

I completely agree that we need to do this in the short term, this issue is not questioning that don't worry :).

But I was wondering if in the longer term, we could think of a better solution since the HTLC txs should be self-sufficient and on-chain fees could in theory be set by simply updating amounts, which better decouples lightning from the on-chain world. It may be a lost battle, but I think it's worth exploring or at least keep in mind in the design space.

@halseth
Copy link
Contributor

halseth commented Feb 17, 2021

I definitely think there are smarter ways to do this long term, but in the short term it seems like the zero-fee HTLCs we currently have is the way to go.

Longer term perhaps either more flexible sighash flags or covenants could make your proposal possible, but If we have those tools available maybe we don't even need HTLC transactions? The reason for having HTLC txs in the first place was to emulate a covenant IIRC.

I'm imagining something like a single CTV output on the commitment for all HTLCs (or PTLCs), that can be spent by transactions that claim a certain amount of the funds by providing preimages, and sending the rest to the other party. You could presign transaction with various fee rates also this way of course. (this needs a lot more research)

@ariard
Copy link
Contributor

ariard commented Feb 18, 2021

How smart we can be with new sighash/covenant proposals we'll hit a fundamental LN design issue. The chain can't guess a state commitment was honest until the justice period is over and no punishment has shown up. Which means using the channel capacity as "blank check" fees, before justice has been established, will always constitute a fee siphoning attack vector. What an efficient feerate for confirmation was at a given tip is always known after the fact.

(In theory you might rely on per-block fee ranges to flag a feerate as a malicious waste, but that sounds like proposing the mempool to be part of the consensus rules, I'm going to die on another hill)

But I was wondering if in the longer term, we could think of a better solution since the HTLC txs should be self-sufficient and on-chain fees could in theory be set by simply updating amounts, which better decouples lightning from the on-chain world. It may be a lost battle, but I think it's worth exploring or at least keep in mind in the design space.

Note that even if you have the HTLC consuming their own capacity as fees, you'll still have to reserve bumping UTXO for the commitment transaction, which must account for the dynamic number of HTLC outputs. If you propose to have the commitment consuming its own capacity you're back to fee siphoning attack, so the fee-bumping/reserve paradigm is here to stay IMHO.

In the ideal case, assuming that force closes aren't correlated with each other, they only actually need a single "well sized" UTXO. Ofc, figuring out what the proper size is for your node doesn't have a very straightforward solution.

Gonna work on this LN fault-tolerance/mempool-congestion/fee-bumping recommendations research paper. Good opportunity to me to dissect current generation of fee estimators :)

I'm imagining something like a single CTV output on the commitment for all HTLCs (or PTLCs), that can be spent by transactions that claim a certain amount of the funds by providing preimages, and sending the rest to the other party. You could presign transaction with various fee rates also this way of course. (this needs a lot more research)

I agree, I would favor HTLCs aggregation in one big block transaction. Already had this conversation with few folks but the design space here is so wide (either taproot, CTV, yet-to-be-designed covenant), so not really a priority IMO.

@t-bast
Copy link
Collaborator Author

t-bast commented Feb 19, 2021

If you propose to have the commitment consuming its own capacity you're back to fee siphoning attack, so the fee-bumping/reserve paradigm is here to stay IMHO.

I agree that additional utxo are still needed for the commit tx, I was only thinking about HTLC txs here, because it's a great multiplier (you can have max-accepted-htlcs HTLCs per channel, which means a lot of on-chain txs to do...whereas only having to bump one commit tx per channel is much more acceptable).

I agree that the design space is very large, especially since it seems like OP_CAT is back on the table! We have a lot of interesting research to do in the coming years, that's something to look forward to ;)

@t-bast t-bast closed this as completed Aug 10, 2021
@t-bast
Copy link
Collaborator Author

t-bast commented Sep 1, 2021

I'm re-opening this issue to keep it under the spotlight as I still strongly believe anchor outputs would be a lot safer if we didn't have to manage utxo sets for a potentially large number of HTLC txs.

I know this isn't feasible today, but I think it's worth keeping in a corner of our minds that this is an important area of research, where more flexibility in bitcoin sighash modes or changes to the channel structure would be very beneficial.

@t-bast t-bast reopened this Sep 1, 2021
@TheBlueMatt
Copy link
Collaborator

Note that with our anchor implementation we are somewhat likely to go with a "one UTXO for all anchor spends" model to avoid a lot of the complexity of managing a ton of UTXOs. Indeed this requires package relay/package RBF, but so does anchor today, at least unless you monitor the mempool for counterparty broadcasts, which I don't think anyone does.

@remyers
Copy link

remyers commented Oct 7, 2021

At the risk of being the "eltoo fixes everything" guy... the fee siphoning attack is based on the premise of penalty transactions. The eltoo replaceable transaction scheme would allow tx fees to be allocated from the self-owned outputs of the eltoo settlement transaction at broadcast time without risking a siphoning attack.

The problem is that an eltoo update tx must confirm before the settlement tx. An update tx has a single output with the total value in the channel so couldn't use this scheme. AJ Towns' Layered Commitments proposal for eltoo might be a way to solve this problem since it breaks out the to-self, to-other and {H,P}TLC outputs in the first layer transaction instead of just the second (ie. the settlement tx in current eltoo).

If we're talking about a sighash solution to this problem, then it might make sense to consider something that is part of a comprehensive anyprevout sighash softfork defined for a new Taproot key version.

@TheBlueMatt
Copy link
Collaborator

Note that with package relay in bitcoin Core it’s substantially easier to implement BYO fees without needing one-output-per-channel. The current proposal for package relay should allow for one output to at least be used across two channels, and there may be a multi-replacement way of using a simple output for more.

@t-bast
Copy link
Collaborator Author

t-bast commented Oct 9, 2021

True, it's better, but fundamentally it would be so much simpler and efficient to just decrease the output amount...we shouldn't need to BYO with external inputs in the first place (in an ideal world)!

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

No branches or pull requests

7 participants