Switch tests from ModifyCoins to AddCoin/SpendCoin

This commit is contained in:
Pieter Wuille 2017-04-25 11:29:34 -07:00
parent 8b3868c1b4
commit 961e483979
1 changed files with 119 additions and 149 deletions

View File

@ -22,6 +22,15 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
namespace namespace
{ {
//! equality test
bool operator==(const Coin &a, const Coin &b) {
// Empty Coin objects are always equal.
if (a.IsPruned() && b.IsPruned()) return true;
return a.fCoinBase == b.fCoinBase &&
a.nHeight == b.nHeight &&
a.out == b.out;
}
class CCoinsViewTest : public CCoinsView class CCoinsViewTest : public CCoinsView
{ {
uint256 hashBestBlock_; uint256 hashBestBlock_;
@ -134,8 +143,9 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
{ {
uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration. uint256 txid = txids[insecure_rand() % txids.size()]; // txid we're going to modify in this iteration.
CCoins& coins = result[txid]; CCoins& coins = result[txid];
CCoinsModifier entry = stack.back()->ModifyCoins(txid); const Coin& entry = stack.back()->AccessCoin(COutPoint(txid, 0));
BOOST_CHECK(coins == *entry); BOOST_CHECK((entry.IsPruned() && coins.IsPruned()) || entry == Coin(coins.vout[0], coins.nHeight, coins.fCoinBase));
if (insecure_rand() % 5 == 0 || coins.IsPruned()) { if (insecure_rand() % 5 == 0 || coins.IsPruned()) {
if (coins.IsPruned()) { if (coins.IsPruned()) {
added_an_entry = true; added_an_entry = true;
@ -144,12 +154,15 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
} }
coins.vout.resize(1); coins.vout.resize(1);
coins.vout[0].nValue = insecure_rand(); coins.vout[0].nValue = insecure_rand();
*entry = coins;
} else { } else {
coins.Clear(); coins.Clear();
entry->Clear();
removed_an_entry = true; removed_an_entry = true;
} }
if (coins.IsPruned()) {
stack.back()->SpendCoin(COutPoint(txid, 0));
} else {
stack.back()->AddCoin(COutPoint(txid, 0), Coin(coins.vout[0], coins.nHeight, coins.fCoinBase), true);
}
} }
// Once every 1000 iterations and at the end, verify the full cache. // Once every 1000 iterations and at the end, verify the full cache.
@ -325,8 +338,9 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// The test is designed to ensure spending a duplicate coinbase will work properly // The test is designed to ensure spending a duplicate coinbase will work properly
// if that ever happens and not resurrect the previously overwritten coinbase // if that ever happens and not resurrect the previously overwritten coinbase
if (duplicateids.count(prevouthash)) if (duplicateids.count(prevouthash)) {
spent_a_duplicate_coinbase = true; spent_a_duplicate_coinbase = true;
}
} }
// Update the expected result to know about the new output coins // Update the expected result to know about the new output coins
@ -341,10 +355,8 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// Track this tx and undo info to use later // Track this tx and undo info to use later
alltxs.insert(std::make_pair(tx.GetHash(),std::make_tuple(tx,undo,oldcoins))); alltxs.insert(std::make_pair(tx.GetHash(),std::make_tuple(tx,undo,oldcoins)));
} } else if (utxoset.size()) {
//1/20 times undo a previous transaction //1/20 times undo a previous transaction
else if (utxoset.size()) {
TxData &txd = FindRandomFrom(utxoset); TxData &txd = FindRandomFrom(utxoset);
CTransaction &tx = std::get<0>(txd); CTransaction &tx = std::get<0>(txd);
@ -365,8 +377,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test)
// See code in DisconnectBlock // See code in DisconnectBlock
// remove outputs // remove outputs
{ {
CCoinsModifier outs = stack.back()->ModifyCoins(undohash); stack.back()->SpendCoin(COutPoint(undohash, 0));
outs->Clear();
} }
// restore inputs // restore inputs
if (!tx.IsCoinBase()) { if (!tx.IsCoinBase()) {
@ -496,6 +507,7 @@ BOOST_AUTO_TEST_CASE(ccoins_serialization)
} }
const static uint256 TXID; const static uint256 TXID;
const static COutPoint OUTPOINT = {uint256(), 0};
const static CAmount PRUNED = -1; const static CAmount PRUNED = -1;
const static CAmount ABSENT = -2; const static CAmount ABSENT = -2;
const static CAmount FAIL = -3; const static CAmount FAIL = -3;
@ -577,10 +589,10 @@ public:
CCoinsViewCacheTest cache{&base}; CCoinsViewCacheTest cache{&base};
}; };
void CheckAccessCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags) void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
{ {
SingleEntryCacheTest test(base_value, cache_value, cache_flags); SingleEntryCacheTest test(base_value, cache_value, cache_flags);
test.cache.AccessCoins(TXID); test.cache.AccessCoin(OUTPOINT);
test.cache.SelfTest(); test.cache.SelfTest();
CAmount result_value; CAmount result_value;
@ -599,39 +611,39 @@ BOOST_AUTO_TEST_CASE(ccoins_access)
* Base Cache Result Cache Result * Base Cache Result Cache Result
* Value Value Value Flags Flags * Value Value Value Flags Flags
*/ */
CheckAccessCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY ); CheckAccessCoin(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckAccessCoins(ABSENT, PRUNED, PRUNED, 0 , 0 ); CheckAccessCoin(ABSENT, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoins(ABSENT, PRUNED, PRUNED, FRESH , FRESH ); CheckAccessCoin(ABSENT, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoins(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY ); CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoins(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(ABSENT, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoins(ABSENT, VALUE2, VALUE2, 0 , 0 ); CheckAccessCoin(ABSENT, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoins(ABSENT, VALUE2, VALUE2, FRESH , FRESH ); CheckAccessCoin(ABSENT, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoins(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY ); CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoins(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(ABSENT, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoins(PRUNED, ABSENT, PRUNED, NO_ENTRY , FRESH ); CheckAccessCoin(PRUNED, ABSENT, PRUNED, NO_ENTRY , FRESH );
CheckAccessCoins(PRUNED, PRUNED, PRUNED, 0 , 0 ); CheckAccessCoin(PRUNED, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoins(PRUNED, PRUNED, PRUNED, FRESH , FRESH ); CheckAccessCoin(PRUNED, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY ); CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoins(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(PRUNED, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoins(PRUNED, VALUE2, VALUE2, 0 , 0 ); CheckAccessCoin(PRUNED, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoins(PRUNED, VALUE2, VALUE2, FRESH , FRESH ); CheckAccessCoin(PRUNED, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoins(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY ); CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoins(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(PRUNED, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoins(VALUE1, ABSENT, VALUE1, NO_ENTRY , 0 ); CheckAccessCoin(VALUE1, ABSENT, VALUE1, NO_ENTRY , 0 );
CheckAccessCoins(VALUE1, PRUNED, PRUNED, 0 , 0 ); CheckAccessCoin(VALUE1, PRUNED, PRUNED, 0 , 0 );
CheckAccessCoins(VALUE1, PRUNED, PRUNED, FRESH , FRESH ); CheckAccessCoin(VALUE1, PRUNED, PRUNED, FRESH , FRESH );
CheckAccessCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY ); CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
CheckAccessCoins(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(VALUE1, PRUNED, PRUNED, DIRTY|FRESH, DIRTY|FRESH);
CheckAccessCoins(VALUE1, VALUE2, VALUE2, 0 , 0 ); CheckAccessCoin(VALUE1, VALUE2, VALUE2, 0 , 0 );
CheckAccessCoins(VALUE1, VALUE2, VALUE2, FRESH , FRESH ); CheckAccessCoin(VALUE1, VALUE2, VALUE2, FRESH , FRESH );
CheckAccessCoins(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY ); CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY , DIRTY );
CheckAccessCoins(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH); CheckAccessCoin(VALUE1, VALUE2, VALUE2, DIRTY|FRESH, DIRTY|FRESH);
} }
void CheckModifyCoins(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags) void CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
{ {
SingleEntryCacheTest test(base_value, cache_value, cache_flags); SingleEntryCacheTest test(base_value, cache_value, cache_flags);
SetCoinsValue(modify_value, *test.cache.ModifyCoins(TXID)); test.cache.SpendCoin(OUTPOINT);
test.cache.SelfTest(); test.cache.SelfTest();
CAmount result_value; CAmount result_value;
@ -641,79 +653,55 @@ void CheckModifyCoins(CAmount base_value, CAmount cache_value, CAmount modify_va
BOOST_CHECK_EQUAL(result_flags, expected_flags); BOOST_CHECK_EQUAL(result_flags, expected_flags);
}; };
BOOST_AUTO_TEST_CASE(ccoins_modify) BOOST_AUTO_TEST_CASE(ccoins_spend)
{ {
/* Check ModifyCoin behavior, requesting a coin from a cache view layered on /* Check SpendCoin behavior, requesting a coin from a cache view layered on
* top of a base view, writing a modification to the coin, and then checking * top of a base view, spending, and then checking
* the resulting entry in the cache after the modification. * the resulting entry in the cache after the modification.
* *
* Base Cache Write Result Cache Result * Base Cache Result Cache Result
* Value Value Value Value Flags Flags * Value Value Value Flags Flags
*/ */
CheckModifyCoins(ABSENT, ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY ); CheckSpendCoins(ABSENT, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckModifyCoins(ABSENT, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH); CheckSpendCoins(ABSENT, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(ABSENT, PRUNED, PRUNED, PRUNED, 0 , DIRTY ); CheckSpendCoins(ABSENT, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(ABSENT, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY ); CheckSpendCoins(ABSENT, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(ABSENT, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY ); CheckSpendCoins(ABSENT, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(ABSENT, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY ); CheckSpendCoins(ABSENT, VALUE2, PRUNED, 0 , DIRTY );
CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, 0 , DIRTY ); CheckSpendCoins(ABSENT, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH); CheckSpendCoins(ABSENT, VALUE2, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY ); CheckSpendCoins(ABSENT, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(ABSENT, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH); CheckSpendCoins(PRUNED, ABSENT, ABSENT, NO_ENTRY , NO_ENTRY );
CheckModifyCoins(ABSENT, VALUE2, PRUNED, PRUNED, 0 , DIRTY ); CheckSpendCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(ABSENT, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY ); CheckSpendCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(ABSENT, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY ); CheckSpendCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(ABSENT, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY ); CheckSpendCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, 0 , DIRTY ); CheckSpendCoins(PRUNED, VALUE2, PRUNED, 0 , DIRTY );
CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH); CheckSpendCoins(PRUNED, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY ); CheckSpendCoins(PRUNED, VALUE2, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(ABSENT, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH); CheckSpendCoins(PRUNED, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(PRUNED, ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY ); CheckSpendCoins(VALUE1, ABSENT, PRUNED, NO_ENTRY , DIRTY );
CheckModifyCoins(PRUNED, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH); CheckSpendCoins(VALUE1, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(PRUNED, PRUNED, PRUNED, PRUNED, 0 , DIRTY ); CheckSpendCoins(VALUE1, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(PRUNED, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY ); CheckSpendCoins(VALUE1, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(PRUNED, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY ); CheckSpendCoins(VALUE1, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(PRUNED, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY ); CheckSpendCoins(VALUE1, VALUE2, PRUNED, 0 , DIRTY );
CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, 0 , DIRTY ); CheckSpendCoins(VALUE1, VALUE2, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH); CheckSpendCoins(VALUE1, VALUE2, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY ); CheckSpendCoins(VALUE1, VALUE2, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(PRUNED, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
CheckModifyCoins(PRUNED, VALUE2, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(PRUNED, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(PRUNED, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(PRUNED, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, 0 , DIRTY );
CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY );
CheckModifyCoins(PRUNED, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
CheckModifyCoins(VALUE1, ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY );
CheckModifyCoins(VALUE1, ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY );
CheckModifyCoins(VALUE1, PRUNED, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(VALUE1, PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(VALUE1, PRUNED, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(VALUE1, PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, 0 , DIRTY );
CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, DIRTY , DIRTY );
CheckModifyCoins(VALUE1, PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
CheckModifyCoins(VALUE1, VALUE2, PRUNED, PRUNED, 0 , DIRTY );
CheckModifyCoins(VALUE1, VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY );
CheckModifyCoins(VALUE1, VALUE2, PRUNED, PRUNED, DIRTY , DIRTY );
CheckModifyCoins(VALUE1, VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY );
CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, 0 , DIRTY );
CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH);
CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, DIRTY , DIRTY );
CheckModifyCoins(VALUE1, VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH);
} }
void CheckModifyNewCoinsBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase) void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
{ {
SingleEntryCacheTest test(base_value, cache_value, cache_flags); SingleEntryCacheTest test(base_value, cache_value, cache_flags);
CAmount result_value; CAmount result_value;
char result_flags; char result_flags;
try { try {
SetCoinsValue(modify_value, *test.cache.ModifyNewCoins(TXID, coinbase)); CTxOut output;
output.nValue = modify_value;
test.cache.AddCoin(OUTPOINT, Coin(std::move(output), 1, coinbase), coinbase);
test.cache.SelfTest();
GetCoinsMapEntry(test.cache.map(), result_value, result_flags); GetCoinsMapEntry(test.cache.map(), result_value, result_flags);
} catch (std::logic_error& e) { } catch (std::logic_error& e) {
result_value = FAIL; result_value = FAIL;
@ -724,64 +712,46 @@ void CheckModifyNewCoinsBase(CAmount base_value, CAmount cache_value, CAmount mo
BOOST_CHECK_EQUAL(result_flags, expected_flags); BOOST_CHECK_EQUAL(result_flags, expected_flags);
} }
// Simple wrapper for CheckModifyNewCoinsBase function above that loops through // Simple wrapper for CheckAddCoinBase function above that loops through
// different possible base_values, making sure each one gives the same results. // different possible base_values, making sure each one gives the same results.
// This wrapper lets the modify_new test below be shorter and less repetitive, // This wrapper lets the coins_add test below be shorter and less repetitive,
// while still verifying that the CoinsViewCache::ModifyNewCoins implementation // while still verifying that the CoinsViewCache::AddCoin implementation
// ignores base values. // ignores base values.
template <typename... Args> template <typename... Args>
void CheckModifyNewCoins(Args&&... args) void CheckAddCoin(Args&&... args)
{ {
for (CAmount base_value : {ABSENT, PRUNED, VALUE1}) for (CAmount base_value : {ABSENT, PRUNED, VALUE1})
CheckModifyNewCoinsBase(base_value, std::forward<Args>(args)...); CheckAddCoinBase(base_value, std::forward<Args>(args)...);
} }
BOOST_AUTO_TEST_CASE(ccoins_modify_new) BOOST_AUTO_TEST_CASE(ccoins_add)
{ {
/* Check ModifyNewCoin behavior, requesting a new coin from a cache view, /* Check AddCoin behavior, requesting a new coin from a cache view,
* writing a modification to the coin, and then checking the resulting * writing a modification to the coin, and then checking the resulting
* entry in the cache after the modification. Verify behavior with the * entry in the cache after the modification. Verify behavior with the
* with the ModifyNewCoin coinbase argument set to false, and to true. * with the AddCoin potential_overwrite argument set to false, and to true.
* *
* Cache Write Result Cache Result Coinbase * Cache Write Result Cache Result potential_overwrite
* Value Value Value Flags Flags * Value Value Value Flags Flags
*/ */
CheckModifyNewCoins(ABSENT, PRUNED, ABSENT, NO_ENTRY , NO_ENTRY , false); CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false);
CheckModifyNewCoins(ABSENT, PRUNED, PRUNED, NO_ENTRY , DIRTY , true ); CheckAddCoin(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true );
CheckModifyNewCoins(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY|FRESH, false); CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false);
CheckModifyNewCoins(ABSENT, VALUE3, VALUE3, NO_ENTRY , DIRTY , true ); CheckAddCoin(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true );
CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, 0 , NO_ENTRY , false); CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false);
CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, 0 , DIRTY , true ); CheckAddCoin(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY , false); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false);
CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, FRESH , NO_ENTRY , true ); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , false); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
CheckModifyNewCoins(PRUNED, PRUNED, PRUNED, DIRTY , DIRTY , true ); CheckAddCoin(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , false); CheckAddCoin(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
CheckModifyNewCoins(PRUNED, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , true ); CheckAddCoin(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, 0 , DIRTY|FRESH, false); CheckAddCoin(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, 0 , DIRTY , true ); CheckAddCoin(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, false); CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false);
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true ); CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , false); CheckAddCoin(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false);
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY , DIRTY , true ); CheckAddCoin(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, false);
CheckModifyNewCoins(PRUNED, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
CheckModifyNewCoins(VALUE2, PRUNED, FAIL , 0 , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, PRUNED, PRUNED, 0 , DIRTY , true );
CheckModifyNewCoins(VALUE2, PRUNED, FAIL , FRESH , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, PRUNED, ABSENT, FRESH , NO_ENTRY , true );
CheckModifyNewCoins(VALUE2, PRUNED, FAIL , DIRTY , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, PRUNED, PRUNED, DIRTY , DIRTY , true );
CheckModifyNewCoins(VALUE2, PRUNED, FAIL , DIRTY|FRESH, NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, PRUNED, ABSENT, DIRTY|FRESH, NO_ENTRY , true );
CheckModifyNewCoins(VALUE2, VALUE3, FAIL , 0 , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, 0 , DIRTY , true );
CheckModifyNewCoins(VALUE2, VALUE3, FAIL , FRESH , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, FRESH , DIRTY|FRESH, true );
CheckModifyNewCoins(VALUE2, VALUE3, FAIL , DIRTY , NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, DIRTY , DIRTY , true );
CheckModifyNewCoins(VALUE2, VALUE3, FAIL , DIRTY|FRESH, NO_ENTRY , false);
CheckModifyNewCoins(VALUE2, VALUE3, VALUE3, DIRTY|FRESH, DIRTY|FRESH, true );
} }
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags) void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)