mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 13:25:43 +01:00
pytest: only_one() helper to catch if RPC returns more elements than we expect
I saw an error in test_gossip_weirdalias in Travis, where listnodes(nodeid) returned *BOTH* nodes; it happened to fail because [0] was the wrong one, but it would have passed if the order had been different. This helper asserts that we really do only have one element, and should catch such bugs faster. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
b876c601a6
commit
7986af1b1e
@ -45,6 +45,13 @@ def to_json(arg):
|
||||
return json.loads(json.dumps(arg))
|
||||
|
||||
|
||||
def only_one(arr):
|
||||
"""Many JSON RPC calls return an array; often we only expect a single entry
|
||||
"""
|
||||
assert len(arr) == 1
|
||||
return arr[0]
|
||||
|
||||
|
||||
def setupBitcoind(directory):
|
||||
global bitcoind
|
||||
bitcoind = utils.BitcoinD(bitcoin_dir=directory, rpcport=None)
|
||||
@ -371,7 +378,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
label = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(20))
|
||||
|
||||
rhash = ldst.rpc.invoice(amt, label, label)['payment_hash']
|
||||
assert ldst.rpc.listinvoices(label)['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(ldst.rpc.listinvoices(label)['invoices'])['status'] == 'unpaid'
|
||||
|
||||
routestep = {
|
||||
'msatoshi': amt,
|
||||
@ -383,7 +390,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
def wait_pay():
|
||||
# Up to 10 seconds for payment to succeed.
|
||||
start_time = time.time()
|
||||
while ldst.rpc.listinvoices(label)['invoices'][0]['status'] != 'paid':
|
||||
while only_one(ldst.rpc.listinvoices(label)['invoices'])['status'] != 'paid':
|
||||
if time.time() > start_time + 10:
|
||||
raise TimeoutError('Payment timed out')
|
||||
time.sleep(0.1)
|
||||
@ -430,7 +437,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1, l2 = self.connect()
|
||||
|
||||
# LOCAL_INITIAL_ROUTING_SYNC + LOCAL_GOSSIP_QUERIES
|
||||
assert l1.rpc.listpeers()['peers'][0]['local_features'] == '88'
|
||||
assert only_one(l1.rpc.listpeers()['peers'])['local_features'] == '88'
|
||||
|
||||
def test_autocleaninvoice(self):
|
||||
l1 = self.node_factory.get_node()
|
||||
@ -450,21 +457,21 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Both should still be there - auto clean cycle not started.
|
||||
# inv1 should be expired
|
||||
assert len(l1.rpc.listinvoices('inv1')['invoices']) == 1
|
||||
assert l1.rpc.listinvoices('inv1')['invoices'][0]['status'] == 'expired'
|
||||
assert only_one(l1.rpc.listinvoices('inv1')['invoices'])['status'] == 'expired'
|
||||
assert len(l1.rpc.listinvoices('inv2')['invoices']) == 1
|
||||
assert l1.rpc.listinvoices('inv2')['invoices'][0]['status'] != 'expired'
|
||||
assert only_one(l1.rpc.listinvoices('inv2')['invoices'])['status'] != 'expired'
|
||||
|
||||
time.sleep(start_time - time.time() + 10) # total 10
|
||||
# inv1 should have deleted, inv2 still there and unexpired.
|
||||
assert len(l1.rpc.listinvoices('inv1')['invoices']) == 0
|
||||
assert len(l1.rpc.listinvoices('inv2')['invoices']) == 1
|
||||
assert l1.rpc.listinvoices('inv2')['invoices'][0]['status'] != 'expired'
|
||||
assert only_one(l1.rpc.listinvoices('inv2')['invoices'])['status'] != 'expired'
|
||||
|
||||
time.sleep(start_time - time.time() + 14) # total 14
|
||||
# inv2 should still be there, but expired
|
||||
assert len(l1.rpc.listinvoices('inv1')['invoices']) == 0
|
||||
assert len(l1.rpc.listinvoices('inv2')['invoices']) == 1
|
||||
assert l1.rpc.listinvoices('inv2')['invoices'][0]['status'] == 'expired'
|
||||
assert only_one(l1.rpc.listinvoices('inv2')['invoices'])['status'] == 'expired'
|
||||
|
||||
time.sleep(start_time - time.time() + 18) # total 18
|
||||
# Everything deleted
|
||||
@ -530,7 +537,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
# Check pay_index is null
|
||||
outputs = l1.db_query('SELECT pay_index IS NULL AS q FROM invoices WHERE label="label";')
|
||||
assert len(outputs) == 1 and outputs[0]['q'] != 0
|
||||
assert only_one(outputs)['q'] != 0
|
||||
|
||||
# Check any-amount invoice
|
||||
inv = l1.rpc.invoice("any", 'label2', 'description2')
|
||||
@ -553,11 +560,11 @@ class LightningDTests(BaseLightningDTests):
|
||||
# FIXME: invoice RPC should return label!
|
||||
|
||||
# Can find by this label.
|
||||
inv = l1.rpc.listinvoices(weird_label)['invoices'][0]
|
||||
inv = only_one(l1.rpc.listinvoices(weird_label)['invoices'])
|
||||
assert inv['label'] == weird_label
|
||||
|
||||
# Can find this in list.
|
||||
inv = l1.rpc.listinvoices()['invoices'][0]
|
||||
inv = only_one(l1.rpc.listinvoices()['invoices'])
|
||||
assert inv['label'] == weird_label
|
||||
|
||||
b11 = l1.rpc.decodepay(inv['bolt11'])
|
||||
@ -573,11 +580,11 @@ class LightningDTests(BaseLightningDTests):
|
||||
# FIXME: invoice RPC should return label!
|
||||
|
||||
# Can find by this label.
|
||||
inv = l1.rpc.listinvoices(weird_label)['invoices'][0]
|
||||
inv = only_one(l1.rpc.listinvoices(weird_label)['invoices'])
|
||||
assert inv['label'] == str(weird_label)
|
||||
|
||||
# Can find this in list.
|
||||
inv = l1.rpc.listinvoices()['invoices'][0]
|
||||
inv = only_one(l1.rpc.listinvoices()['invoices'])
|
||||
assert inv['label'] == str(weird_label)
|
||||
|
||||
b11 = l1.rpc.decodepay(inv['bolt11'])
|
||||
@ -597,8 +604,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
inv = l2.rpc.invoice(msatoshi=123000, label='test_pay', description='description', expiry=1)['bolt11']
|
||||
time.sleep(2)
|
||||
self.assertRaises(RpcError, l1.rpc.pay, inv)
|
||||
assert l2.rpc.listinvoices('test_pay')['invoices'][0]['status'] == 'expired'
|
||||
assert l2.rpc.listinvoices('test_pay')['invoices'][0]['expires_at'] < time.time()
|
||||
assert only_one(l2.rpc.listinvoices('test_pay')['invoices'])['status'] == 'expired'
|
||||
assert only_one(l2.rpc.listinvoices('test_pay')['invoices'])['expires_at'] < time.time()
|
||||
|
||||
# Try deleting it.
|
||||
self.assertRaisesRegex(RpcError,
|
||||
@ -739,14 +746,14 @@ class LightningDTests(BaseLightningDTests):
|
||||
l2.restart()
|
||||
|
||||
# Should reconnect.
|
||||
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['connected'])
|
||||
wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'][0]['connected'])
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
||||
wait_for(lambda: only_one(l2.rpc.listpeers(l1.info['id'])['peers'])['connected'])
|
||||
# Connect command should succeed.
|
||||
l1.rpc.connect(l2.info['id'], 'localhost', l2.port)
|
||||
|
||||
# Stop l2 and wait for l1 to notice.
|
||||
l2.stop()
|
||||
wait_for(lambda: not l1.rpc.listpeers(l2.info['id'])['peers'][0]['connected'])
|
||||
wait_for(lambda: not only_one(l1.rpc.listpeers(l2.info['id'])['peers'])['connected'])
|
||||
|
||||
# Now should fail.
|
||||
self.assertRaisesRegex(RpcError,
|
||||
@ -770,8 +777,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
def test_balance(self):
|
||||
l1, l2 = self.connect()
|
||||
self.fund_channel(l1, l2, 10**6)
|
||||
p1 = l1.rpc.getpeer(peer_id=l2.info['id'], level='info')['channels'][0]
|
||||
p2 = l2.rpc.getpeer(l1.info['id'], 'info')['channels'][0]
|
||||
p1 = only_one(l1.rpc.getpeer(peer_id=l2.info['id'], level='info')['channels'])
|
||||
p2 = only_one(l2.rpc.getpeer(l1.info['id'], 'info')['channels'])
|
||||
assert p1['msatoshi_to_us'] == 10**6 * 1000
|
||||
assert p1['msatoshi_total'] == 10**6 * 1000
|
||||
assert p2['msatoshi_to_us'] == 0
|
||||
@ -880,8 +887,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102'
|
||||
assert b11['expiry'] == 3600
|
||||
assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad'
|
||||
assert b11['fallbacks'][0]['type'] == 'P2PKH'
|
||||
assert b11['fallbacks'][0]['addr'] == 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'
|
||||
assert only_one(b11['fallbacks'])['type'] == 'P2PKH'
|
||||
assert only_one(b11['fallbacks'])['addr'] == 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'
|
||||
|
||||
# > ### On mainnet, with fallback address 1RustyRX2oai4EYYDpQGWvEL62BBGqN9T with extra routing info to go via nodes 029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255 then 039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255
|
||||
# > lnbc20m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqj9n4evl6mr5aj9f58zp6fyjzup6ywn3x6sk8akg5v4tgn2q8g4fhx05wf6juaxu9760yp46454gpg5mtzgerlzezqcqvjnhjh8z3g2qqdhhwkj
|
||||
@ -910,8 +917,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102'
|
||||
assert b11['expiry'] == 3600
|
||||
assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad'
|
||||
assert b11['fallbacks'][0]['type'] == 'P2PKH'
|
||||
assert b11['fallbacks'][0]['addr'] == '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'
|
||||
assert only_one(b11['fallbacks'])['type'] == 'P2PKH'
|
||||
assert only_one(b11['fallbacks'])['addr'] == '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'
|
||||
assert len(b11['routes']) == 1
|
||||
assert len(b11['routes'][0]) == 2
|
||||
assert b11['routes'][0][0]['pubkey'] == '029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'
|
||||
@ -951,8 +958,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102'
|
||||
assert b11['expiry'] == 3600
|
||||
assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad'
|
||||
assert b11['fallbacks'][0]['type'] == 'P2SH'
|
||||
assert b11['fallbacks'][0]['addr'] == '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'
|
||||
assert only_one(b11['fallbacks'])['type'] == 'P2SH'
|
||||
assert only_one(b11['fallbacks'])['addr'] == '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'
|
||||
|
||||
# > ### On mainnet, with fallback (P2WPKH) address bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
|
||||
# > lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfppqw508d6qejxtdg4y5r3zarvary0c5xw7kepvrhrm9s57hejg0p662ur5j5cr03890fa7k2pypgttmh4897d3raaq85a293e9jpuqwl0rnfuwzam7yr8e690nd2ypcq9hlkdwdvycqa0qza8
|
||||
@ -976,8 +983,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102'
|
||||
assert b11['expiry'] == 3600
|
||||
assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad'
|
||||
assert b11['fallbacks'][0]['type'] == 'P2WPKH'
|
||||
assert b11['fallbacks'][0]['addr'] == 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
|
||||
assert only_one(b11['fallbacks'])['type'] == 'P2WPKH'
|
||||
assert only_one(b11['fallbacks'])['addr'] == 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'
|
||||
|
||||
# > ### On mainnet, with fallback (P2WSH) address bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3
|
||||
# > lnbc20m1pvjluezhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqspp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q28j0v3rwgy9pvjnd48ee2pl8xrpxysd5g44td63g6xcjcu003j3qe8878hluqlvl3km8rm92f5stamd3jw763n3hck0ct7p8wwj463cql26ava
|
||||
@ -1001,8 +1008,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert b11['payment_hash'] == '0001020304050607080900010203040506070809000102030405060708090102'
|
||||
assert b11['expiry'] == 3600
|
||||
assert b11['payee'] == '03e7156ae33b0a208d0744199163177e909e80176e55d97a2f221ede0f934dd9ad'
|
||||
assert b11['fallbacks'][0]['type'] == 'P2WSH'
|
||||
assert b11['fallbacks'][0]['addr'] == 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'
|
||||
assert only_one(b11['fallbacks'])['type'] == 'P2WSH'
|
||||
assert only_one(b11['fallbacks'])['addr'] == 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'
|
||||
|
||||
self.assertRaises(RpcError, l1.rpc.decodepay, '1111111')
|
||||
|
||||
@ -1013,7 +1020,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
routestep = {
|
||||
'msatoshi': amt,
|
||||
@ -1027,35 +1034,35 @@ class LightningDTests(BaseLightningDTests):
|
||||
rs['msatoshi'] = rs['msatoshi'] - 1
|
||||
l1.rpc.sendpay(to_json([rs]), rhash)
|
||||
self.assertRaises(RpcError, l1.rpc.waitsendpay, rhash)
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# Gross overpayment (more than factor of 2)
|
||||
rs = copy.deepcopy(routestep)
|
||||
rs['msatoshi'] = rs['msatoshi'] * 2 + 1
|
||||
l1.rpc.sendpay(to_json([rs]), rhash)
|
||||
self.assertRaises(RpcError, l1.rpc.waitsendpay, rhash)
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# Insufficient delay.
|
||||
rs = copy.deepcopy(routestep)
|
||||
rs['delay'] = rs['delay'] - 2
|
||||
l1.rpc.sendpay(to_json([rs]), rhash)
|
||||
self.assertRaises(RpcError, l1.rpc.waitsendpay, rhash)
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# Bad ID.
|
||||
rs = copy.deepcopy(routestep)
|
||||
rs['id'] = '00000000000000000000000000000000'
|
||||
self.assertRaises(RpcError, l1.rpc.sendpay, to_json([rs]), rhash)
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# FIXME: test paying via another node, should fail to pay twice.
|
||||
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
|
||||
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
|
||||
assert p1['channels'][0]['msatoshi_to_us'] == 10**6 * 1000
|
||||
assert p1['channels'][0]['msatoshi_total'] == 10**6 * 1000
|
||||
assert p2['channels'][0]['msatoshi_to_us'] == 0
|
||||
assert p2['channels'][0]['msatoshi_total'] == 10**6 * 1000
|
||||
assert only_one(p1['channels'])['msatoshi_to_us'] == 10**6 * 1000
|
||||
assert only_one(p1['channels'])['msatoshi_total'] == 10**6 * 1000
|
||||
assert only_one(p2['channels'])['msatoshi_to_us'] == 0
|
||||
assert only_one(p2['channels'])['msatoshi_total'] == 10**6 * 1000
|
||||
|
||||
# This works.
|
||||
before = int(time.time())
|
||||
@ -1069,19 +1076,19 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert details['created_at'] >= before
|
||||
assert details['created_at'] <= after
|
||||
# Check receiver
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'paid'
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['pay_index'] == 1
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['msatoshi_received'] == rs['msatoshi']
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['pay_index'] == 1
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['msatoshi_received'] == rs['msatoshi']
|
||||
|
||||
# Balances should reflect it.
|
||||
def check_balances():
|
||||
p1 = l1.rpc.getpeer(l2.info['id'], 'info')
|
||||
p2 = l2.rpc.getpeer(l1.info['id'], 'info')
|
||||
return (
|
||||
p1['channels'][0]['msatoshi_to_us'] == 10**6 * 1000 - amt and
|
||||
p1['channels'][0]['msatoshi_total'] == 10**6 * 1000 and
|
||||
p2['channels'][0]['msatoshi_to_us'] == amt and
|
||||
p2['channels'][0]['msatoshi_total'] == 10**6 * 1000
|
||||
only_one(p1['channels'])['msatoshi_to_us'] == 10**6 * 1000 - amt and
|
||||
only_one(p1['channels'])['msatoshi_total'] == 10**6 * 1000 and
|
||||
only_one(p2['channels'])['msatoshi_to_us'] == amt and
|
||||
only_one(p2['channels'])['msatoshi_total'] == 10**6 * 1000
|
||||
)
|
||||
wait_for(check_balances)
|
||||
|
||||
@ -1092,30 +1099,30 @@ class LightningDTests(BaseLightningDTests):
|
||||
preimage2 = details['payment_preimage']
|
||||
assert preimage == preimage2
|
||||
l1.daemon.wait_for_log('... succeeded')
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'paid'
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['msatoshi_received'] == rs['msatoshi']
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['msatoshi_received'] == rs['msatoshi']
|
||||
|
||||
# Overpaying by "only" a factor of 2 succeeds.
|
||||
rhash = l2.rpc.invoice(amt, 'testpayment3', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment3')['invoices'])['status'] == 'unpaid'
|
||||
routestep = {'msatoshi': amt * 2, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}
|
||||
l1.rpc.sendpay(to_json([routestep]), rhash)
|
||||
preimage3 = l1.rpc.waitsendpay(rhash)['payment_preimage']
|
||||
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'paid'
|
||||
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['msatoshi_received'] == amt * 2
|
||||
assert only_one(l2.rpc.listinvoices('testpayment3')['invoices'])['status'] == 'paid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment3')['invoices'])['msatoshi_received'] == amt * 2
|
||||
|
||||
# Test listpayments
|
||||
payments = l1.rpc.listpayments()['payments']
|
||||
assert len(payments) == 2
|
||||
|
||||
invoice2 = l2.rpc.listinvoices('testpayment2')['invoices'][0]
|
||||
invoice2 = only_one(l2.rpc.listinvoices('testpayment2')['invoices'])
|
||||
payments = l1.rpc.listpayments(payment_hash=invoice2['payment_hash'])['payments']
|
||||
assert len(payments) == 1
|
||||
|
||||
assert payments[0]['status'] == 'complete'
|
||||
assert payments[0]['payment_preimage'] == preimage2
|
||||
|
||||
invoice3 = l2.rpc.listinvoices('testpayment3')['invoices'][0]
|
||||
invoice3 = only_one(l2.rpc.listinvoices('testpayment3')['invoices'])
|
||||
payments = l1.rpc.listpayments(payment_hash=invoice3['payment_hash'])['payments']
|
||||
assert len(payments) == 1
|
||||
|
||||
@ -1192,7 +1199,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert details['created_at'] >= before
|
||||
assert details['created_at'] <= after
|
||||
|
||||
invoice = l2.rpc.listinvoices('test_pay')['invoices'][0]
|
||||
invoice = only_one(l2.rpc.listinvoices('test_pay')['invoices'])
|
||||
assert invoice['status'] == 'paid'
|
||||
assert invoice['paid_at'] >= before
|
||||
assert invoice['paid_at'] <= after
|
||||
@ -1219,8 +1226,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert len(l1.rpc.listpayments()['payments']) == 6
|
||||
|
||||
# Test listpayments indexed by bolt11.
|
||||
assert len(l1.rpc.listpayments(inv)['payments']) == 1
|
||||
assert l1.rpc.listpayments(inv)['payments'][0]['payment_preimage'] == preimage
|
||||
assert only_one(l1.rpc.listpayments(inv)['payments'])['payment_preimage'] == preimage
|
||||
|
||||
def test_pay_optional_args(self):
|
||||
l1, l2 = self.connect()
|
||||
@ -1233,17 +1239,17 @@ class LightningDTests(BaseLightningDTests):
|
||||
inv1 = l2.rpc.invoice(123000, 'test_pay', '1000')['bolt11']
|
||||
l1.rpc.pay(inv1, description='1000')
|
||||
payment1 = l1.rpc.listpayments(inv1)['payments']
|
||||
assert len(payment1) == 1 and payment1[0]['msatoshi'] == 123000
|
||||
assert only_one(payment1)['msatoshi'] == 123000
|
||||
|
||||
inv2 = l2.rpc.invoice(321000, 'test_pay2', 'description')['bolt11']
|
||||
l1.rpc.pay(inv2, riskfactor=5.0)
|
||||
payment2 = l1.rpc.listpayments(inv2)['payments']
|
||||
assert len(payment2) == 1 and payment2[0]['msatoshi'] == 321000
|
||||
assert only_one(payment2)['msatoshi'] == 321000
|
||||
|
||||
anyinv = l2.rpc.invoice('any', 'any_pay', 'description')['bolt11']
|
||||
l1.rpc.pay(anyinv, description='1000', msatoshi='500')
|
||||
payment3 = l1.rpc.listpayments(anyinv)['payments']
|
||||
assert len(payment3) == 1 and payment3[0]['msatoshi'] == 500
|
||||
assert only_one(payment3)['msatoshi'] == 500
|
||||
|
||||
# Should see 3 completed transactions
|
||||
assert len(l1.rpc.listpayments()['payments']) == 3
|
||||
@ -1323,9 +1329,9 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0
|
||||
|
||||
billboard = l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status']
|
||||
billboard = only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status']
|
||||
assert billboard == ['CHANNELD_NORMAL:Funding transaction locked.']
|
||||
billboard = l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]['status']
|
||||
billboard = only_one(l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'])['status']
|
||||
assert billboard == ['CHANNELD_NORMAL:Funding transaction locked.']
|
||||
|
||||
l1.bitcoin.rpc.generate(5)
|
||||
@ -1336,7 +1342,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
if DEVELOPER:
|
||||
wait_for(lambda: len(l1.getactivechannels()) == 2)
|
||||
wait_for(lambda: len(l2.getactivechannels()) == 2)
|
||||
billboard = l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status']
|
||||
billboard = only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status']
|
||||
# This may either be from a local_update or an announce, so just
|
||||
# check for the substring
|
||||
assert 'CHANNELD_NORMAL:Funding transaction locked.' in billboard[0]
|
||||
@ -1362,9 +1368,9 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
|
||||
|
||||
# Now grab the close transaction
|
||||
closetxid = l1.bitcoin.rpc.getrawmempool(False)[0]
|
||||
closetxid = only_one(l1.bitcoin.rpc.getrawmempool(False))
|
||||
|
||||
billboard = l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status']
|
||||
billboard = only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status']
|
||||
assert billboard == ['CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi']
|
||||
l1.bitcoin.rpc.generate(1)
|
||||
|
||||
@ -1375,10 +1381,10 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert closetxid in set([o['txid'] for o in l1.rpc.listfunds()['outputs']])
|
||||
assert closetxid in set([o['txid'] for o in l2.rpc.listfunds()['outputs']])
|
||||
|
||||
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status'] == ['CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi', 'ONCHAIN:Tracking mutual close transaction', 'ONCHAIN:All outputs resolved: waiting 99 more blocks before forgetting channel'])
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status'] == ['CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi', 'ONCHAIN:Tracking mutual close transaction', 'ONCHAIN:All outputs resolved: waiting 99 more blocks before forgetting channel'])
|
||||
|
||||
l1.bitcoin.rpc.generate(9)
|
||||
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status'] == ['CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi', 'ONCHAIN:Tracking mutual close transaction', 'ONCHAIN:All outputs resolved: waiting 90 more blocks before forgetting channel'])
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status'] == ['CLOSINGD_SIGEXCHANGE:We agreed on a closing fee of 5430 satoshi', 'ONCHAIN:Tracking mutual close transaction', 'ONCHAIN:All outputs resolved: waiting 90 more blocks before forgetting channel'])
|
||||
|
||||
# Make sure both have forgotten about it
|
||||
l1.bitcoin.rpc.generate(90)
|
||||
@ -1553,7 +1559,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
bitcoind.generate_block(1)
|
||||
for p in peers:
|
||||
p.daemon.wait_for_log(' to ONCHAIN')
|
||||
wait_for(lambda: p.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]['status'][1] == 'ONCHAIN:Tracking mutual close transaction')
|
||||
wait_for(lambda: only_one(p.rpc.listpeers(l1.info['id'])['peers'][0]['channels'])['status'][1] == 'ONCHAIN:Tracking mutual close transaction')
|
||||
l1.daemon.wait_for_logs([' to ONCHAIN'] * num_peers)
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
@ -1581,7 +1587,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 1
|
||||
|
||||
# Now grab the close transaction
|
||||
closetxid = l1.bitcoin.rpc.getrawmempool(False)[0]
|
||||
closetxid = only_one(l1.bitcoin.rpc.getrawmempool(False))
|
||||
|
||||
# l2 will send out tx (l1 considers it a transient error)
|
||||
bitcoind.generate_block(1)
|
||||
@ -1591,12 +1597,12 @@ class LightningDTests(BaseLightningDTests):
|
||||
l2.daemon.wait_for_log(' to ONCHAIN')
|
||||
l2.daemon.wait_for_log('Propose handling OUR_UNILATERAL/DELAYED_OUTPUT_TO_US by OUR_DELAYED_RETURN_TO_WALLET (.*) after 5 blocks')
|
||||
|
||||
wait_for(lambda: l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'][0]['status'] ==
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers(l2.info['id'])['peers'][0]['channels'])['status'] ==
|
||||
['ONCHAIN:Tracking their unilateral close',
|
||||
'ONCHAIN:All outputs resolved: waiting 99 more blocks before forgetting channel'])
|
||||
|
||||
def check_billboard():
|
||||
billboard = l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]['status']
|
||||
billboard = only_one(l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'])['status']
|
||||
return (
|
||||
len(billboard) == 2 and
|
||||
billboard[0] == 'ONCHAIN:Tracking our own unilateral close' and
|
||||
@ -1615,7 +1621,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
bitcoind.generate_block(95)
|
||||
wait_forget_channels(l1)
|
||||
|
||||
wait_for(lambda: l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]['status'] == ['ONCHAIN:Tracking our own unilateral close', 'ONCHAIN:All outputs resolved: waiting 5 more blocks before forgetting channel'])
|
||||
wait_for(lambda: only_one(l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'])['status'] == ['ONCHAIN:Tracking our own unilateral close', 'ONCHAIN:All outputs resolved: waiting 5 more blocks before forgetting channel'])
|
||||
|
||||
# Now, 100 blocks l2 should be done.
|
||||
bitcoind.generate_block(5)
|
||||
@ -1828,7 +1834,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
||||
|
||||
# Payment failed, BTW
|
||||
assert l2.rpc.listinvoices('onchain_dust_out')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('onchain_dust_out')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
def test_onchain_timeout(self):
|
||||
@ -1898,7 +1904,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
||||
|
||||
# Payment failed, BTW
|
||||
assert l2.rpc.listinvoices('onchain_timeout')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('onchain_timeout')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
def test_onchain_middleman(self):
|
||||
@ -2174,7 +2180,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.daemon.wait_for_log('onchaind complete, forgetting peer')
|
||||
|
||||
# Payment failed, BTW
|
||||
assert l2.rpc.listinvoices('onchain_timeout')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('onchain_timeout')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for dev-set-fees")
|
||||
def test_onchain_all_dust(self):
|
||||
@ -2456,8 +2462,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert set([n['nodeid'] for n in nodes]) == set([l1.info['id'], l2.info['id']])
|
||||
|
||||
# Test listnodes with an arg, while we're here.
|
||||
n1 = l1.rpc.listnodes(l1.info['id'])['nodes'][0]
|
||||
n2 = l1.rpc.listnodes(l2.info['id'])['nodes'][0]
|
||||
n1 = only_one(l1.rpc.listnodes(l1.info['id'])['nodes'])
|
||||
n2 = only_one(l1.rpc.listnodes(l2.info['id'])['nodes'])
|
||||
assert n1['nodeid'] == l1.info['id']
|
||||
assert n2['nodeid'] == l2.info['id']
|
||||
|
||||
@ -2497,9 +2503,9 @@ class LightningDTests(BaseLightningDTests):
|
||||
l2.daemon.wait_for_log('Received node_announcement for node {}'
|
||||
.format(l1.info['id']))
|
||||
|
||||
node = l1.rpc.listnodes(l1.info['id'])['nodes'][0]
|
||||
node = only_one(l1.rpc.listnodes(l1.info['id'])['nodes'])
|
||||
assert node['alias'] == weird_name
|
||||
node = l2.rpc.listnodes(l1.info['id'])['nodes'][0]
|
||||
node = only_one(l2.rpc.listnodes(l1.info['id'])['nodes'])
|
||||
assert node['alias'] == weird_name
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for --dev-no-reconnect")
|
||||
@ -2962,7 +2968,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
# l3 actually disconnects from l4 *and* l2! That means we never see
|
||||
# the (delayed) channel_update from l4.
|
||||
wait_for(lambda: not l3.rpc.listpeers(l4.info['id'])['peers'][0]['connected'])
|
||||
wait_for(lambda: not only_one(l3.rpc.listpeers(l4.info['id'])['peers'])['connected'])
|
||||
l3.rpc.connect(l4.info['id'], 'localhost', l4.port)
|
||||
|
||||
# But it never goes to l1, as there's no channel_update.
|
||||
@ -3037,13 +3043,13 @@ class LightningDTests(BaseLightningDTests):
|
||||
# If they're at different block heights we can get spurious errors.
|
||||
sync_blockheight([l1, l2, l3])
|
||||
|
||||
chanid1 = l1.rpc.getpeer(l2.info['id'])['channels'][0]['short_channel_id']
|
||||
chanid2 = l2.rpc.getpeer(l3.info['id'])['channels'][0]['short_channel_id']
|
||||
assert l2.rpc.getpeer(l1.info['id'])['channels'][0]['short_channel_id'] == chanid1
|
||||
assert l3.rpc.getpeer(l2.info['id'])['channels'][0]['short_channel_id'] == chanid2
|
||||
chanid1 = only_one(l1.rpc.getpeer(l2.info['id'])['channels'])['short_channel_id']
|
||||
chanid2 = only_one(l2.rpc.getpeer(l3.info['id'])['channels'])['short_channel_id']
|
||||
assert only_one(l2.rpc.getpeer(l1.info['id'])['channels'])['short_channel_id'] == chanid1
|
||||
assert only_one(l3.rpc.getpeer(l2.info['id'])['channels'])['short_channel_id'] == chanid2
|
||||
|
||||
rhash = l3.rpc.invoice(100000000, 'testpayment1', 'desc')['payment_hash']
|
||||
assert l3.rpc.listinvoices('testpayment1')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l3.rpc.listinvoices('testpayment1')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# Fee for node2 is 10 millionths, plus 1.
|
||||
amt = 100000000
|
||||
@ -3188,7 +3194,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
assert route[1]['delay'] == 9 + shadow_route
|
||||
|
||||
rhash = l3.rpc.invoice(4999999, 'test_forward_different_fees_and_cltv', 'desc')['payment_hash']
|
||||
assert l3.rpc.listinvoices('test_forward_different_fees_and_cltv')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l3.rpc.listinvoices('test_forward_different_fees_and_cltv')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
# This should work.
|
||||
l1.rpc.sendpay(to_json(route), rhash)
|
||||
@ -3202,7 +3208,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
.format(bitcoind.rpc.getblockcount() + 9 + shadow_route))
|
||||
l3.daemon.wait_for_log("test_forward_different_fees_and_cltv: Actual amount 4999999msat, HTLC expiry {}"
|
||||
.format(bitcoind.rpc.getblockcount() + 9 + shadow_route))
|
||||
assert l3.rpc.listinvoices('test_forward_different_fees_and_cltv')['invoices'][0]['status'] == 'paid'
|
||||
assert only_one(l3.rpc.listinvoices('test_forward_different_fees_and_cltv')['invoices'])['status'] == 'paid'
|
||||
|
||||
# Check that we see all the channels
|
||||
shortids = set(c['short_channel_id'] for c in l2.rpc.listchannels()['channels'])
|
||||
@ -3259,7 +3265,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
rhash = l3.rpc.invoice(4999999, 'test_forward_pad_fees_and_cltv', 'desc')['payment_hash']
|
||||
l1.rpc.sendpay(to_json(route), rhash)
|
||||
l1.rpc.waitsendpay(rhash)
|
||||
assert l3.rpc.listinvoices('test_forward_pad_fees_and_cltv')['invoices'][0]['status'] == 'paid'
|
||||
assert only_one(l3.rpc.listinvoices('test_forward_pad_fees_and_cltv')['invoices'])['status'] == 'paid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1 for --dev-broadcast-interval")
|
||||
def test_htlc_sig_persistence(self):
|
||||
@ -3323,7 +3329,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
inv = l2.rpc.invoice(amt, 'test_htlc_out_timeout', 'desc')['bolt11']
|
||||
assert l2.rpc.listinvoices('test_htlc_out_timeout')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('test_htlc_out_timeout')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
self.executor.submit(l1.rpc.pay, inv)
|
||||
|
||||
@ -3379,7 +3385,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
inv = l2.rpc.invoice(amt, 'test_htlc_in_timeout', 'desc')['bolt11']
|
||||
assert l2.rpc.listinvoices('test_htlc_in_timeout')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('test_htlc_in_timeout')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
self.executor.submit(l1.rpc.pay, inv)
|
||||
|
||||
@ -3590,7 +3596,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
rhash = l2.rpc.invoice(amt, 'test_reconnect_sender_add1', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('test_reconnect_sender_add1')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('test_reconnect_sender_add1')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
|
||||
|
||||
@ -3620,7 +3626,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
rhash = l2.rpc.invoice(amt, 'testpayment', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('testpayment')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
|
||||
|
||||
@ -3647,13 +3653,13 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
|
||||
l1.rpc.sendpay(to_json(route), rhash)
|
||||
for i in range(len(disconnects)):
|
||||
l1.daemon.wait_for_log('Already have funding locked in')
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'paid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
def test_reconnect_receiver_fulfill(self):
|
||||
@ -3678,13 +3684,13 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
amt = 200000000
|
||||
rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash']
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'unpaid'
|
||||
|
||||
route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
|
||||
l1.rpc.sendpay(to_json(route), rhash)
|
||||
for i in range(len(disconnects)):
|
||||
l1.daemon.wait_for_log('Already have funding locked in')
|
||||
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'paid'
|
||||
assert only_one(l2.rpc.listinvoices('testpayment2')['invoices'])['status'] == 'paid'
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
def test_shutdown_reconnect(self):
|
||||
@ -3805,10 +3811,10 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
def is_p2wpkh(output):
|
||||
return output['type'] == 'witness_v0_keyhash' and \
|
||||
address == output['addresses'][0]
|
||||
address == only_one(output['addresses'])
|
||||
|
||||
assert any(is_p2wpkh(output['scriptPubKey']) for output in wallettx['vout'])
|
||||
assert fundingtx['vin'][0]['txid'] == res['wallettxid']
|
||||
assert only_one(fundingtx['vin'])['txid'] == res['wallettxid']
|
||||
|
||||
def test_withdraw(self):
|
||||
amount = 1000000
|
||||
@ -3842,7 +3848,6 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Make sure bitcoind received the withdrawal
|
||||
unspent = l1.bitcoin.rpc.listunspent(0)
|
||||
withdrawal = [u for u in unspent if u['txid'] == out['txid']]
|
||||
assert(len(withdrawal) == 1)
|
||||
|
||||
assert(withdrawal[0]['amount'] == Decimal('0.02'))
|
||||
|
||||
@ -3860,7 +3865,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Make sure l2 received the withdrawal.
|
||||
wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == 1)
|
||||
outputs = l2.db_query('SELECT value FROM outputs WHERE status=0;')
|
||||
assert len(outputs) == 1 and outputs[0]['value'] == 2 * amount
|
||||
assert only_one(outputs)['value'] == 2 * amount
|
||||
|
||||
# Now make sure an additional two of them were marked as spent
|
||||
c = db.cursor()
|
||||
@ -3940,7 +3945,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
self.give_funds(l1, 0.1 * 10**8)
|
||||
|
||||
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
||||
assert len(outputs) == 1 and outputs[0]['value'] == 10000000
|
||||
assert only_one(outputs)['value'] == 10000000
|
||||
|
||||
l1.rpc.fundchannel(l2.info['id'], 1000000)
|
||||
outputs = {r['status']: r['value'] for r in l1.db_query(
|
||||
@ -3958,7 +3963,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
self.give_funds(l1, 0.1 * 10**8)
|
||||
|
||||
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
||||
assert len(outputs) == 1 and outputs[0]['value'] == 10000000
|
||||
assert only_one(outputs)['value'] == 10000000
|
||||
|
||||
l1.rpc.fundchannel(l2.info['id'], "all")
|
||||
|
||||
@ -3985,8 +3990,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Fail because l1 dislikes l2's huge locktime.
|
||||
self.assertRaisesRegex(RpcError, r'to_self_delay \d+ larger than \d+',
|
||||
l1.rpc.fundchannel, l2.info['id'], int(funds / 10))
|
||||
assert l1.rpc.listpeers()['peers'][0]['connected']
|
||||
assert l2.rpc.listpeers()['peers'][0]['connected']
|
||||
assert only_one(l1.rpc.listpeers()['peers'])['connected']
|
||||
assert only_one(l2.rpc.listpeers()['peers'])['connected']
|
||||
|
||||
# Restart l2 without ridiculous locktime.
|
||||
del l2.daemon.opts['watchtime-blocks']
|
||||
@ -3998,8 +4003,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.rpc.fundchannel, l2.info['id'], funds)
|
||||
|
||||
# Should still be connected.
|
||||
assert l1.rpc.listpeers()['peers'][0]['connected']
|
||||
assert l2.rpc.listpeers()['peers'][0]['connected']
|
||||
assert only_one(l1.rpc.listpeers()['peers'])['connected']
|
||||
assert only_one(l2.rpc.listpeers()['peers'])['connected']
|
||||
|
||||
# This works.
|
||||
l1.rpc.fundchannel(l2.info['id'], int(funds / 10))
|
||||
@ -4084,10 +4089,10 @@ class LightningDTests(BaseLightningDTests):
|
||||
wait_for(lambda: len(l1.rpc.listfunds()['outputs']) == 1)
|
||||
|
||||
outputs = l1.db_query('SELECT value FROM outputs WHERE status=0;')
|
||||
assert len(outputs) == 1 and outputs[0]['value'] == 10000000
|
||||
assert only_one(outputs)['value'] == 10000000
|
||||
|
||||
# The address we detect must match what was paid to.
|
||||
output = l1.rpc.listfunds()['outputs'][0]
|
||||
output = only_one(l1.rpc.listfunds()['outputs'])
|
||||
assert output['address'] == addr
|
||||
|
||||
# Send all our money to a P2WPKH address this time.
|
||||
@ -4097,7 +4102,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
time.sleep(1)
|
||||
|
||||
# The address we detect must match what was paid to.
|
||||
output = l1.rpc.listfunds()['outputs'][0]
|
||||
output = only_one(l1.rpc.listfunds()['outputs'])
|
||||
assert output['address'] == addr
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
|
||||
@ -4117,7 +4122,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
self.fund_channel(l1, l2, 100000)
|
||||
|
||||
peers = l1.rpc.listpeers()['peers']
|
||||
assert(len(peers) == 1 and peers[0]['channels'][0]['state'] == 'CHANNELD_NORMAL')
|
||||
assert(only_one(peers[0]['channels'])['state'] == 'CHANNELD_NORMAL')
|
||||
|
||||
# Both nodes should now have exactly one channel in the database
|
||||
for n in (l1, l2):
|
||||
@ -4136,14 +4141,14 @@ class LightningDTests(BaseLightningDTests):
|
||||
del l2.daemon.opts['dev-disconnect']
|
||||
|
||||
# Wait for l1 to notice
|
||||
wait_for(lambda: 'connected' not in l1.rpc.listpeers()['peers'][0]['channels'][0])
|
||||
wait_for(lambda: 'connected' not in only_one(l1.rpc.listpeers()['peers'][0]['channels']))
|
||||
|
||||
# Now restart l2 and it should reload peers/channels from the DB
|
||||
l2.start()
|
||||
wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 1)
|
||||
|
||||
# Wait for the restored HTLC to finish
|
||||
wait_for(lambda: l1.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 99990000, interval=1)
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers()['peers'][0]['channels'])['msatoshi_to_us'] == 99990000, interval=1)
|
||||
|
||||
wait_for(lambda: len([p for p in l1.rpc.listpeers()['peers'] if p['connected']]), interval=1)
|
||||
wait_for(lambda: len([p for p in l2.rpc.listpeers()['peers'] if p['connected']]), interval=1)
|
||||
@ -4153,12 +4158,12 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
# L1 doesn't actually update msatoshi_to_us until it receives
|
||||
# revoke_and_ack from L2, which can take a little bit.
|
||||
wait_for(lambda: l1.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 99980000)
|
||||
assert l2.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 20000
|
||||
wait_for(lambda: only_one(l1.rpc.listpeers()['peers'][0]['channels'])['msatoshi_to_us'] == 99980000)
|
||||
assert only_one(l2.rpc.listpeers()['peers'][0]['channels'])['msatoshi_to_us'] == 20000
|
||||
|
||||
# Finally restart l1, and make sure it remembers
|
||||
l1.restart()
|
||||
assert l1.rpc.listpeers()['peers'][0]['channels'][0]['msatoshi_to_us'] == 99980000
|
||||
assert only_one(l1.rpc.listpeers()['peers'][0]['channels'])['msatoshi_to_us'] == 99980000
|
||||
|
||||
# Now make sure l1 is watching for unilateral closes
|
||||
l2.rpc.dev_fail(l1.info['id'])
|
||||
@ -4197,10 +4202,10 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Should reconnect, and sort the payment out.
|
||||
l1.start()
|
||||
|
||||
wait_for(lambda: l1.rpc.listpayments()['payments'][0]['status'] != 'pending')
|
||||
wait_for(lambda: only_one(l1.rpc.listpayments()['payments'])['status'] != 'pending')
|
||||
|
||||
assert l1.rpc.listpayments()['payments'][0]['status'] == 'complete'
|
||||
assert l2.rpc.listinvoices('inv1')['invoices'][0]['status'] == 'paid'
|
||||
assert only_one(l1.rpc.listpayments()['payments'])['status'] == 'complete'
|
||||
assert only_one(l2.rpc.listinvoices('inv1')['invoices'])['status'] == 'paid'
|
||||
|
||||
# FIXME: We should re-add pre-announced routes on startup!
|
||||
l1.bitcoin.rpc.generate(5)
|
||||
@ -4242,10 +4247,10 @@ class LightningDTests(BaseLightningDTests):
|
||||
# Should reconnect, and fail the payment
|
||||
l1.start()
|
||||
|
||||
wait_for(lambda: l1.rpc.listpayments()['payments'][0]['status'] != 'pending')
|
||||
wait_for(lambda: only_one(l1.rpc.listpayments()['payments'])['status'] != 'pending')
|
||||
|
||||
assert l2.rpc.listinvoices('inv1')['invoices'][0]['status'] == 'expired'
|
||||
assert l1.rpc.listpayments()['payments'][0]['status'] == 'failed'
|
||||
assert only_one(l2.rpc.listinvoices('inv1')['invoices'])['status'] == 'expired'
|
||||
assert only_one(l1.rpc.listpayments()['payments'])['status'] == 'failed'
|
||||
|
||||
# Another attempt should also fail.
|
||||
self.assertRaises(RpcError, l1.rpc.pay, inv1['bolt11'])
|
||||
@ -4269,8 +4274,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.daemon.wait_for_log('dev_disconnect: =WIRE_UPDATE_ADD_HTLC-nocommit')
|
||||
|
||||
# We should see it in listpayments
|
||||
assert l1.rpc.listpayments()['payments'][0]['status'] == 'pending'
|
||||
assert l1.rpc.listpayments()['payments'][0]['payment_hash'] == inv1['payment_hash']
|
||||
assert only_one(l1.rpc.listpayments()['payments'])['status'] == 'pending'
|
||||
assert only_one(l1.rpc.listpayments()['payments'])['payment_hash'] == inv1['payment_hash']
|
||||
|
||||
# Second one will succeed eventually.
|
||||
fut2 = self.executor.submit(l1.rpc.pay, inv1['bolt11'])
|
||||
@ -4620,7 +4625,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
start=l1.daemon.logsearch_start)
|
||||
|
||||
# IO logs should not appear in peer logs.
|
||||
peerlog = l2.rpc.listpeers(l1.info['id'], "io")['peers'][0]['log']
|
||||
peerlog = only_one(l2.rpc.listpeers(l1.info['id'], "io")['peers'])['log']
|
||||
assert not any(l['type'] == 'IO_OUT' or l['type'] == 'IO_IN'
|
||||
for l in peerlog)
|
||||
|
||||
@ -4629,7 +4634,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
self.pay(l1, l2, 200000000)
|
||||
|
||||
# Now it should find it.
|
||||
peerlog = l2.rpc.listpeers(l1.info['id'], "io")['peers'][0]['log']
|
||||
peerlog = only_one(l2.rpc.listpeers(l1.info['id'], "io")['peers'])['log']
|
||||
assert any(l['type'] == 'IO_OUT' for l in peerlog)
|
||||
assert any(l['type'] == 'IO_IN' for l in peerlog)
|
||||
|
||||
@ -4718,7 +4723,7 @@ class LightningDTests(BaseLightningDTests):
|
||||
|
||||
l1.rpc.close(chan)
|
||||
|
||||
channels = l1.rpc.listpeers()['peers'][0]['channels']
|
||||
channels = only_one(l1.rpc.listpeers()['peers'])['channels']
|
||||
assert len(channels) == 3
|
||||
# Most in state ONCHAIN, last is CLOSINGD_COMPLETE
|
||||
for i in range(len(channels) - 1):
|
||||
@ -4855,8 +4860,8 @@ class LightningDTests(BaseLightningDTests):
|
||||
l1.daemon.wait_for_logs(['Received node_announcement for node ' + l2.info['id']])
|
||||
|
||||
# With the node announcement, ensure we see that information in the peer info
|
||||
assert l1.rpc.getpeer(l2.info['id'])['alias'] == l1.rpc.listnodes(l2.info['id'])['nodes'][0]['alias']
|
||||
assert l1.rpc.getpeer(l2.info['id'])['color'] == l1.rpc.listnodes(l2.info['id'])['nodes'][0]['color']
|
||||
assert l1.rpc.getpeer(l2.info['id'])['alias'] == only_one(l1.rpc.listnodes(l2.info['id'])['nodes'])['alias']
|
||||
assert l1.rpc.getpeer(l2.info['id'])['color'] == only_one(l1.rpc.listnodes(l2.info['id'])['nodes'])['color']
|
||||
|
||||
# Close the channel to forget the peer
|
||||
self.assertRaisesRegex(RpcError,
|
||||
|
Loading…
Reference in New Issue
Block a user