Skip to content

Commit eaf6fab

Browse files
committed
pytest: reproduce crash when node disconnects between hooks:
``` lightningd-2 2026-02-09T00:41:35.196Z TRACE lightningd: Plugin peer_connected_logger_a.py returned from peer_connected hook call lightningd-2 2026-02-09T00:41:35.196Z TRACE lightningd: Calling peer_connected hook of plugin peer_connected_logger_b.py lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: FATAL SIGNAL 11 (version v25.12-257-g2a5fbd1-modded) lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: common/daemon.c:46 (send_backtrace) 0x5b2abd7f29bd lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: common/daemon.c:83 (crashdump) 0x5b2abd7f2a0c lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0 ((null)) 0x75950d84532f lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/peer_control.c:1333 (peer_connected_serialize) 0x5b2abd79c964 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/plugin_hook.c:359 (plugin_hook_call_next) 0x5b2abd7ae14a lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/plugin_hook.c:299 (plugin_hook_callback) 0x5b2abd7ae38f lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:701 (plugin_response_handle) 0x5b2abd7a7e28 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/plugin.c:790 (plugin_read_json) 0x5b2abd7ace9c lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:60 (next_plan) 0x5b2abd81dada lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:422 (do_plan) 0x5b2abd81def6 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ccan/ccan/io/io.c:439 (io_ready) 0x5b2abd81dfb3 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ccan/ccan/io/poll.c:470 (io_loop) 0x5b2abd81f0db lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/io_loop_with_timers.c:22 (io_loop_with_timers) 0x5b2abd77c13b lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: lightningd/lightningd.c:1495 (main) 0x5b2abd781c6a lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ../sysdeps/nptl/libc_start_call_main.h:58 (__libc_start_call_main) 0x75950d82a1c9 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: ../csu/libc-start.c:360 (__libc_start_main_impl) 0x75950d82a28a lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: (null):0 ((null)) 0x5b2abd752964 lightningd-2 2026-02-09T00:41:35.293Z **BROKEN** lightningd: backtrace: (null):0 ((null)) 0xffffffffffffffff ``` Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 1b1274d commit eaf6fab

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

tests/plugins/peer_connected_logger_a.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,21 @@
44
"""
55

66
from pyln.client import Plugin
7+
import os
8+
import time
79

810
plugin = Plugin()
911

1012

1113
@plugin.hook('peer_connected')
1214
def on_connected(peer, plugin, **kwargs):
1315
print(f"peer_connected_logger_a {peer['id']} {peer}")
16+
if plugin.get_option("logger_a_sleep") is True:
17+
# Block until file appears
18+
while not os.path.exists("unsleep"):
19+
time.sleep(0.25)
1420
return {'result': 'continue'}
1521

1622

23+
plugin.add_option("logger_a_sleep", False, 'Block until unsleep file exists', opt_type='bool')
1724
plugin.run()

tests/test_plugin.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,30 @@ def check_disconnect():
514514
assert not l1.daemon.is_in_log(f"peer_connected_logger_b {l3id}")
515515

516516

517+
@pytest.mark.xfail(strict=True)
518+
def test_plugin_connected_hook_disconnect_crash(node_factory, executor):
519+
"""A peer disconnnects between plugin hook invocations"""
520+
opts = [{},
521+
{'plugin':
522+
[os.path.join(os.getcwd(),
523+
'tests/plugins/peer_connected_logger_a.py'),
524+
os.path.join(os.getcwd(),
525+
'tests/plugins/peer_connected_logger_b.py')],
526+
'logger_a_sleep': True},
527+
]
528+
529+
l1, l2 = node_factory.get_nodes(2, opts=opts)
530+
executor.submit(l1.rpc.connect, l2.info['id'], 'localhost', l2.port)
531+
l2.daemon.wait_for_log(f'plugin-peer_connected_logger_a.py: peer_connected_logger_a {l1.info["id"]}')
532+
l1.stop()
533+
534+
# Now make first plugin continue...
535+
open(os.path.join(l2.daemon.lightning_dir, TEST_NETWORK, "unsleep"), "w").close()
536+
537+
# Should get log from second
538+
l2.daemon.wait_for_log(f'plugin-peer_connected_logger_b.py: peer_connected_logger_b {l1.info["id"]}')
539+
540+
517541
def test_peer_connected_remote_addr(node_factory):
518542
"""This tests the optional tlv `remote_addr` being passed to a plugin.
519543

0 commit comments

Comments
 (0)