upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/selftest.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 07:52:52 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-08-23 07:52:52 +0000
commitcd4e86d431c3f5848183ca362175d1cb3edfa107 (patch)
treea1ddd2b3011a9e71f55085f7752624a924558c59 /src/selftest.cpp
parent86b39b952d81c8aa6db56beb293e08befdca296e (diff)
selftest: cover the payout ledger properties this series fixes
A new `payout-ledger` self-test, 40 assertions, wired into RunSelfTest and into `make -C src tests`. It runs against a scratch data directory and an in-memory wallet map: it never opens wallet.dat, never touches a real datadir, and never sends anything. What it asserts, defect by defect: - a restart does not duplicate an in-flight record. A matured round is exploded, the process state is thrown away and reloaded from the files twice, and the in-flight list must still hold exactly one record per recipient. Both guards are checked separately -- once with the round-level set restored, and once with it deliberately emptied so only the per-recipient check against gPaying can save it. A paying file already containing the duplicate the old build wrote must collapse on load, with the attempt counts merged upwards rather than reset. - state updates address a slot, not a value. Two records equal in every field -- exactly what the old code produced -- and rescheduling or forgetting one must land on the one it was given. - the ledger file cannot be published from a stale snapshot. An older snapshot published after a newer one must not appear on disk, and four threads publishing 64 large images of the same file in different orders must leave it parseable and equal to the highest version, whatever order they finish in. - a payment with only a legacy comment is recognised as already paid, and the fallback's limits hold: it requires the right recipient, the exact amount and the right height; one legacy transaction cannot settle a second debt; a transaction carrying another round's structured metadata is never accepted as legacy evidence; and the structured match still wins where it applies. - grandfathered zero-hash rounds do not answer for each other, both as a direct test of the round comparison and end to end -- recording a txid against one zero-hash round must leave the other still owed. - the retry clock that is actually used survives a restart. - a forfeit is published rather than silently dropped: the ledger loses that recipient and only that recipient, and the round proof records it with a reason instead of going on advertising the address as owed. - on-disk compatibility, checked against the real shapes: the live production pending_payouts.json (amounts / blockHash / blockHeight / matureAtHeight and nothing else), the merged build's shape including the retryAfter this build no longer writes, and a round trip through this build. Each assertion was verified to fail when its defect is put back: seven mutations were applied one at a time to a scratch copy and every one was caught. Notably, re-introducing either half of the duplicate-record fix alone is caught by its own assertion while the other half still prevents the duplicate -- which is the defence in depth this series was asked for, checked rather than asserted.
Diffstat (limited to 'src/selftest.cpp')
-rw-r--r--src/selftest.cpp5
1 files changed, 4 insertions, 1 deletions
diff --git a/src/selftest.cpp b/src/selftest.cpp
index eed6779..034e1f7 100644
--- a/src/selftest.cpp
+++ b/src/selftest.cpp
@@ -13,6 +13,7 @@
13#include "walletcmd.h" 13#include "walletcmd.h"
14 14
15extern int RunPoolStratumSelfTest(); 15extern int RunPoolStratumSelfTest();
16extern int RunPayoutLedgerSelfTest();
16 17
17// Test results go to the terminal, not to debug.log. 18// Test results go to the terminal, not to debug.log.
18// 19//
@@ -1573,12 +1574,14 @@ int RunSelfTest(const std::string& name)
1573 return RunConsensusLimitsSelfTest(); 1574 return RunConsensusLimitsSelfTest();
1574 if (name == "pool-stratum") 1575 if (name == "pool-stratum")
1575 return RunPoolStratumSelfTest(); 1576 return RunPoolStratumSelfTest();
1577 if (name == "payout-ledger")
1578 return RunPayoutLedgerSelfTest();
1576 if (name == "parse-money") 1579 if (name == "parse-money")
1577 return RunParseMoneySelfTest(); 1580 return RunParseMoneySelfTest();
1578 if (name == "socks5-proxy") 1581 if (name == "socks5-proxy")
1579 return RunSocks5ProxySelfTest(); 1582 return RunSocks5ProxySelfTest();
1580 1583
1581 printf("Unknown self-test '%s'\n", name.c_str()); 1584 printf("Unknown self-test '%s'\n", name.c_str());
1582 printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt, net-message, consensus-limits, pool-stratum, parse-money, socks5-proxy\n"); 1585 printf("Known self-tests: wallet-keypool, wallet-hd, wallet-format, wallet-crypto, wallet-encrypt, net-message, consensus-limits, pool-stratum, payout-ledger, parse-money, socks5-proxy\n");
1583 return 1; 1586 return 1;
1584} 1587}