From 03a69ccfb36861948e11b0871bb9af8f0b280709 Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Wed, 2 Sep 2026 14:14:52 +0000 Subject: payout: never collapse a log line that reports money moving LogPrint()'s burst collapse is right for share and peer chatter and wrong for anything that reports an irreversible change to money. A reorg voided 100 ledger entries totalling 4,950 BTF and the log carried one line, naming one block and 49.49 BTF. The other 99 were counted and never printed, and no "(N similar)" summary appeared either -- a summary was only ever flushed when that same call site fired again, and after the reorg it never did. The missing 4,950 BTF was found by counting entries in pending_payouts.json. Add LogPrintAlways(), which skips the collapse entirely, and move the four payout lines that report money to it: an obligation voided, an obligation dropped, a payment sent, a payment that failed. All four are bursty by nature -- one reorg voids every entry funded by the orphaned block, from a single source line -- which is precisely why one line must not stand in for all of them. Their volume is bounded by how much money moved, which is a number worth the lines. Also sweep expired windows for every call site rather than only the one currently logging, so a burst that stops is still summarised, and report the window's real elapsed time instead of a hardcoded 3s. --- src/rpc.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/rpc.cpp') diff --git a/src/rpc.cpp b/src/rpc.cpp index a4b53ca..2e8f4b8 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -1732,7 +1732,9 @@ static void FlushMaturePayouts() } int64 total = 0; for (auto& kv : it->amounts) total += kv.second; - LogPrint("payout", "[payout] block %d (%s) was orphaned -- voiding %zu" + // Always: one line per voided entry, never a collapsed summary. + // A reorg voids these in a burst from this one source line. + LogPrintAlways("payout", "[payout] block %d (%s) was orphaned -- voiding %zu" " payment(s) totalling %s\n", it->blockHeight, it->blockHash.ToString().substr(0, 14).c_str(), it->amounts.size(), FormatMoney(total).c_str()); @@ -2036,7 +2038,7 @@ static void PayoutThreadFn(void*) // funding block can land at any point in that window. Upstream has // no equivalent -- it decides once, when the entry matures. if (!PayoutBlockStillOnChain(r.blockHash)) { - LogPrint("payout", "[payout] block %d (%s) orphaned while queued" + LogPrintAlways("payout", "[payout] block %d (%s) orphaned while queued" " -- dropping %s to %s\n", r.blockHeight, r.blockHash.ToString().substr(0, 14).c_str(), FormatMoney(r.amount).c_str(), r.address.c_str()); @@ -2205,7 +2207,7 @@ static void PayoutThreadFn(void*) // described by at least one of them at every instant. RecordPayoutTxid(r, wtx.GetHash().GetHex()); ForgetPayment(r); - LogPrint("payout", "[payout] paid %s to %s (tx %s)\n", + LogPrintAlways("payout", "[payout] paid %s to %s (tx %s)\n", FormatMoney(r.amount).c_str(), r.address.c_str(), wtx.GetHash().ToString().substr(0, 12).c_str()); } else { @@ -2263,7 +2265,7 @@ static void PayoutThreadFn(void*) // going away must not turn the log into one line a minute // forever, and must not go quiet either. if (r.retries <= 5 || r.retries % 60 == 0) - LogPrint("payout", "[payout] FAILED to pay %s to %s" + LogPrintAlways("payout", "[payout] FAILED to pay %s to %s" " (%s spendable, wallet unlocked, block %d on" " the main chain) -- attempt %d, retrying in" " 60s; this debt stands until it is paid\n", -- cgit v1.2.3 From b441687b5344454bea16384fe1280e470964faaa Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Thu, 3 Sep 2026 18:31:32 +0000 Subject: payout: move the last two burst-capable money lines to LogPrintAlways Integration review found two more payout lines still on plain LogPrint, both fired per record inside the batch loop in PayoutThreadFn -- the same one-window burst shape as the four already converted. The "writing off" line in ForfeitPayoutRecipient and the "SKIPPED bad address" line at the write-off in PayoutThreadFn both report obligations being destroyed, which is the class of line one summary must never stand in for (issue #3). Message text is unchanged. --- src/rpc.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/rpc.cpp') diff --git a/src/rpc.cpp b/src/rpc.cpp index 2e8f4b8..6531fe8 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -1933,7 +1933,7 @@ static void RecordPayoutTxid(const PayingRecord& r, const std::string& txid) // disagreeing. static void ForfeitPayoutRecipient(const PayingRecord& r, const std::string& reason) { - LogPrint("payout", "[payout] writing off %s owed to %s for block %d: %s\n", + LogPrintAlways("payout", "[payout] writing off %s owed to %s for block %d: %s\n", FormatMoney(r.amount).c_str(), r.address.c_str(), r.blockHeight, reason.c_str()); VersionedBlob blob; @@ -2082,7 +2082,7 @@ static void PayoutThreadFn(void*) const std::string reason = strprintf("'%s' is not a valid address, so no transaction" " can pay it", r.address.c_str()); - LogPrint("payout", "[payout] SKIPPED bad address '%s' --" + LogPrintAlways("payout", "[payout] SKIPPED bad address '%s' --" " %s owed for block %d cannot be paid\n", r.address.c_str(), FormatMoney(r.amount).c_str(), r.blockHeight); -- cgit v1.2.3