Skip to content

Commit

Permalink
pytest: changed tests if we're using experimental-anchors.
Browse files Browse the repository at this point in the history
This is in anticipation of changing the defaults for non-elements.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
  • Loading branch information
rustyrussell committed Feb 7, 2024
1 parent 149be88 commit 0a2f03a
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 74 deletions.
77 changes: 51 additions & 26 deletions tests/test_closing.py
Original file line number Diff line number Diff line change
Expand Up @@ -2643,8 +2643,9 @@ def test_onchain_different_fees(node_factory, bitcoind, executor):
l2.daemon.wait_for_log('htlc 1: SENT_ADD_ACK_COMMIT->RCVD_ADD_ACK_REVOCATION')

# Restart with different feerate for second HTLC.
l1.set_feerates((5000, 5000, 5000, 3750))
l1.restart()
l1.stop()
l1.set_feerates((5000, 5000, 5000, 5000), wait_for_effect=False)
l1.start()
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE')

p3 = executor.submit(l1.pay, l2, 800000000)
Expand All @@ -2658,33 +2659,53 @@ def test_onchain_different_fees(node_factory, bitcoind, executor):
l1.daemon.wait_for_log(' to ONCHAIN')
l2.daemon.wait_for_log(' to ONCHAIN')

# Elements still uses non-anchor version.
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
expected = {'min_possible_feerate': 3750,
'max_possible_feerate': 5005}
else:
expected = {'min_possible_feerate': 5005,
'max_possible_feerate': 11005}

# Both sides should have correct feerate
assert l1.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [{
'min_possible_feerate': 5005,
'max_possible_feerate': 11005
}]
assert l2.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [{
'min_possible_feerate': 5005,
'max_possible_feerate': 11005
}]
assert l1.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [expected]

assert l2.db_query('SELECT min_possible_feerate, max_possible_feerate FROM channels;') == [expected]

bitcoind.generate_block(5)
# Three HTLCs, and one for the to-us output.
l1.daemon.wait_for_logs(['sendrawtx exit 0'] * 4)

# We use 3 blocks for "reasonable depth"
bitcoind.generate_block(3)
# We will, over the next few blocks, spend the to-us and the HTLCs.
# We don't have enough outputs, so the results are a bit random,
# but we will make progress every block!
mark = l1.daemon.logsearch_start

r = re.compile('sendrawtx exit 0')

def count_successful_txs():
l1.daemon.logs_catchup()
return sum([r.search(l) is not None for l in l1.daemon.logs[mark:]])

# First iteration we expect one HTLC-tx and the to-us, then two more htlc txs
num_successful = 1
while num_successful < 3 + 1:
wait_for(lambda: count_successful_txs() > num_successful)
num_successful = count_successful_txs()
bitcoind.generate_block(1)

# This takes at least 3 blocks: now payments can fail
with pytest.raises(Exception):
p1.result(10)
with pytest.raises(Exception):
p2.result(10)
with pytest.raises(Exception):
p3.result(10)

# Two more for HTLC timeout tx to be spent.
bitcoind.generate_block(2)
l1.daemon.wait_for_logs(['sendrawtx exit 0'] * 3)
# Now we need the return-to-wallet spending the htlc tx.
bitcoind.generate_block(4)
while num_successful < 3 + 3 + 1:
wait_for(lambda: count_successful_txs() > num_successful)
num_successful = count_successful_txs()
bitcoind.generate_block(1)

# Now, 100 blocks it should be done.
bitcoind.generate_block(100)
Expand Down Expand Up @@ -2898,7 +2919,7 @@ def test_onchain_multihtlc_our_unilateral(node_factory, bitcoind):
# until l4 says 'all outputs resolved'.
while not l4.daemon.is_in_log('All outputs resolved'):
bitcoind.generate_block(1)
assert bitcoind.rpc.getblockcount() < 200
assert bitcoind.rpc.getblockcount() < 250
sync_blockheight(bitcoind, [l4, l5])

# All payments should be long resolved.
Expand Down Expand Up @@ -2953,7 +2974,7 @@ def test_onchain_multihtlc_their_unilateral(node_factory, bitcoind):
# until l5 says 'all outputs resolved'.
while not l5.daemon.is_in_log('All outputs resolved'):
bitcoind.generate_block(1)
assert bitcoind.rpc.getblockcount() < 200
assert bitcoind.rpc.getblockcount() < 250
sync_blockheight(bitcoind, [l4, l5])

# All payments should be long resolved.
Expand Down Expand Up @@ -2981,6 +3002,8 @@ def test_permfail_htlc_in(node_factory, bitcoind, executor):

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.fundchannel(l2, 10**6)
# Give it some sats for anchor spend! (Extra for elements!)
l2.fundwallet(30000, mine_block=False)

# This will fail at l2's end.
t = executor.submit(l1.pay, l2, 200000000)
Expand Down Expand Up @@ -3574,11 +3597,9 @@ def save_notifications(message, progress, request, **kwargs):

def test_close_twice(node_factory, executor):
# First feerate is too low, second fixes it.
l1, l2 = node_factory.line_graph(2, opts=[{'allow_warning': True,
'may_reconnect': True},
{'allow_warning': True,
'may_reconnect': True,
'feerates': (15000, 15000, 15000, 15000)}])
l1, l2 = node_factory.line_graph(2, opts={'allow_warning': True,
'may_reconnect': True,
'feerates': (15000, 15000, 15000, 15000)})

# This makes it disconnect, since feerate is too low.
fut = executor.submit(l1.rpc.close, l2.info['id'], feerange=['253perkw', '500perkw'])
Expand Down Expand Up @@ -3978,7 +3999,7 @@ def test_peer_anchor_push(node_factory, bitcoind, executor, chainparams):


def test_closing_cpfp(node_factory, bitcoind):
l1, l2 = node_factory.line_graph(2)
l1, l2 = node_factory.line_graph(2, opts={'min-emergency-msat': '2500sat'})

# We want to ignore l1's change output
change = only_one(l1.rpc.listfunds()['outputs'])
Expand All @@ -4004,4 +4025,8 @@ def test_closing_cpfp(node_factory, bitcoind):
# They should now see a single additional output each
sync_blockheight(bitcoind, [l1, l2])
assert len(l1.rpc.listfunds()['outputs']) == 2
assert len(l2.rpc.listfunds()['outputs']) == 1
# This one will also have emergency change if anchors
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
assert len(l2.rpc.listfunds()['outputs']) == 2
else:
assert len(l2.rpc.listfunds()['outputs']) == 1
53 changes: 37 additions & 16 deletions tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -437,8 +437,8 @@ def test_channel_abandon(node_factory, bitcoind):

SATS = 10**6

# Add some for fees
l1.fundwallet(SATS + 10000)
# Add some for fees/emergency-reserve
l1.fundwallet(SATS + 35000)
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
l1.rpc.fundchannel(l2.info['id'], SATS, feerate='1875perkw')

Expand Down Expand Up @@ -1077,8 +1077,12 @@ def test_funding_all(node_factory, bitcoind):

l1.rpc.fundchannel(l2.info['id'], "all")

# Keeps emergency reserve!
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
assert len(outputs) == 0
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
assert outputs == [{'value': 25000}]
else:
assert outputs == []


@pytest.mark.openchannel('v1')
Expand All @@ -1089,7 +1093,7 @@ def test_funding_all_too_much(node_factory):
# l2 isn't wumbo, so channel should not be!
l1, l2 = node_factory.line_graph(2, fundchannel=False, opts=[{}, {'dev-force-features': '-19'}])

addr, txid = l1.fundwallet(2**24 + 10000)
addr, txid = l1.fundwallet(2**24 + 35000)
l1.rpc.fundchannel(l2.info['id'], "all")
assert l1.daemon.is_in_log("'all' was too large for non-wumbo channel, trimming")

Expand Down Expand Up @@ -2419,7 +2423,10 @@ def test_update_fee(node_factory, bitcoind):
# Make payments.
l1.pay(l2, 200000000)
# First payment causes fee update.
l2.daemon.wait_for_log('peer updated fee to 11005')
if 'anchors_zero_fee_htlc_tx/even' in only_one(l2.rpc.listpeerchannels()['channels'])['channel_type']['names']:
l2.daemon.wait_for_log('peer updated fee to 3755')
else:
l2.daemon.wait_for_log('peer updated fee to 11005')
l2.pay(l1, 100000000)

# Now shutdown cleanly.
Expand Down Expand Up @@ -2459,24 +2466,32 @@ def test_fee_limits(node_factory, bitcoind):
# L1 asks for stupid low fee (will actually hit the floor of 253)
l1.stop()
l1.set_feerates((15, 15, 15, 15), False)
# We need to increase l2's floor, so it rejects l1.
l2.set_feerates((15000, 11000, 7500, 3750, 2000))
l1.start()

l1.daemon.wait_for_log('Received WARNING .*: update_fee 258 outside range 1875-75000')
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
fee = 1255
range = '2000-75000'
else:
fee = 258
range = '1875-75000'
l1.daemon.wait_for_log(f'Received WARNING .*: update_fee {fee} outside range {range}')
# They hang up on *us*
l1.daemon.wait_for_log('Peer transient failure in CHANNELD_NORMAL: channeld: Owning subdaemon channeld died')

# Disconnects, but does not error. Make sure it's noted in their status though.
# FIXME: does not happen for l1!
# assert 'update_fee 253 outside range 1875-75000' in only_one(l1.rpc.listpeerchannels(l2.info['id'])['channels'])['status'][0]
assert 'update_fee 258 outside range 1875-75000' in only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['status'][0]
assert f'update_fee {fee} outside range {range}' in only_one(l2.rpc.listpeerchannels(l1.info['id'])['channels'])['status'][0]

assert only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] != 258
assert only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] != fee
# Make l2 accept those fees, and it should recover.
assert only_one(l2.rpc.setchannel(l1.get_channel_scid(l2), ignorefeelimits=True)['channels'])['ignore_fee_limits'] is True
assert only_one(l2.rpc.listpeerchannels()['channels'])['ignore_fee_limits'] is True

# Now we stay happy (and connected!)
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] == 258)
wait_for(lambda: only_one(l2.rpc.listpeerchannels()['channels'])['feerate']['perkw'] == fee)
assert only_one(l2.rpc.listpeerchannels()['channels'])['peer_connected'] is True

l1.rpc.close(l2.info['id'])
Expand All @@ -2490,7 +2505,7 @@ def test_fee_limits(node_factory, bitcoind):

# Trying to open a channel with too low a fee-rate is denied
l1.rpc.connect(l4.info['id'], 'localhost', l4.port)
with pytest.raises(RpcError, match='They sent (ERROR|WARNING) .* feerate_per_kw 253 below minimum'):
with pytest.raises(RpcError, match='They sent (ERROR|WARNING) .* feerate_per_kw .* below minimum'):
l1.fundchannel(l4, 10**6)

# Restore to normal.
Expand All @@ -2507,7 +2522,7 @@ def test_fee_limits(node_factory, bitcoind):

# Try stupid high fees
l1.stop()
l1.set_feerates((15000, 11000 * 10, 7500, 3750), False)
l1.set_feerates((15000, 15000, 15000, 15000, 15000), False)
l1.start()

l3.daemon.wait_for_log('peer_in WIRE_UPDATE_FEE')
Expand Down Expand Up @@ -2589,7 +2604,7 @@ def test_update_fee_reconnect(node_factory, bitcoind):

# Make l1 send out feechange; triggers disconnect/reconnect.
# (Note: < 10% change, so no smoothing here!)
l1.set_feerates((14000, 14000, 14000, 3750))
l1.set_feerates((14000, 14000, 14000, 14000))
l1.daemon.wait_for_log('Setting REMOTE feerate to 14005')
l2.daemon.wait_for_log('Setting LOCAL feerate to 14005')
l1.daemon.wait_for_log(r'dev_disconnect: \+WIRE_COMMITMENT_SIGNED')
Expand Down Expand Up @@ -3354,14 +3369,20 @@ def test_feerate_spam(node_factory, chainparams):
l1.pay(l2, 10**9 - slack)

# It will send this once (may have happened before line_graph's wait)
wait_for(lambda: l1.daemon.is_in_log('Setting REMOTE feerate to 11005'))
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
wait_for(lambda: l1.daemon.is_in_log('Setting REMOTE feerate to 3755'))
else:
wait_for(lambda: l1.daemon.is_in_log('Setting REMOTE feerate to 11005'))
wait_for(lambda: l1.daemon.is_in_log('peer_out WIRE_UPDATE_FEE'))

# Now change feerates to something l1 can't afford.
l1.set_feerates((100000, 100000, 100000, 100000))
l1.set_feerates((200000, 200000, 200000, 200000))

# It will raise as far as it can (48000)
maxfeerate = 48000
# It will raise as far as it can (30000)
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
maxfeerate = 30000
else:
maxfeerate = 48000
l1.daemon.wait_for_log('Setting REMOTE feerate to {}'.format(maxfeerate))
l1.daemon.wait_for_log('peer_out WIRE_UPDATE_FEE')

Expand Down
21 changes: 15 additions & 6 deletions tests/test_misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,15 +295,16 @@ def test_htlc_sig_persistence(node_factory, bitcoind, executor):
_, txid, blocks = l1.wait_for_onchaind_tx('OUR_HTLC_TIMEOUT_TO_US',
'THEIR_UNILATERAL/OUR_HTLC')
assert blocks == 5

bitcoind.generate_block(5)
bitcoind.generate_block(1, wait_for_mempool=txid)
l1.daemon.wait_for_logs([
r'Owning output . (\d+)sat .SEGWIT. txid',
])

# We should now have a) the change from funding, b) the
# unilateral to us, and c) the HTLC respend to us
assert len(l1.rpc.listfunds()['outputs']) == 3
# We should now have 1) the unilateral to us, and b) the HTLC respend to us
# and maybe (c) change.
assert 2 <= len(l1.rpc.listfunds()['outputs']) <= 3


def test_htlc_out_timeout(node_factory, bitcoind, executor):
Expand Down Expand Up @@ -385,6 +386,8 @@ def test_htlc_in_timeout(node_factory, bitcoind, executor):
options={'dev-no-reconnect': None},
feerates=(7500, 7500, 7500, 7500))
l2 = node_factory.get_node()
# Give it some sats for anchor spend!
l2.fundwallet(25000, mine_block=False)

l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
chanid, _ = l1.fundchannel(l2, 10**6)
Expand Down Expand Up @@ -3876,9 +3879,15 @@ def test_set_feerate_offset(node_factory, bitcoind):

l1.pay(l2, 200000000)
# First payment causes fee update, which should reflect the feerate offset.
l1.daemon.wait_for_log('lightningd: update_feerates: feerate = 11100, '
'min=1875, max=150000, penalty=7500')
l2.daemon.wait_for_log('peer updated fee to 11100')
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
feerate = 3850
min_feerate = 253
else:
feerate = 11100
min_feerate = 1875
l1.daemon.wait_for_log(f'lightningd: update_feerates: feerate = {feerate}, '
f'min={min_feerate}, max=150000, penalty=7500')
l2.daemon.wait_for_log(f'peer updated fee to {feerate}')
l2.pay(l1, 100000000)

# Now shutdown cleanly.
Expand Down
32 changes: 9 additions & 23 deletions tests/test_pay.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@ def test_pay_disconnect(node_factory, bitcoind):
l1.set_feerates((10**6, 10**6, 10**6, 10**6), False)

# Wait for l1 notice
l1.daemon.wait_for_log(r'WARNING .*: update_fee \d+ outside range 1875-75000')
if 'anchors_zero_fee_htlc_tx/even' in only_one(l1.rpc.listpeerchannels()['channels'])['channel_type']['names']:
l1.daemon.wait_for_log(r'WARNING .*: update_fee \d+ outside range 253-75000')
else:
l1.daemon.wait_for_log(r'WARNING .*: update_fee \d+ outside range 1875-75000')
# They hang up on us
l1.daemon.wait_for_log(r'Peer transient failure in CHANNELD_NORMAL')

Expand Down Expand Up @@ -2736,42 +2739,25 @@ def test_htlc_too_dusty_outgoing(node_factory, bitcoind, chainparams):
res = only_one(l1.rpc.listsendpays(payment_hash=inv['payment_hash'])['payments'])
assert res['status'] == 'pending'

# Ok, adjust our feerate upward, so the non-dust htlcs are now dust
# note that this is above the buffer we've been keeping, so the channel
# should automatically fail
l1.set_feerates([feerate * 2] * 4, False)
l1.restart()

# Make sure fails before we try sending htlc!
l1.daemon.wait_for_log('Too much dust to update fee')

# the channel should start warning -- too much dust
inv = l2.rpc.invoice(htlc_val_msat, str(num_dusty_htlcs + 1), str(num_dusty_htlcs + 1))
with pytest.raises(RpcError, match=r'WIRE_TEMPORARY_CHANNEL_FAILURE'):
l1.rpc.sendpay(route, inv['payment_hash'], payment_secret=inv['payment_secret'])


def test_htlc_too_dusty_incoming(node_factory, bitcoind):
""" Try to hit the 'too much dust' limit, should fail the HTLC """
feerate = 30000
l1, l2, l3 = node_factory.line_graph(3, opts=[{'may_reconnect': True,
'feerates': (feerate, feerate, feerate, feerate),
'max-dust-htlc-exposure-msat': '200000sat'},
{'may_reconnect': True,
'feerates': (feerate, feerate, feerate, feerate),
'max-dust-htlc-exposure-msat': '100000sat',
'max-dust-htlc-exposure-msat': '1000sat',
'fee-base': 0,
'fee-per-satoshi': 0},
{'max-dust-htlc-exposure-msat': '500000sat'}],
{'max-dust-htlc-exposure-msat': '1000sat'}],
wait_for_announce=True)

# on the l2->l3, and l3 holds all the htlcs hostage
# have l3 hold onto all the htlcs and not fulfill them
l3.rpc.dev_ignore_htlcs(id=l2.info['id'], ignore=True)

# l2's max dust limit is set to 100k
max_dust_limit_sat = 100000
htlc_val_sat = 10000
# l2's max dust limit is set to 1k
max_dust_limit_sat = 1000
htlc_val_sat = 250
htlc_val_msat = htlc_val_sat * 1000
num_dusty_htlcs = max_dust_limit_sat // htlc_val_sat
route = l1.rpc.getroute(l3.info['id'], htlc_val_msat, 1)['route']
Expand Down
Loading

0 comments on commit 0a2f03a

Please sign in to comment.