|
@ -1,7 +1,5 @@ |
|
|
from concurrent import futures |
|
|
from concurrent import futures |
|
|
from decimal import Decimal |
|
|
from decimal import Decimal |
|
|
from hashlib import sha256 |
|
|
|
|
|
from lightning import LightningRpc |
|
|
|
|
|
|
|
|
|
|
|
import copy |
|
|
import copy |
|
|
import json |
|
|
import json |
|
@ -19,7 +17,9 @@ import tempfile |
|
|
import threading |
|
|
import threading |
|
|
import time |
|
|
import time |
|
|
import unittest |
|
|
import unittest |
|
|
|
|
|
|
|
|
import utils |
|
|
import utils |
|
|
|
|
|
from lightning import LightningRpc |
|
|
|
|
|
|
|
|
bitcoind = None |
|
|
bitcoind = None |
|
|
TEST_DIR = tempfile.mkdtemp(prefix='lightning-') |
|
|
TEST_DIR = tempfile.mkdtemp(prefix='lightning-') |
|
@ -33,9 +33,11 @@ if TEST_DEBUG: |
|
|
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) |
|
|
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout) |
|
|
logging.info("Tests running in '%s'", TEST_DIR) |
|
|
logging.info("Tests running in '%s'", TEST_DIR) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def to_json(arg): |
|
|
def to_json(arg): |
|
|
return json.loads(json.dumps(arg)) |
|
|
return json.loads(json.dumps(arg)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def setupBitcoind(directory): |
|
|
def setupBitcoind(directory): |
|
|
global bitcoind |
|
|
global bitcoind |
|
|
bitcoind = utils.BitcoinD(bitcoin_dir=directory, rpcport=28332) |
|
|
bitcoind = utils.BitcoinD(bitcoin_dir=directory, rpcport=28332) |
|
@ -332,8 +334,8 @@ class LightningDTests(BaseLightningDTests): |
|
|
bitcoind.generate_block(5) |
|
|
bitcoind.generate_block(5) |
|
|
# Could happen in any order... |
|
|
# Could happen in any order... |
|
|
l1.daemon.wait_for_logs(['Received channel_update for channel {}\\(0\\)'.format(c) |
|
|
l1.daemon.wait_for_logs(['Received channel_update for channel {}\\(0\\)'.format(c) |
|
|
for c in channel_ids] |
|
|
for c in channel_ids] + |
|
|
+ ['Received channel_update for channel {}\\(1\\)'.format(c) |
|
|
['Received channel_update for channel {}\\(1\\)'.format(c) |
|
|
for c in channel_ids]) |
|
|
for c in channel_ids]) |
|
|
|
|
|
|
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
@ -957,7 +959,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
c = self.fund_channel(lsrc, ldst, 10000000) |
|
|
c = self.fund_channel(lsrc, ldst, 10000000) |
|
|
self.wait_for_routes(lpayer, [c]) |
|
|
self.wait_for_routes(lpayer, [c]) |
|
|
|
|
|
|
|
|
## Setup |
|
|
# Setup |
|
|
# Construct lightningd |
|
|
# Construct lightningd |
|
|
l1 = self.node_factory.get_node() |
|
|
l1 = self.node_factory.get_node() |
|
|
l2 = self.node_factory.get_node() |
|
|
l2 = self.node_factory.get_node() |
|
@ -975,7 +977,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
fund_from_to_payer(l4, l1, l1) |
|
|
fund_from_to_payer(l4, l1, l1) |
|
|
fund_from_to_payer(l4, l2, l1) |
|
|
fund_from_to_payer(l4, l2, l1) |
|
|
|
|
|
|
|
|
## Test |
|
|
# Test |
|
|
inv = l4.rpc.invoice(1234567, 'inv', 'for testing')['bolt11'] |
|
|
inv = l4.rpc.invoice(1234567, 'inv', 'for testing')['bolt11'] |
|
|
l1.rpc.pay(inv) |
|
|
l1.rpc.pay(inv) |
|
|
|
|
|
|
|
@ -1075,8 +1077,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
|
|
|
|
|
# Default feerate = 15000/7500/1000 |
|
|
# Default feerate = 15000/7500/1000 |
|
|
# It will start at the second number, accepting anything above the first. |
|
|
# It will start at the second number, accepting anything above the first. |
|
|
feerates=[ [ 20000, 15000, 7400 ], |
|
|
feerates = [[20000, 15000, 7400], [8000, 1001, 100]] |
|
|
[ 8000, 1001, 100 ] ] |
|
|
|
|
|
amounts = [0, 545999, 546000] |
|
|
amounts = [0, 545999, 546000] |
|
|
num_peers = len(feerates) * len(amounts) |
|
|
num_peers = len(feerates) * len(amounts) |
|
|
self.give_funds(l1, (10**6) * num_peers + 10000 * num_peers) |
|
|
self.give_funds(l1, (10**6) * num_peers + 10000 * num_peers) |
|
@ -1102,8 +1103,8 @@ class LightningDTests(BaseLightningDTests): |
|
|
bitcoind.generate_block(6) |
|
|
bitcoind.generate_block(6) |
|
|
|
|
|
|
|
|
# Now wait for them all to hit normal state, do payments |
|
|
# Now wait for them all to hit normal state, do payments |
|
|
l1.daemon.wait_for_logs(['update for channel .* now ACTIVE'] * num_peers |
|
|
l1.daemon.wait_for_logs(['update for channel .* now ACTIVE'] * num_peers + |
|
|
+ ['to CHANNELD_NORMAL'] * num_peers) |
|
|
['to CHANNELD_NORMAL'] * num_peers) |
|
|
for p in peers: |
|
|
for p in peers: |
|
|
if p.amount != 0: |
|
|
if p.amount != 0: |
|
|
self.pay(l1, p, 100000000) |
|
|
self.pay(l1, p, 100000000) |
|
@ -1726,13 +1727,13 @@ class LightningDTests(BaseLightningDTests): |
|
|
# Outgoing should be active, but not public. |
|
|
# Outgoing should be active, but not public. |
|
|
channels = l1.rpc.listchannels()['channels'] |
|
|
channels = l1.rpc.listchannels()['channels'] |
|
|
assert len(channels) == 1 |
|
|
assert len(channels) == 1 |
|
|
assert channels[0]['active'] == True |
|
|
assert channels[0]['active'] is True |
|
|
assert channels[0]['public'] == False |
|
|
assert channels[0]['public'] is False |
|
|
|
|
|
|
|
|
channels = l2.rpc.listchannels()['channels'] |
|
|
channels = l2.rpc.listchannels()['channels'] |
|
|
assert len(channels) == 1 |
|
|
assert len(channels) == 1 |
|
|
assert channels[0]['active'] == True |
|
|
assert channels[0]['active'] is True |
|
|
assert channels[0]['public'] == False |
|
|
assert channels[0]['public'] is False |
|
|
|
|
|
|
|
|
# Now proceed to funding-depth and do a full gossip round |
|
|
# Now proceed to funding-depth and do a full gossip round |
|
|
l1.bitcoin.generate_block(5) |
|
|
l1.bitcoin.generate_block(5) |
|
@ -1764,9 +1765,9 @@ class LightningDTests(BaseLightningDTests): |
|
|
if DEVELOPER: |
|
|
if DEVELOPER: |
|
|
assert n1['alias'] == 'JUNIORBEAM' |
|
|
assert n1['alias'] == 'JUNIORBEAM' |
|
|
assert n1['color'] == '0266e4' |
|
|
assert n1['color'] == '0266e4' |
|
|
if not 'alias' in n2: |
|
|
if 'alias' not in n2: |
|
|
assert not 'color' in n2 |
|
|
assert 'color' not in n2 |
|
|
assert not 'addresses' in n2 |
|
|
assert 'addresses' not in n2 |
|
|
else: |
|
|
else: |
|
|
assert n2['alias'] == 'SILENTARTIST' |
|
|
assert n2['alias'] == 'SILENTARTIST' |
|
|
assert n2['color'] == '022d22' |
|
|
assert n2['color'] == '022d22' |
|
@ -2359,7 +2360,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
for d in disconnects: |
|
|
for d in disconnects: |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
assert l1.rpc.getpeer(l2.info['id']) == None |
|
|
assert l1.rpc.getpeer(l2.info['id']) is None |
|
|
|
|
|
|
|
|
# This one will succeed. |
|
|
# This one will succeed. |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
@ -2383,7 +2384,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
for d in disconnects: |
|
|
for d in disconnects: |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
assert l1.rpc.getpeer(l2.info['id']) == None |
|
|
assert l1.rpc.getpeer(l2.info['id']) is None |
|
|
|
|
|
|
|
|
# This one will succeed. |
|
|
# This one will succeed. |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
@ -2407,7 +2408,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
|
|
|
|
|
|
# Fundee remembers, funder doesn't. |
|
|
# Fundee remembers, funder doesn't. |
|
|
assert l1.rpc.getpeer(l2.info['id']) == None |
|
|
assert l1.rpc.getpeer(l2.info['id']) is None |
|
|
assert l2.rpc.getpeer(l1.info['id'])['id'] == l1.info['id'] |
|
|
assert l2.rpc.getpeer(l1.info['id'])['id'] == l1.info['id'] |
|
|
|
|
|
|
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
@ -2447,7 +2448,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
|
|
|
|
|
# l2 closes on l1, l1 forgets. |
|
|
# l2 closes on l1, l1 forgets. |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
self.assertRaises(ValueError, l1.rpc.fundchannel, l2.info['id'], 20000) |
|
|
assert l1.rpc.getpeer(l2.info['id']) == None |
|
|
assert l1.rpc.getpeer(l2.info['id']) is None |
|
|
|
|
|
|
|
|
# Reconnect. |
|
|
# Reconnect. |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
|
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) |
|
@ -2788,7 +2789,6 @@ class LightningDTests(BaseLightningDTests): |
|
|
self.assertRaises(ValueError, l1.rpc.withdraw, waddr, 'all') |
|
|
self.assertRaises(ValueError, l1.rpc.withdraw, waddr, 'all') |
|
|
l1.daemon.wait_for_log('Cannot afford fee') |
|
|
l1.daemon.wait_for_log('Cannot afford fee') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_funding_change(self): |
|
|
def test_funding_change(self): |
|
|
"""Add some funds, fund a channel, and make sure we remember the change |
|
|
"""Add some funds, fund a channel, and make sure we remember the change |
|
|
""" |
|
|
""" |
|
@ -2962,7 +2962,7 @@ class LightningDTests(BaseLightningDTests): |
|
|
print(" ".join(l2.daemon.cmd_line + ['--dev-debugger=channeld'])) |
|
|
print(" ".join(l2.daemon.cmd_line + ['--dev-debugger=channeld'])) |
|
|
|
|
|
|
|
|
# Wait for l1 to notice |
|
|
# Wait for l1 to notice |
|
|
wait_for(lambda: not 'connected' in l1.rpc.listpeers()['peers'][0]['channels'][0]) |
|
|
wait_for(lambda: 'connected' not in l1.rpc.listpeers()['peers'][0]['channels'][0]) |
|
|
|
|
|
|
|
|
# Now restart l2 and it should reload peers/channels from the DB |
|
|
# Now restart l2 and it should reload peers/channels from the DB |
|
|
l2.daemon.start() |
|
|
l2.daemon.start() |
|
@ -3194,7 +3194,6 @@ class LightningDTests(BaseLightningDTests): |
|
|
|
|
|
|
|
|
self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'non-number') |
|
|
self.assertRaises(ValueError, l2.rpc.waitanyinvoice, 'non-number') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def test_waitanyinvoice_reversed(self): |
|
|
def test_waitanyinvoice_reversed(self): |
|
|
"""Test waiting for invoices, where they are paid in reverse order |
|
|
"""Test waiting for invoices, where they are paid in reverse order |
|
|
to when they are created. |
|
|
to when they are created. |
|
@ -3311,7 +3310,6 @@ class LightningDTests(BaseLightningDTests): |
|
|
l1.daemon.wait_for_log(' to CLOSINGD_COMPLETE') |
|
|
l1.daemon.wait_for_log(' to CLOSINGD_COMPLETE') |
|
|
l2.daemon.wait_for_log(' to CLOSINGD_COMPLETE') |
|
|
l2.daemon.wait_for_log(' to CLOSINGD_COMPLETE') |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
|
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") |
|
|
def test_fee_limits(self): |
|
|
def test_fee_limits(self): |
|
|
# FIXME: Test case where opening denied. |
|
|
# FIXME: Test case where opening denied. |
|
@ -3491,10 +3489,10 @@ class LightningDTests(BaseLightningDTests): |
|
|
assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir |
|
|
assert configs['bitcoin-datadir'] == bitcoind.bitcoin_dir |
|
|
assert configs['lightning-dir'] == l1.daemon.lightning_dir |
|
|
assert configs['lightning-dir'] == l1.daemon.lightning_dir |
|
|
assert configs['port'] == l1.info['port'] |
|
|
assert configs['port'] == l1.info['port'] |
|
|
assert configs['allow-deprecated-apis'] == False |
|
|
assert configs['allow-deprecated-apis'] is False |
|
|
assert configs['override-fee-rates'] == '15000/7500/1000' |
|
|
assert configs['override-fee-rates'] == '15000/7500/1000' |
|
|
assert configs['network'] == 'regtest' |
|
|
assert configs['network'] == 'regtest' |
|
|
assert configs['ignore-fee-limits'] == False |
|
|
assert configs['ignore-fee-limits'] is False |
|
|
|
|
|
|
|
|
# Test one at a time. |
|
|
# Test one at a time. |
|
|
for c in configs.keys(): |
|
|
for c in configs.keys(): |
|
|