mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-03-03 10:46:58 +01:00
pytest: Test that we record forwardings correctly
Adapts the `test_forward_stats` test to include checks for the `forwarded_payments` table. Will add checks for the `listforwardings` RPC call next. Signed-off-by: Christian Decker <@cdecker>
This commit is contained in:
parent
4b4c549c9d
commit
6efdd5275c
2 changed files with 67 additions and 20 deletions
|
@ -976,30 +976,73 @@ def test_forward_pad_fees_and_cltv(node_factory, bitcoind):
|
||||||
assert only_one(l3.rpc.listinvoices('test_forward_pad_fees_and_cltv')['invoices'])['status'] == 'paid'
|
assert only_one(l3.rpc.listinvoices('test_forward_pad_fees_and_cltv')['invoices'])['status'] == 'paid'
|
||||||
|
|
||||||
|
|
||||||
def test_forward_stats(node_factory):
|
def test_forward_stats(node_factory, bitcoind):
|
||||||
l1, l2, l3 = node_factory.line_graph(3, announce=True)
|
"""Check that we track forwarded payments correctly.
|
||||||
|
|
||||||
inv = l3.rpc.invoice(100000, "first", "desc")['bolt11']
|
We wire up the network to have l1 as payment initiator, l2 as
|
||||||
l1.rpc.pay(inv)
|
forwarded (the one we check) and l3-l5 as payment recipients. l3
|
||||||
|
accepts correctly, l4 refects (because it doesn't know the payment
|
||||||
|
hash) and l5 will keep the HTLC dangling by disconnecting.
|
||||||
|
|
||||||
|
"""
|
||||||
|
amount = 10**4
|
||||||
|
l1, l2, l3 = node_factory.line_graph(3, announce=False)
|
||||||
|
l4 = node_factory.get_node()
|
||||||
|
l5 = node_factory.get_node(may_fail=True)
|
||||||
|
l2.openchannel(l4, 10**6, announce=False)
|
||||||
|
l2.openchannel(l5, 10**6, announce=True)
|
||||||
|
|
||||||
|
bitcoind.generate_block(5)
|
||||||
|
|
||||||
|
wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 8)
|
||||||
|
|
||||||
|
payment_hash = l3.rpc.invoice(amount, "first", "desc")['payment_hash']
|
||||||
|
route = l1.rpc.getroute(l3.info['id'], amount, 1)['route']
|
||||||
|
|
||||||
|
l1.rpc.sendpay(route, payment_hash)
|
||||||
|
l1.rpc.waitsendpay(payment_hash)
|
||||||
|
|
||||||
|
# l4 rejects since it doesn't know the payment_hash
|
||||||
|
route = l1.rpc.getroute(l4.info['id'], amount, 1)['route']
|
||||||
|
payment_hash = "F" * 64
|
||||||
|
with pytest.raises(RpcError):
|
||||||
|
l1.rpc.sendpay(route, payment_hash)
|
||||||
|
l1.rpc.waitsendpay(payment_hash)
|
||||||
|
|
||||||
|
# l5 will hold the HTLC hostage and walk away
|
||||||
|
route = l1.rpc.getroute(l5.info['id'], amount, 1)['route']
|
||||||
|
payment_hash = l5.rpc.invoice(amount, "first", "desc")['payment_hash']
|
||||||
|
l1.rpc.sendpay(route, payment_hash)
|
||||||
|
|
||||||
|
# Wait for the HTLC to be added, then try to kill it to keep the
|
||||||
|
# HTLC pending. This is racy but there seems to be no good
|
||||||
|
# alternative
|
||||||
|
l5.daemon.wait_for_log(r'RCVD_ADD_HTLC/SENT_ADD_HTLC')
|
||||||
|
l5.daemon.wait_for_log(r'peer_out WIRE_COMMITMENT_SIGNED')
|
||||||
|
l5.daemon.kill()
|
||||||
|
print("Killed!")
|
||||||
|
|
||||||
|
# Select all forwardings, ordered by htlc_id to ensure the order
|
||||||
|
# matches below
|
||||||
|
forwardings = l2.db_query("SELECT *, in_msatoshi - out_msatoshi as fee "
|
||||||
|
"FROM forwarded_payments "
|
||||||
|
"ORDER BY in_htlc_id;")
|
||||||
|
assert(len(forwardings) == 3)
|
||||||
|
states = [f['state'] for f in forwardings]
|
||||||
|
assert(states == [1, 2, 0]) # settled, failed, offered
|
||||||
|
|
||||||
inchan = l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]
|
inchan = l2.rpc.listpeers(l1.info['id'])['peers'][0]['channels'][0]
|
||||||
outchan = l2.rpc.listpeers(l3.info['id'])['peers'][0]['channels'][0]
|
outchan = l2.rpc.listpeers(l3.info['id'])['peers'][0]['channels'][0]
|
||||||
|
|
||||||
def extract_stats(c):
|
|
||||||
return {k: v for k, v in c.items() if 'in_' in k or 'out_' in k}
|
|
||||||
|
|
||||||
instats = extract_stats(inchan)
|
|
||||||
outstats = extract_stats(outchan)
|
|
||||||
|
|
||||||
# Check that we correctly account channel changes
|
# Check that we correctly account channel changes
|
||||||
assert instats['in_payments_offered'] == 1
|
assert inchan['in_payments_offered'] == 3
|
||||||
assert instats['in_payments_fulfilled'] == 1
|
assert inchan['in_payments_fulfilled'] == 1
|
||||||
assert instats['in_msatoshi_offered'] >= 100000
|
assert inchan['in_msatoshi_offered'] >= 3 * amount
|
||||||
assert instats['in_msatoshi_offered'] == instats['in_msatoshi_fulfilled']
|
assert inchan['in_msatoshi_fulfilled'] >= amount
|
||||||
|
|
||||||
assert outstats['out_payments_offered'] == 1
|
assert outchan['out_payments_offered'] == 1
|
||||||
assert outstats['out_payments_fulfilled'] == 1
|
assert outchan['out_payments_fulfilled'] == 1
|
||||||
assert outstats['out_msatoshi_offered'] >= 100000
|
assert outchan['out_msatoshi_offered'] >= amount
|
||||||
assert outstats['out_msatoshi_offered'] == outstats['out_msatoshi_fulfilled']
|
assert outchan['out_msatoshi_offered'] == outchan['out_msatoshi_fulfilled']
|
||||||
|
|
||||||
assert outstats['out_msatoshi_fulfilled'] < instats['in_msatoshi_fulfilled']
|
assert outchan['out_msatoshi_fulfilled'] < inchan['in_msatoshi_fulfilled']
|
||||||
|
|
|
@ -380,8 +380,12 @@ class LightningNode(object):
|
||||||
self.may_fail = may_fail
|
self.may_fail = may_fail
|
||||||
self.may_reconnect = may_reconnect
|
self.may_reconnect = may_reconnect
|
||||||
|
|
||||||
def openchannel(self, remote_node, capacity, addrtype="p2sh-segwit", confirm=True, announce=True):
|
def openchannel(self, remote_node, capacity, addrtype="p2sh-segwit", confirm=True, announce=True, connect=True):
|
||||||
addr, wallettxid = self.fundwallet(10 * capacity, addrtype)
|
addr, wallettxid = self.fundwallet(10 * capacity, addrtype)
|
||||||
|
|
||||||
|
if connect and remote_node.info['id'] not in [p['id'] for p in self.rpc.listpeers()['peers']]:
|
||||||
|
self.rpc.connect(remote_node.info['id'], '127.0.0.1', remote_node.daemon.port)
|
||||||
|
|
||||||
fundingtx = self.rpc.fundchannel(remote_node.info['id'], capacity)
|
fundingtx = self.rpc.fundchannel(remote_node.info['id'], capacity)
|
||||||
|
|
||||||
# Wait for the funding transaction to be in bitcoind's mempool
|
# Wait for the funding transaction to be in bitcoind's mempool
|
||||||
|
|
Loading…
Add table
Reference in a new issue