Skip to content

Commit 561848a

Browse files
committed
Exercise non-DIRTY spent coins in caches in fuzz test
1 parent 59e6828 commit 561848a

File tree

1 file changed

+18
-8
lines changed

1 file changed

+18
-8
lines changed

src/test/fuzz/coinscache_sim.cpp

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,13 @@ struct CacheLevel
133133
}
134134
};
135135

136-
/** Class for the base of the hierarchy (roughly simulating a memory-backed CCoinsViewDB). */
136+
/** Class for the base of the hierarchy (roughly simulating a memory-backed CCoinsViewDB).
137+
*
138+
* The initial state consists of the empty UTXO set, though coins whose output index
139+
* is 3 (mod 5) always have GetCoin() succeed (but returning an IsSpent() coin unless a UTXO
140+
* exists). Coins whose output index is 4 (mod 5) have GetCoin() always succeed after being spent.
141+
* This exercises code paths with spent, non-DIRTY cache entries.
142+
*/
137143
class CoinsViewBottom final : public CCoinsView
138144
{
139145
std::map<COutPoint, Coin> m_data;
@@ -143,6 +149,10 @@ class CoinsViewBottom final : public CCoinsView
143149
{
144150
auto it = m_data.find(outpoint);
145151
if (it == m_data.end()) {
152+
if ((outpoint.n % 5) == 3) {
153+
coin.Clear();
154+
return true;
155+
}
146156
return false;
147157
} else {
148158
coin = it->second;
@@ -164,7 +174,7 @@ class CoinsViewBottom final : public CCoinsView
164174
{
165175
for (auto it = data.begin(); it != data.end(); it = erase ? data.erase(it) : std::next(it)) {
166176
if (it->second.flags & CCoinsCacheEntry::DIRTY) {
167-
if (it->second.coin.IsSpent()) {
177+
if (it->second.coin.IsSpent() && (it->first.n % 5) != 4) {
168178
m_data.erase(it->first);
169179
} else if (erase) {
170180
m_data[it->first] = std::move(it->second.coin);
@@ -173,10 +183,10 @@ class CoinsViewBottom final : public CCoinsView
173183
}
174184
} else {
175185
/* For non-dirty entries being written, compare them with what we have. */
186+
auto it2 = m_data.find(it->first);
176187
if (it->second.coin.IsSpent()) {
177-
assert(m_data.count(it->first) == 0);
188+
assert(it2 == m_data.end() || it2->second.IsSpent());
178189
} else {
179-
auto it2 = m_data.find(it->first);
180190
assert(it2 != m_data.end());
181191
assert(it->second.coin.out == it2->second.out);
182192
assert(it->second.coin.fCoinBase == it2->second.fCoinBase);
@@ -262,9 +272,9 @@ FUZZ_TARGET(coinscache_sim)
262272
auto real = caches.back()->GetCoin(data.outpoints[outpointidx], realcoin);
263273
// Compare results.
264274
if (!sim.has_value()) {
265-
assert(!real);
275+
assert(!real || realcoin.IsSpent());
266276
} else {
267-
assert(!realcoin.IsSpent());
277+
assert(real && !realcoin.IsSpent());
268278
const auto& simcoin = data.coins[sim->first];
269279
assert(realcoin.out == simcoin.out);
270280
assert(realcoin.fCoinBase == simcoin.fCoinBase);
@@ -457,9 +467,9 @@ FUZZ_TARGET(coinscache_sim)
457467
bool real = bottom.GetCoin(data.outpoints[outpointidx], realcoin);
458468
auto sim = lookup(outpointidx, 0);
459469
if (!sim.has_value()) {
460-
assert(!real);
470+
assert(!real || realcoin.IsSpent());
461471
} else {
462-
assert(!realcoin.IsSpent());
472+
assert(real && !realcoin.IsSpent());
463473
assert(realcoin.out == data.coins[sim->first].out);
464474
assert(realcoin.fCoinBase == data.coins[sim->first].fCoinBase);
465475
assert(realcoin.nHeight == sim->second);

0 commit comments

Comments
 (0)