sql: add test that triggers bug on channelmoves
What changed, and why it matters
This commit only adds a new test case that demonstrates a bug. The test is marked as expected to fail (xfail). It shows that running a SQL query on the 'channelmoves' table can crash a node if the number of channel movements exceeds an internal list limit. The actual crash-causing code is not fixed here, so this commit by itself does not resolve the issue.
Treat this as a bug report with a reproducer, not a security fix. Investigate the root cause in the SQL/listchannelmoves integration, add bounds checking or pagination, and run the new test to confirm the crash before and after a real fix. Consider whether an untrusted RPC user could trigger the crash via SQL queries.
Security signals we found
Denial-of-service vector: SQL query on channelmoves can crash a node
Test-only commit documenting a reproducible crash
No patch or mitigation present in this commit
Evidence from the diff
The diff adds a test in tests/test_plugin.py named test_sql_limit_per_list. It creates a 3-node line graph with the middle node configured with dev-sqllistlimit=10, generates 20 invoices/payments to create channelmoves entries, then runs a SQL query against channelmoves. The test is decorated with @pytest.mark.xfail(strict=True), meaning it documents a known failure. The commit message states that updating channelmoves crashes SQL when listchannelmoves has more elements than limit_per_list. No fix is included in this commit.
Changed components
tests/test_plugin.pychannelmoves SQL table handlinglistchannelmoves internal limitInspect captured patch +11 / −0
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index df6193db..a2f197bc 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -4410,6 +4410,17 @@ def test_sql_deprecated(node_factory, bitcoind):
assert ret == {'rows': [[1]]}
+@pytest.mark.xfail(strict=True)
+def test_sql_limit_per_list(node_factory):
+ l1, l2, l3 = node_factory.line_graph(
+ 3, wait_for_announce=True, opts=[{}, {"dev-sqllistlimit": 10}, {}]
+ )
+ for i in range(20):
+ inv = l3.rpc.invoice(1000, f"inv-{i}", f"inv-{i}")["bolt11"]
+ l1.rpc.xpay(inv)
+ l2.rpc.sql("SELECT created_index, payment_hash FROM channelmoves")
+
+
def test_plugin_persist_option(node_factory):
"""test that options from config file get remembered across plugin stop/start"""
plugin_path = os.path.join(os.getcwd(), 'contrib/plugins/helloworld.py')
Why this scored 40/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.