pytest: fix flake in test_coinmoves_unilateral_htlc_fulfill / test_coinmoves_unilateral_htlc_timeout
What changed, and why it matters
This commit fixes a flaky automated test in Core Lightning. The test sometimes failed because the size of a Bitcoin transaction signature can randomly vary by one byte, changing the transaction fee and the leftover change amount. The fix reads the actual change amount from the blockchain instead of hardcoding an expected value. It is not a security fix and does not affect production code.
No security action required. This is a test-only reliability improvement. Reviewers may verify the new assertion still validates the expected coin-move structure and that the value lookup uses the correct output index.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch modifies two pytest test functions in tests/test_coinmoves.py. Previously they asserted exact expected coin-move amounts (15579000 msat) for the anchor-spend change output. Because DER-encoded ECDSA signatures can vary in length (w=1283 vs w=1284), the commitment transaction weight and thus the child anchor-spend fee vary, producing a different change output (15586000 msat ~1/128 of the time). The fix queries bitcoind.rpc.gettxout(anchor_spend_txid, 0)[‘value’] at runtime and uses that value in the expected coin-move records, eliminating the hardcoded assumption.
Changed components
tests/test_coinmoves.pytest_coinmoves_unilateral_htlc_timeouttest_coinmoves_unilateral_htlc_fulfillInspect captured patch +14 / −4
diff --git a/tests/test_coinmoves.py b/tests/test_coinmoves.py
index 0cdefe83..21f6dea8 100644
--- a/tests/test_coinmoves.py
+++ b/tests/test_coinmoves.py
@@ -727,6 +727,11 @@ def test_coinmoves_unilateral_htlc_timeout(node_factory, bitcoind):
line = l1.daemon.is_in_log('Tracking output.*/OUR_HTLC')
htlc = int(re.search(r'output [0-9a-f]{64}:([0-9]):', line).group(1))
+ # commitment tx weight can vary (DER sigs, FML) and so even though the feerate target
+ # is fixed, the amount of the child tx we create will vary, hence the change varies.
+ # So it's usually 15579000, but one in 128 it will be 15586000...
+ anchor_change_msats = bitcoind.rpc.gettxout(anchor_spend_txid, 0)['value'] * 100_000_000_000
+
expected_chain1 += [{'account_id': 'wallet', # Anchor spend from fundchannel change
'blockheight': 104,
'credit_msat': 0,
@@ -738,10 +743,10 @@ def test_coinmoves_unilateral_htlc_timeout(node_factory, bitcoind):
'utxo': f"{fundchannel['txid']}:{fundchannel['outnum'] ^ 1}"},
{'account_id': 'wallet', # change from anchor spend
'blockheight': 104,
- 'credit_msat': 15579000,
+ 'credit_msat': anchor_change_msats,
'debit_msat': 0,
'extra_tags': [],
- 'output_msat': 15579000,
+ 'output_msat': anchor_change_msats,
'primary_tag': 'deposit',
'utxo': f"{anchor_spend_txid}:0"},
{'account_id': fundchannel['channel_id'],
@@ -1221,6 +1226,11 @@ def test_coinmoves_unilateral_htlc_fulfill(node_factory, bitcoind):
line = l1.daemon.is_in_log('Tracking output.*/OUR_HTLC')
htlc = int(re.search(r'output [0-9a-f]{64}:([0-9]):', line).group(1))
+ # commitment tx weight can vary (DER sigs, FML) and so even though the feerate target
+ # is fixed, the amount of the child tx we create will vary, hence the change varies.
+ # So it's usually 15579000, but one in 128 it will be 15586000...
+ anchor_change_msats = bitcoind.rpc.gettxout(anchor_spend_txid, 0)['value'] * 100_000_000_000
+
expected_chain1 += [{'account_id': 'wallet', # Anchor spend from fundchannel change
'blockheight': 104,
'credit_msat': 0,
@@ -1232,10 +1242,10 @@ def test_coinmoves_unilateral_htlc_fulfill(node_factory, bitcoind):
'utxo': f"{fundchannel['txid']}:{fundchannel['outnum'] ^ 1}"},
{'account_id': 'wallet', # Change from anchor spend
'blockheight': 104,
- 'credit_msat': 15579000,
+ 'credit_msat': anchor_change_msats,
'debit_msat': 0,
'extra_tags': [],
- 'output_msat': 15579000,
+ 'output_msat': anchor_change_msats,
'primary_tag': 'deposit',
'utxo': f"{anchor_spend_txid}:0"},
{'account_id': fundchannel['channel_id'],
Why this scored 15/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.