|
|
@ -1,4 +1,3 @@ |
|
|
|
from binascii import hexlify, unhexlify |
|
|
|
from concurrent import futures |
|
|
|
from decimal import Decimal |
|
|
|
from hashlib import sha256 |
|
|
@ -43,7 +42,7 @@ def setupBitcoind(directory): |
|
|
|
try: |
|
|
|
bitcoind.start() |
|
|
|
except: |
|
|
|
tearDownBitcoind() |
|
|
|
teardown_bitcoind() |
|
|
|
raise |
|
|
|
|
|
|
|
info = bitcoind.rpc.getblockchaininfo() |
|
|
@ -63,6 +62,7 @@ def wait_for(success, timeout=30, interval=0.1): |
|
|
|
if time.time() > start_time + timeout: |
|
|
|
raise ValueError("Error waiting for {}", success) |
|
|
|
|
|
|
|
|
|
|
|
def wait_forget_channels(node): |
|
|
|
"""This node is closing all of its channels, check we are forgetting them |
|
|
|
""" |
|
|
@ -70,12 +70,14 @@ def wait_forget_channels(node): |
|
|
|
assert node.rpc.listpeers()['peers'] == [] |
|
|
|
assert node.db_query("SELECT * FROM channels") == [] |
|
|
|
|
|
|
|
|
|
|
|
def sync_blockheight(nodes): |
|
|
|
target = bitcoind.rpc.getblockcount() |
|
|
|
for n in nodes: |
|
|
|
wait_for(lambda: n.rpc.getinfo()['blockheight'] == target) |
|
|
|
|
|
|
|
def tearDownBitcoind(): |
|
|
|
|
|
|
|
def teardown_bitcoind(): |
|
|
|
global bitcoind |
|
|
|
try: |
|
|
|
bitcoind.rpc.stop() |
|
|
@ -83,6 +85,7 @@ def tearDownBitcoind(): |
|
|
|
bitcoind.proc.kill() |
|
|
|
bitcoind.proc.wait() |
|
|
|
|
|
|
|
|
|
|
|
class NodeFactory(object): |
|
|
|
"""A factory to setup and start `lightningd` daemons. |
|
|
|
""" |
|
|
@ -217,7 +220,7 @@ class BaseLightningDTests(unittest.TestCase): |
|
|
|
ok = self.node_factory.killall([not n.may_fail for n in self.node_factory.nodes]) |
|
|
|
self.executor.shutdown(wait=False) |
|
|
|
|
|
|
|
tearDownBitcoind() |
|
|
|
teardown_bitcoind() |
|
|
|
err_count = 0 |
|
|
|
# Do not check for valgrind error files if it is disabled |
|
|
|
if VALGRIND: |
|
|
@ -234,6 +237,7 @@ class BaseLightningDTests(unittest.TestCase): |
|
|
|
if not ok: |
|
|
|
raise Exception("At least one lightning exited with unexpected non-zero return code") |
|
|
|
|
|
|
|
|
|
|
|
class LightningDTests(BaseLightningDTests): |
|
|
|
def connect(self): |
|
|
|
l1 = self.node_factory.get_node() |
|
|
@ -259,7 +263,6 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
def fund_channel(self, l1, l2, amount): |
|
|
|
# Generates a block, so we know next tx will be first in block. |
|
|
|
self.give_funds(l1, amount + 1000000) |
|
|
|
|
|
|
|
tx = l1.rpc.fundchannel(l2.info['id'], amount)['tx'] |
|
|
|
# Technically, this is async to fundchannel. |
|
|
|
l1.daemon.wait_for_log('sendrawtx exit 0') |
|
|
@ -270,14 +273,14 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
l2.daemon.wait_for_logs(['update for channel .* now ACTIVE', 'to CHANNELD_NORMAL']) |
|
|
|
|
|
|
|
# Hacky way to find our output. |
|
|
|
decoded=bitcoind.rpc.decoderawtransaction(tx) |
|
|
|
decoded = bitcoind.rpc.decoderawtransaction(tx) |
|
|
|
for out in decoded['vout']: |
|
|
|
# Sometimes a float? Sometimes a decimal? WTF Python?! |
|
|
|
if out['scriptPubKey']['type'] == 'witness_v0_scripthash': |
|
|
|
if out['value'] == Decimal(amount) / 10**8 or out['value'] * 10**8 == amount: |
|
|
|
return "{}:1:{}".format(bitcoind.rpc.getblockcount(), out['n']) |
|
|
|
# Intermittent decoding failure. See if it decodes badly twice? |
|
|
|
decoded2=bitcoind.rpc.decoderawtransaction(tx) |
|
|
|
decoded2 = bitcoind.rpc.decoderawtransaction(tx) |
|
|
|
raise ValueError("Can't find {} payment in {} (1={} 2={})".format(amount, tx, decoded, decoded2)) |
|
|
|
|
|
|
|
def line_graph(self, n=2): |
|
|
@ -382,7 +385,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
# Wait for route propagation. |
|
|
|
self.wait_for_routes(l1, [chanid]) |
|
|
|
|
|
|
|
inv = l2.rpc.invoice(123000, 'test_pay', 'description', 1)['bolt11'] |
|
|
|
inv = l2.rpc.invoice(msatoshi=123000, label='test_pay', description='description', expiry=1)['bolt11'] |
|
|
|
time.sleep(2) |
|
|
|
self.assertRaises(ValueError, l1.rpc.pay, inv) |
|
|
|
assert l2.rpc.listinvoices('test_pay')['invoices'][0]['status'] == 'expired' |
|
|
@ -439,10 +442,10 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
l2.daemon.wait_for_log('hand_back_peer {}: now local again'.format(l1.info['id'])) |
|
|
|
|
|
|
|
# Reconnect should be a noop |
|
|
|
ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
|
ret = l1.rpc.connect(l2.info['id'], 'localhost', port=l2.info['port']) |
|
|
|
assert ret['id'] == l2.info['id'] |
|
|
|
|
|
|
|
ret = l2.rpc.connect(l1.info['id'], 'localhost', l1.info['port']) |
|
|
|
ret = l2.rpc.connect(l1.info['id'], host='localhost', port=l1.info['port']) |
|
|
|
assert ret['id'] == l1.info['id'] |
|
|
|
|
|
|
|
# Should still only have one peer! |
|
|
@ -450,11 +453,10 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
assert len(l2.rpc.listpeers()) == 1 |
|
|
|
|
|
|
|
def test_balance(self): |
|
|
|
l1,l2 = self.connect() |
|
|
|
l1, l2 = self.connect() |
|
|
|
|
|
|
|
self.fund_channel(l1, l2, 10**6) |
|
|
|
|
|
|
|
p1 = l1.rpc.getpeer(l2.info['id'], 'info')['channels'][0] |
|
|
|
p1 = l1.rpc.getpeer(peer_id=l2.info['id'], level='info')['channels'][0] |
|
|
|
p2 = l2.rpc.getpeer(l1.info['id'], 'info')['channels'][0] |
|
|
|
assert p1['msatoshi_to_us'] == 10**6 * 1000 |
|
|
|
assert p1['msatoshi_total'] == 10**6 * 1000 |
|
|
@ -1042,7 +1044,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
+ ['to CHANNELD_NORMAL'] * num_peers) |
|
|
|
for p in peers: |
|
|
|
if p.amount != 0: |
|
|
|
self.pay(l1,p,100000000) |
|
|
|
self.pay(l1, p, 100000000) |
|
|
|
|
|
|
|
# Now close |
|
|
|
for p in peers: |
|
|
@ -1372,7 +1374,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
# Payment should succeed. |
|
|
|
l1.bitcoin.generate_block(1) |
|
|
|
l1.daemon.wait_for_log('THEIR_UNILATERAL/OUR_HTLC gave us preimage') |
|
|
|
err = q.get(timeout = 10) |
|
|
|
err = q.get(timeout=10) |
|
|
|
if err: |
|
|
|
print("Got err from sendpay thread") |
|
|
|
raise err |
|
|
@ -1467,13 +1469,13 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
self.fund_channel(l1, l2, 10**6) |
|
|
|
|
|
|
|
# Move some across to l2. |
|
|
|
self.pay(l1,l2,200000000) |
|
|
|
self.pay(l1, l2, 200000000) |
|
|
|
|
|
|
|
assert not l1.daemon.is_in_log('=WIRE_COMMITMENT_SIGNED') |
|
|
|
assert not l2.daemon.is_in_log('=WIRE_COMMITMENT_SIGNED') |
|
|
|
|
|
|
|
# Now, this will get stuck due to l1 commit being disabled.. |
|
|
|
t = self.pay(l2,l1,100000000,async=True) |
|
|
|
t = self.pay(l2, l1, 100000000, async=True) |
|
|
|
# Make sure we get signature from them. |
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_UPDATE_ADD_HTLC') |
|
|
|
l1.daemon.wait_for_log('peer_in WIRE_COMMITMENT_SIGNED') |
|
|
@ -1530,7 +1532,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
self.fund_channel(l1, l2, 10**6) |
|
|
|
|
|
|
|
# This will fail at l2's end. |
|
|
|
t=self.pay(l1,l2,200000000,async=True) |
|
|
|
t = self.pay(l1, l2, 200000000, async=True) |
|
|
|
|
|
|
|
l2.daemon.wait_for_log('dev_disconnect permfail') |
|
|
|
l2.daemon.wait_for_log('sendrawtx exit 0') |
|
|
@ -2945,7 +2947,6 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
preimage = l1.rpc.pay(inv1['bolt11'])['preimage'] |
|
|
|
assert l1.rpc.dev_rhash(preimage)['rhash'] == inv1['payment_hash'] |
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
|
|
def test_payment_failed_persistence(self): |
|
|
|
# Start two nodes and open a channel.. die during payment. |
|
|
@ -3499,6 +3500,5 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
l1.restart() |
|
|
|
assert len(l1.rpc.listpeers()['peers']) == 0 |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
unittest.main(verbosity=2) |
|
|
|