coins: check unspent‑overwrite before `cachedCoinsUsage` change in `AddCoin`

The exception could be triggered during fuzz testing which leaves the accounting in a bad state.
The related fuzz test cannot be adjusted yet since other similar accounting adjustments have to be made for that to be possible.
This commit is contained in:
Lőrinc 2025-04-18 23:21:02 +02:00
parent f377bd7468
commit 5820b01b49
1 changed files with 3 additions and 3 deletions

View File

@ -76,9 +76,6 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
bool inserted; bool inserted;
std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>()); std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
bool fresh = false; bool fresh = false;
if (!inserted) {
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
}
if (!possible_overwrite) { if (!possible_overwrite) {
if (!it->second.coin.IsSpent()) { if (!it->second.coin.IsSpent()) {
throw std::logic_error("Attempted to overwrite an unspent coin (when possible_overwrite is false)"); throw std::logic_error("Attempted to overwrite an unspent coin (when possible_overwrite is false)");
@ -98,6 +95,9 @@ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possi
// DIRTY, then it can be marked FRESH. // DIRTY, then it can be marked FRESH.
fresh = !it->second.IsDirty(); fresh = !it->second.IsDirty();
} }
if (!inserted) {
cachedCoinsUsage -= it->second.coin.DynamicMemoryUsage();
}
it->second.coin = std::move(coin); it->second.coin = std::move(coin);
CCoinsCacheEntry::SetDirty(*it, m_sentinel); CCoinsCacheEntry::SetDirty(*it, m_sentinel);
if (fresh) CCoinsCacheEntry::SetFresh(*it, m_sentinel); if (fresh) CCoinsCacheEntry::SetFresh(*it, m_sentinel);