Skip to content

Commit 150d065

Browse files
niftyneicdecker
authored andcommitted
tests: check for incoming + outgoing dust limits
1 parent b193eb0 commit 150d065

File tree

1 file changed

+107
-0
lines changed

1 file changed

+107
-0
lines changed

tests/test_pay.py

+107
Original file line numberDiff line numberDiff line change
@@ -2436,6 +2436,113 @@ def test_lockup_drain(node_factory, bitcoind):
24362436
l2.pay(l1, total // 2)
24372437

24382438

2439+
@pytest.mark.developer("needs DEVELOPER=1 for dev_ignore_htlcs")
2440+
def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams):
2441+
""" Try to hit the 'too much dust' limit, should fail the HTLC """
2442+
feerate = 10000
2443+
2444+
# elements txs are bigger so they become dusty faster
2445+
max_dust_limit_sat = 100000 if chainparams['elements'] else 50000
2446+
non_dust_htlc_val_sat = 20000 if chainparams['elements'] else 10000
2447+
htlc_val_sat = 10000 if chainparams['elements'] else 5000
2448+
2449+
l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True,
2450+
'feerates': (feerate, feerate, feerate, feerate),
2451+
'max-dust-htlc-exposure-msat': '{}sat'.format(max_dust_limit_sat),
2452+
'allow_warning': True})
2453+
2454+
# l2 holds all of l1's htlcs hostage
2455+
l2.rpc.dev_ignore_htlcs(id=l1.info['id'], ignore=True)
2456+
2457+
# l2's max dust limit is set to 100k
2458+
htlc_val_msat = htlc_val_sat * 1000
2459+
num_dusty_htlcs = max_dust_limit_sat // htlc_val_sat
2460+
2461+
# add a some non-dusty htlcs, these will fail when we raise the dust limit
2462+
route = l1.rpc.getroute(l2.info['id'], non_dust_htlc_val_sat * 1000, 1)['route']
2463+
for i in range(0, 3):
2464+
inv = l2.rpc.invoice((non_dust_htlc_val_sat * 1000), str(i + 100), str(i + 100))
2465+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2466+
l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs')
2467+
res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])
2468+
assert res['status'] == 'pending'
2469+
2470+
# add some dusty-htlcs
2471+
route = l1.rpc.getroute(l2.info['id'], htlc_val_msat, 1)['route']
2472+
for i in range(0, num_dusty_htlcs):
2473+
inv = l2.rpc.invoice(htlc_val_msat, str(i), str(i))
2474+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2475+
l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs')
2476+
res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])
2477+
assert res['status'] == 'pending'
2478+
2479+
# one more should tip it over, and return a payment failure
2480+
inv = l2.rpc.invoice(htlc_val_msat, str(num_dusty_htlcs), str(num_dusty_htlcs))
2481+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2482+
l1.daemon.wait_for_log('CHANNEL_ERR_DUST_FAILURE')
2483+
wait_for(lambda: only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])['status'] == 'failed')
2484+
2485+
# but we can still add a non dust htlc
2486+
route = l1.rpc.getroute(l2.info['id'], non_dust_htlc_val_sat * 1000, 1)['route']
2487+
inv = l2.rpc.invoice((10000 * 1000), str(120), str(120))
2488+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2489+
l2.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs')
2490+
res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])
2491+
assert res['status'] == 'pending'
2492+
2493+
# Ok, adjust our feerate upward, so the non-dust htlcs are now dust
2494+
# note that this is above the buffer we've been keeping, so the channel
2495+
# should automatically fail
2496+
l1.set_feerates([feerate * 2] * 4, False)
2497+
l1.restart()
2498+
2499+
# the channel should fail -- too much dust
2500+
inv = l2.rpc.invoice(htlc_val_msat, str(num_dusty_htlcs + 1), str(num_dusty_htlcs + 1))
2501+
with pytest.raises(RpcError, match=r'WIRE_UNKNOWN_NEXT_PEER'):
2502+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2503+
2504+
2505+
@pytest.mark.developer("needs DEVELOPER=1 for dev_ignore_htlcs")
2506+
def test_htlc_too_dusty_incoming(node_factory, bitcoind):
2507+
""" Try to hit the 'too much dust' limit, should fail the HTLC """
2508+
feerate = 30000
2509+
l1, l2, l3 = node_factory.line_graph(3, opts=[{'may_reconnect': True,
2510+
'feerates': (feerate, feerate, feerate, feerate),
2511+
'max-dust-htlc-exposure-msat': '200000sat'},
2512+
{'may_reconnect': True,
2513+
'feerates': (feerate, feerate, feerate, feerate),
2514+
'max-dust-htlc-exposure-msat': '100000sat',
2515+
'fee-base': 0,
2516+
'fee-per-satoshi': 0},
2517+
{'max-dust-htlc-exposure-msat': '500000sat'}],
2518+
wait_for_announce=True)
2519+
2520+
# on the l2->l3, and l3 holds all the htlcs hostage
2521+
# have l3 hold onto all the htlcs and not fulfill them
2522+
l3.rpc.dev_ignore_htlcs(id=l2.info['id'], ignore=True)
2523+
2524+
# l2's max dust limit is set to 100k
2525+
max_dust_limit_sat = 100000
2526+
htlc_val_sat = 10000
2527+
htlc_val_msat = htlc_val_sat * 1000
2528+
num_dusty_htlcs = max_dust_limit_sat // htlc_val_sat
2529+
route = l1.rpc.getroute(l3.info['id'], htlc_val_msat, 1)['route']
2530+
2531+
# l1 sends as much money as it can
2532+
for i in range(0, num_dusty_htlcs):
2533+
inv = l3.rpc.invoice(htlc_val_msat, str(i), str(i))
2534+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2535+
l3.daemon.wait_for_log(r'their htlc .* dev_ignore_htlcs')
2536+
res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])
2537+
assert res['status'] == 'pending'
2538+
2539+
# one more should tip it over, and return a payment failure
2540+
inv = l3.rpc.invoice(htlc_val_msat, str(num_dusty_htlcs), str(num_dusty_htlcs))
2541+
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])
2542+
l2.daemon.wait_for_log('failing immediately, as requested')
2543+
wait_for(lambda: only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])['status'] == 'failed')
2544+
2545+
24392546
def test_error_returns_blockheight(node_factory, bitcoind):
24402547
"""Test that incorrect_or_unknown_payment_details returns block height"""
24412548
l1, l2 = node_factory.line_graph(2)

0 commit comments

Comments
 (0)