pytest: test for parallel refresh.
What changed, and why it matters
This commit adds a test that demonstrates a bug: when the Core Lightning node's SQL interface is asked to refresh the same internal table from multiple requests at the same time, it can hit a database uniqueness error. The test is marked as expected to fail for now, so it documents the problem rather than fixing it. It appears to be a reliability issue in the SQL plugin's refresh logic rather than a security vulnerability that can be exploited by an attacker.
Treat as a bug report/test addition, not an immediate security patch. Developers should review the SQL plugin's refresh logic to make table refreshes atomic or idempotent under concurrent access. Users do not need to take urgent action unless the SQL RPC is exposed to untrusted callers, in which case the crash/DoS surface should be evaluated after a fix is available.
Security signals we found
Race condition in SQL table refresh (parallel query handling)
Database UNIQUE constraint failure under concurrent load
Test-only commit; no production code change
Evidence from the diff
The patch adds test_sql_parallel in tests/test_plugin.py, marked @pytest.mark.xfail(strict=True). The test launches five concurrent l1.rpc.sql("SELECT * FROM chainmoves") calls and expects a failure. The docstring notes the observed failure: UNIQUE constraint failed: chainmoves.created_index during INSERT INTO chainmoves while refreshing the table. This indicates a race condition in the SQL plugin’s table-refresh mechanism when parallel queries trigger refreshes of the same derived table. The commit does not contain a fix; it only reproduces/tests the issue.
Changed components
tests/test_plugin.pySQL plugin table refresh logic (chainmoves / channelmoves)lightningd RPC sql interfaceInspect captured patch +14 / −0
diff --git a/tests/test_plugin.py b/tests/test_plugin.py
index 72768199..d84c645c 100644
--- a/tests/test_plugin.py
+++ b/tests/test_plugin.py
@@ -4258,6 +4258,20 @@ def test_sql_crash(node_factory, bitcoind):
l1.rpc.sql(f"SELECT * FROM peerchannels;")
+@pytest.mark.xfail(strict=True)
+def test_sql_parallel(node_factory, executor):
+ """Parallel refreshes of tables causes SQL errors:
+ Error executing INSERT INTO chainmoves VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?); on row 0: UNIQUE constraint failed: chainmoves.created_index
+ """
+ l1, l2 = node_factory.line_graph(2)
+
+ futs = []
+ for _ in range(5):
+ futs.append(executor.submit(l1.rpc.sql, "SELECT * FROM chainmoves"))
+ for f in futs:
+ f.result(TIMEOUT)
+
+
def test_listchannels_broken_message(node_factory):
"""This gave a bogus BROKEN message with deprecated-apis enabled"""
l1 = node_factory.get_node(options={'allow-deprecated-apis': True})
Why this scored 33/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.