From fde353ab00dbcb9bc7718e579b29daff4315c1f9 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Fri, 7 Aug 2020 12:44:55 +0930 Subject: [PATCH] pytest: use get_nodes more widely. I started replacing all get_node() calls, but got bored, so then just did the tests which call get_node() 3 times or more. Ends up not making a measurable speed difference, but it does make some things neater and more standard. Times with SLOW_MACHINE=1 (given that's how Travis tests): Time before (non-valgrind): 393 sec (had 3 failures?) Time after (non-valgrind): 410 sec Time before (valgrind): 890 seconds (had 2 failures) Time after (valgrind): 892 sec Signed-off-by: Rusty Russell --- tests/test_closing.py | 270 ++++++++++++++++----------------------- tests/test_connection.py | 33 +++-- tests/test_gossip.py | 50 ++++---- tests/test_invoices.py | 4 +- tests/test_misc.py | 56 ++++---- tests/test_pay.py | 80 +++++------- tests/test_plugin.py | 11 +- 7 files changed, 215 insertions(+), 289 deletions(-) diff --git a/tests/test_closing.py b/tests/test_closing.py index b57cad250..193f2471f 100644 --- a/tests/test_closing.py +++ b/tests/test_closing.py @@ -278,16 +278,14 @@ def test_closing_negotiation_reconnect(node_factory, bitcoind): disconnects = ['-WIRE_CLOSING_SIGNED', '@WIRE_CLOSING_SIGNED', '+WIRE_CLOSING_SIGNED'] - l1 = node_factory.get_node(disconnect=disconnects, may_reconnect=True) - l2 = node_factory.get_node(may_reconnect=True) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - - chan = l1.fund_channel(l2, 10**6) + l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': disconnects, + 'may_reconnect': True}, + {'may_reconnect': True}]) l1.pay(l2, 200000000) assert bitcoind.rpc.getmempoolinfo()['size'] == 0 - l1.rpc.close(chan) + l1.rpc.close(l2.info['id']) l1.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN') l2.daemon.wait_for_log(' to CHANNELD_SHUTTING_DOWN') @@ -362,20 +360,14 @@ def test_closing_specified_destination(node_factory, bitcoind, chainparams): def closing_negotiation_step(node_factory, bitcoind, chainparams, opts): - rate = 29006 # closing fee negotiation starts at 21000 - opener = node_factory.get_node(feerates=(rate, rate, rate, rate)) - - rate = 27625 # closing fee negotiation starts at 20000 - peer = node_factory.get_node(feerates=(rate, rate, rate, rate)) + orate = 29006 # closing fee negotiation starts at 21000 + prate = 27625 # closing fee negotiation starts at 20000 + opener, peer = node_factory.line_graph(2, opts=[{'feerates': (orate, orate, orate, orate)}, + {'feerates': (prate, prate, prate, prate)}]) opener_id = opener.info['id'] peer_id = peer.info['id'] - fund_amount = 10**6 - - opener.rpc.connect(peer_id, 'localhost', peer.port) - opener.fund_channel(peer, fund_amount) - assert bitcoind.rpc.getmempoolinfo()['size'] == 0 if opts['close_initiated_by'] == 'opener': @@ -508,15 +500,14 @@ def test_penalty_inhtlc(node_factory, bitcoind, executor, chainparams): coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') # We suppress each one after first commit; HTLC gets added not fulfilled. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], - may_fail=True, feerates=(7500, 7500, 7500, 7500), - allow_broken_log=True, - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED-nocommit'], - options={'plugin': coin_mvt_plugin}) + l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': ['=WIRE_COMMITMENT_SIGNED-nocommit'], + 'may_fail': True, + 'feerates': (7500, 7500, 7500, 7500), + 'allow_broken_log': True, + 'plugin': coin_mvt_plugin}, + {'disconnect': ['=WIRE_COMMITMENT_SIGNED-nocommit'], + 'plugin': coin_mvt_plugin}]) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) channel_id = first_channel_id(l1, l2) # Now, this will get stuck due to l1 commit being disabled.. @@ -605,16 +596,14 @@ def test_penalty_outhtlc(node_factory, bitcoind, executor, chainparams): coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') # First we need to get funds to l2, so suppress after second. # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'], - may_fail=True, - feerates=(7500, 7500, 7500, 7500), - allow_broken_log=True, - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(disconnect=['=WIRE_COMMITMENT_SIGNED*3-nocommit'], - options={'plugin': coin_mvt_plugin}) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) + l1, l2 = node_factory.line_graph(2, + opts=[{'disconnect': ['=WIRE_COMMITMENT_SIGNED*3-nocommit'], + 'may_fail': True, + 'feerates': (7500, 7500, 7500, 7500), + 'allow_broken_log': True, + 'plugin': coin_mvt_plugin}, + {'disconnect': ['=WIRE_COMMITMENT_SIGNED*3-nocommit'], + 'plugin': coin_mvt_plugin}]) channel_id = first_channel_id(l1, l2) # Move some across to l2. @@ -727,38 +716,29 @@ def test_penalty_htlc_tx_fulfill(node_factory, bitcoind, chainparams): # We track channel balances, to verify that accounting is ok. coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') - l1 = node_factory.get_node(disconnect=['=WIRE_UPDATE_FULFILL_HTLC', - '-WIRE_UPDATE_FULFILL_HTLC'], - may_reconnect=True, - options={'dev-no-reconnect': None}) - l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin, - 'disable-mpp': None, - 'dev-no-reconnect': None}, - may_reconnect=True, - allow_broken_log=True) - l3 = node_factory.get_node(options={'plugin': coin_mvt_plugin, - 'dev-no-reconnect': None}, - may_reconnect=True, - allow_broken_log=True) - l4 = node_factory.get_node(may_reconnect=True, options={'dev-no-reconnect': None}) + l1, l2, l3, l4 = node_factory.line_graph(4, + opts=[{'disconnect': ['-WIRE_UPDATE_FULFILL_HTLC'], + 'may_reconnect': True, + 'dev-no-reconnect': None}, + {'plugin': coin_mvt_plugin, + 'disable-mpp': None, + 'dev-no-reconnect': None, + 'may_reconnect': True, + 'allow_broken_log': True}, + {'plugin': coin_mvt_plugin, + 'dev-no-reconnect': None, + 'may_reconnect': True, + 'allow_broken_log': True}, + {'dev-no-reconnect': None, + 'may_reconnect': True}], + wait_for_announce=True) - l2.rpc.connect(l1.info['id'], 'localhost', l1.port) - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - l3.rpc.connect(l4.info['id'], 'localhost', l4.port) - - c12 = l2.fund_channel(l1, 10**6) - l2.fund_channel(l3, 10**6) - c34 = l3.fund_channel(l4, 10**6) channel_id = first_channel_id(l2, l3) - bitcoind.generate_block(5) - l1.wait_channel_active(c34) - l4.wait_channel_active(c12) - # push some money so that 1 + 4 can both send htlcs - inv = l1.rpc.invoice(10**9 // 2, '1', 'balancer') - l2.rpc.pay(inv['bolt11']) - l2.rpc.waitsendpay(inv['payment_hash']) + inv = l2.rpc.invoice(10**9 // 2, '1', 'balancer') + l1.rpc.pay(inv['bolt11']) + l1.rpc.waitsendpay(inv['payment_hash']) inv = l4.rpc.invoice(10**9 // 2, '1', 'balancer') l2.rpc.pay(inv['bolt11']) @@ -874,43 +854,31 @@ def test_penalty_htlc_tx_timeout(node_factory, bitcoind, chainparams): # We track channel balances, to verify that accounting is ok. coin_mvt_plugin = os.path.join(os.getcwd(), 'tests/plugins/coin_movements.py') - l1 = node_factory.get_node(disconnect=['=WIRE_UPDATE_FULFILL_HTLC', - '-WIRE_UPDATE_FULFILL_HTLC'], - may_reconnect=True, - options={'dev-no-reconnect': None}) - l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin, - 'dev-no-reconnect': None}, - may_reconnect=True, - allow_broken_log=True) - l3 = node_factory.get_node(options={'plugin': coin_mvt_plugin, - 'dev-no-reconnect': None}, - may_reconnect=True, - allow_broken_log=True) - l4 = node_factory.get_node(may_reconnect=True, options={'dev-no-reconnect': None}) - l5 = node_factory.get_node(disconnect=['-WIRE_UPDATE_FULFILL_HTLC'], - may_reconnect=True, - options={'dev-no-reconnect': None}) + l1, l2, l3, l4, l5 = node_factory.get_nodes(5, + opts=[{'disconnect': ['-WIRE_UPDATE_FULFILL_HTLC'], + 'may_reconnect': True, + 'dev-no-reconnect': None}, + {'plugin': coin_mvt_plugin, + 'dev-no-reconnect': None, + 'may_reconnect': True, + 'allow_broken_log': True}, + {'plugin': coin_mvt_plugin, + 'dev-no-reconnect': None, + 'may_reconnect': True, + 'allow_broken_log': True}, + {'dev-no-reconnect': None}, + {'disconnect': ['-WIRE_UPDATE_FULFILL_HTLC'], + 'may_reconnect': True, + 'dev-no-reconnect': None}]) - l2.rpc.connect(l1.info['id'], 'localhost', l1.port) - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - l3.rpc.connect(l4.info['id'], 'localhost', l4.port) - l3.rpc.connect(l5.info['id'], 'localhost', l5.port) + node_factory.join_nodes([l1, l2, l3, l4], wait_for_announce=True) + node_factory.join_nodes([l3, l5], wait_for_announce=True) - c12 = l2.fund_channel(l1, 10**6) - l2.fund_channel(l3, 10**6) - c34 = l3.fund_channel(l4, 10**6) - c35 = l3.fund_channel(l5, 10**6) channel_id = first_channel_id(l2, l3) - bitcoind.generate_block(5) - l1.wait_channel_active(c34) - l1.wait_channel_active(c35) - l4.wait_channel_active(c12) - l5.wait_channel_active(c12) - # push some money so that 1 + 4 can both send htlcs - inv = l1.rpc.invoice(10**9 // 2, '1', 'balancer') - l2.rpc.pay(inv['bolt11']) + inv = l2.rpc.invoice(10**9 // 2, '1', 'balancer') + l1.rpc.pay(inv['bolt11']) inv = l4.rpc.invoice(10**9 // 2, '1', 'balancer') l2.rpc.pay(inv['bolt11']) @@ -1027,22 +995,22 @@ def test_onchain_first_commit(node_factory, bitcoind): # HTLC 1->2, 1 fails just after funding. disconnects = ['+WIRE_FUNDING_LOCKED', 'permfail'] - l1 = node_factory.get_node(disconnect=disconnects, options={'plugin': coin_mvt_plugin}) # Make locktime different, as we once had them reversed! - l2 = node_factory.get_node(options={'watchtime-blocks': 10, 'plugin': coin_mvt_plugin}) + l1, l2 = node_factory.line_graph(2, opts=[{'disconnect': disconnects, + 'plugin': coin_mvt_plugin}, + {'watchtime-blocks': 10, + 'plugin': coin_mvt_plugin}], + fundchannel=False) l1.fundwallet(10**7) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.rpc.fundchannel(l2.info['id'], 10**6) l1.daemon.wait_for_log('sendrawtx exit 0') - l1.bitcoin.generate_block(1) + bitcoind.generate_block(1) # l1 will drop to chain. l1.daemon.wait_for_log('permfail') l1.daemon.wait_for_log('sendrawtx exit 0') - l1.bitcoin.generate_block(1) + bitcoind.generate_block(1) l1.daemon.wait_for_log(' to ONCHAIN') l2.daemon.wait_for_log(' to ONCHAIN') @@ -1117,14 +1085,11 @@ def test_onchain_unwatch(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_onchaind_replay(node_factory, bitcoind): disconnects = ['+WIRE_REVOKE_AND_ACK', 'permfail'] - options = {'watchtime-blocks': 201, 'cltv-delta': 101} # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(options=options, disconnect=disconnects, - feerates=(7500, 7500, 7500, 7500)) - l2 = node_factory.get_node(options=options) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) + l1, l2 = node_factory.line_graph(2, opts=[{'watchtime-blocks': 201, 'cltv-delta': 101, + 'disconnect': disconnects, + 'feerates': (7500, 7500, 7500, 7500)}, + {'watchtime-blocks': 201, 'cltv-delta': 101}]) rhash = l2.rpc.invoice(10**8, 'onchaind_replay', 'desc')['payment_hash'] routestep = { @@ -1176,13 +1141,12 @@ def test_onchain_dust_out(node_factory, bitcoind, executor): # HTLC 1->2, 1 fails after it's irrevocably committed disconnects = ['@WIRE_REVOKE_AND_ACK', 'permfail'] # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=disconnects, - feerates=(7500, 7500, 7500, 7500), - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin}) + l1, l2 = node_factory.line_graph(2, + opts=[{'disconnect': disconnects, + 'feerates': (7500, 7500, 7500, 7500), + 'plugin': coin_mvt_plugin}, + {'plugin': coin_mvt_plugin}]) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) channel_id = first_channel_id(l1, l2) # Must be dust! @@ -1248,13 +1212,12 @@ def test_onchain_timeout(node_factory, bitcoind, executor): # HTLC 1->2, 1 fails just after it's irrevocably committed disconnects = ['+WIRE_REVOKE_AND_ACK*3', 'permfail'] # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node(disconnect=disconnects, - feerates=(7500, 7500, 7500, 7500), - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin}) + l1, l2 = node_factory.line_graph(2, + opts=[{'disconnect': disconnects, + 'feerates': (7500, 7500, 7500, 7500), + 'plugin': coin_mvt_plugin}, + {'plugin': coin_mvt_plugin}]) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) channel_id = first_channel_id(l1, l2) rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] @@ -1333,9 +1296,10 @@ def test_onchain_middleman(node_factory, bitcoind): # HTLC 1->2->3, 1->2 goes down after 2 gets preimage from 3. disconnects = ['-WIRE_UPDATE_FULFILL_HTLC', 'permfail'] - l1 = node_factory.get_node(options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(disconnect=disconnects, options={'plugin': coin_mvt_plugin}) - l3 = node_factory.get_node() + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'plugin': coin_mvt_plugin}, + {'plugin': coin_mvt_plugin, + 'disconnect': disconnects}, + {}]) # l2 connects to both, so l1 can't reconnect and thus l2 drops to chain l2.rpc.connect(l1.info['id'], 'localhost', l1.port) @@ -1422,12 +1386,11 @@ def test_onchain_middleman_their_unilateral_in(node_factory, bitcoind): l1_disconnects = ['=WIRE_UPDATE_FULFILL_HTLC', 'permfail'] l2_disconnects = ['-WIRE_UPDATE_FULFILL_HTLC'] - l1 = node_factory.get_node(disconnect=l1_disconnects, - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(disconnect=l2_disconnects, - options={'plugin': coin_mvt_plugin}) - l3 = node_factory.get_node() - + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'plugin': coin_mvt_plugin, + 'disconnect': l1_disconnects}, + {'plugin': coin_mvt_plugin, + 'disconnect': l2_disconnects}, + {}]) l2.rpc.connect(l1.info['id'], 'localhost', l1.port) l2.rpc.connect(l3.info['id'], 'localhost', l3.port) @@ -1508,20 +1471,12 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind): disconnects = ['-WIRE_UPDATE_FAIL_HTLC', 'permfail'] - l1 = node_factory.get_node(disconnect=disconnects, - options={'plugin': coin_mvt_plugin}) - l2 = node_factory.get_node(options={'plugin': coin_mvt_plugin}) - - l2.rpc.connect(l1.info['id'], 'localhost', l1.port) - - c12 = l2.fund_channel(l1, 10**6) + l1, l2 = node_factory.line_graph(2, opts=[{'plugin': coin_mvt_plugin}, + {'disconnect': disconnects, + 'plugin': coin_mvt_plugin}]) channel_id = first_channel_id(l1, l2) - bitcoind.generate_block(5) - l1.wait_channel_active(c12) - sync_blockheight(bitcoind, [l1, l2]) - - route = l2.rpc.getroute(l1.info['id'], 10**8, 1)["route"] + route = l1.rpc.getroute(l2.info['id'], 10**8, 1)["route"] assert len(route) == 1 q = queue.Queue() @@ -1530,7 +1485,7 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind): try: # rhash is fake rhash = 'B1' * 32 - l2.rpc.sendpay(route, rhash) + l1.rpc.sendpay(route, rhash) q.put(None) except Exception as err: q.put(err) @@ -1539,16 +1494,16 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind): t.daemon = True t.start() - # l1 will drop to chain. - l1.daemon.wait_for_log('sendrawtx exit 0') - l1.bitcoin.generate_block(1) - l2.daemon.wait_for_log(' to ONCHAIN') + # l2 will drop to chain. + l2.daemon.wait_for_log('sendrawtx exit 0') + l2.bitcoin.generate_block(1) l1.daemon.wait_for_log(' to ONCHAIN') - l2.daemon.wait_for_log('THEIR_UNILATERAL/OUR_HTLC') + l2.daemon.wait_for_log(' to ONCHAIN') + l1.daemon.wait_for_log('THEIR_UNILATERAL/OUR_HTLC') - # l2 should wait til to_self_delay (10), then fulfill onchain - l1.bitcoin.generate_block(9) - l2.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US', + # l1 should wait til to_self_delay (10), then fulfill onchain + l2.bitcoin.generate_block(9) + l1.wait_for_onchaind_broadcast('OUR_HTLC_TIMEOUT_TO_US', 'THEIR_UNILATERAL/OUR_HTLC') err = q.get(timeout=10) @@ -1559,13 +1514,13 @@ def test_onchain_their_unilateral_out(node_factory, bitcoind): assert not t.is_alive() # 100 blocks after last spend, l1+l2 should be done. - l1.bitcoin.generate_block(100) - l2.daemon.wait_for_log('onchaind complete, forgetting peer') + l2.bitcoin.generate_block(100) l1.daemon.wait_for_log('onchaind complete, forgetting peer') + l2.daemon.wait_for_log('onchaind complete, forgetting peer') # Verify accounting for l1 & l2 - assert account_balance(l1, channel_id) == 0 assert account_balance(l2, channel_id) == 0 + assert account_balance(l1, channel_id) == 0 def test_listfunds_after_their_unilateral(node_factory, bitcoind): @@ -1603,12 +1558,9 @@ def test_onchain_feechange(node_factory, bitcoind, executor): # We need 2 to drop to chain, because then 1's HTLC timeout tx # is generated on-the-fly, and is thus feerate sensitive. disconnects = ['-WIRE_UPDATE_FAIL_HTLC', 'permfail'] - l1 = node_factory.get_node(may_reconnect=True) - l2 = node_factory.get_node(disconnect=disconnects, - may_reconnect=True) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l1.fund_channel(l2, 10**6) + l1, l2 = node_factory.line_graph(2, opts=[{'may_reconnect': True}, + {'may_reconnect': True, + 'disconnect': disconnects}]) rhash = l2.rpc.invoice(10**8, 'onchain_timeout', 'desc')['payment_hash'] # We underpay, so it fails. diff --git a/tests/test_connection.py b/tests/test_connection.py index 314dd7b8f..d099706fb 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -171,12 +171,11 @@ def test_opening_tiny_channel(node_factory): l4_min_capacity = 10000 # the current default l5_min_capacity = 20000 # a server with more than default minimum - l1 = node_factory.get_node(options={'min-capacity-sat': l1_min_capacity}) - l2 = node_factory.get_node(options={'min-capacity-sat': l2_min_capacity}) - l3 = node_factory.get_node(options={'min-capacity-sat': l3_min_capacity}) - l4 = node_factory.get_node(options={'min-capacity-sat': l4_min_capacity}) - l5 = node_factory.get_node(options={'min-capacity-sat': l5_min_capacity}) - + l1, l2, l3, l4, l5 = node_factory.get_nodes(5, opts=[{'min-capacity-sat': l1_min_capacity}, + {'min-capacity-sat': l2_min_capacity}, + {'min-capacity-sat': l3_min_capacity}, + {'min-capacity-sat': l4_min_capacity}, + {'min-capacity-sat': l5_min_capacity}]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l3.info['id'], 'localhost', l3.port) l1.rpc.connect(l4.info['id'], 'localhost', l4.port) @@ -212,9 +211,7 @@ def test_opening_tiny_channel(node_factory): def test_second_channel(node_factory): - l1 = node_factory.get_node() - l2 = node_factory.get_node() - l3 = node_factory.get_node() + l1, l2, l3 = node_factory.get_nodes(3) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l3.info['id'], 'localhost', l3.port) @@ -428,9 +425,7 @@ def test_reconnect_no_update(node_factory, executor): def test_connect_stresstest(node_factory, executor): # This test is unreliable, but it's better than nothing. - l1 = node_factory.get_node(may_reconnect=True) - l2 = node_factory.get_node(may_reconnect=True) - l3 = node_factory.get_node(may_reconnect=True) + l1, l2, l3 = node_factory.get_nodes(3, opts={'may_reconnect': True}) # Hack l3 into a clone of l2, to stress reconnect code. l3.stop() @@ -1162,9 +1157,8 @@ def test_funding_close_upfront(node_factory, bitcoind): @unittest.skipIf(TEST_NETWORK != 'regtest', "External wallet support doesn't work with elements yet.") def test_funding_external_wallet(node_factory, bitcoind): - l1 = node_factory.get_node(options={'funding-confirms': 2}) - l2 = node_factory.get_node(options={'funding-confirms': 2}) - l3 = node_factory.get_node() + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'funding-confirms': 2}, + {'funding-confirms': 2}, {}]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert(l1.rpc.listpeers()['peers'][0]['id'] == l2.info['id']) @@ -1422,7 +1416,12 @@ def test_update_fee(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_fee_limits(node_factory, bitcoind): - l1, l2 = node_factory.line_graph(2, opts={'dev-max-fee-multiplier': 5, 'may_reconnect': True}, fundchannel=True) + l1, l2, l3, l4 = node_factory.get_nodes(4, opts=[{'dev-max-fee-multiplier': 5, 'may_reconnect': True}, + {'dev-max-fee-multiplier': 5, 'may_reconnect': True}, + {'ignore-fee-limits': True, 'may_reconnect': True}, + {}]) + + node_factory.join_nodes([l1, l2], fundchannel=True) # Kick off fee adjustment using HTLC. l1.pay(l2, 1000) @@ -1441,7 +1440,6 @@ def test_fee_limits(node_factory, bitcoind): sync_blockheight(bitcoind, [l1, l2]) # Trying to open a channel with too low a fee-rate is denied - l4 = node_factory.get_node() l1.rpc.connect(l4.info['id'], 'localhost', l4.port) with pytest.raises(RpcError, match='They sent error .* feerate_per_kw 253 below minimum'): l1.fund_channel(l4, 10**6) @@ -1452,7 +1450,6 @@ def test_fee_limits(node_factory, bitcoind): l1.start() # Try with node which sets --ignore-fee-limits - l3 = node_factory.get_node(options={'ignore-fee-limits': 'true'}, may_reconnect=True) l1.rpc.connect(l3.info['id'], 'localhost', l3.port) chan = l1.fund_channel(l3, 10**6) diff --git a/tests/test_gossip.py b/tests/test_gossip.py index fee9d9f16..562056ce3 100644 --- a/tests/test_gossip.py +++ b/tests/test_gossip.py @@ -456,10 +456,11 @@ def test_routing_gossip_reconnect(node_factory): # Connect two peers, reconnect and then see if we resume the # gossip. disconnects = ['-WIRE_CHANNEL_ANNOUNCEMENT'] - l1 = node_factory.get_node(disconnect=disconnects, - may_reconnect=True) - l2 = node_factory.get_node(may_reconnect=True) - l3 = node_factory.get_node() + l1, l2, l3 = node_factory.get_nodes(3, + opts=[{'disconnect': disconnects, + 'may_reconnect': True}, + {'may_reconnect': True}, + {}]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.openchannel(l2, 20000) @@ -475,17 +476,13 @@ def test_routing_gossip_reconnect(node_factory): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_gossip_no_empty_announcements(node_factory, bitcoind): # Need full IO logging so we can see gossip - opts = {'log-level': 'io'} - l1, l2 = node_factory.get_nodes(2, opts=opts) # l3 sends CHANNEL_ANNOUNCEMENT to l2, but not CHANNEL_UDPATE. - l3 = node_factory.get_node(disconnect=['+WIRE_CHANNEL_ANNOUNCEMENT'], - options={'dev-no-reconnect': None}, - may_reconnect=True) - l4 = node_factory.get_node(may_reconnect=True) - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - l3.rpc.connect(l4.info['id'], 'localhost', l4.port) + l1, l2, l3, l4 = node_factory.line_graph(4, opts=[{'log-level': 'io'}, + {'log-level': 'io'}, + {'disconnect': ['+WIRE_CHANNEL_ANNOUNCEMENT'], + 'may_reconnect': True}, + {'may_reconnect': True}], + fundchannel=False) # Make an announced-but-not-updated channel. l3.fund_channel(l4, 10**5) @@ -1094,9 +1091,11 @@ def test_gossipwith(node_factory): def test_gossip_notices_close(node_factory, bitcoind): # We want IO logging so we can replay a channel_announce to l1; # We also *really* do feed it bad gossip! - l1 = node_factory.get_node(options={'log-level': 'io'}, - allow_bad_gossip=True) - l2, l3 = node_factory.line_graph(2) + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'log-level': 'io', + 'allow_bad_gossip': True}, + {}, + {}]) + node_factory.join_nodes([l2, l3]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) bitcoind.generate_block(5) @@ -1174,7 +1173,8 @@ def test_getroute_exclude_duplicate(node_factory): @unittest.skipIf(not DEVELOPER, "gossip propagation is slow without DEVELOPER=1") def test_getroute_exclude(node_factory, bitcoind): """Test getroute's exclude argument""" - l1, l2, l3, l4 = node_factory.line_graph(4, wait_for_announce=True) + l1, l2, l3, l4, l5 = node_factory.get_nodes(5) + node_factory.join_nodes([l1, l2, l3, l4], wait_for_announce=True) # This should work route = l1.rpc.getroute(l4.info['id'], 1, 1)['route'] @@ -1230,7 +1230,6 @@ def test_getroute_exclude(node_factory, bitcoind): with pytest.raises(RpcError): l1.rpc.getroute(l4.info['id'], 1, 1, exclude=[l3.info['id'], chan_l2l4]) - l5 = node_factory.get_node() l1.rpc.connect(l5.info['id'], 'localhost', l5.port) scid15 = l1.fund_channel(l5, 1000000, wait_for_active=False) l5.rpc.connect(l4.info['id'], 'localhost', l4.port) @@ -1520,10 +1519,10 @@ def test_gossip_announce_unknown_block(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, "gossip without DEVELOPER=1 is slow") def test_gossip_no_backtalk(node_factory): - l1, l2 = node_factory.line_graph(2, wait_for_announce=True) - - # This connects, gets gossip, but should *not* play it back. - l3 = node_factory.get_node(options={'log-level': 'io'}) + # l3 connects, gets gossip, but should *not* play it back. + l1, l2, l3 = node_factory.get_nodes(3, + opts=[{}, {}, {'log-level': 'io'}]) + node_factory.join_nodes([l1, l2], wait_for_announce=True) l3.rpc.connect(l2.info['id'], 'localhost', l2.port) # Will get channel_announce, then two channel_update and two node_announcement @@ -1539,12 +1538,13 @@ def test_gossip_no_backtalk(node_factory): @unittest.skipIf(not DEVELOPER, "Needs --dev-gossip") @unittest.skipIf(TEST_NETWORK != 'regtest', "Channel announcement contains genesis hash, receiving node discards on mismatch") def test_gossip_ratelimit(node_factory): + l1, l2, l3 = node_factory.get_nodes(3, + opts=[{}, {}, {'dev-gossip-time': 1568096251}]) # These make the channel exist, but we use our own gossip. - l1, l2 = node_factory.line_graph(2, wait_for_announce=True) + node_factory.join_nodes([l1, l2], wait_for_announce=True) # Here are some ones I generated earlier (by removing gossip # ratelimiting) - l3 = node_factory.get_node(options={'dev-gossip-time': 1568096251}) subprocess.run(['devtools/gossipwith', '--max-messages=0', '{}@localhost:{}'.format(l3.info['id'], l3.port), diff --git a/tests/test_invoices.py b/tests/test_invoices.py index 6068a1ea5..ef0ac1241 100644 --- a/tests/test_invoices.py +++ b/tests/test_invoices.py @@ -183,7 +183,8 @@ def test_invoice_routeboost(node_factory, bitcoind): def test_invoice_routeboost_private(node_factory, bitcoind): """Test routeboost 'r' hint in bolt11 invoice for private channels """ - l1, l2 = node_factory.line_graph(2, fundamount=16777215, announce_channels=False) + l1, l2, l3 = node_factory.get_nodes(3) + node_factory.join_nodes([l1, l2], fundamount=16777215, announce_channels=False) scid = l1.get_channel_scid(l2) @@ -245,7 +246,6 @@ def test_invoice_routeboost_private(node_factory, bitcoind): # The existence of a public channel, even without capacity, will suppress # the exposure of private channels. - l3 = node_factory.get_node() l3.rpc.connect(l2.info['id'], 'localhost', l2.port) scid2 = l3.fund_channel(l2, (10**5)) bitcoind.generate_block(5) diff --git a/tests/test_misc.py b/tests/test_misc.py index 7e50d40bf..18a909981 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -35,8 +35,7 @@ def test_stop_pending_fundchannel(node_factory, executor): freeing the daemon, but that needs a DB transaction to be open. """ - l1 = node_factory.get_node() - l2 = node_factory.get_node() + l1, l2 = node_factory.get_nodes(2) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) @@ -69,8 +68,8 @@ def test_names(node_factory): ('0265b6ab5ec860cd257865d61ef0bbf5b3339c36cbda8b26b74e7f1dca490b6518', 'LOUDPHOTO', '0265b6') ] - for key, alias, color in configs: - n = node_factory.get_node() + nodes = node_factory.get_nodes(len(configs)) + for n, (key, alias, color) in zip(nodes, configs): assert n.daemon.is_in_log(r'public key {}, alias {}.* \(color #{}\)' .format(key, alias, color)) @@ -180,17 +179,19 @@ def test_lightningd_still_loading(node_factory, bitcoind, executor): } # Start it, establish channel, get extra funds. - l1, l2 = node_factory.line_graph(2, opts={'may_reconnect': True, 'wait_for_bitcoind_sync': False}) + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'may_reconnect': True, + 'wait_for_bitcoind_sync': False}, + {'may_reconnect': True, + 'wait_for_bitcoind_sync': False}, + {}]) + node_factory.join_nodes([l1, l2]) # Balance l1<->l2 channel l1.pay(l2, 10**9 // 2) l1.stop() - # Start extra node. - l3 = node_factory.get_node() - - # Now make sure it's behind. + # Now make sure l2 is behind. bitcoind.generate_block(2) # Make sure l2/l3 are synced sync_blockheight(bitcoind, [l2, l3]) @@ -463,11 +464,7 @@ def test_htlc_in_timeout(node_factory, bitcoind, executor): @unittest.skipIf(not DEVELOPER, "needs DEVELOPER=1") def test_bech32_funding(node_factory, chainparams): # Don't get any funds from previous runs. - l1 = node_factory.get_node(random_hsm=True) - l2 = node_factory.get_node(random_hsm=True) - - # connect - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1, l2 = node_factory.line_graph(2, opts={'random_hsm': True}, fundchannel=False) # fund a bech32 address and then open a channel with it res = l1.openchannel(l2, 20000, 'bech32') @@ -1380,25 +1377,16 @@ def test_reserve_enforcement(node_factory, executor): def test_htlc_send_timeout(node_factory, bitcoind, compat): """Test that we don't commit an HTLC to an unreachable node.""" # Feerates identical so we don't get gratuitous commit to update them - l1 = node_factory.get_node( - options={'log-level': 'io'}, - feerates=(7500, 7500, 7500, 7500) - ) + l1, l2, l3 = node_factory.line_graph(3, opts=[{'log-level': 'io', + 'feerates': (7500, 7500, 7500, 7500)}, + # Blackhole it after it sends HTLC_ADD to l3. + {'log-level': 'io', + 'feerates': (7500, 7500, 7500, 7500), + 'disconnect': ['0WIRE_UPDATE_ADD_HTLC']}, + {}], + wait_for_announce=True) - # Blackhole it after it sends HTLC_ADD to l3. - l2 = node_factory.get_node(disconnect=['0WIRE_UPDATE_ADD_HTLC'], - options={'log-level': 'io'}, - feerates=(7500, 7500, 7500, 7500)) - l3 = node_factory.get_node() - - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - - l1.fund_channel(l2, 10**6) - chanid2 = l2.fund_channel(l3, 10**6) - - # Make sure channels get announced. - bitcoind.generate_block(5) + chanid2 = l2.get_channel_scid(l3) # Make sure we have 30 seconds without any incoming traffic from l3 to l2 # so it tries to ping before sending WIRE_COMMITMENT_SIGNED. @@ -2247,8 +2235,8 @@ def test_sendcustommsg(node_factory): """ plugin = os.path.join(os.path.dirname(__file__), "plugins", "custommsg.py") opts = {'log-level': 'io', 'plugin': plugin} - l1, l2, l3 = node_factory.line_graph(3, opts=opts) - l4 = node_factory.get_node(options=opts) + l1, l2, l3, l4 = node_factory.get_nodes(4, opts=opts) + node_factory.join_nodes([l1, l2, l3]) l2.connect(l4) l3.stop() msg = r'ff' * 32 diff --git a/tests/test_pay.py b/tests/test_pay.py index 5baeeb1eb..533fb8764 100644 --- a/tests/test_pay.py +++ b/tests/test_pay.py @@ -142,9 +142,12 @@ def test_pay_exclude_node(node_factory, bitcoind): opts = [ {'disable-mpp': None}, {'plugin': os.path.join(os.getcwd(), 'tests/plugins/fail_htlcs.py')}, + {}, + {'fee-base': 100, 'fee-per-satoshi': 1000}, {} ] - l1, l2, l3 = node_factory.line_graph(3, opts=opts, wait_for_announce=True) + l1, l2, l3, l4, l5 = node_factory.get_nodes(5, opts=opts) + node_factory.join_nodes([l1, l2, l3], wait_for_announce=True) amount = 10**8 inv = l3.rpc.invoice(amount, "test1", 'description')['bolt11'] @@ -169,8 +172,6 @@ def test_pay_exclude_node(node_factory, bitcoind): # l1->l4->l5->l3 is the longer route. This makes sure this route won't be # tried for the first pay attempt. Just to be sure we also raise the fees # that l4 leverages. - l4 = node_factory.get_node(options={'fee-base': 100, 'fee-per-satoshi': 1000}) - l5 = node_factory.get_node() l1.rpc.connect(l4.info['id'], 'localhost', l4.port) l4.rpc.connect(l5.info['id'], 'localhost', l5.port) l5.rpc.connect(l3.info['id'], 'localhost', l3.port) @@ -1072,9 +1073,9 @@ def test_forward_different_fees_and_cltv(node_factory, bitcoind): # 1. D: 400 base + 4000 millionths # We don't do D yet. - l1 = node_factory.get_node(options={'cltv-delta': 10, 'fee-base': 100, 'fee-per-satoshi': 1000}) - l2 = node_factory.get_node(options={'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}) - l3 = node_factory.get_node(options={'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}) + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'cltv-delta': 10, 'fee-base': 100, 'fee-per-satoshi': 1000}, + {'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}, + {'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}]) ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] @@ -1178,9 +1179,9 @@ def test_forward_different_fees_and_cltv(node_factory, bitcoind): def test_forward_pad_fees_and_cltv(node_factory, bitcoind): """Test that we are allowed extra locktime delta, and fees""" - l1 = node_factory.get_node(options={'cltv-delta': 10, 'fee-base': 100, 'fee-per-satoshi': 1000}) - l2 = node_factory.get_node(options={'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}) - l3 = node_factory.get_node(options={'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}) + l1, l2, l3 = node_factory.get_nodes(3, opts=[{'cltv-delta': 10, 'fee-base': 100, 'fee-per-satoshi': 1000}, + {'cltv-delta': 20, 'fee-base': 200, 'fee-per-satoshi': 2000}, + {'cltv-delta': 30, 'cltv-final': 9, 'fee-base': 300, 'fee-per-satoshi': 3000}]) ret = l1.rpc.connect(l2.info['id'], 'localhost', l2.port) assert ret['id'] == l2.info['id'] @@ -1236,9 +1237,8 @@ def test_forward_stats(node_factory, bitcoind): """ amount = 10**5 - l1, l2, l3 = node_factory.line_graph(3, wait_for_announce=False) - l4 = node_factory.get_node() - l5 = node_factory.get_node(may_fail=True) + l1, l2, l3, l4, l5 = node_factory.get_nodes(5, opts=[{}] * 4 + [{'may_fail': True}]) + node_factory.join_nodes([l1, l2, l3], wait_for_announce=False) l2.openchannel(l4, 10**6, wait_for_announce=False) l2.openchannel(l5, 10**6, wait_for_announce=True) @@ -1347,12 +1347,12 @@ def test_forward_local_failed_stats(node_factory, bitcoind, executor): disconnects = ['-WIRE_UPDATE_FAIL_HTLC', 'permfail'] - l1 = node_factory.get_node() - l2 = node_factory.get_node() - l3 = node_factory.get_node() - l4 = node_factory.get_node(disconnect=disconnects) - l5 = node_factory.get_node() - l6 = node_factory.get_node() + l1, l2, l3, l4, l5, l6 = node_factory.get_nodes(6, opts=[{}, + {}, + {}, + {'disconnect': disconnects}, + {}, + {}]) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l2.rpc.connect(l3.info['id'], 'localhost', l3.port) @@ -1813,12 +1813,10 @@ def test_setchannelfee_usage(node_factory, bitcoind): DEF_BASE = 10 DEF_PPM = 100 - l1 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l2 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l3 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) + l1, l2, l3 = node_factory.get_nodes(3, + opts={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) + node_factory.join_nodes([l1, l2]) l1.rpc.connect(l3.info['id'], 'localhost', l3.port) - l1.fund_channel(l2, 1000000) def channel_get_fees(scid): return l1.db.query( @@ -1933,9 +1931,7 @@ def test_setchannelfee_state(node_factory, bitcoind): DEF_BASE = 0 DEF_PPM = 0 - l0 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l1 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l2 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) + l0, l1, l2 = node_factory.get_nodes(3, opts={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) # connection and funding l0.rpc.connect(l1.info['id'], 'localhost', l1.port) @@ -2132,9 +2128,7 @@ def test_setchannelfee_all(node_factory, bitcoind): DEF_BASE = 10 DEF_PPM = 100 - l1 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l2 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) - l3 = node_factory.get_node(options={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) + l1, l2, l3 = node_factory.get_nodes(3, opts={'fee-base': DEF_BASE, 'fee-per-satoshi': DEF_PPM}) l1.rpc.connect(l2.info['id'], 'localhost', l2.port) l1.rpc.connect(l3.info['id'], 'localhost', l3.port) l1.fund_channel(l2, 1000000) @@ -2351,16 +2345,11 @@ def test_error_returns_blockheight(node_factory, bitcoind): @unittest.skipIf(not DEVELOPER, 'Needs dev-routes') def test_tlv_or_legacy(node_factory, bitcoind): - l1, l2, l3 = node_factory.get_nodes(3, - opts={'plugin': os.path.join(os.getcwd(), 'tests/plugins/print_htlc_onion.py')}) + l1, l2, l3 = node_factory.line_graph(3, + opts={'plugin': os.path.join(os.getcwd(), 'tests/plugins/print_htlc_onion.py')}) - # Set up a channel from 1->2 first. - l1.rpc.connect(l2.info['id'], 'localhost', l2.port) - scid12 = l1.fund_channel(l2, 1000000) - - # Now set up 2->3. - l2.rpc.connect(l3.info['id'], 'localhost', l3.port) - scid23 = l2.fund_channel(l3, 1000000) + scid12 = l1.get_channel_scid(l2) + scid23 = l2.get_channel_scid(l3) # We need to force l3 to provide route hint from l2 (it won't normally, # since it sees l2 as a dead end). @@ -2378,8 +2367,8 @@ def test_tlv_or_legacy(node_factory, bitcoind): l2.daemon.wait_for_log("Got onion.*'type': 'legacy'") l3.daemon.wait_for_log("Got onion.*'type': 'tlv'") - # Turns out we only need 3 more blocks to announce l1->l2 channel. - bitcoind.generate_block(3) + # We need 5 more blocks to announce l1->l2 channel. + bitcoind.generate_block(5) # Make sure l1 knows about l2 wait_for(lambda: 'alias' in l1.rpc.listnodes(l2.info['id'])['nodes'][0]) @@ -3031,7 +3020,7 @@ def test_pay_exemptfee(node_factory, compat): @unittest.skipIf(not DEVELOPER, "Requires use_shadow flag") -def test_pay_peer(node_factory): +def test_pay_peer(node_factory, bitcoind): """If we have a direct channel to the destination we should use that. This is complicated a bit by not having sufficient capacity, but the @@ -3042,11 +3031,10 @@ def test_pay_peer(node_factory): v / l3 """ - l1, l2 = node_factory.line_graph(2, fundamount=10**6) - l3 = node_factory.get_node() - - l1.openchannel(l3, 10**6, wait_for_announce=False) - l3.openchannel(l2, 10**6, wait_for_announce=True) + l1, l2, l3 = node_factory.get_nodes(3) + node_factory.join_nodes([l1, l2]) + node_factory.join_nodes([l1, l3]) + node_factory.join_nodes([l3, l2], wait_for_announce=True) wait_for(lambda: len(l1.rpc.listchannels()['channels']) == 6) diff --git a/tests/test_plugin.py b/tests/test_plugin.py index ae6eecee2..5415f6671 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -789,13 +789,14 @@ def test_forward_event_notification(node_factory, bitcoind, executor): amount = 10**8 disconnects = ['-WIRE_UPDATE_FAIL_HTLC', 'permfail'] - l1, l2, l3 = node_factory.line_graph(3, opts=[ + l1, l2, l3, l4, l5 = node_factory.get_nodes(5, opts=[ {}, {'plugin': os.path.join(os.getcwd(), 'tests/plugins/forward_payment_status.py')}, - {} - ], wait_for_announce=True) - l4 = node_factory.get_node() - l5 = node_factory.get_node(disconnect=disconnects) + {}, + {}, + {'disconnect': disconnects}]) + + node_factory.join_nodes([l1, l2, l3], wait_for_announce=True) l2.openchannel(l4, 10**6, wait_for_announce=False) l2.openchannel(l5, 10**6, wait_for_announce=True)