Anthony Towns [ARCHIVE] on Nostr: 📅 Original date posted:2020-02-23 📝 Original message: On Fri, Feb 21, 2020 at ...
📅 Original date posted:2020-02-23
📝 Original message:
On Fri, Feb 21, 2020 at 12:35:20PM +1030, Rusty Russell wrote:
> > I think the way it would end up working
> > is that the further the route extends, the greater the payments are, so:
> > A -> B : B sends A 1msat per minute
> > A -> B -> C : C sends B 2msat per minute, B forwards 1msat/min to A
> > A -> B -> C -> D : D sends C 3 msat, etc
> > A -> B -> C -> D -> E : E sends D 4 msat, etc
> > so each node is receiving +1 msat/minute, except for the last one, who's
> > paying n msat/minute, where n is the number of hops to have gotten up to
> > the last one. There's the obvious privacy issue there, with fairly
> > obvious ways to fudge around it, I think.
> Yes, it needs to scale with distance to work at all. However, it has
> the same problems with other upfront schemes: how does E know to send
> 4msat per minute?
D tells it "if you want this HTLC, you'll need to pay 4msat/minute after
the grace period of 65 seconds". Which also means A as the originator can
also choose whatever fees they like. The only consequence of choosing too
high a fee is that it's more likely one of the intermediate nodes will
say "screw that!" and abort the HTLC before it gets to the destination.
> > I think it might make sense for the payments to have a grace period --
> > ie, "if you keep this payment open longer than 20 seconds, you have to
> > start paying me x msat/minute, but if it fulfills or cancels before
> > then, it's all good".
> But whatever the grace period, I can just rely on knowing that B is in
> Australia (with a 1 second HTLC commit time) to make that node bleed
> satoshis. I can send A->B->C, and have C fail the htlc after 19
> seconds for free. But B has to send 1msat to A. B can't blame A or C,
> since this attack could come from further away, too.
So A gives B a grace period of 35 seconds, B deducts 5 seconds
processing time and 10 seconds for latency, so gives C a grace period of
20 seconds; C rejects after 19 seconds, and B still has 15 seconds to
notify A before he has to start paying fees. Same setup as decreasing
timelocks when forwarding HTLCs.
> And if there is a grace period, I can just gum up the network with lots
> of slow-but-not-slow-enough HTLCs.
Well, it reduces the "gum up the network for <timeout> blocks" to "gum
up the network for <grace period> seconds", which seems like a pretty
big win. I think if you had 20 hops each with a 1 minute grace period,
and each channel had a max_accepted_htlcs of 30, you'd need 25 HTLCs per
second to block 1000 channels (so 2.7% of the 36k channels 1ml reports),
so at the very least, successfully performing this attack would be
demonstrating lightning's solved bitcoin's transactions-per-second
limitation?
I think you could do better by having the acceptable grace period be
dynamic: both (a) requiring a shorter grace period the more funds a HTLC
locks up, which stops a single HTLC from gumming up the channel, and (b)
requiring a shorter grace period the more active HTLCs you have (or, the
more active HTLCs you have that are in the grace period, perhaps). That
way if the network is loaded, you're prioritising more efficient routes
(or at least ones that are willing to pay their way), and if it's under
attack, you're dynamically increasing the resources needed to maintain
the attack.
Anyway, that's my hot take; not claiming it's a perfect solution or
final answer, rather that this still seems worth brainstorming out.
My feeling is that this might interact nicely with the sender-initiated
upfront fee. Like, you could replace a grace period of 30 seconds at
2msat/minute by always charging 2msat/minute but doing a forward payment
of 1msat. But at this point I can't keep it all in my head at once to
figure out something that really makes sense.
> > Maybe this also implies a different protocol for HTLC forwarding,
> > something like:
> > 1. A sends the HTLC onion packet to B
> > 2. B decrypts it, makes sure it makes sense
> > 3. B sends a half-signed updated channel state back to A
> > 4. A accepts it, and forwards the other half-signed channel update to B
> > so that at any point before (4) Alice can say "this is taking too long,
> > I'll start losing money" and safely abort the HTLC she was forwarding to
> > Bob to avoid paying fees; while only after (4) can she start the time on
> > expecting Bob to start paying fees that she'll forward back. That means
> > 1.5 round-trips before Bob can really forward the HTLC on to Carol;
> > but maybe it's parallelisable, so Bob/Carol could start at (1) as soon
> > as Alice/Bob has finished (2).
> We added a ping-before-commit[1] to avoid the case where B has disconnected
> and we don't know yet; we have to assume an HTLC is stuck once we send
> commitment_signed. This would be a formalization of that, but I don't
> think it's any better?
I don't think it's any better as things stand, but with the "B pays A
holding fees" I think it becomes necessary. If you've got a route
A->B->C then from B's perspective I think it currently looks like:
A->B: here's a HTLC, locked in
B->C: ping
C->B: pong!
B->C: updated commitment with HTLC locked in
C->B: *silence*
at which point the best B can do is unilaterally close the B/C channel
with their pre-HTLC commitment, but they still have to wait for that to
confirm before they can safely cancel the HTLC with A, and that will
likely take more than whatever the grace period is, so B will be losing
money on holding fees.
Whereas:
A->B: here's a HTLC, locked in
B->C: HTLC proposal
C->B: sure: updated commitment with HTLC locked in
B->C: great, corresponding updated commitment, plus revocation
C->B: revocation
means that if C goes silent before B receives a new commitment, B can
cancel the HTLC with A with no risk (B can publish the old commitment
still even if the new arrives later, and C can only publish the pre-HTLC
commitment), and if C goes silent after B receives the new commitment, B
can drop the new commitment to the blockchain and pay A's fees out of it.
> There's an old proposal to fast-fail HTLCs: Bob sends an new message "I
> would fail this HTLC once it's committed, here's the error"
Yeah, you could do "B->C: proposal, C->B: no way!" instead of "sure" to
fast fail the above too.
And I think something like that's necessary (at least with my view of how
this "keep the HTLC open" payment would work), otherwise B could send C a
"1 microsecond grace period, rate of 3e11 msat/minute, HTLC for 100 sat,
timeout of 2016 blocks" and if C couldn't reject it immediately would
owe B 50c per millisecond it took to cancel.
Cheers,
aj
📝 Original message:
On Fri, Feb 21, 2020 at 12:35:20PM +1030, Rusty Russell wrote:
> > I think the way it would end up working
> > is that the further the route extends, the greater the payments are, so:
> > A -> B : B sends A 1msat per minute
> > A -> B -> C : C sends B 2msat per minute, B forwards 1msat/min to A
> > A -> B -> C -> D : D sends C 3 msat, etc
> > A -> B -> C -> D -> E : E sends D 4 msat, etc
> > so each node is receiving +1 msat/minute, except for the last one, who's
> > paying n msat/minute, where n is the number of hops to have gotten up to
> > the last one. There's the obvious privacy issue there, with fairly
> > obvious ways to fudge around it, I think.
> Yes, it needs to scale with distance to work at all. However, it has
> the same problems with other upfront schemes: how does E know to send
> 4msat per minute?
D tells it "if you want this HTLC, you'll need to pay 4msat/minute after
the grace period of 65 seconds". Which also means A as the originator can
also choose whatever fees they like. The only consequence of choosing too
high a fee is that it's more likely one of the intermediate nodes will
say "screw that!" and abort the HTLC before it gets to the destination.
> > I think it might make sense for the payments to have a grace period --
> > ie, "if you keep this payment open longer than 20 seconds, you have to
> > start paying me x msat/minute, but if it fulfills or cancels before
> > then, it's all good".
> But whatever the grace period, I can just rely on knowing that B is in
> Australia (with a 1 second HTLC commit time) to make that node bleed
> satoshis. I can send A->B->C, and have C fail the htlc after 19
> seconds for free. But B has to send 1msat to A. B can't blame A or C,
> since this attack could come from further away, too.
So A gives B a grace period of 35 seconds, B deducts 5 seconds
processing time and 10 seconds for latency, so gives C a grace period of
20 seconds; C rejects after 19 seconds, and B still has 15 seconds to
notify A before he has to start paying fees. Same setup as decreasing
timelocks when forwarding HTLCs.
> And if there is a grace period, I can just gum up the network with lots
> of slow-but-not-slow-enough HTLCs.
Well, it reduces the "gum up the network for <timeout> blocks" to "gum
up the network for <grace period> seconds", which seems like a pretty
big win. I think if you had 20 hops each with a 1 minute grace period,
and each channel had a max_accepted_htlcs of 30, you'd need 25 HTLCs per
second to block 1000 channels (so 2.7% of the 36k channels 1ml reports),
so at the very least, successfully performing this attack would be
demonstrating lightning's solved bitcoin's transactions-per-second
limitation?
I think you could do better by having the acceptable grace period be
dynamic: both (a) requiring a shorter grace period the more funds a HTLC
locks up, which stops a single HTLC from gumming up the channel, and (b)
requiring a shorter grace period the more active HTLCs you have (or, the
more active HTLCs you have that are in the grace period, perhaps). That
way if the network is loaded, you're prioritising more efficient routes
(or at least ones that are willing to pay their way), and if it's under
attack, you're dynamically increasing the resources needed to maintain
the attack.
Anyway, that's my hot take; not claiming it's a perfect solution or
final answer, rather that this still seems worth brainstorming out.
My feeling is that this might interact nicely with the sender-initiated
upfront fee. Like, you could replace a grace period of 30 seconds at
2msat/minute by always charging 2msat/minute but doing a forward payment
of 1msat. But at this point I can't keep it all in my head at once to
figure out something that really makes sense.
> > Maybe this also implies a different protocol for HTLC forwarding,
> > something like:
> > 1. A sends the HTLC onion packet to B
> > 2. B decrypts it, makes sure it makes sense
> > 3. B sends a half-signed updated channel state back to A
> > 4. A accepts it, and forwards the other half-signed channel update to B
> > so that at any point before (4) Alice can say "this is taking too long,
> > I'll start losing money" and safely abort the HTLC she was forwarding to
> > Bob to avoid paying fees; while only after (4) can she start the time on
> > expecting Bob to start paying fees that she'll forward back. That means
> > 1.5 round-trips before Bob can really forward the HTLC on to Carol;
> > but maybe it's parallelisable, so Bob/Carol could start at (1) as soon
> > as Alice/Bob has finished (2).
> We added a ping-before-commit[1] to avoid the case where B has disconnected
> and we don't know yet; we have to assume an HTLC is stuck once we send
> commitment_signed. This would be a formalization of that, but I don't
> think it's any better?
I don't think it's any better as things stand, but with the "B pays A
holding fees" I think it becomes necessary. If you've got a route
A->B->C then from B's perspective I think it currently looks like:
A->B: here's a HTLC, locked in
B->C: ping
C->B: pong!
B->C: updated commitment with HTLC locked in
C->B: *silence*
at which point the best B can do is unilaterally close the B/C channel
with their pre-HTLC commitment, but they still have to wait for that to
confirm before they can safely cancel the HTLC with A, and that will
likely take more than whatever the grace period is, so B will be losing
money on holding fees.
Whereas:
A->B: here's a HTLC, locked in
B->C: HTLC proposal
C->B: sure: updated commitment with HTLC locked in
B->C: great, corresponding updated commitment, plus revocation
C->B: revocation
means that if C goes silent before B receives a new commitment, B can
cancel the HTLC with A with no risk (B can publish the old commitment
still even if the new arrives later, and C can only publish the pre-HTLC
commitment), and if C goes silent after B receives the new commitment, B
can drop the new commitment to the blockchain and pay A's fees out of it.
> There's an old proposal to fast-fail HTLCs: Bob sends an new message "I
> would fail this HTLC once it's committed, here's the error"
Yeah, you could do "B->C: proposal, C->B: no way!" instead of "sure" to
fast fail the above too.
And I think something like that's necessary (at least with my view of how
this "keep the HTLC open" payment would work), otherwise B could send C a
"1 microsecond grace period, rate of 3e11 msat/minute, HTLC for 100 sat,
timeout of 2016 blocks" and if C couldn't reject it immediately would
owe B 50c per millisecond it took to cancel.
Cheers,
aj