Skip to content

Commit 4b7b1a3

Browse files
committed
Extend coins_tests
>>> backports bitcoin/bitcoin@ce23efa
1 parent 8cf2dc0 commit 4b7b1a3

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

src/test/coins_tests.cpp

Lines changed: 43 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 += 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

Comments
 (0)