Hey Matt,

Thanks for brainstorming this, that's an interesting variation of what
I proposed for option 1. It is indeed simpler for bookkeeping, but there
are still some additional complications to figure out.

Do you think this should support multiple concurrent leases? I think it
shouldn't because the additional complexity isn't worth it. Maybe buying
a new lease should simply override the existing one? That isn't entirely
trivial either, because while we're waiting for the splice transaction
that contains the new lease to confirm, we need to keep track of the old
lease as well on commitment transactions based on the previous funding
output.

What should we do when the lease ends? The seller doesn't want to keep
the additional output, because it's costly for them if they need to
force-close. But how do we synchronize to update the commit tx, since
nodes may not be at exactly the same block height? We'll need to
introduce a new message for that and negotiate a quiescence session.

Also, if the seller splices in, do you agree that the amount should go
to their unencumbered output?

I've been prototyping the proposal I made previously, and I'm not very
satisfied with it. It's a lot of additional complexity that interacts
with many parts of the codebase (e.g. splicing, force-close management,
channel reserve), mostly linked to the addition of a new output to the
commitment transaction.

I'm less and less convinced that we should go down that road: sellers
will always have ways of being dishonest (by not relaying HTLCs, force
closing regardless of the CLTV, or getting back some of their funds
through pending HTLCs). I'm afraid we'll be adding a lot of complexity
to the protocol (which in practice, means compatibility bugs and force
closes) without much benefit. It would be a whole lot simpler to not
add any CLTV on the seller side. Sure, they can still take their funds
out whenever they want, but that will be reflected in the price. And if
you're an interesting buyer that generates routing activity, they'll
keep that liquidity around (most likely longer than the lease you were
ready to pay for). That better matches the dynamics of how people want
to allocate their liquidity efficiently. And if you pay for liquidity
and don't get it long enough, then it's fine, just don't buy from that
node again, you only lost a small amount in that process!

I know this is controversial, but I think it's hard to appreciate the
additional complexity that these new CLTV-based outputs add. We need
more code that implements this thoroughly (on top of an implementation
that supports splicing) to have informed opinions on whether this
additional complexity really makes sense.

Cheers,
Bastien

Le ven. 8 déc. 2023 à 23:32, Matt Morehouse <mattmoreho...@gmail.com> a
écrit :

> Unless I'm missing something, we can make option 2 work with CLTV
> enforcement as well.  In fact, I think that makes the bookkeeping much
> simpler.
>
> Suppose the leased amount is X.  No counters are needed.  All we need
> is to ensure the seller's first X sats in the commitment are always
> encumbered by the CLTV.  Anything above X can go to a second output
> that's unencumbered.  That's it.
>
> Here's an example.  Alice leases 10k sats from Bob and also puts up
> 10k sats to make the channel balanced.  The initial commitment
> transaction looks like this:
>
> Alice: 10k sats
> Bob: 10k sats with CLTV
>
> Bob offers a 2k sats HTLC1 to Alice.  The commitment becomes:
>
> Alice: 10k sats
> Bob: 8k sats with CLTV
> HTLC1: 2k sats
>
> HTLC1 is fulfilled:
>
> Alice: 12k sats
> Bob: 8k sats with CLTV
>
> Alice offers a 4k sats HTLC2 to Bob:
>
> Alice: 8k sats
> Bob: 8k sats with CLTV
> HTLC2: 4k sats
>
> HTLC2 is fulfilled.  Since Bob now has a total balance greater than
> 10k sats, the excess goes to an unencumbered output:
>
> Alice: 8k sats
> Bob: 10k sats with CLTV
> Bob: 2k sats
>
> Bob offers a 1k sats HTLC3 to Alice.  The sats always come out of
> Bob's unencumbered output first:
>
> Alice: 8k sats
> Bob: 10k sats with CLTV
> Bob: 1k sats
> HTLC3: 1k sats
>
> Bob offers a 3k sats HTLC4 to Alice.  The sats always come out of
> Bob's unencumbered output first.  The remaining sats come out of the
> encumbered output:
>
> Alice: 8k sats
> Bob: 8k sats with CLTV
> HTLC3: 1k sats
> HTLC4: 3k sats
>
> HTLC3 is fulfilled and HTLC4 is failed.  Bob's total balance will
> increase to 11k sats, so the first 10k sats are encumbered and the
> last 1k are unencumbered:
>
> Alice: 9k sats
> Bob: 10k sats with CLTV
> Bob: 1k sats
>
>
> Alice can never lock up more than 10k sats on Bob's side, since that
> was the agreed lease amount.  Bob can still play games with circular
> routing or force closing with HTLCs outstanding to unlock some of his
> liquidity early, but that is also the case with every other proposal
> so far.  Hence the importance of limiting HTLC value in flight.
>
>
> On Fri, Dec 8, 2023 at 3:48 PM Bastien TEINTURIER <bast...@acinq.fr>
> wrote:
> >
> > Hey all,
> >
> > I'd like to detail a bit more my statement from the last email.
> >
> > > I personally think it has to be the first option, because the second
> > > one exposes the seller to griefing
> >
> > That is my current conclusion *if we want to provide some kind of lease
> > enforcement via CLTV*, and we want to ensure it protects both the buyer
> > and the seller equally.
> >
> > But we can look at it from a different angle: if what people want to
> > buy is option 2, then we should find a way to make option 2 work. In
> > my opinion, option 2 would be best without any CLTV enforcement of the
> > lease, and relying only on incentives (and thus letting the buyer take
> > the risk that the seller splices out or force-closes).
> >
> > But maybe then it doesn't even make sense to have lease durations? Maybe
> > we only need to provide a feature to buy X amount of inbound liquidity
> > now, and let the seller decide whether they want to keep that liquidity
> > available for a long time or move it elsewhere.
> >
> > Cheers,
> > Bastien
> >
> > Le ven. 8 déc. 2023 à 09:00, Bastien TEINTURIER <bast...@acinq.fr> a
> écrit :
> >>
> >> Hey Matt,
> >>
> >> > The question then is really: do operators want to buy/sell X sats of
> >> > inbound flow or Y days of an open channel with an initial inbound
> >> > balance of X sats?
> >>
> >> Agreed, this is what we need to decide. I personally think it has to be
> >> the first option, because the second one exposes the seller to griefing
> >> by the attack described in my first email, which makes it impossible for
> >> the seller to find the right price for that channel because they don't
> >> know how much liquidity will actually end up being locked.
> >>
> >> But that's definitely up for debate if people feel otherwise!
> >>
> >> Thanks,
> >> Bastien
> >>
> >> Le jeu. 7 déc. 2023 à 22:18, Matt Morehouse <mattmoreho...@gmail.com>
> a écrit :
> >>>
> >>> On Mon, Dec 4, 2023 at 9:48 AM Bastien TEINTURIER <bast...@acinq.fr>
> wrote:
> >>> >
> >>> > But I've thought about it more, and the following strategy may work:
> >>> >
> >>> > - store three counters for the seller's funds:
> >>> >   - `to_local`: seller's funds that are not leased
> >>> >   - `to_local_leased`: seller's funds that are leased
> >>> >   - `to_local_leased_owed`: similar to `to_local_leased`, without
> taking
> >>> >     into account pending HTLCs sent by the seller
> >>> > - when the seller sends HTLCs:
> >>> >   - deduce the HTLC amounts from `to_local_leased` first
> >>> >   - when `to_local_leased` reaches `0 sat`, deduce from `to_local`
> >>> >   - keep `to_local_leased_owed` unchanged
> >>> > - when HTLCs sent by the seller are fulfilled:
> >>> >   - deduce the HTLC amounts from `to_local_leased_owed`
> >>> > - when HTLCs sent by the seller are failed:
> >>> >   - add the corresponding amount to `to_local_leased` first
> >>> >   - once `to_local_leased = to_local_leased_owed`, add the remaining
> >>> >     amount to `to_local`
> >>> > - when creating commitment transactions:
> >>> >   - if `to_local_leased` is greater than dust, create a corresponding
> >>> >     output with a CLTV matching the lease
> >>> >   - if `to_local` is greater than dust, create a corresponding output
> >>> >     without any CLTV lease
> >>>
> >>> Neat idea.  This changes the meaning of liquidity ads slightly -- the
> >>> liquidity is only leased for the one-way trip, and any channel balance
> >>> that comes back to the seller is not encumbered.  In other words,
> >>> instead of the channel itself being leased, only the initial inbound
> >>> liquidity is.  Once the cumulative flow to the buyer meets the leased
> >>> amount, the seller can reclaim any balance on their side without
> >>> penalty.  Of course if there's enough bidirectional flow happening,
> >>> the seller may choose to keep the channel open to earn more fees.
> >>>
> >>> The question then is really: do operators want to buy/sell X sats of
> >>> inbound flow or Y days of an open channel with an initial inbound
> >>> balance of X sats?
> >>>
> >>> >
> >>> > This computation must occur when sending/receiving `commit_sig`. The
> >>> > order in which we evaluate those updates matters: we must start with
> >>> > the `update_fulfill_htlc` updates before the `update_fail_htlc` ones,
> >>> > because we need to start by updating `to_local_leased_owed`. I
> believe
> >>> > that works, but it needs more analysis. Please try to break it, and
> let
> >>> > me know what you find!
> >>>
> >>> On first look, I think this works.  I'll study it closer if we decide
> >>> this is the direction we want to go.
> >>>
> >>> >
> >>> > We also need to handle concurrent leases. We want to support the
> >>> > following scenario:
> >>> >
> >>> > - Alice buys 10k sats from Bob for one month
> >>> > - 1 week later, the on-chain fees are very low: Alice buys 50k sats
> >>> >   from Bob for 6 months
> >>> > - 1 more week later, she buys 10k sats from Bob for one week
> >>> >
> >>> > We thus have three concurrent leases, with overlapping lease
> durations.
> >>> > That's costly for the channel initiator, because we must add three
> new
> >>> > outputs to the commitment transactions. But that part should be ok,
> the
> >>> > seller should price that in its decision to fund the lease or not.
> >>> >
> >>> > I think we would need to have three `to_local_leased_owed` buckets,
> one
> >>> > per lease. How do we order them, to decide from which bucket we take
> >>> > funds first? I think the option that makes the most sense is to order
> >>> > them by lease expiry (not by lease start or lease amount, which could
> >>> > be unfair to the buyer).
> >>> >
> >>> > Would that create scenarios where one side can cheat? Are there
> issues
> >>> > with channel reserve because of the increased commit tx weight?
> >>> >
> >>> > Cheers,
> >>> > Bastien
> >>> >
> >>> > Le sam. 2 déc. 2023 à 03:23, ZmnSCPxj <zmnsc...@protonmail.com> a
> écrit :
> >>> >>
> >>> >> Halfway through, I thought "is it not possible to have two
> Bob-owned outputs that sum up to the total Bob-owned amount, with a CLTV on
> up to the amount that was purchased and the rest (if above dust limit)
> without a CLTV?"
> >>> >>
> >>> >> so e.g. if the purchased amount is 2 units but the total channel
> capacity is 12 units:
> >>> >>
> >>> >> * Bob owns 0 units: no Bob outputs
> >>> >> * Bob owns 1 unit: Bob has a CLTV-encumbered output of 1 unit
> >>> >> * Bob owns 2 units: Bob has a CLTV-encumbered output of 2 units
> >>> >> * Bob owns 3 units (assuming 1 unit is above dust limit):  Bob has:
> >>> >>   * A CLTV-encumbered output of 2 units
> >>> >>   * An ordinary output of 1 unit
> >>> >> * etc.
> >>> >>
> >>> >> This locks up only the agreed-upon amount but lets Bob keep any
> amount above the rest.
> >>> >>
> >>> >> Alternately, only allow CLTV-locking if the buyer is not providing
> its own funds (i.e. pure inbound purchase).
> >>> >> This is still effectively my original idea as then any funds Alice
> wants to add would be in a separate, unencumbered channel.
> >>> >>
> >>> >> Regards,
> >>> >> ZmnSCPxj
> >>> >>
> >>> >>
> >>> >> Sent with Proton Mail secure email.
> >>> >>
> >>> >> On Friday, December 1st, 2023 at 5:45 PM, Bastien TEINTURIER <
> bast...@acinq.fr> wrote:
> >>> >>
> >>> >>
> >>> >> > Good morning list,
> >>> >> >
> >>> >> > I've been thinking a lot about liquidity ads recently, and I want
> to
> >>> >> > highlight some subtleties that should be taken into account in the
> >>> >> > protocol design. This is a rather long post, but I believe this is
> >>> >> > important to make sure we get it right and strike the right
> balance
> >>> >> > between protocol complexity and incentives design. Strap in, grab
> a
> >>> >> > coffee, and enjoy the ride.
> >>> >> >
> >>> >> > First of all, it's important to understand exactly what you are
> buying
> >>> >> > when paying for a liquidity ad. There are two dimensions here: an
> amount
> >>> >> > and a duration. If Alice buys 100 000 sats of inbound liquidity
> from Bob
> >>> >> > for one month, what exactly does that mean? Obviously, it means
> that Bob
> >>> >> > will immediately add 100 000 sats (or more) to his side of the
> channel,
> >>> >> > and Alice will pay a fee proportional to that amount *and* that
> duration
> >>> >> > (because locking funds for one month should cost more than
> locking funds
> >>> >> > for one day). But is that really the only thing that Alice is
> buying?
> >>> >> >
> >>> >> > The current spec proposal adds a CLTV of one month to the seller's
> >>> >> > output in the commitment transactions. Without that CLTV, the
> seller
> >>> >> > could accept the trade, and immediately close the channel to
> reuse the
> >>> >> > funds elsewhere. This CLTV protects the buyer from malicious
> sellers.
> >>> >> > But it is actually doing a lot more: what Alice has bought is
> actually
> >>> >> > *any* liquidity that ends up on Bob's side, for a whole month.
> And the
> >>> >> > issue is that this is impossible for Bob to price correctly, and
> can be
> >>> >> > used for liquidity griefing attacks against him.
> >>> >> >
> >>> >> > Imagine that Alice opens a 1 BTC channel with Bob and asks him to
> add
> >>> >> > 10 000 sats of inbound liquidity for a month. This sounds
> interesting
> >>> >> > for Bob, because Alice is bringing a lot of funds in, so he can
> expect
> >>> >> > payments to flow towards him which will bring him routing fees.
> And she
> >>> >> > isn't asking for a lot of liquidity, so Bob can definitely spare
> that.
> >>> >> > But then Alice sends all the channels funds through Bob to Carol.
> This
> >>> >> > means that Bob now has 1 BTC locked for the whole month, while
> Alice
> >>> >> > only paid for 10 000 sats! He earned some routing fees, but that
> isn't
> >>> >> > enough to make up for the long duration of the lock. If payments
> keep
> >>> >> > flowing in both directions with enough velocity, this is great
> for both
> >>> >> > Bob and Alice. But if the channel is then unused, or Alice just
> goes
> >>> >> > offline, this was a very bad investment for Bob. With splicing,
> Bob
> >>> >> > cannot even know beforehand how much liquidity is potentially at
> risk,
> >>> >> > because Alice may splice funds in after paying for the liquidity
> ad.
> >>> >> >
> >>> >> > If Alice pays for a 10 000 sats lease, we only want those 10 000
> sats
> >>> >> > to be encumbered with a CLTV. But this is actually not
> enforceable. We
> >>> >> > could create a separate output in the commitment transaction with
> the
> >>> >> > leased funds and a CLTV, while keeping the rest of the seller's
> funds in
> >>> >> > a normal output that doesn't have a CLTV. But then what happens
> when
> >>> >> > HTLCs are relayed and then failed? To which output should we add
> the
> >>> >> > funds back? Any strategy we use here can be exploited either by
> the
> >>> >> > seller to drain the leased funds back to its non-CLTV-locked
> output,
> >>> >> > or by the buyer to keep funds in the CLTV-locked output forever.
> >>> >> >
> >>> >> > Adding a CLTV thus protects the buyer at the expense of the
> seller. In
> >>> >> > some cases this is ok: if you are a new seller who wants to
> attract
> >>> >> > buyers, you may be willing to take that risk. But in most cases,
> the
> >>> >> > seller is going to be more reputable than the buyer, and has more
> >>> >> > incentives to behave correctly than the buyer. When buying
> liquidity,
> >>> >> > you will likely look at the network's topology, and buy from
> nodes that
> >>> >> > are well-connected, or known to be reliable. Or if you are a
> mobile
> >>> >> > wallet user, you'll be buying from your LSPs, who have incentives
> to
> >>> >> > behave honestly to earn fees and attract new users. In those
> scenarios,
> >>> >> > the buyers will very often be new nodes, without any public
> channels,
> >>> >> > which means that the seller has no way of knowing what their
> incentives
> >>> >> > are beforehand. It thus makes more sense to protect the seller
> than to
> >>> >> > protect the buyer. For those use-cases, the simplest solution is
> to not
> >>> >> > add a CLTV at all: the buyer is taking the risk that the seller
> removes
> >>> >> > the liquidity before the end of the lease. But if that happens,
> they'll
> >>> >> > just mourn their lost fees, blacklist that node, and move on.
> There will
> >>> >> > be a lot more buyers than sellers in that market, so I believe
> that this
> >>> >> > model makes sense for most large public nodes.
> >>> >> >
> >>> >> > I think that both use-cases should be supported, so I suggest
> making the
> >>> >> > CLTV enforcement of the lease optional. It will be up to each
> seller to
> >>> >> > decide whether they are willing to take the risk of locking their
> funds
> >>> >> > to attract buyers or not. Sellers can (should) price that
> additional
> >>> >> > risk in their advertised rates.
> >>> >> >
> >>> >> > In the case where the CLTV is enforced, splicing brings in
> additional
> >>> >> > subtleties. We should prevent the seller from making any
> splice-out,
> >>> >> > otherwise they would effectively be bypassing the lease CLTV. But
> we
> >>> >> > should allow the seller to splice-in, and the buyer should still
> be
> >>> >> > allowed to splice-in and splice-out. Unfortunately, the seller can
> >>> >> > prevent the buyer from splicing funds in and out of the channel,
> by
> >>> >> > simply adding splice-out outputs in any splice attempt: the buyer
> has
> >>> >> > no other choice than aborting that splice.
> >>> >> >
> >>> >> > I initially thought that we could actually use splice-out to get
> the
> >>> >> > best of both worlds: add a CLTV on the seller's output, but allow
> them
> >>> >> > to splice-out whatever funds are "in excess" of the leased
> amount. But
> >>> >> > that doesn't work, because the buyer can unilaterally reject the
> splice
> >>> >> > attempt, and the seller still ends up with all their funds locked
> for
> >>> >> > the lease duration (even though the seller can also play the
> abort game
> >>> >> > to prevent the buyer from making any splice, as described above).
> >>> >> >
> >>> >> > Thanks for reading this long post, I think this will be useful if
> you
> >>> >> > are planning on selling liquidity through liquidity ads, as you
> should
> >>> >> > fully understand the drawbacks of the CLTV lock. I do want to
> highlight
> >>> >> > that this is a great protocol, and that a liquidity marketplace
> is an
> >>> >> > important building block for lightning. We'll be working hard to
> make
> >>> >> > sure you can find this in your favorite implementations soon!
> >>> >> >
> >>> >> > Cheers,
> >>> >> > Bastien
> >
> > _______________________________________________
> > Lightning-dev mailing list
> > Lightning-dev@lists.linuxfoundation.org
> > https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev
>
_______________________________________________
Lightning-dev mailing list
Lightning-dev@lists.linuxfoundation.org
https://lists.linuxfoundation.org/mailman/listinfo/lightning-dev

Reply via email to