Skip to content

Commit ee60bd1

Browse files
committed
fix: rfc #740 requires 100% feespike margin
Changelog-Fixed: Use lightning-rfc #740 feespike margin factor of 2
1 parent 2b2ee87 commit ee60bd1

File tree

4 files changed

+43
-34
lines changed

4 files changed

+43
-34
lines changed

channeld/full_channel.c

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -390,26 +390,31 @@ static struct amount_sat fee_for_htlcs(const struct channel *channel,
390390
return commit_tx_base_fee(feerate, untrimmed);
391391
}
392392

393-
/* There is a corner case where the funder can spend so much that the
393+
/*
394+
* There is a corner case where the funder can spend so much that the
394395
* non-funder can't add any non-dust HTLCs (since the funder would
395396
* have to pay the additional fee, but it can't afford to). This
396397
* leads to the channel starving at the feast! This was reported by
397398
* ACINQ's @t-bast
398399
* (https://github.com/lightningnetwork/lightning-rfc/issues/728) and
399-
* demonstrated with c-lightning by @m-schmook
400+
* demonstrated with c-lightning by @m-schmoock
400401
* (https://github.com/ElementsProject/lightning/pull/3498).
401402
*
402403
* To mostly avoid this situation, at least from our side, we apply an
403404
* additional constraint when we're funder trying to add an HTLC: make
404-
* sure we can afford one more HTLC, even if fees increase 50%.
405+
* sure we can afford one more HTLC, even if fees increase by 100%.
405406
*
406407
* We could do this for the peer, as well, by rejecting their HTLC
407408
* immediately in this case. But rejecting a remote HTLC here causes
408409
* us to get upset with them and close the channel: we're not well
409410
* architected to reject HTLCs in channeld (it's usually lightningd's
410411
* job, but it doesn't have all the channel balance change calculation
411412
* logic. So we look after ourselves for now, and hope other nodes start
412-
* self-regulating too. */
413+
* self-regulating too.
414+
*
415+
* This mitigation will become BOLT #2 standard by:
416+
* https://github.com/lightningnetwork/lightning-rfc/issues/740
417+
*/
413418
static bool local_funder_has_fee_headroom(const struct channel *channel,
414419
struct amount_msat remainder,
415420
const struct htlc **committed,
@@ -428,14 +433,14 @@ static bool local_funder_has_fee_headroom(const struct channel *channel,
428433
feerate,
429434
committed, adding, removing);
430435

431-
/* Now, how much would it cost us if feerate increases 50% and we added
436+
/* Now, how much would it cost us if feerate increases 100% and we added
432437
* another HTLC? */
433-
fee = commit_tx_base_fee(feerate + feerate/2, untrimmed + 1);
438+
fee = commit_tx_base_fee(2 * feerate, untrimmed + 1);
434439
if (amount_msat_greater_eq_sat(remainder, fee))
435440
return true;
436441

437-
status_debug("Adding HTLC would leave us only %s:"
438-
" we need %s for another HTLC if fees increase 50%% to %uperkw",
442+
status_debug("Adding HTLC would leave us only %s: we need %s for"
443+
" another HTLC if fees increase by 100%% to %uperkw",
439444
type_to_string(tmpctx, struct amount_msat, &remainder),
440445
type_to_string(tmpctx, struct amount_sat, &fee),
441446
feerate + feerate/2);

lightningd/peer_control.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -550,10 +550,11 @@ static struct amount_sat commit_txfee(const struct channel *channel,
550550
num_untrimmed_htlcs++;
551551
}
552552

553-
/* Funder is conservative: makes sure it allows an extra HTLC
554-
* even if feerate increases 50% */
555-
return commit_tx_base_fee(local_feerate + local_feerate / 2,
556-
num_untrimmed_htlcs + 1);
553+
/*
554+
* Having 2-times feespike margin will become BOLT #2 standard by:
555+
* https://github.com/lightningnetwork/lightning-rfc/issues/740
556+
*/
557+
return commit_tx_base_fee(local_feerate * 2, num_untrimmed_htlcs + 1);
557558
}
558559

559560
static void subtract_offered_htlcs(const struct channel *channel,

tests/test_connection.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2207,7 +2207,7 @@ def test_change_chaining(node_factory, bitcoind):
22072207
def test_feerate_spam(node_factory, chainparams):
22082208
l1, l2 = node_factory.line_graph(2)
22092209

2210-
slack = 35000000
2210+
slack = 45000000
22112211
# Pay almost everything to l2.
22122212
l1.pay(l2, 10**9 - slack)
22132213

@@ -2218,8 +2218,8 @@ def test_feerate_spam(node_factory, chainparams):
22182218
# Now change feerates to something l1 can't afford.
22192219
l1.set_feerates((100000, 100000, 100000))
22202220

2221-
# It will raise as far as it can (34000)
2222-
l1.daemon.wait_for_log('Setting REMOTE feerate to 34000')
2221+
# It will raise as far as it can (48000)
2222+
l1.daemon.wait_for_log('Setting REMOTE feerate to 48000')
22232223
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE')
22242224

22252225
# But it won't do it again once it's at max.

tests/test_pay.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -584,37 +584,30 @@ def test_sendpay_cant_afford(node_factory):
584584
opts={'feerates': (15000, 15000, 15000)})
585585

586586
# Can't pay more than channel capacity.
587-
def pay(lsrc, ldst, amt, label=None):
588-
if not label:
589-
label = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))
590-
rhash = ldst.rpc.invoice(amt, label, label)['payment_hash']
591-
routestep = {'msatoshi': amt, 'id': ldst.info['id'], 'delay': 5, 'channel': '1x1x1'}
592-
lsrc.rpc.sendpay([routestep], rhash)
593-
lsrc.rpc.waitsendpay(rhash)
594-
595587
with pytest.raises(RpcError):
596-
pay(l1, l2, 10**9 + 1)
588+
l1.pay(l2, 10**9 + 1)
597589

598590
# This is the fee, which needs to be taken into account for l1.
599-
available = 10**9 - 24030000
591+
print(l1.rpc.listpeers())
592+
available = 10**9 - 32040000
600593
# Reserve is 1%.
601594
reserve = 10**7
602595

603596
# Can't pay past reserve.
604597
with pytest.raises(RpcError):
605-
pay(l1, l2, available)
598+
l1.pay(l2, available)
606599
with pytest.raises(RpcError):
607-
pay(l1, l2, available - reserve + 1)
600+
l1.pay(l2, available - reserve + 1)
608601

609602
# Can pay up to reserve (1%)
610-
pay(l1, l2, available - reserve)
603+
l1.pay(l2, available - reserve)
611604

612605
# And now it can't pay back, due to its own reserve.
613606
with pytest.raises(RpcError):
614-
pay(l2, l1, available - reserve)
607+
l2.pay(l1, available - reserve)
615608

616609
# But this should work.
617-
pay(l2, l1, available - reserve * 2)
610+
l2.pay(l1, available - reserve * 2)
618611

619612

620613
def test_decodepay(node_factory):
@@ -1561,7 +1554,7 @@ def test_pay_retry(node_factory, bitcoind):
15611554
"""Make sure pay command retries properly. """
15621555
def exhaust_channel(funder, fundee, scid, already_spent=0):
15631556
"""Spend all available capacity (10^6 - 1%) of channel"""
1564-
maxpay = (10**6 - 10**6 // 100 - 13440) * 1000 - already_spent
1557+
maxpay = (10**6 - 10**6 // 100 - 16020) * 1000 - already_spent
15651558
inv = fundee.rpc.invoice(maxpay,
15661559
''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20)),
15671560
"exhaust_channel")
@@ -2293,17 +2286,27 @@ def test_lockup_drain(node_factory, bitcoind):
22932286
except RpcError:
22942287
msat //= 2
22952288

2296-
# Even if feerate now increases 1.5x (22500), l2 should be able to send
2289+
# Even if feerate now increases 2x (30000), l2 should be able to send
22972290
# non-dust HTLC to l1.
2298-
l1.set_feerates([22500] * 3, False)
2291+
l1.set_feerates([30000] * 3, False)
22992292
# Restart forces fast fee adjustment (otherwise it's smoothed and takes
23002293
# a very long time!).
23012294
l1.restart()
23022295
wait_for(lambda: only_one(l1.rpc.listpeers()['peers'])['connected'])
2303-
assert(l1.rpc.feerates('perkw')['perkw']['normal'] == 22500)
2296+
assert(l1.rpc.feerates('perkw')['perkw']['normal'] == 30000)
23042297

23052298
l2.pay(l1, total // 2)
23062299

2300+
# But if feerate increase just a little more, l2 should not be able to send
2301+
# non-fust HTLC to l1
2302+
l1.set_feerates([30002] * 3, False) # TODO: why does 30001 fail, off by one in C code?
2303+
l1.restart()
2304+
wait_for(lambda: only_one(l1.rpc.listpeers()['peers'])['connected'])
2305+
assert(l1.rpc.feerates('perkw')['perkw']['normal'] == 30002)
2306+
2307+
with pytest.raises(RpcError, match=r".*Capacity exceeded.*"):
2308+
l2.pay(l1, total // 2)
2309+
23072310

23082311
def test_error_returns_blockheight(node_factory, bitcoind):
23092312
"""Test that incorrect_or_unknown_payment_details returns block height"""

0 commit comments

Comments
 (0)