(node_factory, bitcoind, executor)
| 2319 | @unittest.skipIf(os.environ.get("TEST_CHECK_DBSTMTS", None) == "1", |
| 2320 | "We kill l2, dblog plugin replay will be unreliable") |
| 2321 | def test_channel_persistence(node_factory, bitcoind, executor): |
| 2322 | # Start two nodes and open a channel (to remember). l2 will |
| 2323 | # mysteriously die while committing the first HTLC so we can |
| 2324 | # check that HTLCs reloaded from the DB work. |
| 2325 | # Feerates identical so we don't get gratuitous commit to update them |
| 2326 | disable_commit_after = 1 |
| 2327 | if EXPERIMENTAL_DUAL_FUND: |
| 2328 | disable_commit_after = 2 |
| 2329 | |
| 2330 | l1 = node_factory.get_node(may_reconnect=True, feerates=(7500, 7500, 7500, |
| 2331 | 7500)) |
| 2332 | l2 = node_factory.get_node(options={'dev-disable-commit-after': disable_commit_after}, |
| 2333 | may_reconnect=True, start=False) |
| 2334 | # Saving IO can cause JSON errors when we check it, due to partial writes if we |
| 2335 | # get lucky when we kill it. |
| 2336 | del l2.daemon.opts['dev-save-plugin-io'] |
| 2337 | l2.start() |
| 2338 | l1.rpc.connect(l2.info['id'], 'localhost', l2.port) |
| 2339 | |
| 2340 | # Neither node should have a channel open, they are just connected |
| 2341 | for n in (l1, l2): |
| 2342 | assert(n.db_query('SELECT COUNT(id) as count FROM channels;')[0]['count'] == 0) |
| 2343 | |
| 2344 | l1.fundchannel(l2, 100000) |
| 2345 | |
| 2346 | channels = l1.rpc.listpeerchannels()['channels'] |
| 2347 | assert(only_one(channels)['state'] == 'CHANNELD_NORMAL') |
| 2348 | |
| 2349 | # Both nodes should now have exactly one channel in the database |
| 2350 | for n in (l1, l2): |
| 2351 | assert(n.db_query('SELECT COUNT(id) as count FROM channels;')[0]['count'] == 1) |
| 2352 | |
| 2353 | # Fire off a sendpay request, it'll get interrupted by a restart |
| 2354 | executor.submit(l1.pay, l2, 10000) |
| 2355 | # Wait for it to be committed to, i.e., stored in the DB |
| 2356 | l1.daemon.wait_for_log('peer_in WIRE_CHANNEL_READY') |
| 2357 | l1.daemon.wait_for_log('peer_in WIRE_COMMITMENT_SIGNED') |
| 2358 | |
| 2359 | # Stop l2, l1 will reattempt to connect |
| 2360 | print("Killing l2 in mid HTLC") |
| 2361 | l2.daemon.kill() |
| 2362 | |
| 2363 | # Clear the disconnect and timer stop so we can proceed normally |
| 2364 | del l2.daemon.opts['dev-disable-commit-after'] |
| 2365 | |
| 2366 | # Wait for l1 to notice |
| 2367 | wait_for(lambda: 'connected' not in l1.rpc.listpeerchannels()['channels']) |
| 2368 | |
| 2369 | # Now restart l2 and it should reload peers/channels from the DB |
| 2370 | l2.start() |
| 2371 | wait_for(lambda: len(l2.rpc.listpeers()['peers']) == 1) |
| 2372 | |
| 2373 | # Wait for the restored HTLC to finish |
| 2374 | wait_for(lambda: only_one(l1.rpc.listpeerchannels()['channels'])['to_us_msat'] == 99990000) |
| 2375 | |
| 2376 | wait_for(lambda: len([p for p in l1.rpc.listpeers()['peers'] if p['connected']])) |
| 2377 | wait_for(lambda: len([p for p in l2.rpc.listpeers()['peers'] if p['connected']])) |
| 2378 |
nothing calls this directly
no test coverage detected