Browse Source

Make Python code conform to the Python PEP 8 style guide

ppa-0.6.1
practicalswift 7 years ago
committed by Christian Decker
parent
commit
ae7d857c44
  1. 9
      tests/benchmark.py
  2. 276
      tests/test_lightningd.py
  3. 19
      tests/utils.py
  4. 72
      tools/generate-wire.py

9
tests/benchmark.py

@ -1,16 +1,13 @@
from concurrent.futures import ThreadPoolExecutor
from lightning import LightningRpc
from test_lightningd import NodeFactory
import logging import logging
import pytest import pytest
import random import random
import utils import utils
from concurrent import futures from concurrent import futures
from test_lightningd import NodeFactory
from time import time from time import time
from tqdm import tqdm from tqdm import tqdm
num_workers = 480 num_workers = 480
num_payments = 10000 num_payments = 10000
@ -21,6 +18,7 @@ def executor():
yield ex yield ex
ex.shutdown(wait=False) ex.shutdown(wait=False)
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
def bitcoind(): def bitcoind():
bitcoind = utils.BitcoinD(rpcport=28332) bitcoind = utils.BitcoinD(rpcport=28332)
@ -42,12 +40,14 @@ def bitcoind():
bitcoind.proc.kill() bitcoind.proc.kill()
bitcoind.proc.wait() bitcoind.proc.wait()
@pytest.fixture @pytest.fixture
def node_factory(request, bitcoind, executor): def node_factory(request, bitcoind, executor):
nf = NodeFactory(request.node.name, bitcoind, executor) nf = NodeFactory(request.node.name, bitcoind, executor)
yield nf yield nf
nf.killall() nf.killall()
def test_single_hop(node_factory, executor): def test_single_hop(node_factory, executor):
l1 = node_factory.get_node() l1 = node_factory.get_node()
l2 = node_factory.get_node() l2 = node_factory.get_node()
@ -74,6 +74,7 @@ def test_single_hop(node_factory, executor):
diff = time() - start_time diff = time() - start_time
print("Done. %d payments performed in %f seconds (%f payments per second)" % (num_payments, diff, num_payments / diff)) print("Done. %d payments performed in %f seconds (%f payments per second)" % (num_payments, diff, num_payments / diff))
def test_single_payment(node_factory, benchmark): def test_single_payment(node_factory, benchmark):
l1 = node_factory.get_node() l1 = node_factory.get_node()
l2 = node_factory.get_node() l2 = node_factory.get_node()

276
tests/test_lightningd.py

@ -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)
@ -105,7 +107,7 @@ class NodeFactory(object):
TEST_DIR, self.testname, "lightning-{}/".format(node_id)) TEST_DIR, self.testname, "lightning-{}/".format(node_id))
socket_path = os.path.join(lightning_dir, "lightning-rpc").format(node_id) socket_path = os.path.join(lightning_dir, "lightning-rpc").format(node_id)
port = 16330+node_id port = 16330 + node_id
daemon = utils.LightningD(lightning_dir, self.bitcoind.bitcoin_dir, port=port, random_hsm=random_hsm) daemon = utils.LightningD(lightning_dir, self.bitcoind.bitcoin_dir, port=port, random_hsm=random_hsm)
# If we have a disconnect string, dump it to a file for daemon. # If we have a disconnect string, dump it to a file for daemon.
if disconnect: if disconnect:
@ -192,10 +194,10 @@ class BaseLightningDTests(unittest.TestCase):
def printValgrindErrors(self, node): def printValgrindErrors(self, node):
errors, fname = self.getValgrindErrors(node) errors, fname = self.getValgrindErrors(node)
if errors: if errors:
print("-"*31, "Valgrind errors", "-"*32) print("-" * 31, "Valgrind errors", "-" * 32)
print("Valgrind error file:", fname) print("Valgrind error file:", fname)
print(errors) print(errors)
print("-"*80) print("-" * 80)
return 1 if errors else 0 return 1 if errors else 0
def getCrashLog(self, node): def getCrashLog(self, node):
@ -211,10 +213,10 @@ class BaseLightningDTests(unittest.TestCase):
def printCrashLog(self, node): def printCrashLog(self, node):
errors, fname = self.getCrashLog(node) errors, fname = self.getCrashLog(node)
if errors: if errors:
print("-"*10, "{} (last 50 lines)".format(fname), "-"*10) print("-" * 10, "{} (last 50 lines)".format(fname), "-" * 10)
for l in errors[-50:]: for l in errors[-50:]:
print(l, end='') print(l, end='')
print("-"*80) print("-" * 80)
return 1 if errors else 0 return 1 if errors else 0
def tearDown(self): def tearDown(self):
@ -249,7 +251,7 @@ class LightningDTests(BaseLightningDTests):
l1.daemon.wait_for_log('WIRE_GOSSIPCTL_HAND_BACK_PEER') l1.daemon.wait_for_log('WIRE_GOSSIPCTL_HAND_BACK_PEER')
l2.daemon.wait_for_log('WIRE_GOSSIPCTL_HAND_BACK_PEER') l2.daemon.wait_for_log('WIRE_GOSSIPCTL_HAND_BACK_PEER')
return l1,l2 return l1, l2
# Waits until l1 notices funds # Waits until l1 notices funds
def give_funds(self, l1, satoshi): def give_funds(self, l1, satoshi):
@ -289,13 +291,13 @@ class LightningDTests(BaseLightningDTests):
""" """
nodes = [self.node_factory.get_node() for _ in range(n)] nodes = [self.node_factory.get_node() for _ in range(n)]
for i in range(len(nodes)-1): for i in range(len(nodes) - 1):
nodes[i].rpc.connect( nodes[i].rpc.connect(
nodes[i+1].info['id'], nodes[i + 1].info['id'],
'localhost', 'localhost',
nodes[i+1].info['port'] nodes[i + 1].info['port']
) )
self.fund_channel(nodes[i], nodes[i+1], 10**6) self.fund_channel(nodes[i], nodes[i + 1], 10**6)
return nodes return nodes
@ -307,9 +309,9 @@ class LightningDTests(BaseLightningDTests):
assert ldst.rpc.listinvoices(label)['invoices'][0]['status'] == 'unpaid' assert ldst.rpc.listinvoices(label)['invoices'][0]['status'] == 'unpaid'
routestep = { routestep = {
'msatoshi' : amt, 'msatoshi': amt,
'id' : ldst.info['id'], 'id': ldst.info['id'],
'delay' : 5, 'delay': 5,
'channel': '1:1:1' 'channel': '1:1:1'
} }
@ -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")
@ -379,7 +381,7 @@ class LightningDTests(BaseLightningDTests):
assert b11.count('1') == 1 assert b11.count('1') == 1
def test_invoice_expiry(self): def test_invoice_expiry(self):
l1,l2 = self.connect() l1, l2 = self.connect()
chanid = self.fund_channel(l1, l2, 10**6) chanid = self.fund_channel(l1, l2, 10**6)
@ -417,22 +419,22 @@ class LightningDTests(BaseLightningDTests):
w1 = self.executor.submit(l2.rpc.waitinvoice, 'inv1') w1 = self.executor.submit(l2.rpc.waitinvoice, 'inv1')
w2 = self.executor.submit(l2.rpc.waitinvoice, 'inv2') w2 = self.executor.submit(l2.rpc.waitinvoice, 'inv2')
w3 = self.executor.submit(l2.rpc.waitinvoice, 'inv3') w3 = self.executor.submit(l2.rpc.waitinvoice, 'inv3')
time.sleep(2) # total 2 time.sleep(2) # total 2
assert not w1.done() assert not w1.done()
assert not w2.done() assert not w2.done()
assert not w3.done() assert not w3.done()
time.sleep(4) # total 6 time.sleep(4) # total 6
assert not w1.done() assert not w1.done()
self.assertRaises(ValueError, w2.result) self.assertRaises(ValueError, w2.result)
assert not w3.done() assert not w3.done()
time.sleep(6) # total 12 time.sleep(6) # total 12
self.assertRaises(ValueError, w1.result) self.assertRaises(ValueError, w1.result)
assert not w3.done() assert not w3.done()
time.sleep(8) # total 20 time.sleep(8) # total 20
self.assertRaises(ValueError, w3.result) self.assertRaises(ValueError, w3.result)
def test_connect(self): def test_connect(self):
l1,l2 = self.connect() l1, l2 = self.connect()
# These should be in gossipd. # These should be in gossipd.
assert l1.rpc.getpeer(l2.info['id'])['state'] == 'GOSSIPING' assert l1.rpc.getpeer(l2.info['id'])['state'] == 'GOSSIPING'
@ -713,7 +715,7 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.decodepay, '1111111') self.assertRaises(ValueError, l1.rpc.decodepay, '1111111')
def test_sendpay(self): def test_sendpay(self):
l1,l2 = self.connect() l1, l2 = self.connect()
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -722,9 +724,9 @@ class LightningDTests(BaseLightningDTests):
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid' assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
routestep = { routestep = {
'msatoshi' : amt, 'msatoshi': amt,
'id' : l2.info['id'], 'id': l2.info['id'],
'delay' : 5, 'delay': 5,
'channel': '1:1:1' 'channel': '1:1:1'
} }
@ -786,10 +788,10 @@ class LightningDTests(BaseLightningDTests):
# Overpaying by "only" a factor of 2 succeeds. # Overpaying by "only" a factor of 2 succeeds.
rhash = l2.rpc.invoice(amt, 'testpayment3', 'desc')['payment_hash'] rhash = l2.rpc.invoice(amt, 'testpayment3', 'desc')['payment_hash']
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'unpaid' assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'unpaid'
routestep = { 'msatoshi' : amt * 2, 'id' : l2.info['id'], 'delay' : 5, 'channel': '1:1:1'} routestep = {'msatoshi': amt * 2, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}
preimage3 = l1.rpc.sendpay(to_json([routestep]), rhash) preimage3 = l1.rpc.sendpay(to_json([routestep]), rhash)
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'paid' assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['status'] == 'paid'
assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['msatoshi_received'] == amt*2 assert l2.rpc.listinvoices('testpayment3')['invoices'][0]['msatoshi_received'] == amt * 2
# Test listpayments # Test listpayments
payments = l1.rpc.listpayments()['payments'] payments = l1.rpc.listpayments()['payments']
@ -810,7 +812,7 @@ class LightningDTests(BaseLightningDTests):
assert payments[0]['payment_preimage'] == preimage3['preimage'] assert payments[0]['payment_preimage'] == preimage3['preimage']
def test_sendpay_cant_afford(self): def test_sendpay_cant_afford(self):
l1,l2 = self.connect() l1, l2 = self.connect()
# Note, this is in SATOSHI, rest are in MILLISATOSHI! # Note, this is in SATOSHI, rest are in MILLISATOSHI!
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
@ -834,12 +836,12 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, self.pay, l2, l1, available - reserve) self.assertRaises(ValueError, self.pay, l2, l1, available - reserve)
# But this should work. # But this should work.
self.pay(l2, l1, available - reserve*2) self.pay(l2, l1, available - reserve * 2)
def test_pay0(self): def test_pay0(self):
"""Test paying 0 amount """Test paying 0 amount
""" """
l1,l2 = self.connect() l1, l2 = self.connect()
# Set up channel. # Set up channel.
chanid = self.fund_channel(l1, l2, 10**6) chanid = self.fund_channel(l1, l2, 10**6)
self.wait_for_routes(l1, [chanid]) self.wait_for_routes(l1, [chanid])
@ -849,10 +851,10 @@ class LightningDTests(BaseLightningDTests):
rhash = inv['payment_hash'] rhash = inv['payment_hash']
routestep = { routestep = {
'msatoshi' : 0, 'msatoshi': 0,
'id' : l2.info['id'], 'id': l2.info['id'],
'delay' : 10, 'delay': 10,
'channel' : chanid 'channel': chanid
} }
# Amount must be nonzero! # Amount must be nonzero!
@ -860,7 +862,7 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.sendpay, to_json([routestep]), rhash) l1.rpc.sendpay, to_json([routestep]), rhash)
def test_pay(self): def test_pay(self):
l1,l2 = self.connect() l1, l2 = self.connect()
chanid = self.fund_channel(l1, l2, 10**6) chanid = self.fund_channel(l1, l2, 10**6)
@ -903,10 +905,10 @@ class LightningDTests(BaseLightningDTests):
assert l1.rpc.listpayments(inv)['payments'][0]['payment_preimage'] == preimage['preimage'] assert l1.rpc.listpayments(inv)['payments'][0]['payment_preimage'] == preimage['preimage']
def test_pay_optional_args(self): def test_pay_optional_args(self):
l1,l2 = self.connect() l1, l2 = self.connect()
chanid = self.fund_channel(l1, l2, 10**6) chanid = self.fund_channel(l1, l2, 10**6)
# Wait for route propagation. # Wait for route propagation.
self.wait_for_routes(l1, [chanid]) self.wait_for_routes(l1, [chanid])
@ -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)
@ -996,7 +998,7 @@ class LightningDTests(BaseLightningDTests):
l2.daemon.wait_for_log('to_self_delay 100 larger than 99') l2.daemon.wait_for_log('to_self_delay 100 larger than 99')
def test_closing(self): def test_closing(self):
l1,l2 = self.connect() l1, l2 = self.connect()
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.pay(l1, l2, 200000000) self.pay(l1, l2, 200000000)
@ -1075,9 +1077,8 @@ 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)
@ -1123,10 +1124,10 @@ class LightningDTests(BaseLightningDTests):
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_permfail(self): def test_permfail(self):
l1,l2 = self.connect() l1, l2 = self.connect()
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
# Make sure l2 has received sig with 0 htlcs! # Make sure l2 has received sig with 0 htlcs!
l2.daemon.wait_for_log('Received commit_sig with 0 htlc sigs') l2.daemon.wait_for_log('Received commit_sig with 0 htlc sigs')
@ -1222,10 +1223,10 @@ class LightningDTests(BaseLightningDTests):
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_onchain_unwatch(self): def test_onchain_unwatch(self):
"""Onchaind should not watch random spends""" """Onchaind should not watch random spends"""
l1,l2 = self.connect() l1, l2 = self.connect()
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
l1.rpc.dev_fail(l2.info['id']) l1.rpc.dev_fail(l2.info['id'])
l1.daemon.wait_for_log('Failing due to dev-fail command') l1.daemon.wait_for_log('Failing due to dev-fail command')
@ -1281,9 +1282,9 @@ class LightningDTests(BaseLightningDTests):
# Must be dust! # Must be dust!
rhash = l2.rpc.invoice(1, 'onchain_dust_out', 'desc')['payment_hash'] rhash = l2.rpc.invoice(1, 'onchain_dust_out', 'desc')['payment_hash']
routestep = { routestep = {
'msatoshi' : 1, 'msatoshi': 1,
'id' : l2.info['id'], 'id': l2.info['id'],
'delay' : 5, 'delay': 5,
'channel': '1:1:1' 'channel': '1:1:1'
} }
@ -1334,9 +1335,9 @@ class LightningDTests(BaseLightningDTests):
rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash']
# We underpay, so it fails. # We underpay, so it fails.
routestep = { routestep = {
'msatoshi' : 10**8 - 1, 'msatoshi': 10**8 - 1,
'id' : l2.info['id'], 'id': l2.info['id'],
'delay' : 5, 'delay': 5,
'channel': '1:1:1' 'channel': '1:1:1'
} }
@ -1468,7 +1469,7 @@ class LightningDTests(BaseLightningDTests):
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
# Now, this will get stuck due to l1 commit being disabled.. # Now, this will get stuck due to l1 commit being disabled..
t = self.pay(l1,l2,100000000,async=True) t = self.pay(l1, l2, 100000000, async=True)
assert len(l1.getactivechannels()) == 1 assert len(l1.getactivechannels()) == 1
assert len(l2.getactivechannels()) == 1 assert len(l2.getactivechannels()) == 1
@ -1630,7 +1631,7 @@ class LightningDTests(BaseLightningDTests):
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
# This will fail at l2's end. # 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('dev_disconnect permfail')
l2.daemon.wait_for_log('sendrawtx exit 0') l2.daemon.wait_for_log('sendrawtx exit 0')
@ -1672,7 +1673,7 @@ class LightningDTests(BaseLightningDTests):
self.fund_channel(l2, l1, 10**6) self.fund_channel(l2, l1, 10**6)
# This will fail at l2's end. # This will fail at l2's end.
t=self.pay(l2,l1,200000000,async=True) t = self.pay(l2, l1, 200000000, async=True)
l2.daemon.wait_for_log('dev_disconnect permfail') l2.daemon.wait_for_log('dev_disconnect permfail')
l2.daemon.wait_for_log('sendrawtx exit 0') l2.daemon.wait_for_log('sendrawtx exit 0')
@ -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'
@ -1794,9 +1795,9 @@ class LightningDTests(BaseLightningDTests):
l1.bitcoin.rpc.generate(6) l1.bitcoin.rpc.generate(6)
# Channels should be activated locally # Channels should be activated locally
wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True]*4) wait_for(lambda: [c['active'] for c in l1.rpc.listchannels()['channels']] == [True] * 4)
wait_for(lambda: [c['active'] for c in l2.rpc.listchannels()['channels']] == [True]*4) wait_for(lambda: [c['active'] for c in l2.rpc.listchannels()['channels']] == [True] * 4)
wait_for(lambda: [c['active'] for c in l3.rpc.listchannels()['channels']] == [True]*4) wait_for(lambda: [c['active'] for c in l3.rpc.listchannels()['channels']] == [True] * 4)
# All of them should send a keepalive message # All of them should send a keepalive message
l1.daemon.wait_for_logs([ l1.daemon.wait_for_logs([
@ -1858,7 +1859,7 @@ class LightningDTests(BaseLightningDTests):
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_ping(self): def test_ping(self):
l1,l2 = self.connect() l1, l2 = self.connect()
# Test gossip pinging. # Test gossip pinging.
self.ping_tests(l1, l2) self.ping_tests(l1, l2)
@ -1903,8 +1904,8 @@ class LightningDTests(BaseLightningDTests):
l1 = nodes[0] l1 = nodes[0]
l5 = nodes[4] l5 = nodes[4]
for i in range(len(nodes)-1): for i in range(len(nodes) - 1):
src, dst = nodes[i], nodes[i+1] src, dst = nodes[i], nodes[i + 1]
src.rpc.connect(dst.info['id'], 'localhost', dst.info['port']) src.rpc.connect(dst.info['id'], 'localhost', dst.info['port'])
src.openchannel(dst, 20000) src.openchannel(dst, 20000)
@ -1914,7 +1915,7 @@ class LightningDTests(BaseLightningDTests):
def settle_gossip(n): def settle_gossip(n):
"""Wait for gossip to settle at the node """Wait for gossip to settle at the node
""" """
expected_connections = 2*(len(nodes) - 1) expected_connections = 2 * (len(nodes) - 1)
start_time = time.time() start_time = time.time()
# Wait at most 10 seconds, broadcast interval is 1 second # Wait at most 10 seconds, broadcast interval is 1 second
while time.time() - start_time < 10: while time.time() - start_time < 10:
@ -1930,19 +1931,19 @@ class LightningDTests(BaseLightningDTests):
# Deep check that all channels are in there # Deep check that all channels are in there
comb = [] comb = []
for i in range(len(nodes) - 1): for i in range(len(nodes) - 1):
comb.append((nodes[i].info['id'], nodes[i+1].info['id'])) comb.append((nodes[i].info['id'], nodes[i + 1].info['id']))
comb.append((nodes[i+1].info['id'], nodes[i].info['id'])) comb.append((nodes[i + 1].info['id'], nodes[i].info['id']))
for n in nodes: for n in nodes:
seen = [] seen = []
channels = n.rpc.listchannels()['channels'] channels = n.rpc.listchannels()['channels']
for c in channels: for c in channels:
seen.append((c['source'],c['destination'])) seen.append((c['source'], c['destination']))
assert set(seen) == set(comb) assert set(seen) == set(comb)
def test_forward(self): def test_forward(self):
# Connect 1 -> 2 -> 3. # Connect 1 -> 2 -> 3.
l1,l2 = self.connect() l1, l2 = self.connect()
l3 = self.node_factory.get_node() l3 = self.node_factory.get_node()
ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port']) ret = l2.rpc.connect(l3.info['id'], 'localhost', l3.info['port'])
@ -1970,14 +1971,14 @@ class LightningDTests(BaseLightningDTests):
amt = 100000000 amt = 100000000
fee = amt * 10 // 1000000 + 1 fee = amt * 10 // 1000000 + 1
baseroute = [ { 'msatoshi' : amt + fee, baseroute = [{'msatoshi': amt + fee,
'id' : l2.info['id'], 'id': l2.info['id'],
'delay' : 12, 'delay': 12,
'channel' : chanid1 }, 'channel': chanid1},
{ 'msatoshi' : amt, {'msatoshi': amt,
'id' : l3.info['id'], 'id': l3.info['id'],
'delay' : 6, 'delay': 6,
'channel' : chanid2 } ] 'channel': chanid2}]
# Unknown other peer # Unknown other peer
route = copy.deepcopy(baseroute) route = copy.deepcopy(baseroute)
@ -2064,7 +2065,7 @@ class LightningDTests(BaseLightningDTests):
# here for simplicity: # here for simplicity:
# FIXME: Add shadow route # FIXME: Add shadow route
shadow_route=0 shadow_route = 0
route = l2.rpc.getroute(l3.info['id'], 4999999, 1)["route"] route = l2.rpc.getroute(l3.info['id'], 4999999, 1)["route"]
assert len(route) == 1 assert len(route) == 1
@ -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'])
@ -2492,9 +2493,9 @@ class LightningDTests(BaseLightningDTests):
rhash = l2.rpc.invoice(amt, 'test_reconnect_sender_add1', 'desc')['payment_hash'] 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 l2.rpc.listinvoices('test_reconnect_sender_add1')['invoices'][0]['status'] == 'unpaid'
route = [ { 'msatoshi' : amt, 'id' : l2.info['id'], 'delay' : 5, 'channel': '1:1:1'} ] route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
for i in range(0,len(disconnects)): for i in range(0, len(disconnects)):
self.assertRaises(ValueError, l1.rpc.sendpay, to_json(route), rhash) self.assertRaises(ValueError, l1.rpc.sendpay, to_json(route), rhash)
# Wait for reconnection. # Wait for reconnection.
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
@ -2520,12 +2521,12 @@ class LightningDTests(BaseLightningDTests):
rhash = l2.rpc.invoice(amt, 'testpayment', 'desc')['payment_hash'] rhash = l2.rpc.invoice(amt, 'testpayment', 'desc')['payment_hash']
assert l2.rpc.listinvoices('testpayment')['invoices'][0]['status'] == 'unpaid' assert l2.rpc.listinvoices('testpayment')['invoices'][0]['status'] == 'unpaid'
route = [ { 'msatoshi' : amt, 'id' : l2.info['id'], 'delay' : 5, 'channel': '1:1:1'} ] route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
# This will send commit, so will reconnect as required. # This will send commit, so will reconnect as required.
l1.rpc.sendpay(to_json(route), rhash) l1.rpc.sendpay(to_json(route), rhash)
# Should have printed this for every reconnect. # Should have printed this for every reconnect.
for i in range(0,len(disconnects)): for i in range(0, len(disconnects)):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
@ -2546,7 +2547,7 @@ class LightningDTests(BaseLightningDTests):
rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash'] rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash']
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid' assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
route = [ { 'msatoshi' : amt, 'id' : l2.info['id'], 'delay' : 5, 'channel': '1:1:1'} ] route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
l1.rpc.sendpay(to_json(route), rhash) l1.rpc.sendpay(to_json(route), rhash)
for i in range(len(disconnects)): for i in range(len(disconnects)):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
@ -2576,7 +2577,7 @@ class LightningDTests(BaseLightningDTests):
rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash'] rhash = l2.rpc.invoice(amt, 'testpayment2', 'desc')['payment_hash']
assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid' assert l2.rpc.listinvoices('testpayment2')['invoices'][0]['status'] == 'unpaid'
route = [ { 'msatoshi' : amt, 'id' : l2.info['id'], 'delay' : 5, 'channel': '1:1:1'} ] route = [{'msatoshi': amt, 'id': l2.info['id'], 'delay': 5, 'channel': '1:1:1'}]
l1.rpc.sendpay(to_json(route), rhash) l1.rpc.sendpay(to_json(route), rhash)
for i in range(len(disconnects)): for i in range(len(disconnects)):
l1.daemon.wait_for_log('Already have funding locked in') l1.daemon.wait_for_log('Already have funding locked in')
@ -2592,7 +2593,7 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0 assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0
@ -2620,7 +2621,7 @@ class LightningDTests(BaseLightningDTests):
l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port']) l1.rpc.connect(l2.info['id'], 'localhost', l2.info['port'])
self.fund_channel(l1, l2, 10**6) self.fund_channel(l1, l2, 10**6)
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0 assert l1.bitcoin.rpc.getmempoolinfo()['size'] == 0
@ -2660,7 +2661,7 @@ class LightningDTests(BaseLightningDTests):
def is_p2wpkh(output): def is_p2wpkh(output):
return output['type'] == 'witness_v0_keyhash' and \ return output['type'] == 'witness_v0_keyhash' and \
address == output['addresses'][0] address == output['addresses'][0]
assert any(is_p2wpkh(output['scriptPubKey']) for output in wallettx['vout']) assert any(is_p2wpkh(output['scriptPubKey']) for output in wallettx['vout'])
assert fundingtx['vin'][0]['txid'] == res['wallettxid'] assert fundingtx['vin'][0]['txid'] == res['wallettxid']
@ -2693,7 +2694,7 @@ class LightningDTests(BaseLightningDTests):
self.assertRaises(ValueError, l1.rpc.withdraw, waddr, 'not an amount') self.assertRaises(ValueError, l1.rpc.withdraw, waddr, 'not an amount')
self.assertRaises(ValueError, l1.rpc.withdraw, waddr, -amount) self.assertRaises(ValueError, l1.rpc.withdraw, waddr, -amount)
out = l1.rpc.withdraw(waddr, 2*amount) out = l1.rpc.withdraw(waddr, 2 * amount)
# Make sure bitcoind received the withdrawal # Make sure bitcoind received the withdrawal
unspent = l1.bitcoin.rpc.listunspent(0) unspent = l1.bitcoin.rpc.listunspent(0)
@ -2710,13 +2711,13 @@ class LightningDTests(BaseLightningDTests):
# Now send some money to l2. # Now send some money to l2.
# lightningd uses P2SH-P2WPKH # lightningd uses P2SH-P2WPKH
waddr = l2.rpc.newaddr()['address'] waddr = l2.rpc.newaddr()['address']
out = l1.rpc.withdraw(waddr, 2*amount) out = l1.rpc.withdraw(waddr, 2 * amount)
l1.bitcoin.rpc.generate(1) l1.bitcoin.rpc.generate(1)
# Make sure l2 received the withdrawal. # Make sure l2 received the withdrawal.
wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == 1) wait_for(lambda: len(l2.rpc.listfunds()['outputs']) == 1)
outputs = l2.db_query('SELECT value FROM outputs WHERE status=0;') outputs = l2.db_query('SELECT value FROM outputs WHERE status=0;')
assert len(outputs) == 1 and outputs[0]['value'] == 2*amount assert len(outputs) == 1 and outputs[0]['value'] == 2 * amount
# Now make sure an additional two of them were marked as spent # Now make sure an additional two of them were marked as spent
c = db.cursor() c = db.cursor()
@ -2726,10 +2727,10 @@ class LightningDTests(BaseLightningDTests):
# Simple test for withdrawal to P2WPKH # Simple test for withdrawal to P2WPKH
# Address from: https://bc-2.jp/tools/bech32demo/index.html # Address from: https://bc-2.jp/tools/bech32demo/index.html
waddr = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx' waddr = 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx'
self.assertRaises(ValueError, l1.rpc.withdraw, 'xx1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'xx1qw508d6qejxtdg4y5r3zarvary0c5xw7kxpjzsx', 2 * amount)
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1pw508d6qejxtdg4y5r3zarvary0c5xw7kdl9fad', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1pw508d6qejxtdg4y5r3zarvary0c5xw7kdl9fad', 2 * amount)
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxxxxxx', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qw508d6qejxtdg4y5r3zarvary0c5xw7kxxxxxx', 2 * amount)
out = l1.rpc.withdraw(waddr, 2*amount) out = l1.rpc.withdraw(waddr, 2 * amount)
l1.bitcoin.rpc.generate(1) l1.bitcoin.rpc.generate(1)
# Now make sure additional two of them were marked as spent # Now make sure additional two of them were marked as spent
c = db.cursor() c = db.cursor()
@ -2739,10 +2740,10 @@ class LightningDTests(BaseLightningDTests):
# Simple test for withdrawal to P2WSH # Simple test for withdrawal to P2WSH
# Address from: https://bc-2.jp/tools/bech32demo/index.html # Address from: https://bc-2.jp/tools/bech32demo/index.html
waddr = 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7' waddr = 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7'
self.assertRaises(ValueError, l1.rpc.withdraw, 'xx1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'xx1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', 2 * amount)
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qsm03tq', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1prp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qsm03tq', 2 * amount)
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qxxxxxx', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qxxxxxx', 2 * amount)
out = l1.rpc.withdraw(waddr, 2*amount) out = l1.rpc.withdraw(waddr, 2 * amount)
l1.bitcoin.rpc.generate(1) l1.bitcoin.rpc.generate(1)
# Now make sure additional two of them were marked as spent # Now make sure additional two of them were marked as spent
c = db.cursor() c = db.cursor()
@ -2751,21 +2752,21 @@ class LightningDTests(BaseLightningDTests):
# failure testing for invalid SegWit addresses, from BIP173 # failure testing for invalid SegWit addresses, from BIP173
# HRP character out of range # HRP character out of range
self.assertRaises(ValueError, l1.rpc.withdraw, ' 1nwldj5', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, ' 1nwldj5', 2 * amount)
# overall max length exceeded # overall max length exceeded
self.assertRaises(ValueError, l1.rpc.withdraw, 'an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'an84characterslonghumanreadablepartthatcontainsthenumber1andtheexcludedcharactersbio1569pvx', 2 * amount)
# No separator character # No separator character
self.assertRaises(ValueError, l1.rpc.withdraw, 'pzry9x0s0muk', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'pzry9x0s0muk', 2 * amount)
# Empty HRP # Empty HRP
self.assertRaises(ValueError, l1.rpc.withdraw, '1pzry9x0s0muk', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, '1pzry9x0s0muk', 2 * amount)
# Invalid witness version # Invalid witness version
self.assertRaises(ValueError, l1.rpc.withdraw, 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', 2 * amount)
# Invalid program length for witness version 0 (per BIP141) # Invalid program length for witness version 0 (per BIP141)
self.assertRaises(ValueError, l1.rpc.withdraw, 'BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', 2 * amount)
# Mixed case # Mixed case
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', 2 * amount)
# Non-zero padding in 8-to-5 conversion # Non-zero padding in 8-to-5 conversion
self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv', 2*amount) self.assertRaises(ValueError, l1.rpc.withdraw, 'tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv', 2 * amount)
# Should have 6 outputs available. # Should have 6 outputs available.
c = db.cursor() c = db.cursor()
@ -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
""" """
@ -2804,7 +2804,7 @@ class LightningDTests(BaseLightningDTests):
'SELECT status, SUM(value) AS value FROM outputs GROUP BY status;')} 'SELECT status, SUM(value) AS value FROM outputs GROUP BY status;')}
# The 10m out is spent and we have a change output of 9m-fee # The 10m out is spent and we have a change output of 9m-fee
assert outputs[0] > 8990000 assert outputs[0] > 8990000
assert outputs[2] == 10000000 assert outputs[2] == 10000000
def test_funding_fail(self): def test_funding_fail(self):
@ -2826,7 +2826,7 @@ class LightningDTests(BaseLightningDTests):
# Fail because l1 dislikes l2's huge locktime. # Fail because l1 dislikes l2's huge locktime.
self.assertRaisesRegex(ValueError, r'to_self_delay \d+ larger than \d+', self.assertRaisesRegex(ValueError, r'to_self_delay \d+ larger than \d+',
l1.rpc.fundchannel, l2.info['id'], int(funds/10)) l1.rpc.fundchannel, l2.info['id'], int(funds / 10))
assert l1.rpc.listpeers()['peers'][0]['connected'] assert l1.rpc.listpeers()['peers'][0]['connected']
assert l2.rpc.listpeers()['peers'][0]['connected'] assert l2.rpc.listpeers()['peers'][0]['connected']
@ -2844,7 +2844,7 @@ class LightningDTests(BaseLightningDTests):
assert l2.rpc.listpeers()['peers'][0]['connected'] assert l2.rpc.listpeers()['peers'][0]['connected']
# This works. # This works.
l1.rpc.fundchannel(l2.info['id'], int(funds/10)) l1.rpc.fundchannel(l2.info['id'], int(funds / 10))
def test_funding_toolarge(self): def test_funding_toolarge(self):
"""Try to create a giant channel""" """Try to create a giant channel"""
@ -2868,7 +2868,7 @@ class LightningDTests(BaseLightningDTests):
assert 'Funding satoshi must be <= 16777215' in str(err) assert 'Funding satoshi must be <= 16777215' in str(err)
# This should work. # This should work.
amount = amount-1 amount = amount - 1
l1.rpc.fundchannel(l2.info['id'], amount) l1.rpc.fundchannel(l2.info['id'], amount)
def test_lockin_between_restart(self): def test_lockin_between_restart(self):
@ -2910,7 +2910,7 @@ class LightningDTests(BaseLightningDTests):
sync_blockheight([l1]) sync_blockheight([l1])
assert len(l1.rpc.listfunds()['outputs']) == 1 assert len(l1.rpc.listfunds()['outputs']) == 1
def test_addfunds_from_block(self): def test_addfunds_from_block(self):
"""Send funds to the daemon without telling it explicitly """Send funds to the daemon without telling it explicitly
""" """
@ -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.
@ -3258,8 +3257,8 @@ class LightningDTests(BaseLightningDTests):
self.wait_for_routes(l1, [chanid]) self.wait_for_routes(l1, [chanid])
# Make payments. # Make payments.
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
self.pay(l2,l1,100000000) self.pay(l2, l1, 100000000)
# Now shutdown cleanly. # Now shutdown cleanly.
l1.rpc.close(l2.info['id']) l1.rpc.close(l2.info['id'])
@ -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.
@ -3371,8 +3369,8 @@ class LightningDTests(BaseLightningDTests):
# Wait for reconnect.... # Wait for reconnect....
l1.daemon.wait_for_log('Applying feerate 14000 to LOCAL') l1.daemon.wait_for_log('Applying feerate 14000 to LOCAL')
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
self.pay(l2,l1,100000000) self.pay(l2, l1, 100000000)
# They should both have gotten commits with correct feerate. # They should both have gotten commits with correct feerate.
assert l1.daemon.is_in_log('got commitsig [0-9]*: feerate 14000') assert l1.daemon.is_in_log('got commitsig [0-9]*: feerate 14000')
@ -3417,7 +3415,7 @@ class LightningDTests(BaseLightningDTests):
pid2 = re.search(r'pid ([0-9]*),', pidline).group(1) pid2 = re.search(r'pid ([0-9]*),', pidline).group(1)
l2.daemon.wait_for_log(' to CHANNELD_NORMAL') l2.daemon.wait_for_log(' to CHANNELD_NORMAL')
fut = self.pay(l1,l2,200000000,async=True) fut = self.pay(l1, l2, 200000000, async=True)
# WIRE_UPDATE_ADD_HTLC = 128 = 0x0080 # WIRE_UPDATE_ADD_HTLC = 128 = 0x0080
l1.daemon.wait_for_log(r'channeld.*:\[OUT\] 0080') l1.daemon.wait_for_log(r'channeld.*:\[OUT\] 0080')
@ -3428,7 +3426,7 @@ class LightningDTests(BaseLightningDTests):
# Send it sigusr1: should turn off logging. # Send it sigusr1: should turn off logging.
subprocess.run(['kill', '-USR1', pid1]) subprocess.run(['kill', '-USR1', pid1])
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
assert not l1.daemon.is_in_log(r'channeld.*:\[OUT\] 0080', assert not l1.daemon.is_in_log(r'channeld.*:\[OUT\] 0080',
start=l1.daemon.logsearch_start) start=l1.daemon.logsearch_start)
@ -3442,7 +3440,7 @@ class LightningDTests(BaseLightningDTests):
# Turn on in l2 channel logging. # Turn on in l2 channel logging.
subprocess.run(['kill', '-USR1', pid2]) subprocess.run(['kill', '-USR1', pid2])
self.pay(l1,l2,200000000) self.pay(l1, l2, 200000000)
# Now it should find it. # Now it should find it.
peerlog = l2.rpc.listpeers(l1.info['id'], "io")['peers'][0]['log'] peerlog = l2.rpc.listpeers(l1.info['id'], "io")['peers'][0]['log']
@ -3452,7 +3450,7 @@ class LightningDTests(BaseLightningDTests):
@unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1")
def test_pay_disconnect(self): def test_pay_disconnect(self):
"""If the remote node has disconnected, we fail payment, but can try again when it reconnects""" """If the remote node has disconnected, we fail payment, but can try again when it reconnects"""
l1,l2 = self.connect() l1, l2 = self.connect()
chanid = self.fund_channel(l1, l2, 10**6) chanid = self.fund_channel(l1, l2, 10**6)
@ -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():
@ -3523,7 +3521,7 @@ class LightningDTests(BaseLightningDTests):
channels = l1.rpc.listpeers()['peers'][0]['channels'] channels = l1.rpc.listpeers()['peers'][0]['channels']
assert len(channels) == 3 assert len(channels) == 3
# Most in state ONCHAIND_MUTUAL, last is CLOSINGD_COMPLETE # Most in state ONCHAIND_MUTUAL, last is CLOSINGD_COMPLETE
for i in range(len(channels)-1): for i in range(len(channels) - 1):
assert channels[i]['state'] == 'ONCHAIND_MUTUAL' assert channels[i]['state'] == 'ONCHAIND_MUTUAL'
assert channels[-1]['state'] == 'CLOSINGD_COMPLETE' assert channels[-1]['state'] == 'CLOSINGD_COMPLETE'

19
tests/utils.py

@ -1,6 +1,4 @@
from bitcoin.rpc import RawProxy as BitcoinProxy import binascii
from lightning import LightningRpc
import logging import logging
import os import os
import re import re
@ -8,7 +6,8 @@ import sqlite3
import subprocess import subprocess
import threading import threading
import time import time
import binascii
from bitcoin.rpc import RawProxy as BitcoinProxy
BITCOIND_CONFIG = { BITCOIND_CONFIG = {
@ -28,6 +27,7 @@ LIGHTNINGD_CONFIG = {
DEVELOPER = os.getenv("DEVELOPER", "0") == "1" DEVELOPER = os.getenv("DEVELOPER", "0") == "1"
def write_config(filename, opts): def write_config(filename, opts):
with open(filename, 'w') as f: with open(filename, 'w') as f:
for k, v in opts.items(): for k, v in opts.items():
@ -109,7 +109,7 @@ class TailableProc(object):
self.running = False self.running = False
self.proc.stdout.close() self.proc.stdout.close()
def is_in_log(self, regex, start = 0): def is_in_log(self, regex, start=0):
"""Look for `regex` in the logs.""" """Look for `regex` in the logs."""
ex = re.compile(regex) ex = re.compile(regex)
@ -135,7 +135,6 @@ class TailableProc(object):
exs = [re.compile(r) for r in regexs] exs = [re.compile(r) for r in regexs]
start_time = time.time() start_time = time.time()
pos = self.logsearch_start pos = self.logsearch_start
initial_pos = len(self.logs)
while True: while True:
if timeout is not None and time.time() > start_time + timeout: if timeout is not None and time.time() > start_time + timeout:
print("Time-out: can't find {} in logs".format(exs)) print("Time-out: can't find {} in logs".format(exs))
@ -152,7 +151,7 @@ class TailableProc(object):
continue continue
for r in exs.copy(): for r in exs.copy():
self.logsearch_start = pos+1 self.logsearch_start = pos + 1
if r.search(self.logs[pos]): if r.search(self.logs[pos]):
logging.debug("Found '%s' in logs", r) logging.debug("Found '%s' in logs", r)
exs.remove(r) exs.remove(r)
@ -178,7 +177,7 @@ class SimpleBitcoinProxy:
library to close, reopen and reauth upon failure. library to close, reopen and reauth upon failure.
""" """
def __init__(self, btc_conf_file, *args, **kwargs): def __init__(self, btc_conf_file, *args, **kwargs):
self.__btc_conf_file__= btc_conf_file self.__btc_conf_file__ = btc_conf_file
def __getattr__(self, name): def __getattr__(self, name):
if name.startswith('__') and name.endswith('__'): if name.startswith('__') and name.endswith('__'):
@ -240,6 +239,7 @@ class BitcoinD(TailableProc):
# lightning-4 => 0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199 aka JUNIORFELONY #0382ce # lightning-4 => 0382ce59ebf18be7d84677c2e35f23294b9992ceca95491fcf8a56c6cb2d9de199 aka JUNIORFELONY #0382ce
# lightning-5 => 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e aka SOMBERFIRE #032cf1 # lightning-5 => 032cf15d1ad9c4a08d26eab1918f732d8ef8fdc6abb9640bf3db174372c491304e aka SOMBERFIRE #032cf1
class LightningD(TailableProc): class LightningD(TailableProc):
def __init__(self, lightning_dir, bitcoin_dir, port=9735, random_hsm=False): def __init__(self, lightning_dir, bitcoin_dir, port=9735, random_hsm=False):
TailableProc.__init__(self, lightning_dir) TailableProc.__init__(self, lightning_dir)
@ -281,6 +281,7 @@ class LightningD(TailableProc):
self.proc.wait(timeout) self.proc.wait(timeout)
return self.proc.returncode return self.proc.returncode
class LightningNode(object): class LightningNode(object):
def __init__(self, daemon, rpc, btc, executor, may_fail=False): def __init__(self, daemon, rpc, btc, executor, may_fail=False):
self.rpc = rpc self.rpc = rpc
@ -316,7 +317,7 @@ class LightningNode(object):
self.bitcoin.generate_block(1) self.bitcoin.generate_block(1)
#fut.result(timeout=5) # fut.result(timeout=5)
# Now wait for confirmation # Now wait for confirmation
self.daemon.wait_for_log(" to CHANNELD_NORMAL|STATE_NORMAL") self.daemon.wait_for_log(" to CHANNELD_NORMAL|STATE_NORMAL")

72
tools/generate-wire.py

@ -3,10 +3,11 @@
import argparse import argparse
import copy import copy
from collections import namedtuple
import fileinput import fileinput
import re import re
from collections import namedtuple
Enumtype = namedtuple('Enumtype', ['name', 'value']) Enumtype = namedtuple('Enumtype', ['name', 'value'])
type2size = { type2size = {
@ -36,8 +37,9 @@ varlen_structs = [
'wirestring', 'wirestring',
] ]
class FieldType(object): class FieldType(object):
def __init__(self,name): def __init__(self, name):
self.name = name self.name = name
def is_assignable(self): def is_assignable(self):
@ -96,6 +98,7 @@ sizetypemap = {
1: FieldType('u8') 1: FieldType('u8')
} }
# It would be nicer if we had put '*u8' in spec and disallowed bare lenvar. # It would be nicer if we had put '*u8' in spec and disallowed bare lenvar.
# In practice we only recognize lenvar when it's the previous field. # In practice we only recognize lenvar when it's the previous field.
@ -129,7 +132,7 @@ class Field(object):
# Bolts use just a number: Guess type based on size. # Bolts use just a number: Guess type based on size.
if options.bolt: if options.bolt:
base_size = int(size) base_size = int(size)
self.fieldtype = Field._guess_type(message,self.name,base_size) self.fieldtype = Field._guess_type(message, self.name, base_size)
# There are some arrays which we have to guess, based on sizes. # There are some arrays which we have to guess, based on sizes.
tsize = FieldType._typesize(self.fieldtype.name) tsize = FieldType._typesize(self.fieldtype.name)
if base_size % tsize != 0: if base_size % tsize != 0:
@ -144,11 +147,11 @@ class Field(object):
self.fieldtype = FieldType(size) self.fieldtype = FieldType(size)
def basetype(self): def basetype(self):
base=self.fieldtype.name base = self.fieldtype.name
if base.startswith('struct '): if base.startswith('struct '):
base=base[7:] base = base[7:]
elif base.startswith('enum '): elif base.startswith('enum '):
base=base[5:] base = base[5:]
return base return base
def is_padding(self): def is_padding(self):
@ -185,7 +188,7 @@ class Field(object):
if base_size in sizetypemap: if base_size in sizetypemap:
return sizetypemap[base_size] return sizetypemap[base_size]
raise ValueError('Unknown size {} for {}'.format(base_size,fieldname)) raise ValueError('Unknown size {} for {}'.format(base_size, fieldname))
fromwire_impl_templ = """bool fromwire_{name}({ctx}const void *p{args}) fromwire_impl_templ = """bool fromwire_{name}({ctx}const void *p{args})
{{ {{
@ -234,8 +237,9 @@ printwire_impl_templ = """void printwire_{name}(const u8 *cursor)
}} }}
""" """
class Message(object): class Message(object):
def __init__(self,name,enum,comments): def __init__(self, name, enum, comments):
self.name = name self.name = name
self.enum = enum self.enum = enum
self.comments = comments self.comments = comments
@ -252,13 +256,13 @@ class Message(object):
if f.is_array() or f.is_variable_size(): if f.is_array() or f.is_variable_size():
raise ValueError('Field {} has non-simple length variable {}' raise ValueError('Field {} has non-simple length variable {}'
.format(field.name, field.lenvar)) .format(field.name, field.lenvar))
f.is_len_var = True; f.is_len_var = True
f.lenvar_for = field f.lenvar_for = field
return return
raise ValueError('Field {} unknown length variable {}' raise ValueError('Field {} unknown length variable {}'
.format(field.name, field.lenvar)) .format(field.name, field.lenvar))
def addField(self,field): def addField(self, field):
# We assume field lengths are 16 bit, to avoid overflow issues and # We assume field lengths are 16 bit, to avoid overflow issues and
# massive allocations. # massive allocations.
if field.is_variable_size(): if field.is_variable_size():
@ -285,7 +289,7 @@ class Message(object):
subcalls.append('\t\tfromwire_{}(&cursor, &plen, {} + i);' subcalls.append('\t\tfromwire_{}(&cursor, &plen, {} + i);'
.format(basetype, name)) .format(basetype, name))
def print_fromwire(self,is_header): def print_fromwire(self, is_header):
ctx_arg = 'const tal_t *ctx, ' if self.has_variable_fields else '' ctx_arg = 'const tal_t *ctx, ' if self.has_variable_fields else ''
args = [] args = []
@ -296,7 +300,7 @@ class Message(object):
elif f.is_array(): elif f.is_array():
args.append(', {} {}[{}]'.format(f.fieldtype.name, f.name, f.num_elems)) args.append(', {} {}[{}]'.format(f.fieldtype.name, f.name, f.num_elems))
else: else:
ptrs='*' ptrs = '*'
# If we're handing a variable array, we need a ptr-to-ptr. # If we're handing a variable array, we need a ptr-to-ptr.
if f.is_variable_size(): if f.is_variable_size():
ptrs += '*' ptrs += '*'
@ -311,7 +315,7 @@ class Message(object):
subcalls = [] subcalls = []
for f in self.fields: for f in self.fields:
basetype=f.basetype() basetype = f.basetype()
for c in f.comments: for c in f.comments:
subcalls.append('\t/*{} */'.format(c)) subcalls.append('\t/*{} */'.format(c))
@ -331,7 +335,7 @@ class Message(object):
subcalls.append('\t*{} = {} ? tal_arr(ctx, {}, {}) : NULL;' subcalls.append('\t*{} = {} ? tal_arr(ctx, {}, {}) : NULL;'
.format(f.name, f.lenvar, typename, f.lenvar)) .format(f.name, f.lenvar, typename, f.lenvar))
self.print_fromwire_array(subcalls, basetype, f, '*'+f.name, self.print_fromwire_array(subcalls, basetype, f, '*' + f.name,
f.lenvar) f.lenvar)
elif f.is_assignable(): elif f.is_assignable():
subcalls.append("\t//3th case {name}".format(name=f.name)) subcalls.append("\t//3th case {name}".format(name=f.name))
@ -369,9 +373,9 @@ class Message(object):
.format(basetype, f.name)) .format(basetype, f.name))
else: else:
subcalls.append('\t\ttowire_{}(&p, {} + i);' subcalls.append('\t\ttowire_{}(&p, {} + i);'
.format(basetype, f.name)) .format(basetype, f.name))
def print_towire(self,is_header): def print_towire(self, is_header):
template = towire_header_templ if is_header else towire_impl_templ template = towire_header_templ if is_header else towire_impl_templ
args = [] args = []
for f in self.fields: for f in self.fields:
@ -391,29 +395,29 @@ class Message(object):
if f.is_len_var: if f.is_len_var:
field_decls.append('\t{0} {1} = tal_count({2});'.format( field_decls.append('\t{0} {1} = tal_count({2});'.format(
f.fieldtype.name, f.name, f.lenvar_for.name f.fieldtype.name, f.name, f.lenvar_for.name
)); ))
subcalls = [] subcalls = []
for f in self.fields: for f in self.fields:
basetype=f.fieldtype.name basetype = f.fieldtype.name
if basetype.startswith('struct '): if basetype.startswith('struct '):
basetype=basetype[7:] basetype = basetype[7:]
elif basetype.startswith('enum '): elif basetype.startswith('enum '):
basetype=basetype[5:] basetype = basetype[5:]
for c in f.comments: for c in f.comments:
subcalls.append('\t/*{} */'.format(c)) subcalls.append('\t/*{} */'.format(c))
if f.is_padding(): if f.is_padding():
subcalls.append('\ttowire_pad(&p, {});' subcalls.append('\ttowire_pad(&p, {});'
.format(f.num_elems)) .format(f.num_elems))
elif f.is_array(): elif f.is_array():
self.print_towire_array(subcalls, basetype, f, f.num_elems) self.print_towire_array(subcalls, basetype, f, f.num_elems)
elif f.is_variable_size(): elif f.is_variable_size():
self.print_towire_array(subcalls, basetype, f, f.lenvar) self.print_towire_array(subcalls, basetype, f, f.lenvar)
else: else:
subcalls.append('\ttowire_{}(&p, {});' subcalls.append('\ttowire_{}(&p, {});'
.format(basetype, f.name)) .format(basetype, f.name))
return template.format( return template.format(
name=self.name, name=self.name,
@ -438,13 +442,13 @@ class Message(object):
subcalls.append('\tprintf("[");') subcalls.append('\tprintf("[");')
subcalls.append('\tfor (size_t i = 0; i < {}; i++) {{' subcalls.append('\tfor (size_t i = 0; i < {}; i++) {{'
.format(num_elems)) .format(num_elems))
subcalls.append('\t\t{} v;'.format(f.fieldtype.name)); subcalls.append('\t\t{} v;'.format(f.fieldtype.name))
if f.fieldtype.is_assignable(): if f.fieldtype.is_assignable():
subcalls.append('\t\tv = fromwire_{}(&cursor, plen);' subcalls.append('\t\tv = fromwire_{}(&cursor, plen);'
.format(name,basetype)) .format(name, basetype))
else: else:
# We don't handle this yet! # We don't handle this yet!
assert not basetype in varlen_structs assert(basetype not in varlen_structs)
subcalls.append('\t\tfromwire_{}(&cursor, &plen, &v);' subcalls.append('\t\tfromwire_{}(&cursor, &plen, &v);'
.format(basetype)) .format(basetype))
@ -455,13 +459,13 @@ class Message(object):
subcalls.append('\t}') subcalls.append('\t}')
subcalls.append('\tprintf("]");') subcalls.append('\tprintf("]");')
def print_printwire(self,is_header): def print_printwire(self, is_header):
template = printwire_header_templ if is_header else printwire_impl_templ template = printwire_header_templ if is_header else printwire_impl_templ
fields = ['\t{} {};\n'.format(f.fieldtype.name, f.name) for f in self.fields if f.is_len_var] fields = ['\t{} {};\n'.format(f.fieldtype.name, f.name) for f in self.fields if f.is_len_var]
subcalls = [] subcalls = []
for f in self.fields: for f in self.fields:
basetype=f.basetype() basetype = f.basetype()
for c in f.comments: for c in f.comments:
subcalls.append('\t/*{} */'.format(c)) subcalls.append('\t/*{} */'.format(c))
@ -489,9 +493,9 @@ class Message(object):
.format(f.fieldtype.name, f.name, basetype)) .format(f.fieldtype.name, f.name, basetype))
else: else:
# Don't handle these yet. # Don't handle these yet.
assert not basetype in varlen_structs assert(basetype not in varlen_structs)
subcalls.append('\t{} {};'. subcalls.append('\t{} {};'.
format(f.fieldtype.name, f.name)); format(f.fieldtype.name, f.name))
subcalls.append('\tfromwire_{}(&cursor, &plen, &{});' subcalls.append('\tfromwire_{}(&cursor, &plen, &{});'
.format(basetype, f.name)) .format(basetype, f.name))
@ -506,6 +510,7 @@ class Message(object):
subcalls='\n'.join(subcalls) subcalls='\n'.join(subcalls)
) )
def find_message(messages, name): def find_message(messages, name):
for m in messages: for m in messages:
if m.name == name: if m.name == name:
@ -513,6 +518,7 @@ def find_message(messages, name):
return None return None
def find_message_with_option(messages, optional_messages, name, option): def find_message_with_option(messages, optional_messages, name, option):
fullname = name + "_" + option.replace('-', '_') fullname = name + "_" + option.replace('-', '_')
@ -563,8 +569,8 @@ for line in fileinput.input(options.files):
if len(parts) == 2: if len(parts) == 2:
# eg commit_sig,132 # eg commit_sig,132
messages.append(Message(parts[0],Enumtype("WIRE_" + parts[0].upper(), parts[1]), comments)) messages.append(Message(parts[0], Enumtype("WIRE_" + parts[0].upper(), parts[1]), comments))
comments=[] comments = []
prevfield = None prevfield = None
else: else:
if len(parts) == 4: if len(parts) == 4:
@ -586,7 +592,7 @@ for line in fileinput.input(options.files):
# time (multiple fields can use the same lenvar). # time (multiple fields can use the same lenvar).
if not f.lenvar: if not f.lenvar:
prevfield = parts[2] prevfield = parts[2]
comments=[] comments = []
header_template = """/* This file was generated by generate-wire.py */ header_template = """/* This file was generated by generate-wire.py */
/* Do not modify this file! Modify the _csv file it was generated from. */ /* Do not modify this file! Modify the _csv file it was generated from. */
@ -678,7 +684,7 @@ for m in messages:
enums += '\t{} = {},\n'.format(m.enum.name, m.enum.value) enums += '\t{} = {},\n'.format(m.enum.name, m.enum.value)
includes = '\n'.join(includes) includes = '\n'.join(includes)
cases = ['case {enum.name}: return "{enum.name}";'.format(enum=m.enum) for m in messages] cases = ['case {enum.name}: return "{enum.name}";'.format(enum=m.enum) for m in messages]
printcases = ['case {enum.name}: printf("{enum.name}:\\n"); printwire_{name}(msg); return;'.format(enum=m.enum,name=m.name) for m in messages] printcases = ['case {enum.name}: printf("{enum.name}:\\n"); printwire_{name}(msg); return;'.format(enum=m.enum, name=m.name) for m in messages]
if options.printwire: if options.printwire:
decls = [m.print_printwire(options.header) for m in messages + messages_with_option] decls = [m.print_printwire(options.header) for m in messages + messages_with_option]

Loading…
Cancel
Save