From a5300386813937e38810a86153811941047ea578 Mon Sep 17 00:00:00 2001 From: bitflash-maintainer Date: Sun, 23 Aug 2026 11:48:56 +0000 Subject: payout: take the mutex that guards the in-flight list while loading it LoadPaying appends to gPaying and increments gPayingNextId, and both are annotated as guarded by gPayoutExecMutex. It took neither. Nothing is racing it today: it is called from the pool startup path before the payout thread is spawned, and the self-test calls it on one thread. But that is a fact about its callers, not about the function, and the annotation is what the next person to add a caller will read. The lock is uncontended here by construction, so there is nothing to weigh against taking it. Property: every mutation of gPaying and gPayingNextId in this file happens under the mutex they are documented to be guarded by. --- src/rpc.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/rpc.cpp') diff --git a/src/rpc.cpp b/src/rpc.cpp index c382926..a9eca8a 100644 --- a/src/rpc.cpp +++ b/src/rpc.cpp @@ -962,6 +962,14 @@ static void LoadPaying() fclose(f); try { nlohmann::json arr = nlohmann::json::parse(s); + // gPaying and gPayingNextId are both annotated as guarded by + // gPayoutExecMutex and this was mutating them without it. Safe today + // -- LoadPaying only runs at startup, before the payout thread is + // spawned -- but "safe because of where it is called from" is a fact + // about the caller, not about this function, and the annotation is + // what every other reader will trust. The mutex is uncontended here by + // construction, so taking it costs nothing. + std::lock_guard lk(gPayoutExecMutex); for (const auto& obj : arr) { PayingRecord r; r.address = obj["address"].get(); -- cgit v1.2.3