From e0453ee7bfb873cecde3c8744fd6b10d526ebf84 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Thu, 9 Oct 2025 12:55:48 +0200 Subject: [PATCH 1/3] plugin: fix feature_set allocation Using `tal_dup_or_null` does not set the tal context to the included bytes array. Luckily we already have a function tha deeply duplicates a `feature_set`: `feature_set_dup` Signed-off-by: Peter Neuroth --- lightningd/plugin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lightningd/plugin.c b/lightningd/plugin.c index 5d031e73af9a..42718c27bb7a 100644 --- a/lightningd/plugin.c +++ b/lightningd/plugin.c @@ -1821,7 +1821,7 @@ static const char *plugin_parse_getmanifest_response(const char *buffer, } /* Store fset to allow to remove feature bits when init returns disabled */ - plugin->fset = tal_dup_or_null(plugin, struct feature_set, fset); + plugin->fset = feature_set_dup(plugin, fset); } else { plugin->fset = NULL; } From 32ab8fc11f93ac4052332b8607b8f3abbb2d8b41 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Thu, 9 Oct 2025 14:11:31 +0200 Subject: [PATCH 2/3] test: check that features get removed when ... a plugin is disabled during init. Signed-off-by: Peter Neuroth --- tests/plugins/feature-test.py | 9 +++++++++ tests/test_plugin.py | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/tests/plugins/feature-test.py b/tests/plugins/feature-test.py index 02be45004e5c..459002167239 100755 --- a/tests/plugins/feature-test.py +++ b/tests/plugins/feature-test.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 from pyln.client import Plugin +import os # Register a different set feature of feature bits for each location so we can # later check that they are being passed correctly. @@ -12,4 +13,12 @@ ) +@plugin.init() +def init(configuration, options, plugin): + disable = os.getenv("PLUGIN_DISABLE") + if disable: + return {'disable': 'init saying disable'} + return {} + + plugin.run() diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 82f832d42c2c..5359c609e229 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -1748,6 +1748,28 @@ def test_plugin_feature_announce(node_factory): assert node['features'] == expected_node_features(extra=[203]) +def test_plugin_feature_remove(node_factory, monkeypatch): + """Check that features registered by plugins get removed if a plugin + disables itself. + + We set the following feature bits we don't want to include if the plugin is + disabled during init. + - 1 << 201 for `init` messages + - 1 << 203 for `node_announcement` + - 1 << 205 for bolt11 invoices + """ + + monkeypatch.setenv("PLUGIN_DISABLE", "1") + plugin = os.path.join(os.path.dirname(__file__), 'plugins/feature-test.py') + l1 = node_factory.get_node(options={'plugin': plugin}) + + # Check that we don't include the features set in getmanifest. + our_feats = l1.rpc.getinfo()["our_features"] + assert((int(our_feats["init"], 16) & (1 << 201)) == 0) + assert((int(our_feats["node"], 16) & (1 << 203)) == 0) + assert((int(our_feats["invoice"], 16) & (1 << 205)) == 0) + + def test_hook_chaining(node_factory): """Check that hooks are called in order and the chain exits correctly From f9e938c1e4dfb109fbe825df3ca13ba8be471b70 Mon Sep 17 00:00:00 2001 From: Peter Neuroth Date: Fri, 10 Oct 2025 17:01:14 +0200 Subject: [PATCH 3/3] test: refactor plugin to use parameter not envvar Signed-off-by: Peter Neuroth --- tests/plugins/feature-test.py | 4 ++-- tests/test_plugin.py | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/plugins/feature-test.py b/tests/plugins/feature-test.py index 459002167239..12cf76821a7c 100755 --- a/tests/plugins/feature-test.py +++ b/tests/plugins/feature-test.py @@ -15,10 +15,10 @@ @plugin.init() def init(configuration, options, plugin): - disable = os.getenv("PLUGIN_DISABLE") - if disable: + if options.get('disable-on-init'): return {'disable': 'init saying disable'} return {} +plugin.add_option('disable-on-init', False, 'disable plugin on init', opt_type='bool') plugin.run() diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 5359c609e229..7e15fbf2d304 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -1748,7 +1748,7 @@ def test_plugin_feature_announce(node_factory): assert node['features'] == expected_node_features(extra=[203]) -def test_plugin_feature_remove(node_factory, monkeypatch): +def test_plugin_feature_remove(node_factory): """Check that features registered by plugins get removed if a plugin disables itself. @@ -1759,9 +1759,8 @@ def test_plugin_feature_remove(node_factory, monkeypatch): - 1 << 205 for bolt11 invoices """ - monkeypatch.setenv("PLUGIN_DISABLE", "1") plugin = os.path.join(os.path.dirname(__file__), 'plugins/feature-test.py') - l1 = node_factory.get_node(options={'plugin': plugin}) + l1 = node_factory.get_node(options={'plugin': plugin, 'disable-on-init': True}) # Check that we don't include the features set in getmanifest. our_feats = l1.rpc.getinfo()["our_features"]