bolts icon indicating copy to clipboard operation
bolts copied to clipboard

interactive-tx: Add dual-funding flow, using the interactive tx protocol (feature 28/29)

Open niftynei opened this issue 3 years ago • 11 comments

This commit adds the interactive transaction construction protocol, as well as the first practical example of using it, v2 of channel establishment.

Note that for v2 we also update the channel_id, which now uses the hash of the revocation_basepoints. We move away from using the funding transaction id, as the introduction of RBF makes it such that a single channel may have many funding transaction id's over the course of its lifetime.

The easiest way to understand the gist of this PR is this video, which explains the prior protocol and overviews this one.

https://youtu.be/i_GxmNZjwhk

niftynei avatar Mar 02 '21 03:03 niftynei

26/27 already taken by #814 (at least, I proposed it move there to avoid clash)? Try 28/29?

rustyrussell avatar Mar 02 '21 04:03 rustyrussell

Would it make sense to add optional auth_token field (up to 33 bytes?) so that one could only allow dual-funded channels for authorized peers? Or maybe to identify how much the other side wants to put into the channel.

Can be done by node ID too but this may lead to less UX hassle as the ID doesn't need to be transferred back-and-forth.

Kixunil avatar Apr 08 '21 08:04 Kixunil

open_channel2 and accept_channel2 are easily extensible via TLVs for authentication schemes.

On Thu, Apr 8, 2021 at 03:47 Martin Habovštiak @.***> wrote:

Would it make sense to add optional auth_token field (up to 33 bytes?) so that one could only allow dual-funded channels for authorized peers? Or maybe to identify how much the other side wants to put into the channel.

Can be done by node ID too but this may lead to less UX hassle as the ID doesn't need to be transferred back-and-forth.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/lightningnetwork/lightning-rfc/pull/851#issuecomment-815577821, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIMAKOVGO6NB7VE4DOZXQLTHVUQLANCNFSM4YN3DDXA .

niftynei avatar Apr 08 '21 14:04 niftynei

Yes, I mean perhaps it'd be beneficial to have a standardized field so that clients implement the interface of filling that in. Would be real shame if only LND could open authenticated channel to LND, Elair to Ecliar and c-lightning to c-lightning...

Basically have a way for the server to provide hex/base64 string that user fills in to get double-funded channel. This will be easier if all impls agree on the field being used.

Kixunil avatar Apr 09 '21 06:04 Kixunil

I think this proposal is a great opportunity to provide a standard way of paying for liquidity (to help with the initial inbound liquidity problem). Maybe it's worth a separate PR that will enrich the interactive-tx protocol (and can be merged separately), I'll work on that once I've done a more thorough review of this PR.

The high-level idea is to simply introduce new TLVs to allow participants to:

  • announce the fee they would charge to provide liquidity (funds on their side) -> probably in node_announcement
  • request the remote participants to add X sats by paying that fee -> in the interactive-tx messages

Deducing the fee from the initial main outputs would then be deterministic and could be verified before finalizing the funding tx, which is great. It would remove the hackish uses of push_msat in trusted liquidity providers.

It would also provide an incentive for nodes to add funds to channels where they're not the initiator. Because without such a fee, it will be hard to automate the addition of funds when we're fundee, because we most likely don't want to add some of our funds to every channel that remote nodes open to us (otherwise they could easily deplete our utxo pool).

Any thought on this high-level proposal before I start diving into technical details?

t-bast avatar Jun 07 '21 09:06 t-bast

I think this proposal is a great opportunity to provide a standard way of paying for liquidity (to help with the initial inbound liquidity problem). Maybe it's worth a separate PR that will enrich the interactive-tx protocol (and can be merged separately), I'll work on that once I've done a more thorough review of this PR.

The high-level idea is to simply introduce new TLVs to allow participants to:

  • announce the fee they would charge to provide liquidity (funds on their side) -> probably in node_announcement
  • request the remote participants to add X sats by paying that fee -> in the interactive-tx messages

Deducing the fee from the initial main outputs would then be deterministic and could be verified before finalizing the funding tx, which is great. It would remove the hackish uses of push_msat in trusted liquidity providers.

It would also provide an incentive for nodes to add funds to channels where they're not the initiator. Because without such a fee, it will be hard to automate the addition of funds when we're fundee, because we most likely don't want to add some of our funds to every channel that remote nodes open to us (otherwise they could easily deplete our utxo pool).

Any thought on this high-level proposal before I start diving into technical details?

I think this is a great idea! So great in fact that I've already written up a spec draft and have started working on implementing it. I just pushed up the draft version #878, and would love to collaborate, get your feedback on it.

niftynei avatar Jun 07 '21 22:06 niftynei

Should we recommend to verify finalized interactive transaction against client's full-node transaction standardness verifier.

Hm. Ideally we would specify all of the "standardness" rules here so as not to be dependent on the 'standardness verifier' implementation, however that list seems to fairly changeable. Better to specify what to do in the case that the broadcast fails? (double spend the inputs/attempt another RBF).

Should we enrich failure modes ? ... In that case of scenario, honest double-spend of one's inputs after a timeout might be wiser.

Yeah, the 'double spending of an input to cancel an open' is a bit implicit here, it's probably worthwhile to call it out explicitly.

Should we introduce the interactive transaction section in its own BOLT ? As the 2 above points underscore it, multi-party funded transaction in the context of trust-minimized counterparty is far harder to get right than single-funded transaction. We migh land first this chunk, and from then enrich/harden the spec with best practices as we discover more edge cases and base layer support improves and we might add poodle or an equivalent solution to the privacy issues.

Yeah, I think this is a good idea, and something that we can do naturally/easily after this is merged (and more sections of the spec adopt it/use it)

niftynei avatar Jun 08 '21 17:06 niftynei

Thanks for the feedback @t-bast! I've updated the draft with most of your comments. One big takeaway is that you'd like to see the reserve amount re-included in the protocol. What do you think about changing this to a "use_reserve" flag, rather than a reserve amount?

niftynei avatar Aug 16 '21 23:08 niftynei

One big takeaway is that you'd like to see the reserve amount re-included in the protocol. What do you think about changing this to a "use_reserve" flag, rather than a reserve amount?

Great suggestion, that would work for me, I have no scenario where I need to set the channel reserve to a specific non-default value, I just need to be able to disable it for wallet UX.

t-bast avatar Aug 18 '21 14:08 t-bast

should easily generalize to N party transaction building

fun fact, CLN does this today w/ the current protocol when you do multifundchannel with multiple liquidity ad buys (done as multiple 2-party negotiations on top of the same tx)

niftynei avatar May 12 '22 19:05 niftynei

We already do this (resend tx_signatures on reconect) in CLN; updating the spec to reflect that is a great idea!

Ack on the squash/rebase!

On Tue, May 17, 2022 at 08:13 Bastien Teinturier @.***> wrote:

@.**** commented on this pull request.

In 02-peer-protocol.md https://github.com/lightning/bolts/pull/851#discussion_r874796210:

    • MUST send tx_signatures

+#### Rationale + +The first commitment transaction has no HTLCs. + +### Sharing funding signatures: tx_signatures + +After a valid commitment_signature has been received +from the peer and a commitment_signature has been sent, a peer:

    • MUST transmit a tx_signatures message with their signatures for
  • the funding transaction

+#### Requirements + +The sending node:

We should add a requirement to retransmit signatures on reconnection:

  • MUST retransmit tx_signatures when reconnecting

Otherwise we may stumble upon the following dead-lock:

  • Alice and Bob have exchanged everything up to commit_sig
  • Alice goes first and sends her tx_signatures
  • But Bob disconnects without receiving them
  • On reconnection:
    • Alice:
      • is waiting for Bob's tx_signatures to be able to publish the funding tx
      • cannot forget the channel because she doesn't know whether Bob has received her signatures or not
    • Bob:
      • has forgotten the channel because he never received Alice's tx_signatures
      • cannot prove it to Alice

If peers retransmit their latest tx_signatures on reconnection, we get rid of this deadlock. Does that make sense?

Also, it may be time to squash and rebase :)

— Reply to this email directly, view it on GitHub https://github.com/lightning/bolts/pull/851#pullrequestreview-975443730, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAIMAKOP7FZIOP27QGELGZDVKOLPRANCNFSM4YN3DDXA . You are receiving this because you were mentioned.Message ID: @.***>

niftynei avatar May 17 '22 13:05 niftynei

I spent more time thinking about the tx_signatures ordering issue, and I think we should do opener first (as proposed in https://github.com/niftynei/lightning-rfc/pull/9) instead of amount-based ordering.

@morehouse @niftynei @ddustin @rustyrussell can you please spend some time going through this detailed analysis and let me know your thoughts?

Let's summarize the issue first to make sure we won't talk past each other. When both peers add funds to an interactive transaction, the first one to send tx_signatures is exposed to the following griefing attack:

  • Alice sends tx_signatures -> funds are now locked and the other peer may publish the funding tx at any time
  • Alice doesn't receive Bob's tx_signatures and the funding tx doesn't seem to be broadcast
  • After an implementation-specific tx_signatures_timeout has passed, Alice decides that Bob is malicious and puts her inputs back in her wallet to eventually double-spend them

The important aspect of this attack is that whatever Alice does to defend herself, whenever she accepts a dual-funded channel she risks having some liquidity locked for tx_signatures_timeout.

Now let's consider the case where Alice is using liquidity ads. This will likely be the main scenario where a node exposes itself to that kind of griefing attack. Mallory connects to Alice and requests a dual-funded channel by paying for Alice's liquidity ads. Alice now has to evaluate the risk she's taking.

If Mallory already has channels with other peers on the network, the risk is probably acceptable: Mallory has paid some on-chain fees associated with her node_id (which acts a some DoS/Sybil protection), so in the worst case where she's malicious Alice can ban her node_id for future attempts. But what if Mallory doesn't have any public channel? In that case, banning her node_id will be useless, as she can create another one for free. One of the goals of liquidity ads is to help such new nodes bootstrap themselves into the network by paying for initial connections, so Alice still wants to accept some of these requests. Alice could for example allocate a fixed amount of liquidity per day for nodes that don't have any channels to bound her exposure: max_liquidity_for_new_nodes. But the issue is that Mallory can trivially repeat the attack with new node_ids to ensure that all of Alice's max_liquidity_for_new_nodes is constantly locked, which prevents honest new nodes from using Alice's liquidity ads. This could be solved by using PoDLes, but if we can avoid additional complexity, it would be great.

@morehouse and I suggest that by default, the opener should send their tx_signatures first. It's a trivial change that fixes the issue because:

  • The liquidity providers won't have to sign first, so they can blindly accept requests from any node
  • The liquidity providers already have an established presence in the network so they're much less likely to cheat and grief the opening node
  • Opening nodes will never initiate a channel open with an unknown node that doesn't have any channel on the network, so they're protected from the most risky case
  • Opening nodes choose who they try to open a channel with, whereas accepting nodes don't, so they're inherently better protected

The only issue with that proposal is that it prevents opening nodes from batching multiple channel open, which is a feature we'd like to keep. My proposal in https://github.com/niftynei/lightning-rfc/pull/9 is to let the opening node ask the other node to sign first, using a tlv in open_channel2. From the liquidity provider's point of view, I believe this is strictly better than always signing first because they could configure their risk policy like this:

  • Allocate max_liquidity_for_first_sign_new_nodes to nodes that don't have any channel yet and want the liquidity provider to sign first
  • Allocate max_liquidity_for_first_sign_existing_nodes to nodes that already have channels and want the liquidity provider to sign first
  • Allocate max_liquidity_for_second_sign for nodes that let the liquidity provider sign second

We'll most likely have: max_liquidity_for_second_sign >> max_liquidity_for_first_sign_existing_nodes >> max_liquidity_for_first_sign_new_nodes. When under attack, liquidity providers can simply disable the first one or first two options. That will still let nodes request liquidity (potentially without the batching option), which is much better than stopping everything. More generally, nodes that already have a few channels will be lower risks, so liquidity providers will more easily accept their batched channel open.

One drawback that was mentioned during the spec meeting is that the opener is revealing that they're doing a batched transaction when they ask the liquidity provider to sign first. But I don't think that holds: whenever the opener adds more than two outputs to the transaction, it's already obvious that they're batching it with something else. I don't see how this would be a real issue in practice, but maybe someone can detail that concern?

t-bast avatar Oct 25 '22 15:10 t-bast

Worked with @niftynei to put some of the more ephemeral discussion into something in writing and I'm just going to paste it here:

Who signs first?

In the land before time he who had the biggest club made the decisions. Today’s world calls for balanced incentives with taxes on aggressive clubbing so we can all enjoy a safe and effective Lightning network.

With dual open & liquidity ads a new class of club becomes possible. Collaboratively opening channels requires participants to “put their sats on the table” in the form of utxos.

The first to sign locks their utxos up first. While they won’t lose these sats, they will be locked up for some time.

The question as to who should be the one to “lock in” first is an interesting one. A couple proposals are on the table:

  1. Randomly / whomever wants
  2. The one who initiated (open/splice)
  3. The one with the least sats on the table

To understand what’s the best mode let’s look at it backwards. If I’m an attacker wanting to bring clubbing back to the neighborhood in the form of locked funds, how do I do it in various scenarios?

1) Random signer This is the simplest. I participate in ongoing negotiations and never sign. The more sessions I can get access to the more havoc I can inflict. (Utxos are unavailable for use elsewhere until some node configured timeout elapses for the utxo reservation)

2) Initiator Whoever initiates has to sign first. Even with large parties, everyone was invited by someone whom they consider “first” relative to themselves.

A few problems arise however.

If I initiate a three way tx open with Alice and Bob, they will both see me as first. (Neither of them knows there’s another party in the negotiation)

If Alice decides to add funds but Bob doesn’t, this works okay. I send Alice my signature, she sees the signature covers all inputs and signs back. Now I send this completed bundle to Bob and all is well.

Now what happens if Alice and Bob add funds?

Now there is no set of signatures I can send Alice or Bob to show a complete signature package.

If I sign what I can and give it to Alice — she will see Bob’s funds in the bundle completely unsigned. Since I am “first” she refuses to sign until Bob’s funds are signed for.

If I go to Bob I have the same problem in reverse. Alice and Bob correctly, according to this rule, never agree to sign.

So the party must end.

In a variant of this solution, liquidity providers always sign last. This successfully protects the liquidity provider from griefing attacks by moving the griefing risk to the leasee. However the problem for leasees has gotten worse.

A malicious actor can advertise on the open market that they’re willing to open channels with people, acquire the signatures of the users, and never sign themselves. This attack is low cost and could be done at scale to many users. These users are not in an ideal position to maintain blacklists of utxos without trusting some source for them.

The net effect of this attack would be users learning the open market for liquidity is unreliable and push them to only using liquidity providers with high reputation. While good for the liquidity high reputation providers, this attack could prove detrimental to an open market for liquidity.

It would seem it is important to solve the griefing attack for both the liquidity sellers and liquidity buyers.

3) Lowest Sats First Whoever has the least on the line signs first. This elegantly matches incentives among the party participants and requires a malicious actor to always lock up more funds than the victim, without giving special treatment to any particular actor.

If liquidity providers maintain a blacklist of utxos used in attacks the cost to the attacker goes even higher – they must both lock up more funds than the victim and pay miner fees to repeat the attack. This rather neatly makes the cost of the attack scale linearly with the impact of the attack.

In large parties the flow works out correctly as well because this is all ending up a single transaction. This provides an atomic measure of who is adding the least and most. A tie breaker is needed when sat added amounts are equal but an attacker can still not lock up more funds than they put down. When combined with a utxo blacklist the cost to the attacker still remains higher.

When counting who has the least sats, all sats brought by a party member are considered in the calculation. This count includes everyone they invited to the party as well. This both neatly simplifies the calculation and makes the correct signing order cascade across party members.

Some examples: Alice adds 1btc <-> Bob adds 2 btc <-> Charlie adds 0.5btc Alice compares 1btc to 2.5btc (Bob + Charlie) and sees she has less, so she signs Charlie compares 0.5bc to 3btc (Bob + Alice) and sees he has less, so he signs Bob see’s he’s the last one left and signs

Alice adds 1btc <-> Bob adds 0.5btc <-> Charlie adds 2btc Alice compares 1btc to 2.5 (Bob + Charlie) and sees shes has less, so she signs Bob compares 1.5btc (Alice + himself) to 2 (Charlie) and sees he has less, so he signs Charlie see’s hes last and signs

Alice has 1btc <-> Bob adds 0.75btc <-> Charlie adds 0.75btc Alice compares 1btc to 1.5btc (Bob + Charlie) and sees she has less, so she signs Charlie compares 0.75btc to 1.75btc (Bob + Alice) and sees he has less, so he signs Bob sees he’s last and signs

This solution works the same way as the number of participants scales up. An important note is Bob adds the value of all sats ‘on the other side’ of him when comparing to a given peer.

Here are some examples of Bob’s calculations:

Alice adds 1btc <-> Bob adds 2 btc <-> Charlie adds 0.5btc Bob compares 2.5btc (himself + Charlie) to 1btc and doesn’t sign first to Alice Bob compares 3btc (himself + Alice) to 0.5btc and doesn’t sign first to Charlie

Alice adds 1btc <-> Bob adds 0.5btc <-> Charlie adds 2btc Bob compares 2.5btc (himself + Charlie) to 1btc and doesn't sign first to Alice Bob compares 1.5btc (himself + Alice) to 2btc and signs before Charlie (but after Alice)

Alice has 1btc <-> Bob adds 0.75btc <-> Charlie adds 0.75btc Bob compares 1.5btc (himself + Charlie) to 1btc and doesn’t sign first to Alice Bob compares 1.75btc (himself + Alice) to 0.75btc and doesn’t sign first to Bob

Special Note: This all assumes circular parties are disallowed (as the current interactive tx spec specifies (dual-funding/splicing)). Circular parties are when channel partners knowingly or unknowingly create a loop in the party participants. An example: Alice -> Bob -> Charlie ^ This dual open / splice works no problem

Alice -> Bob -> Charlie -> Alice ^ This creates a circular loop that causes problems for “lowest sats signs first”.

In the future support for circular loops may possibly be added and some proposals exist for making it possible but they are not complete.

Loops are detectable when you see your own inputs sent back to you by another party. An example: Alice sends utxoA -> Bob Bob sends utxoA + utxoB -> Charlie Charlie sends utxoA + utxoB + utxoC -> Alice

Alice now see Charlie send her own utox (utxoA) back to her. Once detected she sends tx_abort to all her participant connections (Bob + Charlie in this case), canceling the circular loop.

ddustin avatar Oct 25 '22 17:10 ddustin

This could be solved by using PoDLes, but if we can avoid additional complexity, it would be great.

I don't think we can solve this issue in a robust way w/o PODLEs or some other proof of spendable funds.

As @ddustin points out, a node buying liquidity via a liquidity ad is also subject to some form of this griefing attack; the surface area is just different.

fwiw I think the most pragmatic way to resolve this would be to:

  • use the "most sats goes last" ordering as rule, but with the caveat that anyone MAY send tx-sigs as soon as they want/first
  • work on an improvement to the protocol which sends PODLEs as proof of funds before utxo exchange/negotation.

PODLEs also have a nice property of fixing other issues (providing a proof before sharing utxo information) as well as the "funds lockup for X time" that this griefing attack has. PODLES combine with the "most sats goes last" nicely, as they require proof of actually having the most funds on-chain in order to achieve that coveted second-payer slot.

Also note that no matter how we order the tx-sigs, failure at this point in the protocol is unavoidable. Any robust implementation will need to handle the case of a failure to open (bad sigs sent, mempool gets too full), so what order we send tx-sigs has the potential to reduce the flexibility of the protocol, but not actually remove a failure case.

niftynei avatar Oct 25 '22 19:10 niftynei

@ddustin it feels like you're not taking the contents of my comment into account? Your analysis of incentives ignores the fact that opening node and accepting node are not at all symmetric and equal here, since the opening node chooses who to connect to whereas the accepting node doesn't. Also, you seem to ignore my proposal to explicitly request the other participant to sign first (which ensures that multi-fund works).

Also note that no matter how we order the tx-sigs, failure at this point in the protocol is unavoidable. Any robust implementation will need to handle the case of a failure to open (bad sigs sent, mempool gets too full), so what order we send tx-sigs has the potential to reduce the flexibility of the protocol, but not actually remove a failure case.

Of course, but there's a fundamental difference between how much you're exposed to it depending on what ordering we choose. My comment details why opener goes first (with optional request to go last) is vastly superior in that regard because it completely removes one class of attacks. I'm not sure you've fully appreciated that?

With the proposal I'm laying out, there's no need for PoDLes (thus less complexity, which is extremely desirable) since we can use a node's existing channels as an anti-DoS measure?

The most pragmatic solution would be to start with opener goes first which offers the best trade-offs today, and switch to least contributed amount goes first once we add PoDLes?

t-bast avatar Oct 26 '22 06:10 t-bast

Without proof of UTXO ownership, the least-sats-contributed method still exposes both the opener to one-off griefing and the acceptor to sustained griefing (DoS) attacks.

Without proof of UTXO ownership, the opener-goes-first method exposes only the opener to one-off griefing.

If we're going to merge a partial solution, I would push for opener-goes-first to easily prevent the DoS attack. When we're ready for PoDLEs, we can switch to least-sats-goes-first.

morehouse avatar Oct 26 '22 15:10 morehouse

Left a comment on niftynei#9, but will repost general sentiment here.

Having a flag to let a peer know "i'm not sending signatures until last" is a decent compromise, I think, to removing the batching capability entirely via protocol update vs leaving large accepters exposed to fund-lockup griefing attacks. I'm ok moving forward with this, but would like for the general, non-flagged case to default to being "largest contrib goes last", for all reasons previously stated.

niftynei avatar Oct 27 '22 02:10 niftynei

Still reviewing the current state of the discussion, though here some initial thoughts.

In the multi-party setup (N > 2), I think there is a concern of a "miner harvesting" attack. If the rule "most sats goes last", a miner can introduce the upper bound UTXO, and as such withhold the completion of the signature collection process. After an implementation-specific tx_signature_timeout, all the participants are lured to double-spend their inputs for which they release their tx_signatures. (I think the miner could even execute a sneaky version of this attack by pinning the batching transaction and directly connecting to the broadcast nodes of the victim to be the solo miner knowledgeable of the double-spend...).

Beyond, in the multi-party setup, as raised few times, there is an asymmetric timevalue DoS, where one participant can inflict damage to the N-1 honest participant at the cost of "most sats" timevalue wasted from the attacker. It could be argued a fair coin toss protocol deciding randomly who among the set of participants should release its tx_signatures could be more robust against that type of attack. However, I'm starting to think "reputation assessment" of the counterparties should be done as preliminary step of adding any inputs, and tx_signatures order could be left unspecified, as the problem is solved earlier in the pipeline.

Note, I don't think PoDles would work straight out-the-box, even if we assume open access to the UTXO blacklist by LN mobile clients. As you would have to account for mobile peers with flappy Internet connections non-penalized after few cancellations of tx_signatures likely for a reasonable UX. I think this "forgiveness" margin would be a margin of exploitation for griefing attackers.

In the two-party configuration as laid out by Bastien, where the acceptor is the LSP, I think risk management policy based on the channel-weight of the participant is robust enough against known attacks. There is no "miner-harvesting" issue, as the lower trusted participant goes first with signature announcement. The timevalue waste risk can be controlled by inspecting the channel fees cost of the lower trusted participant. In lack of directly connected channels or public channels, the liquidity available can be strictly bounded. Indeed, we don't have a good solution to reputation bootstrap in Lightning, an issue also encountered in solving jamming issues.

If we're concerned about centralization vectors brought by LSP enforcing their risk-management policies, another solution could be a premium fee paid by the last tx_signatures announcer, which I think is done with flows of PeerSwap. This works well in 2-party setup, far less in multi-party ones.

All that said, I think the subject of transaction signature exchange is better left outside the scope of this v0.1 of the interactive transaction construction protocol, the ordering of signature could be left floating for now. We can add new BOLT extensions as we're learning the optimal risk management strategy in face of griefing/miner harvesting attacks.

ariard avatar Nov 08 '22 01:11 ariard

It could be argued a fair coin toss protocol deciding randomly who among the set of participants should release its tx_signatures could be more robust against that type of attack.

That's true, but that would clearly break any attempts at batching transactions if the ordering is randomized...for more than 2 participants, that may still be the best solution and we may have to accept the fact that we cannot guarantee support for batching.

All that said, I think the subject of transaction signature exchange is better left outside the scope of this v0.1 of the interactive transaction construction protocol, the ordering of signature could be left floating for now.

I don't think we can, otherwise what we'll see in practice is that channel open attempts will deadlock because each peer is waiting for the other to start. I think we have to decide a deterministic ordering for channel open v2, but I agree we can then revisit it later to change the ordering if we find a more satisfying solution.

t-bast avatar Nov 08 '22 07:11 t-bast

I don't think we can, otherwise what we'll see in practice is that channel open attempts will deadlock because each peer is waiting for the other to start. I think we have to decide a deterministic ordering for channel open v2, but I agree we can then revisit it later to change the ordering if we find a more satisfying solution.

Just to clarify, I think I aimed to say you need for sure a deterministic ordering based on "opener-first" or "most sats goes last", though we should let the party at advantage to be free to broadcast earlier if you're okay to bear the risk as a per-implementation/operator policy. E.g opener-first, if you're acceptor you can release your signature earlier than expected or "most sats goes last" higher stakers can go first (opener MUST release signature first, acceptor MAY release signature second). An operator should have flexibility to take more risks, if it allows to construct dual-funding/batching with more users, I think. I agree we have to decide on one way or other for a deterministic ordering. at least for channel open v2.

ariard avatar Nov 17 '22 02:11 ariard

Just to clarify, I think I aimed to say you need for sure a deterministic ordering based on "opener-first" or "most sats goes last", though we should let the party at advantage to be free to broadcast earlier if you're okay to bear the risk as a per-implementation/operator policy.

Right, we 100% agree then!

t-bast avatar Nov 17 '22 13:11 t-bast

@morehouse we discussed the ordering of tx_signatures during yesterday's spec meeting, and @cdecker, @niftynei and @rustyrussell proposed a very good strategy to protect against the liquidity griefing attack while preserving the smaller contributed amount goes first rule (and thus enabling batching by default). Their idea is to simply reuse the same utxos in every dual funding attempt, until you get a funding attempt that is fully signed.

Imagine that we are Alice in the following scenario:

  • Bob initiates a dual funding attempt with us, where we add utxoA_1 and utxoA_2
  • We sign first and don't receive Bob's signatures
  • Carol initiates a dual funding attempt with us: we add the same utxos utxoA_1 and utxoA_2
  • We sign first and don't receive Carol's signatures
  • Dave initiates a dual funding attempt with us: we add the same utxos again
  • Dave sends us signatures, so we broadcast our funding tx with Dave which automatically invalidates the malicious funding attempts with Bob and Carol
  • We also mark utxoA_1 and utxoA_2 as locked/reserved to stop adding them to future dual funding attempts

What's interesting with this strategy is that you don't have to actively decide whether your remote is malicious and didn't send their signatures: the first honest channel will automatically clean up the dishonest attempts.

The only issue with this proposal is that if you have multiple honest interactive-tx sessions happening at exactly the same time, you will use the same utxo(s) for all of them and only one will result in a channel being opened. However, the time window where that can happen is in the range of seconds: in practice you probably won't often open multiple channels per second, and even if you do, it's always possible to retry the funding attempt after noticing that the funding tx was double-spent. You can also use a pool of unlocked utxos instead of always reusing the previous ones, which avoids this issue in most cases (but means you reveal more of your utxos to a potential attacker).

From an implementation's perspective, that is trivial to implement: you simply don't lock/reserve utxos added to dual funding attempts until you get valid remote signatures. With this strategy, we don't even need to add a require_confirmed_inputs tlv to override the default ordering (as proposed in https://github.com/niftynei/lightning-rfc/pull/9) which keeps the proposal simple. WDYT?

t-bast avatar Nov 22 '22 09:11 t-bast

From an implementation's perspective, that is trivial to implement: you simply don't lock/reserve utxos added to dual funding attempts until you get valid remote signatures.

Cool, simple enough. I think this is good enough for now.

Should we mention this recommendation in the spec?

morehouse avatar Nov 23 '22 15:11 morehouse

Should we mention this recommendation in the spec?

Definitely, that's an important recommendation for implementers (a SHOULD requirement somewhere with some details in one of the rationale sections).

t-bast avatar Nov 23 '22 15:11 t-bast

However, the time window where that can happen is in the range of seconds: in practice you probably won't often open multiple channels per second, and even if you do, it's always possible to retry the funding attempt after noticing that the funding tx was double-spent.

To re-echo the concern raised during the meeting the window slots still must be limited from a node's memory-management viewpoint. I think an adversary can still occupy all the "dual-funding" window slots offered by your node. If you don't have whitelisting of your peer connections, or at least rate-limiting, I think an adversary can just "front-run" all your p2p connections to prevent a honest user to access a time window slot. Which lead me think not releasing a signature as an opener after few "grace" tries could be punished at the p2p layer by a disconnection. This way we defer the issue to the node p2p inbound connection strategy.

Another solution, we could request UTXO ownership signing as we're doing in BOLT7 to accept a new channel_announcement. Here you wouldn't accept to occupy a "time window" slot without such proof.

ariard avatar Nov 24 '22 01:11 ariard

To re-echo the concern raised during the meeting the window slots still must be limited from a node's memory-management viewpoint.

But that is completely independent of the signatures ordering, right? We need some form of DoS protection here regardless of who signs first? So we know we have to figure it out at some point, but we can start without it. The first version of dual funding in eclair won't have limits on the number of concurrent sessions, but that is something to keep in mind. Requiring a proof of something scarce (UTXO ownership) in open_channel2 would probably be a good way of solving this later.

t-bast avatar Nov 24 '22 08:11 t-bast

But that is completely independent of the signatures ordering, right? We need some form of DoS protection here regardless of who signs first? So we know we have to figure it out at some point, but we can start without it. The first version of dual funding in eclair won't have limits on the number of concurrent sessions, but that is something to keep in mind.

Agree this is independent of the signatures ordering, and I think peer connection rate-limits is something all implementations need to keep in mind, beyond the dual-funding case.

ariard avatar Dec 01 '22 01:12 ariard

Ok, I added fixes for things as noted.

Most controversially, tx_add_input now requires the sender to specify the est_witness_weight for each input that they send. This changes it from being an assumed minimum value of 107 weight units.

Also added the second-commitment-point to open_channel2; note that we can't change the channel_ready message as it's written though to remove the now duplicated commitment point transmission, as it's currently being used by v1 opens.

We could introduce a new message without the field. Or not change it. Open to suggestions.

niftynei avatar Dec 16 '22 20:12 niftynei

Most controversially, tx_add_input now requires the sender to specify the est_witness_weight for each input that they send. This changes it from being an assumed minimum value of 107 weight units.

Is it useful though? If your peer tells you their witness will be 30 WU, it passes the fee check, and then they send a 300 WU witness, having this est_witness_weight didn't provide any meaningful value, did it?

It feels to me that we should just remove est_witness_weight and use a witness weight of 0 when computing the minimum weight of the transaction and its minimum required fee, because we can't really do better. Or am I missing something?

t-bast avatar Dec 19 '22 14:12 t-bast

It feels to me that we should just remove est_witness_weight and use a witness weight of 0 when computing the minimum weight of the transaction and its minimum required fee, because we can't really do better.

I agree here. Also, it's not clear to me what action we should take if there is a large discrepancy between est_witness_weight and the actual weight we receive.

dunxen avatar Dec 22 '22 20:12 dunxen