Skip to content

Commit 9d97db0

Browse files
committed
Add unit test for UpdateCoins
(adapted from bitcoin/bitcoin@1cf3dd8, removing the 'spent_a_duplicate_coinbase' checks)
1 parent 0965d3a commit 9d97db0

File tree

1 file changed

+105
-0
lines changed

1 file changed

+105
-0
lines changed

src/test/coins_tests.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,111 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
202202
BOOST_CHECK(missed_an_entry);
203203
}
204204

205+
// This test is similar to the previous test
206+
// except the emphasis is on testing the functionality of UpdateCoins
207+
// random txs are created and UpdateCoins is used to update the cache stack
208+
BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
209+
{
210+
// A simple map to track what we expect the cache stack to represent.
211+
std::map<uint256, CCoins> result;
212+
213+
// The cache stack.
214+
CCoinsViewTest base; // A CCoinsViewTest at the bottom.
215+
std::vector<CCoinsViewCacheTest*> stack; // A stack of CCoinsViewCaches on top.
216+
stack.push_back(new CCoinsViewCacheTest(&base)); // Start with one cache.
217+
218+
// Track the txids we've used and whether they have been spent or not
219+
std::map<uint256, CAmount> coinbaseids;
220+
std::set<uint256> alltxids;
221+
222+
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
223+
{
224+
CMutableTransaction tx;
225+
tx.vin.resize(1);
226+
tx.vout.resize(1);
227+
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
228+
unsigned int height = InsecureRand32();
229+
230+
// 1/10 times create a coinbase
231+
if (InsecureRandRange(10) == 0 || coinbaseids.size() < 10) {
232+
// PIVX: don't test for duplicate coinbases as those are not possible due to
233+
// BIP34 enforced since the beginning.
234+
coinbaseids[tx.GetHash()] = tx.vout[0].nValue;
235+
assert(CTransaction(tx).IsCoinBase());
236+
}
237+
// 9/10 times create a regular tx
238+
else {
239+
uint256 prevouthash;
240+
// equally likely to spend coinbase or non coinbase
241+
std::set<uint256>::iterator txIt = alltxids.lower_bound(GetRandHash());
242+
if (txIt == alltxids.end()) {
243+
txIt = alltxids.begin();
244+
}
245+
prevouthash = *txIt;
246+
247+
// Construct the tx to spend the coins of prevouthash
248+
tx.vin[0].prevout.hash = prevouthash;
249+
tx.vin[0].prevout.n = 0;
250+
251+
// Update the expected result of prevouthash to know these coins are spent
252+
CCoins& oldcoins = result[prevouthash];
253+
oldcoins.Clear();
254+
255+
// It is of particular importance here that once we spend a coinbase tx hash
256+
// it is no longer available to be duplicated (or spent again)
257+
// BIP 34 in conjunction with enforcing BIP 30 (at least until BIP 34 was active)
258+
// results in the fact that no coinbases were duplicated after they were already spent
259+
alltxids.erase(prevouthash);
260+
coinbaseids.erase(prevouthash);
261+
262+
assert(!CTransaction(tx).IsCoinBase());
263+
}
264+
// Track this tx to possibly spend later
265+
alltxids.insert(tx.GetHash());
266+
267+
// Update the expected result to know about the new output coins
268+
CCoins &coins = result[tx.GetHash()];
269+
coins.FromTx(tx, height);
270+
271+
UpdateCoins(tx, *(stack.back()), height);
272+
}
273+
274+
// Once every 1000 iterations and at the end, verify the full cache.
275+
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) {
276+
for (std::map<uint256, CCoins>::iterator it = result.begin(); it != result.end(); it++) {
277+
const CCoins* coins = stack.back()->AccessCoins(it->first);
278+
if (coins) {
279+
BOOST_CHECK(*coins == it->second);
280+
} else {
281+
BOOST_CHECK(it->second.IsPruned());
282+
}
283+
}
284+
}
285+
286+
if (InsecureRandRange(100) == 0) {
287+
// Every 100 iterations, change the cache stack.
288+
if (stack.size() > 0 && InsecureRandBool() == 0) {
289+
stack.back()->Flush();
290+
delete stack.back();
291+
stack.pop_back();
292+
}
293+
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) {
294+
CCoinsView* tip = &base;
295+
if (stack.size() > 0) {
296+
tip = stack.back();
297+
}
298+
stack.push_back(new CCoinsViewCacheTest(tip));
299+
}
300+
}
301+
}
302+
303+
// Clean up the stack.
304+
while (stack.size() > 0) {
305+
delete stack.back();
306+
stack.pop_back();
307+
}
308+
}
309+
205310
BOOST_AUTO_TEST_CASE(ccoins_serialization)
206311
{
207312
// Good example

0 commit comments

Comments
 (0)