@@ -87,9 +87,12 @@ class CCoinsViewCacheTest : public CCoinsViewCache
8787 {
8888 // Manually recompute the dynamic usage of the whole data, and compare it.
8989 size_t ret = memusage::DynamicUsage (cacheCoins);
90+ size_t count = 0 ;
9091 for (CCoinsMap::iterator it = cacheCoins.begin (); it != cacheCoins.end (); it++) {
9192 ret += memusage::DynamicUsage (it->second .coins );
93+ ++count;
9294 }
95+ BOOST_CHECK_EQUAL (GetCacheSize (), count);
9396 BOOST_CHECK_EQUAL (memusage::DynamicUsage (*this ), ret);
9497 }
9598
@@ -118,10 +121,12 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
118121 bool removed_all_caches = false ;
119122 bool reached_4_caches = false ;
120123 bool added_an_entry = false ;
124+ bool added_an_unspendable_entry = false ;
121125 bool removed_an_entry = false ;
122126 bool updated_an_entry = false ;
123127 bool found_an_entry = false ;
124128 bool missed_an_entry = false ;
129+ bool uncached_an_entry = false ;
125130
126131 // A simple map to track what we expect the cache stack to represent.
127132 std::map<COutPoint, Coin> result;
@@ -143,35 +148,50 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
143148 {
144149 uint256 txid = txids[InsecureRandRange (txids.size ())]; // txid we're going to modify in this iteration.
145150 Coin& coin = result[COutPoint (txid, 0 )];
146- const Coin& entry = stack.back ()->AccessCoin (COutPoint (txid, 0 ));
151+ const Coin& entry = (InsecureRandRange (500 ) == 0 ) ?
152+ AccessByTxid (*stack.back (), txid) : stack.back ()->AccessCoin (COutPoint (txid, 0 )
153+ );
147154 BOOST_CHECK (coin == entry);
148155 if (InsecureRandRange (5 ) == 0 || coin.IsPruned ()) {
149- if (coin.IsPruned ()) {
150- added_an_entry = true ;
156+ Coin newcoin;
157+ newcoin.out .nValue = InsecureRand32 ();
158+ newcoin.nHeight = 1 ;
159+ if (InsecureRandRange (16 ) == 0 && coin.IsPruned ()) {
160+ newcoin.out .scriptPubKey .assign (1 + (InsecureRand32 () & 0x3F ), OP_RETURN);
161+ BOOST_CHECK (newcoin.out .scriptPubKey .IsUnspendable ());
162+ added_an_unspendable_entry = true ;
151163 } else {
152- updated_an_entry = true ;
164+ newcoin.out .scriptPubKey .assign (InsecureRand32 () & 0x3F , 0 ); // Random sizes so we can test memory usage accounting
165+ (coin.IsPruned () ? added_an_entry : updated_an_entry) = true ;
166+ coin = newcoin;
153167 }
154- coin.out .nValue = InsecureRand32 ();
155- coin.nHeight = 1 ;
168+ stack.back ()->AddCoin (COutPoint (txid, 0 ), std::move (newcoin), !coin.IsPruned () || InsecureRandBool ());
156169 } else {
157- coin.Clear ();
158170 removed_an_entry = true ;
159- }
160- if (coin.IsPruned ()) {
171+ coin.Clear ();
161172 stack.back ()->SpendCoin (COutPoint (txid, 0 ));
162- } else {
163- stack.back ()->AddCoin (COutPoint (txid, 0 ), Coin (coin), true );
164173 }
165174 }
166175
176+ // One every 10 iterations, remove a random entry from the cache
177+ if (InsecureRandRange (10 ) == 0 ) {
178+ COutPoint out (txids[InsecureRandRange (txids.size ())], 0 );
179+ int cacheid = InsecureRandRange (stack.size ());
180+ stack[cacheid]->Uncache (out);
181+ uncached_an_entry |= !stack[cacheid]->HaveCoinsInCache (out);
182+ }
183+
167184 // Once every 1000 iterations and at the end, verify the full cache.
168185 if (InsecureRandRange (1000 ) == 1 || i == NUM_SIMULATION_ITERATIONS - 1 ) {
169186 for (auto it = result.begin (); it != result.end (); it++) {
187+ bool have = stack.back ()->HaveCoins (it->first );
170188 const Coin& coin = stack.back ()->AccessCoin (it->first );
189+ BOOST_CHECK (have == !coin.IsPruned ());
171190 BOOST_CHECK (coin == it->second );
172191 if (coin.IsPruned ()) {
173192 missed_an_entry = true ;
174193 } else {
194+ BOOST_CHECK (stack.back ()->HaveCoinsInCache (it->first ));
175195 found_an_entry = true ;
176196 }
177197 }
@@ -222,10 +242,12 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
222242 BOOST_CHECK (removed_all_caches);
223243 BOOST_CHECK (reached_4_caches);
224244 BOOST_CHECK (added_an_entry);
245+ BOOST_CHECK (added_an_unspendable_entry);
225246 BOOST_CHECK (removed_an_entry);
226247 BOOST_CHECK (updated_an_entry);
227248 BOOST_CHECK (found_an_entry);
228249 BOOST_CHECK (missed_an_entry);
250+ BOOST_CHECK (uncached_an_entry);
229251}
230252
231253// Store of all necessary tx and undo data for next test
@@ -367,11 +389,21 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
367389 // Once every 1000 iterations and at the end, verify the full cache.
368390 if (InsecureRandRange (1000 ) == 1 || i == NUM_SIMULATION_ITERATIONS - 1 ) {
369391 for (auto it = result.begin (); it != result.end (); it++) {
392+ bool have = stack.back ()->HaveCoins (it->first );
370393 const Coin& coin = stack.back ()->AccessCoin (it->first );
394+ BOOST_CHECK (have == !coin.IsPruned ());
371395 BOOST_CHECK (coin == it->second );
372396 }
373397 }
374398
399+ // One every 10 iterations, remove a random entry from the cache
400+ if (utxoset.size () > 1 && InsecureRandRange (20 ) == 0 ) {
401+ stack[InsecureRandRange (stack.size ())]->Uncache (FindRandomFrom (utxoset)->first );
402+ }
403+ if (disconnectedids.size () > 1 && InsecureRandRange (20 ) == 0 ) {
404+ stack[InsecureRandRange (stack.size ())]->Uncache (FindRandomFrom (disconnectedids)->first );
405+ }
406+
375407 if (InsecureRandRange (100 ) == 0 ) {
376408 // Every 100 iterations, change the cache stack.
377409 if (stack.size () > 0 && InsecureRandBool () == 0 ) {
0 commit comments