Skip to content

Commit ce23efa

Browse files
committed
Extend coins_tests
1 parent 5083079 commit ce23efa

File tree

1 file changed

+45
-11
lines changed

1 file changed

+45
-11
lines changed

src/test/coins_tests.cpp

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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 += it->second.coins.DynamicMemoryUsage();
93+
++count;
9294
}
95+
BOOST_CHECK_EQUAL(GetCacheSize(), count);
9396
BOOST_CHECK_EQUAL(DynamicMemoryUsage(), 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,36 +148,49 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
143148
{
144149
uint256 txid = txids[insecure_rand() % 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 = (insecure_rand() % 500 == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
147152
BOOST_CHECK(coin == entry);
148153

149154
if (insecure_rand() % 5 == 0 || coin.IsPruned()) {
150-
if (coin.IsPruned()) {
151-
added_an_entry = true;
155+
Coin newcoin;
156+
newcoin.out.nValue = insecure_rand();
157+
newcoin.nHeight = 1;
158+
if (insecure_rand() % 16 == 0 && coin.IsPruned()) {
159+
newcoin.out.scriptPubKey.assign(1 + (insecure_rand() & 0x3F), OP_RETURN);
160+
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable());
161+
added_an_unspendable_entry = true;
152162
} else {
153-
updated_an_entry = true;
163+
newcoin.out.scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
164+
(coin.IsPruned() ? added_an_entry : updated_an_entry) = true;
165+
coin = newcoin;
154166
}
155-
coin.out.nValue = insecure_rand();
156-
coin.nHeight = 1;
167+
stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsPruned() || insecure_rand() & 1);
157168
} else {
158-
coin.Clear();
159169
removed_an_entry = true;
160-
}
161-
if (coin.IsPruned()) {
170+
coin.Clear();
162171
stack.back()->SpendCoin(COutPoint(txid, 0));
163-
} else {
164-
stack.back()->AddCoin(COutPoint(txid, 0), Coin(coin), true);
165172
}
166173
}
167174

175+
// One every 10 iterations, remove a random entry from the cache
176+
if (insecure_rand() % 10) {
177+
COutPoint out(txids[insecure_rand() % txids.size()], 0);
178+
int cacheid = insecure_rand() % stack.size();
179+
stack[cacheid]->Uncache(out);
180+
uncached_an_entry |= !stack[cacheid]->HaveCoinsInCache(out);
181+
}
182+
168183
// Once every 1000 iterations and at the end, verify the full cache.
169184
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
170185
for (auto it = result.begin(); it != result.end(); it++) {
186+
bool have = stack.back()->HaveCoins(it->first);
171187
const Coin& coin = stack.back()->AccessCoin(it->first);
188+
BOOST_CHECK(have == !coin.IsPruned());
172189
BOOST_CHECK(coin == it->second);
173190
if (coin.IsPruned()) {
174191
missed_an_entry = true;
175192
} else {
193+
BOOST_CHECK(stack.back()->HaveCoinsInCache(it->first));
176194
found_an_entry = true;
177195
}
178196
}
@@ -222,10 +240,12 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
222240
BOOST_CHECK(removed_all_caches);
223241
BOOST_CHECK(reached_4_caches);
224242
BOOST_CHECK(added_an_entry);
243+
BOOST_CHECK(added_an_unspendable_entry);
225244
BOOST_CHECK(removed_an_entry);
226245
BOOST_CHECK(updated_an_entry);
227246
BOOST_CHECK(found_an_entry);
228247
BOOST_CHECK(missed_an_entry);
248+
BOOST_CHECK(uncached_an_entry);
229249
}
230250

231251
// Store of all necessary tx and undo data for next test
@@ -275,6 +295,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
275295
tx.vin.resize(1);
276296
tx.vout.resize(1);
277297
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
298+
tx.vout[0].scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
278299
unsigned int height = insecure_rand();
279300
Coin oldcoins;
280301

@@ -393,11 +414,24 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
393414
// Once every 1000 iterations and at the end, verify the full cache.
394415
if (insecure_rand() % 1000 == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
395416
for (auto it = result.begin(); it != result.end(); it++) {
417+
bool have = stack.back()->HaveCoins(it->first);
396418
const Coin& coin = stack.back()->AccessCoin(it->first);
419+
BOOST_CHECK(have == !coin.IsPruned());
397420
BOOST_CHECK(coin == it->second);
398421
}
399422
}
400423

424+
// One every 10 iterations, remove a random entry from the cache
425+
if (utxoset.size() > 1 && insecure_rand() % 30) {
426+
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first);
427+
}
428+
if (disconnectedids.size() > 1 && insecure_rand() % 30) {
429+
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnectedids)->first);
430+
}
431+
if (duplicateids.size() > 1 && insecure_rand() % 30) {
432+
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicateids)->first);
433+
}
434+
401435
if (insecure_rand() % 100 == 0) {
402436
// Every 100 iterations, flush an intermediate cache
403437
if (stack.size() > 1 && insecure_rand() % 2 == 0) {

0 commit comments

Comments
 (0)