lightningnetwork / lnd

Lightning Network Daemon ⚡️
MIT License
7.64k stars 2.08k forks source link

Feature: Liquidity ads (lightning native dual funded channels) #6569

Open zerofeerouting opened 2 years ago

zerofeerouting commented 2 years ago

Background

As per the proposed BOLT specification by @niftynei (https://github.com/lightning/bolts/pull/878), there is a way to allow for dual funded channels natively without having to run additional and implementation specific software on top.

The feature is already implemented and rolled out in CLN. ACINQ is currently implementing it for eclair if I understand correctly.

It would be great if the most common lightning implementation would support this feature as well.

There is a feature bounty for this, which I will match up to 10,000,000 sats:
https://btcpay.zerofeerouting.com/apps/6RNpv94dQvWV3n65Fze2xrubbAm/crowdfund

I really hope this feature will be implemented, should make lightning more robust and less dependend on centralized points of failure.

Roasbeef commented 2 years ago

A would-be implementor should first become intimately familiar with the existing dual funding flow in the internal wallet, which was implemented in 2015 or so: https://github.com/lightningnetwork/lnd/blob/7106ea59db9ade78d65bb46605f94637900c0e3f/lnwallet/test/test_interface.go#L444-L655. One will also likely want to look at the history of the reservation system, and how the single funder flow was added after the initial dual funding reservations (see the single prefix/suffix on some of the new methods).

zerofeerouting commented 2 years ago

Cool! Thank you for the feedback and the pointers!

Darth-Coin commented 2 years ago

I would like to add something in regards to this proposal.

Add also a feature that will lock that channel for a specific CLTV time (agreed by parties) and could not be force closed until at least that block height agreed.

It is useless and painful to have a channel contract to open a dual funded channel that after 1-2 days got forced closed, for various reasons, that users cannot control.

All these force closing channels that happen lately in mass are totally wrong and make unusable LN. In the last 10 days I got 20 channels forced closed. Why? Because somehow on the path the HTLCs got stuck and I am the one penalized for no reason. I am not the one that had the node offline or not forwarding the payment.

Some channels I paid for them and now I got them forced closed. This have to be addressed somehow.

C-Otto commented 2 years ago

Because somehow on the path the HTLCs got stuck and I am the one penalized for no reason. I am not the one that had the node offline or not forwarding the payment.

In this case your node force-closed the channels. If you don't want this to happen, you could tweak your own code - with the risk that the "offline" counter party steals the funds in said HTLCs. There's a reason why unilateral closes happen automatically, and I'm pretty sure you're not the only node operator who hates it when it happens.

That being said, delaying/disallowing unilateral channel closes is a very bad idea. They are required in certain situations, and aside from bugs there are plenty of situations where the one who issues the close needs to mitigate some kind of risk.

Darth-Coin commented 2 years ago

Opening a channel is a contract. A contract must have a grace period. Right now users can't set a specific time, agreed between them, until when the channel is open. The CLTV is used only as a punishment or dispute time, but is NOT the time of the contract. So is useless to have a contract that I don't know when will be void or canceled.

So if you have a renting contract for a house, but the owner will not put any term until you could stay in that house. Then once you paid the rent for the first 3 months, the owner come and kick you out, because the contract doesn't have any term. How is that a bad idea disallowing the owner to kick you out now ?

C-Otto commented 2 years ago

Contracts usually require trust, either in the other party, or some higher entity. In situations where one node issues a unilateral close automatically, there's some kind of dispute (most likely because one party is offline). The blockchain is the higher entity that settles the dispute. I don't see how this can be fixed, as it's at the core of how the LN works.

Your example lacks the reason for the owner kicking you out. If it's the equivalent of a manual "lncli closechannel --force": sure, that's bad. But what if you (the renter) didn't pay rent, or your check bounced, or you're about to destroy the house?

I'd say we shouldn't have this discussion in here, as it's an underlying problem (property?) of the LN.

zerofeerouting commented 2 years ago

@Darth-Coin - that can't work. There always is a reason for automated force-closes, usually to safe one (or both) peer's funds. Prohibiting this will put the peer that can't force-close at a disadvantage.

A channel where both peers want the channel to be force-closed, that can't be force-closed due to some agreement is just dead weight, since both parties would just disable it.

Darth-Coin commented 2 years ago

Then create a special signature that both parties have to sign after agree to close that channel before the time.

zerofeerouting commented 2 years ago

You're derailing this issue with something unrelated.

dni commented 2 years ago

is anyone seriously working on this issue?

morehouse commented 1 year ago

Hi folks. I've quit my day job and am interested in working on this.

@niftynei's spec for liquidity ads seems to be shelved until the dual funding spec is finalized and merged. I've left feedback on both specs. In particular, I think there's some major changes we should make to liquidity ads around how leases are enforced (CLTV seems simpler and cleaner than the current update_blockheight hack, and we can easily put timelocks on more branches in HTLCs).

Regardless, dual funding is what we need to implement first in LND, and the spec for that seems more mature. We should be able to implement experimental support for the current spec draft, and update as the spec is finalized. Later we can revisit how to best implement liquidity ads.

I'm currently working on an implementation plan for dual funding. I'll post some ideas here for feedback later this week.

zerofeerouting commented 1 year ago

@morehouse - very cool, that you're interested in doing this. Feel free to create a feature branch and / or ask questions here in the ticket. I am unaware of anyone else working on this at the moment.

The bounty raised by me is currently 0.104 BTC plus the 0.1 BTC I will personally give. (so 0.204 BTC as of now). I think we might be able to raise additional awareness if there is some progress. Would love to see liquidity ads happening!

morehouse commented 1 year ago

I'm still working through the implementation/testing details, but here's some ideas I have so far. Feedback is appreciated.

Funding Manager

The funding manager needs to handle all the new messages from 02-peer-protocol.md in https://github.com/lightning/bolts/pull/851.

open_channel2 / accept_channel2

These are very similar to open_channel and accept_channel, except that the acceptor can contribute funds too.

When we are the acceptor, it is simple to create an lnwallet.InitFundingReserveMsg with both local and remote funding amounts.

But when we're the opener, we don't know what the peer will contribute until they send accept_channel2. So we can't provide the exact remote funding amount in InitFundingReserveMsg. Instead, we can give an estimate based on a minimum amount required by the user. For example, the CLI could be:

$ lncli dualfundchannel node-key local-amt min-remote-amt [max-remote-amt]

We then use min-remote-amt in the InitFundingReserveMsg to validate local/remote balances, dust limits, etc. and to choose the required to_self, max_htlc_value_in_flight_msat, etc.

Once we get an accept_channel2 back, we verify that the remote's funding amount is within our required range, update the reservation to the exact remote funding amount and revalidate. Note that we don't get to tweak our to_self, max_htlc_value_in_flight_msat or other parameters after this, which is a limitation of the protocol.

At this point, we can't call reservation.ProcessContribution yet, as we don't have the remote's inputs/outputs. So we'll save a partially constructed remoteContribution in the reservation context.

Interactive Tx Construction

This entails the new tx_add_input, tx_add_output, tx_remove_input, tx_remove_output, and tx_complete messages.

Since the wallet has already reserved our inputs and change outputs, and we know how to construct the funding output, the state machine for this interaction is fairly simple. We'll ping-pong with the peer, first sending our inputs one by one, then our outputs, then the funding output if we're the opener. For each message from the peer, we'll validate and add/remove the input/output given.

When we have sent and received a tx_complete in succession, we can finish constructing the remoteContribution and call reservation.ProcessContribution.

Signature Exchange

This is the tricky part.

We need to first exchange commitment_signed and then tx_signatures. After we have sent our tx_signatures, the peer could broadcast the funding transaction at any point, so we need to persist the channel in the DB before sending tx_signatures. If we don't have the peer's tx_signatures yet at that point, we can't just call reservation.CompleteReservation and be done, since it will fail to validate the funding transaction.

We'll need to break apart CompleteReservation into different parts:

commitment_signed

After calling ProcessContribution, we can immediately send our commitment_signed.

When we get the peer's commitment_signed, we'll call reservation.AddCommitmentSig.

tx_signatures

If it is our job to send tx_signatures first, we'll call reservation.SaveChannel and then send tx_signatures. Otherwise, we'll wait for the peer's tx_signatures.

Once we get the peer's tx_signatures, we'll call reservation.AddFundingTxSigs. If we haven't sent our tx_signatures, we'll do reservation.SaveChannel and send them. Otherwise we might need to update the saved channel in the DB now that we have funding tx sigs (or maybe we can rely on retransmission of tx_signatures on restart as currently suggested on the spec).

At this point, we can broadcast the funding transaction.

morehouse commented 1 year ago

Handling Failures

Before we sent tx_signatures

We simply remove any wallet reservation and related context, sending an error as a courtesy. We can use failFundingFlow for this.

After we sent tx_signatures

We must keep the OpenChannel in the DB and monitor the blockchain until an input is double spent. We can remove the wallet reservation and related context to allow our inputs to be productively double spent in another transaction, but we don't need to proactively double-spend (and incur fees) as long as we keep monitoring the pending channel.

We can monitor for double spends in a new method advancePendingDualChannelState patterned after advancePendingChannelState. In addition to watching for the funding txid onchain, it will also watch for double spends of any input in the funding tx. If the funding tx confirms, we will advance the funding state as usual. If an input is double spent, we will remove the pending channel from the DB and exit the current (monitoring) goroutine.

Handling Disconnects

Before we sent tx_signatures

On restart, we automatically forget the reservation and related context. If the peer disconnected and lost state without sending us an error, the current zombie cleanup loop will remove our reservation context after a timeout.

After we sent tx_signatures

On restart, we load the pending OpenChannel from the DB. Based on a recent update to the spec, we'll need to resend tx_signatures . To do this, we can add a new TLV to the DB record that contains a list of input indexes signed by us. This will allow us to extract our tx_signatures from the stored FundingTx and resend them. If our stored FundingTx also has signatures from our peer, we can rebroadcast it immediately. Otherwise we wait for the peer to (re)send their tx_signatures. Since we've already sent our tx_signatures, we need to spawn a advanceFundingState goroutine to monitor the onchain state even if we don't have a fully signed FundingTx to broadcast.

To help a disconnected peer get our tx_signatures when they come back online, we can always send tx_signatures in a waitForPeerOnline loop, as we currently do for funding_locked.

morehouse commented 1 year ago

RBF

We should support RBF replacement of pending channels until they confirm. This feature is not necessary for the MVP, but thinking about it now may influence other aspects of the design.

CLI

$ lncli feebumpchannel chan-id local-amt min-remote-amt [max-remote-amt]

Tracking in-flight channels

We'll maintain an inFlightChannels map[chanID][]*OpenChannel in the funding manager, tracking all possible versions of a channel that could confirm. On restart, this map will be reconstructed from OpenChannels in the DB, and goroutines will be spawned to monitor the blockchain for each possible version.

tx_init_rbf / tx_ack_rbf

When handling these messages, nearly all channel parameters are reused from the original open_channel2 / accept_channel2. We can put most functionality for this in a new wallet method InitRbfReservation(inFlightChannels, LocalAmt, RemoteAmt) (see below).

If the peer sends us a new contribution amount that doesn't fit in our min-max range, we abort the RBF attempt.

DB changes

We need to keep track of the funding feerate for each RBF attempt, so we can ensure we're bumping it by at least 25/24 each time. We'll add a field for this to OpenChannel and serialize it as a TLV in the DB.

Wallet

Since the interactive-tx protocol is more granular than the v1 protocol, it makes sense to break down the wallet / reservation API into smaller functions. As a secondary benefit, we may be able to share more code between the single/dual funding flows.

Note that my thinking here as evolved over the past couple weeks, so the design here doesn't match 100% with what's described in the Funding Manager section above.

Current Flow

v1 Opener

  1. lnwallet.InitChannelReservation
  2. reservation.SetOurUpfrontShutdown
  3. reservation.SetNumConfsRequired
  4. reservation.CommitConstraints
  5. reservation.ProcessContribution
  6. reservation.CompleteReservation

v1 Acceptor

  1. lnwallet.InitChannelReservation
  2. reservation.SetNumConfsRequired
  3. reservation.CommitConstraints
  4. reservation.SetOurUpfrontShutdown
  5. reservation.ProcessSingleContribution
  6. reservation.CompleteReservationSingle

New Flow

v2 Opener

  1. lnwallet.InitChannelReservation - Same as before, plus takes an estimated or actual RemoteFundingAmt and runs the usual checks. Handles an UpfrontShutdown script as well.
  2. reservation.UpdateRemoteFundingAmt - Updates the remote funding amount to the actual value specified in accept_channel2, and reruns affected checks.
  3. reservation.ProcessChannelParams - Takes a ChannelConstraints, a ChannelContribution, and NumConfsRequired, validates them and stores their values in the reservation. Does not attempt to construct the funding tx.
  4. reservation.ProcessContribution - Takes the remote's inputs/outputs, compiles and signs the funding tx, and compiles and signs the commitment tx.
  5. reservation.ProcessCommitmentSig - Verifies and saves the remote's commitment sig.
  6. reservation.SaveChannel - Stores the pending OpenChannel in the DB and returns it.
  7. reservation.ProcessTxSigs - Verifies and stores the remote's funding tx sigs.
  8. reservation.Complete - Removes any references to the reservation from the wallet.

v2 Acceptor

  1. lnwallet.InitChannelReservation - uses the actual RemoteFundingAmt specified in open_channel2.
  2. reservation.ProcessChannelParams
  3. reservation.ProcessContribution
  4. reservation.ProcessCommitmentSig
  5. reservation.ProcessTxSigs
  6. reservation.SaveChannel
  7. reservation.Complete

v1 Opener

  1. lnwallet.InitChannelReservation
  2. reservation.ProcessChannelParams
  3. reservation.ProcessContribution - uses empty inputs/outputs since remote doesn't contribute
  4. reservation.ProcessCommitmentSig
  5. reservation.SaveChannel
  6. reservation.Complete

v1 Acceptor

  1. lnwallet.InitChannelReservation
  2. reservation.ProcessChannelParams
  3. reservation.ProcessOutpoint - stores the outpoint specified in funding_created and compiles and signs the commitment tx
  4. reservation.ProcessCommitmentSig
  5. reservation.SaveChannel
  6. reservation.Complete

RBF Flow

Initiator

  1. lnwallet.InitRbfReservation - Takes a slice of in-flight OpenChannels, the LocalFundingAmt, and an estimated RemoteFundingAmt. Extracts the common channel parameters from the first OpenChannel, and initializes a reservation from them. Uses a new RbfChannelFunder to select inputs, preferring inputs already used for the in-flight OpenChannels.
  2. reservation.UpdateRemoteFundingAmt
  3. reservation.ProcessContribution
  4. reservation.ProcessCommitmentSig
  5. reservation.SaveChannel
  6. reservation.ProcessTxSigs
  7. reservation.Complete

Non-initiator

  1. lnwallet.InitRbfReservation - Uses the actual RemoteFundingAmt specified in tx_init_rbf.
  2. reservation.ProcessContribution
  3. reservation.ProcessCommitmentSig
  4. reservation.ProcessTxSigs
  5. reservation.SaveChannel
  6. reservation.Complete
morehouse commented 1 year ago

Misc

Dual Funding Policies

I propose the following initial (experimental) config parameters for handling dual funding requests:

ChannelAcceptor

Initial MVP

The channel acceptor will need to handle the new lnwire.OpenChannel2 message in addition to lnwire.OpenChannel. We can add a new DualAccept to the interface for this, and a new DualChannelAcceptRequest type to hold the OpenChannel2.

For RPCAcceptor, we can pipe the v2 channel data into the existing lnrpc.ChannelAcceptRequest, dropping the new fields (locktime and funding feerate). This way we can avoid changing the RPCAcceptor protobuf interface while dual funding is considered experimental.

End goal

Besides full RPCAcceptor support for the new OpenChannel2 fields, we may also want the ability to specify a local funding amount in the ChannelAcceptResponse. This would allow the user to write their own logic for handling dual funding requests. However, this doesn't work well for RBF attempts that change the funding amount, since we'll be missing the other OpenChannel2 fields. Perhaps a new ChannelAcceptor.RbfAccept interface method would be useful.

Marking Dual Funding Experimental

I don't think it makes sense to create an entire RPC sub-server for dual funding, but I didn't see any other examples in the codebase of separating code as experimental. Is an "EXPERIMENTAL" warning in the documentation all we need here?

morehouse commented 1 year ago

Implementation & Testing Plan

To simplify code review, I propose we break the implementation into 5 major PRs:

  1. Open & Accept v2
  2. Interactive Tx Construction
  3. Signature Exchange
  4. CLI / RPCs, itests, docs
  5. RBF

Open & Accept v2

Implement support for open_channel2 and accept_channel2. This includes wire support, funding manager logic, some refactoring of the LightningWallet flow, and some ChannelAcceptor refactoring for v2.

We'll have fuzz tests for the new wire messages and unit tests for other things. I will also manually test for interop with CLN and eclair.

Interactive Tx Construction

Implement support for cooperatively constructing the funding tx with the peer. This includes wire support for tx_[add|remove]_[input|output], tx_complete, and tx_abort; funding manager logic and state machine; and likely some LightningWallet work to handle serial_ids.

We'll have fuzz tests for the new wire messages and unit tests for other things. I will also manually test for interop with CLN and eclair.

Signature Exchange

Implement support for exchanging commitment and funding tx signatures. This includes wire support for tx_signatuers, funding manager logic for the exchanges and monitoring pending channel state afterward, refactoring the LightningWallet flow, updating OpenChannel DB serialization to encode a list of funding tx inputs we signed, and modifying htlcswitch.channelLink to retransmit tx_signatures when necessary.

Testing will be the same as previous PRs, with an emphasis on handling disconnects and other failures after sending tx_signatures.

CLI / RPCs, itests, docs

Implement the CLI, RPCs, and configuration necessary for the client to dual fund channels. Implement e2e itests using the new RPCs. Document the new experimental configuration and APIs. Reject any RBF attempts for now.

RBF

Implement support for RBFing funding txs. Includes wire support for tx_[init|ack]_rbf, the new LightningWallet.InitRbfReservation method, a new RbfChanFunder to be used by LightningWallet, funding manager logic for juggling multiple RBF attempts, updating OpenChannel DB serialization to encode FundingFeeRate, a new CLI/RPC command to initiate an RBF fee-bump, and itests for RBF.

Next Steps

I'm ready to start implementation. I'll refer back to this design in future PRs and do my best to ease the code review process. If there's any major concerns about anything above, please chime in now before I go too far in the wrong direction.

Roasbeef commented 1 year ago

Hey @morehouse, thx for jotting down your thoughts/planned here before jumping into the implementation. Just catching up with this a bit now, but thought I'd drop a few comments here to help nudge you in the direction.

I think one thing you should keep in mind, is that a lot of the funding/reservation code is super old in terms of lnd's lifetime. Files like lnwallet/reservation.go and lnwallet/wallet.go were amongst the very first files to be committed to the lnd wallet (initial milestone was getting our version fo dual funding working back then). As a result, I think we either need to commit early on to do aggressively refactoring, or chose to explicitly leave it out of the set of planned work.

One other thing to keep in mind, is that a mega PR implementing everything in one swoop will be very difficult to review, and will likely just sit in review limbo. As a result, I recommend that you try to chop things up into small pieces when possbile. In addition, there're a few other funding related issue or PRs in the tracker. Helping to address some of the these issues, or help in PR review before creating a very large change will serve to help to give your work weight from the PoV of existing contributors. As always in an open source project, everyone wants to have their pet feature merged, but they don't want to help to review PRs (just take a look at the 138 open PRs we have today).

With that said, some in line comments follow.

open_channel2 / accept_channel2 Once we get an accept_channel2 back, we verify that the remote's funding amount is within our required range, update the reservation to the exact remote funding amount and revalidate.

How will the code determine what the "required" range is on the accepting side? One thing about single funder is that you can kinda jsut accept w/e as long as it doesn't create a crazy imbalance. Do you have any ideas on how you'd want to expose this to the responder? Today we have the channel acceptor itself, which can be a fine spot for this, as then it would mean that any dual funding request must be manually approved. IMO this is how it should be, since dual funding means that you need to commit funds instead of just the other party. If it becomes auto accept, then users could find themselves in a situation where all the funds they had on chain to open to oether peers was instead sucked up by a few peers looking to connect out to the network.

I think one other relevant question here (which I don't think yet has a satifactory answer on the spec level is): how will we attempt to mitigate privacy leafs w.r.t UTXOs? In short, if I want to learn your wallet balance, i just make a series of dual funding requests, and bail out of all of them, collect all the utxos you sent over, rinse and repeat. I think this might be less of an issue if we make them hidden behind the channel acceptor, but I still think we want something here as otherwise this is perfect for any chainalysis like snoopers (trace the UTXOs going into and out of an lnd node).

Signature Exchange We'll need to break apart CompleteReservation into different parts:

I think we should hesitate to also break down the process into a smaller, more encapsulated state machine.

One thing I didn't see touched on above is the question of: UTXO validation. How would we handle the issue of a peer sending us an invalid or spent input? What if they spend the input after we broadcast the funding transaction? This can result in the wallet funds effectively being stuck, unless we do an explicit double spend. Related to the question of UTXO validation is also if the desired validation mechanism is actually light client compatible or not.

Re double spending our own inputs, this is a relevant PR that we'd likely want to wrap up before the main work here begins: https://github.com/lightningnetwork/lnd/pull/6400.

Dual Funding Policies

See above, I think the channel acceptor route might be preferable, since it lets users have a lot more granular control. AFAICT, these proposed config settings wouldn't be peer aware, so a single peer can repeatedly fund a channel to have all our funds allocated towards them.

morehouse commented 1 year ago

@Roasbeef: Thanks for your thoughts and advice.

As a result, I think we either need to commit early on to do aggressively refactoring, or chose to explicitly leave it out of the set of planned work.

Agreed. I think aggressive refactoring is going to be cleanest.

One other thing to keep in mind, is that a mega PR implementing everything in one swoop will be very difficult to review, and will likely just sit in review limbo. As a result, I recommend that you try to chop things up into small pieces when possbile.

As described above (Implementation & Testing Plan), we can easily break the work into 5 logical chunks. We can probably do even smaller PRs at the cost of losing context for some of the changes. But if we're aligned on the overall design, maybe we don't need as much context within the PRs.

In addition, there're a few other funding related issue or PRs in the tracker. Helping to address some of the these issues, or help in PR review before creating a very large change will serve to help to give your work weight from the PoV of existing contributors. As always in an open source project, everyone wants to have their pet feature merged, but they don't want to help to review PRs (just take a look at the 138 open PRs we have today).

I'll take a look and see what outstanding issues make sense to address during this work. And I should be some help with PRs now that I'm familiar with the funding flow.

How will the code determine what the "required" range is on the accepting side? One thing about single funder is that you can kinda jsut accept w/e as long as it doesn't create a crazy imbalance. Do you have any ideas on how you'd want to expose this to the responder? Today we have the channel acceptor itself, which can be a fine spot for this, as then it would mean that any dual funding request must be manually approved. IMO this is how it should be, since dual funding means that you need to commit funds instead of just the other party. If it becomes auto accept, then users could find themselves in a situation where all the funds they had on chain to open to oether peers was instead sucked up by a few peers looking to connect out to the network.

Right, I think full ChannelAcceptor support is the end goal here. I proposed the default-off dual_fund.match feature for initial testing and experimentation, which we could probably implement entirely as a ChannelAcceptor too. If we're concerned about naive users getting burned by the experimental matching feature, we could choose to expose it only via devrpc.

I think one other relevant question here (which I don't think yet has a satifactory answer on the spec level is): how will we attempt to mitigate privacy leafs w.r.t UTXOs? In short, if I want to learn your wallet balance, i just make a series of dual funding requests, and bail out of all of them, collect all the utxos you sent over, rinse and repeat. I think this might be less of an issue if we make them hidden behind the channel acceptor, but I still think we want something here as otherwise this is perfect for any chainalysis like snoopers (trace the UTXOs going into and out of an lnd node).

From the spec side, I believe the eventual answer is something like PoDLEs. PoDLEs were deemed too complex for the initial (current) spec, but will likely be needed to properly address the privacy issues you describe, along with some griefing issues.

I'd argue we should leave the privacy concerns to the ChannelAcceptor for now, where we can do things like only contribute funds for vetted nodes. Users that are dual funding regularly will have their UTXOs publicly known in short order anyway (if they aren't already). Lloyd Fournier expanded this line of reasoning here.

I think we should hesitate to also break down the process into a smaller, more encapsulated state machine.

What are your thoughts on my proposed funding flow in the Wallet section under New Flow?

One thing I didn't see touched on above is the question of: UTXO validation. How would we handle the issue of a peer sending us an invalid or spent input?

The spec dictates that the full prevtx is sent for each input. Thus we can validate by hashing the prevtx and checking the blockchain for the outpoint. This should be light client compatible using BtcWallet.GetUtxo and the pkScript extracted via btcd.

What if they spend the input after we broadcast the funding transaction? This can result in the wallet funds effectively being stuck, unless we do an explicit double spend.

We will monitor the blockchain for all funding transaction inputs until the transaction confirms or an input is double spent. When a double spend is detected, we release the lock on our UTXOs and (after the double spend has X confirmations) forget about the pending channel. This will allow us to spend the UTXOs at our leisure, without incurring extra fees.

See above, I think the channel acceptor route might be preferable, since it lets users have a lot more granular control. AFAICT, these proposed config settings wouldn't be peer aware, so a single peer can repeatedly fund a channel to have all our funds allocated towards them.

Agreed, let's build the logic into the channel acceptor.

zerofeerouting commented 3 months ago

Is anyone working on this? I still have the 10,140,920 sats I collected for this feature.

If nobody comes forward (i.e. being close to have this merged), I will donate the sats to HRF as originally indicated:

https://gist.github.com/zerofeerouting/53f12f329449357a353b9fcfe490b688

morehouse commented 3 months ago

@zerofeerouting I'm no longer working on this, though LL has expressed interest in dual funding if someone else wants to take over. I can assist with code reviews since I'm quite familiar with the spec.

bufo24 commented 3 months ago

I am interested in working on this. I just am getting started with working inside the LND codebase but love to use this project to get myself more engaged