aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPieter Wuille <pieter@wuille.net>2023-02-01 18:28:08 -0500
committerPieter Wuille <pieter@wuille.net>2023-02-01 23:14:12 -0500
commitb0ff31084006ac7d4a7afba3190ca75f5f8441af (patch)
tree909dc06de479080bab43ca090efaa8ea2b359b9c
parent3c9cea1340fd1358d6854209d782922864945eb0 (diff)
downloadbitcoin-b0ff31084006ac7d4a7afba3190ca75f5f8441af.tar.xz
Add CCoinsViewCache::SanityCheck() and use it in fuzz test
-rw-r--r--src/coins.cpp17
-rw-r--r--src/coins.h3
-rw-r--r--src/test/fuzz/coinscache_sim.cpp9
3 files changed, 28 insertions, 1 deletions
diff --git a/src/coins.cpp b/src/coins.cpp
index e98bf816ab..8d99019bb0 100644
--- a/src/coins.cpp
+++ b/src/coins.cpp
@@ -314,6 +314,23 @@ void CCoinsViewCache::ReallocateCache()
::new (&cacheCoins) CCoinsMap();
}
+void CCoinsViewCache::SanityCheck() const
+{
+ size_t recomputed_usage = 0;
+ for (const auto& [_, entry] : cacheCoins) {
+ unsigned attr = 0;
+ if (entry.flags & CCoinsCacheEntry::DIRTY) attr |= 1;
+ if (entry.flags & CCoinsCacheEntry::FRESH) attr |= 2;
+ if (entry.coin.IsSpent()) attr |= 4;
+ // Only 5 combinations are possible.
+ assert(attr != 2 && attr != 4 && attr != 7);
+
+ // Recompute cachedCoinsUsage.
+ recomputed_usage += entry.coin.DynamicMemoryUsage();
+ }
+ assert(recomputed_usage == cachedCoinsUsage);
+}
+
static const size_t MIN_TRANSACTION_OUTPUT_WEIGHT = WITNESS_SCALE_FACTOR * ::GetSerializeSize(CTxOut(), PROTOCOL_VERSION);
static const size_t MAX_OUTPUTS_PER_BLOCK = MAX_BLOCK_WEIGHT / MIN_TRANSACTION_OUTPUT_WEIGHT;
diff --git a/src/coins.h b/src/coins.h
index 710b8c7c83..a2764d32bb 100644
--- a/src/coins.h
+++ b/src/coins.h
@@ -320,6 +320,9 @@ public:
//! See: https://stackoverflow.com/questions/42114044/how-to-release-unordered-map-memory
void ReallocateCache();
+ //! Run an internal sanity check on the cache data structure. */
+ void SanityCheck() const;
+
private:
/**
* @note this is marked const, but may actually append to `cacheCoins`, increasing
diff --git a/src/test/fuzz/coinscache_sim.cpp b/src/test/fuzz/coinscache_sim.cpp
index c3f732f075..b794888ca2 100644
--- a/src/test/fuzz/coinscache_sim.cpp
+++ b/src/test/fuzz/coinscache_sim.cpp
@@ -51,7 +51,8 @@ struct PrecomputedData
const uint8_t ser[4] = {uint8_t(i), uint8_t(i >> 8), uint8_t(i >> 16), uint8_t(i >> 24)};
uint256 hash;
CSHA256().Write(PREFIX_S, 1).Write(ser, sizeof(ser)).Finalize(hash.begin());
- /* Convert hash to scriptPubkeys. */
+ /* Convert hash to scriptPubkeys (of different lengths, so SanityCheck's cached memory
+ * usage check has a chance to detect mismatches). */
switch (i % 5U) {
case 0: /* P2PKH */
coins[i].out.scriptPubKey.resize(25);
@@ -381,6 +382,7 @@ FUZZ_TARGET(coinscache_sim)
[&]() { // Remove a cache level.
// Apply to real caches (this reduces caches.size(), implicitly doing the same on the simulation data).
+ caches.back()->SanityCheck();
caches.pop_back();
},
@@ -420,6 +422,11 @@ FUZZ_TARGET(coinscache_sim)
);
}
+ // Sanity check all the remaining caches
+ for (const auto& cache : caches) {
+ cache->SanityCheck();
+ }
+
// Full comparison between caches and simulation data, from bottom to top,
// as AccessCoin on a higher cache may affect caches below it.
for (unsigned sim_idx = 1; sim_idx <= caches.size(); ++sim_idx) {