|
|
@ -43,7 +43,7 @@ public: |
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
|
coin = it->second; |
|
|
|
coin = it->second; |
|
|
|
if (coin.IsSpent() && insecure_randbool() == 0) { |
|
|
|
if (coin.IsSpent() && InsecureRandBool() == 0) { |
|
|
|
// Randomly return false in case of an empty entry.
|
|
|
|
// Randomly return false in case of an empty entry.
|
|
|
|
return false; |
|
|
|
return false; |
|
|
|
} |
|
|
|
} |
|
|
@ -64,7 +64,7 @@ public: |
|
|
|
if (it->second.flags & CCoinsCacheEntry::DIRTY) { |
|
|
|
if (it->second.flags & CCoinsCacheEntry::DIRTY) { |
|
|
|
// Same optimization used in CCoinsViewDB is to only write dirty entries.
|
|
|
|
// Same optimization used in CCoinsViewDB is to only write dirty entries.
|
|
|
|
map_[it->first] = it->second.coin; |
|
|
|
map_[it->first] = it->second.coin; |
|
|
|
if (it->second.coin.IsSpent() && insecure_randrange(3) == 0) { |
|
|
|
if (it->second.coin.IsSpent() && InsecureRandRange(3) == 0) { |
|
|
|
// Randomly delete empty entries on write.
|
|
|
|
// Randomly delete empty entries on write.
|
|
|
|
map_.erase(it->first); |
|
|
|
map_.erase(it->first); |
|
|
|
} |
|
|
|
} |
|
|
@ -139,31 +139,31 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) |
|
|
|
std::vector<uint256> txids; |
|
|
|
std::vector<uint256> txids; |
|
|
|
txids.resize(NUM_SIMULATION_ITERATIONS / 8); |
|
|
|
txids.resize(NUM_SIMULATION_ITERATIONS / 8); |
|
|
|
for (unsigned int i = 0; i < txids.size(); i++) { |
|
|
|
for (unsigned int i = 0; i < txids.size(); i++) { |
|
|
|
txids[i] = insecure_rand256(); |
|
|
|
txids[i] = InsecureRand256(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { |
|
|
|
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { |
|
|
|
// Do a random modification.
|
|
|
|
// Do a random modification.
|
|
|
|
{ |
|
|
|
{ |
|
|
|
uint256 txid = txids[insecure_randrange(txids.size())]; // txid we're going to modify in this iteration.
|
|
|
|
uint256 txid = txids[InsecureRandRange(txids.size())]; // txid we're going to modify in this iteration.
|
|
|
|
Coin& coin = result[COutPoint(txid, 0)]; |
|
|
|
Coin& coin = result[COutPoint(txid, 0)]; |
|
|
|
const Coin& entry = (insecure_randrange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); |
|
|
|
const Coin& entry = (InsecureRandRange(500) == 0) ? AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0)); |
|
|
|
BOOST_CHECK(coin == entry); |
|
|
|
BOOST_CHECK(coin == entry); |
|
|
|
|
|
|
|
|
|
|
|
if (insecure_randrange(5) == 0 || coin.IsSpent()) { |
|
|
|
if (InsecureRandRange(5) == 0 || coin.IsSpent()) { |
|
|
|
Coin newcoin; |
|
|
|
Coin newcoin; |
|
|
|
newcoin.out.nValue = insecure_rand(); |
|
|
|
newcoin.out.nValue = InsecureRand32(); |
|
|
|
newcoin.nHeight = 1; |
|
|
|
newcoin.nHeight = 1; |
|
|
|
if (insecure_randrange(16) == 0 && coin.IsSpent()) { |
|
|
|
if (InsecureRandRange(16) == 0 && coin.IsSpent()) { |
|
|
|
newcoin.out.scriptPubKey.assign(1 + insecure_randbits(6), OP_RETURN); |
|
|
|
newcoin.out.scriptPubKey.assign(1 + InsecureRandBits(6), OP_RETURN); |
|
|
|
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); |
|
|
|
BOOST_CHECK(newcoin.out.scriptPubKey.IsUnspendable()); |
|
|
|
added_an_unspendable_entry = true; |
|
|
|
added_an_unspendable_entry = true; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
newcoin.out.scriptPubKey.assign(insecure_randbits(6), 0); // Random sizes so we can test memory usage accounting
|
|
|
|
newcoin.out.scriptPubKey.assign(InsecureRandBits(6), 0); // Random sizes so we can test memory usage accounting
|
|
|
|
(coin.IsSpent() ? added_an_entry : updated_an_entry) = true; |
|
|
|
(coin.IsSpent() ? added_an_entry : updated_an_entry) = true; |
|
|
|
coin = newcoin; |
|
|
|
coin = newcoin; |
|
|
|
} |
|
|
|
} |
|
|
|
stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || insecure_rand() & 1); |
|
|
|
stack.back()->AddCoin(COutPoint(txid, 0), std::move(newcoin), !coin.IsSpent() || InsecureRand32() & 1); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
removed_an_entry = true; |
|
|
|
removed_an_entry = true; |
|
|
|
coin.Clear(); |
|
|
|
coin.Clear(); |
|
|
@ -172,15 +172,15 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// One every 10 iterations, remove a random entry from the cache
|
|
|
|
// One every 10 iterations, remove a random entry from the cache
|
|
|
|
if (insecure_randrange(10) == 0) { |
|
|
|
if (InsecureRandRange(10) == 0) { |
|
|
|
COutPoint out(txids[insecure_rand() % txids.size()], 0); |
|
|
|
COutPoint out(txids[InsecureRand32() % txids.size()], 0); |
|
|
|
int cacheid = insecure_rand() % stack.size(); |
|
|
|
int cacheid = InsecureRand32() % stack.size(); |
|
|
|
stack[cacheid]->Uncache(out); |
|
|
|
stack[cacheid]->Uncache(out); |
|
|
|
uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); |
|
|
|
uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Once every 1000 iterations and at the end, verify the full cache.
|
|
|
|
// Once every 1000 iterations and at the end, verify the full cache.
|
|
|
|
if (insecure_randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { |
|
|
|
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { |
|
|
|
for (auto it = result.begin(); it != result.end(); it++) { |
|
|
|
for (auto it = result.begin(); it != result.end(); it++) { |
|
|
|
bool have = stack.back()->HaveCoin(it->first); |
|
|
|
bool have = stack.back()->HaveCoin(it->first); |
|
|
|
const Coin& coin = stack.back()->AccessCoin(it->first); |
|
|
|
const Coin& coin = stack.back()->AccessCoin(it->first); |
|
|
@ -198,22 +198,22 @@ BOOST_AUTO_TEST_CASE(coins_cache_simulation_test) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (insecure_randrange(100) == 0) { |
|
|
|
if (InsecureRandRange(100) == 0) { |
|
|
|
// Every 100 iterations, flush an intermediate cache
|
|
|
|
// Every 100 iterations, flush an intermediate cache
|
|
|
|
if (stack.size() > 1 && insecure_randbool() == 0) { |
|
|
|
if (stack.size() > 1 && InsecureRandBool() == 0) { |
|
|
|
unsigned int flushIndex = insecure_randrange(stack.size() - 1); |
|
|
|
unsigned int flushIndex = InsecureRandRange(stack.size() - 1); |
|
|
|
stack[flushIndex]->Flush(); |
|
|
|
stack[flushIndex]->Flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (insecure_randrange(100) == 0) { |
|
|
|
if (InsecureRandRange(100) == 0) { |
|
|
|
// Every 100 iterations, change the cache stack.
|
|
|
|
// Every 100 iterations, change the cache stack.
|
|
|
|
if (stack.size() > 0 && insecure_randbool() == 0) { |
|
|
|
if (stack.size() > 0 && InsecureRandBool() == 0) { |
|
|
|
//Remove the top cache
|
|
|
|
//Remove the top cache
|
|
|
|
stack.back()->Flush(); |
|
|
|
stack.back()->Flush(); |
|
|
|
delete stack.back(); |
|
|
|
delete stack.back(); |
|
|
|
stack.pop_back(); |
|
|
|
stack.pop_back(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (stack.size() == 0 || (stack.size() < 4 && insecure_randbool())) { |
|
|
|
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { |
|
|
|
//Add a new cache
|
|
|
|
//Add a new cache
|
|
|
|
CCoinsView* tip = &base; |
|
|
|
CCoinsView* tip = &base; |
|
|
|
if (stack.size() > 0) { |
|
|
|
if (stack.size() > 0) { |
|
|
@ -253,7 +253,7 @@ UtxoData utxoData; |
|
|
|
|
|
|
|
|
|
|
|
UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { |
|
|
|
UtxoData::iterator FindRandomFrom(const std::set<COutPoint> &utxoSet) { |
|
|
|
assert(utxoSet.size()); |
|
|
|
assert(utxoSet.size()); |
|
|
|
auto utxoSetIt = utxoSet.lower_bound(COutPoint(insecure_rand256(), 0)); |
|
|
|
auto utxoSetIt = utxoSet.lower_bound(COutPoint(InsecureRand256(), 0)); |
|
|
|
if (utxoSetIt == utxoSet.end()) { |
|
|
|
if (utxoSetIt == utxoSet.end()) { |
|
|
|
utxoSetIt = utxoSet.begin(); |
|
|
|
utxoSetIt = utxoSet.begin(); |
|
|
|
} |
|
|
|
} |
|
|
@ -286,7 +286,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) |
|
|
|
std::set<COutPoint> utxoset; |
|
|
|
std::set<COutPoint> utxoset; |
|
|
|
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { |
|
|
|
for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) { |
|
|
|
uint32_t randiter = insecure_rand(); |
|
|
|
uint32_t randiter = InsecureRand32(); |
|
|
|
|
|
|
|
|
|
|
|
// 19/20 txs add a new transaction
|
|
|
|
// 19/20 txs add a new transaction
|
|
|
|
if (randiter % 20 < 19) { |
|
|
|
if (randiter % 20 < 19) { |
|
|
@ -294,14 +294,14 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) |
|
|
|
tx.vin.resize(1); |
|
|
|
tx.vin.resize(1); |
|
|
|
tx.vout.resize(1); |
|
|
|
tx.vout.resize(1); |
|
|
|
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
|
|
|
|
tx.vout[0].nValue = i; //Keep txs unique unless intended to duplicate
|
|
|
|
tx.vout[0].scriptPubKey.assign(insecure_rand() & 0x3F, 0); // Random sizes so we can test memory usage accounting
|
|
|
|
tx.vout[0].scriptPubKey.assign(InsecureRand32() & 0x3F, 0); // Random sizes so we can test memory usage accounting
|
|
|
|
unsigned int height = insecure_rand(); |
|
|
|
unsigned int height = InsecureRand32(); |
|
|
|
Coin old_coin; |
|
|
|
Coin old_coin; |
|
|
|
|
|
|
|
|
|
|
|
// 2/20 times create a new coinbase
|
|
|
|
// 2/20 times create a new coinbase
|
|
|
|
if (randiter % 20 < 2 || coinbase_coins.size() < 10) { |
|
|
|
if (randiter % 20 < 2 || coinbase_coins.size() < 10) { |
|
|
|
// 1/10 of those times create a duplicate coinbase
|
|
|
|
// 1/10 of those times create a duplicate coinbase
|
|
|
|
if (insecure_randrange(10) == 0 && coinbase_coins.size()) { |
|
|
|
if (InsecureRandRange(10) == 0 && coinbase_coins.size()) { |
|
|
|
auto utxod = FindRandomFrom(coinbase_coins); |
|
|
|
auto utxod = FindRandomFrom(coinbase_coins); |
|
|
|
// Reuse the exact same coinbase
|
|
|
|
// Reuse the exact same coinbase
|
|
|
|
tx = std::get<0>(utxod->second); |
|
|
|
tx = std::get<0>(utxod->second); |
|
|
@ -411,7 +411,7 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Once every 1000 iterations and at the end, verify the full cache.
|
|
|
|
// Once every 1000 iterations and at the end, verify the full cache.
|
|
|
|
if (insecure_randrange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { |
|
|
|
if (InsecureRandRange(1000) == 1 || i == NUM_SIMULATION_ITERATIONS - 1) { |
|
|
|
for (auto it = result.begin(); it != result.end(); it++) { |
|
|
|
for (auto it = result.begin(); it != result.end(); it++) { |
|
|
|
bool have = stack.back()->HaveCoin(it->first); |
|
|
|
bool have = stack.back()->HaveCoin(it->first); |
|
|
|
const Coin& coin = stack.back()->AccessCoin(it->first); |
|
|
|
const Coin& coin = stack.back()->AccessCoin(it->first); |
|
|
@ -421,31 +421,31 @@ BOOST_AUTO_TEST_CASE(updatecoins_simulation_test) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// One every 10 iterations, remove a random entry from the cache
|
|
|
|
// One every 10 iterations, remove a random entry from the cache
|
|
|
|
if (utxoset.size() > 1 && insecure_randrange(30) == 0) { |
|
|
|
if (utxoset.size() > 1 && InsecureRandRange(30) == 0) { |
|
|
|
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); |
|
|
|
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(utxoset)->first); |
|
|
|
} |
|
|
|
} |
|
|
|
if (disconnected_coins.size() > 1 && insecure_randrange(30) == 0) { |
|
|
|
if (disconnected_coins.size() > 1 && InsecureRandRange(30) == 0) { |
|
|
|
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); |
|
|
|
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(disconnected_coins)->first); |
|
|
|
} |
|
|
|
} |
|
|
|
if (duplicate_coins.size() > 1 && insecure_randrange(30) == 0) { |
|
|
|
if (duplicate_coins.size() > 1 && InsecureRandRange(30) == 0) { |
|
|
|
stack[insecure_rand() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); |
|
|
|
stack[InsecureRand32() % stack.size()]->Uncache(FindRandomFrom(duplicate_coins)->first); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (insecure_randrange(100) == 0) { |
|
|
|
if (InsecureRandRange(100) == 0) { |
|
|
|
// Every 100 iterations, flush an intermediate cache
|
|
|
|
// Every 100 iterations, flush an intermediate cache
|
|
|
|
if (stack.size() > 1 && insecure_randbool() == 0) { |
|
|
|
if (stack.size() > 1 && InsecureRandBool() == 0) { |
|
|
|
unsigned int flushIndex = insecure_randrange(stack.size() - 1); |
|
|
|
unsigned int flushIndex = InsecureRandRange(stack.size() - 1); |
|
|
|
stack[flushIndex]->Flush(); |
|
|
|
stack[flushIndex]->Flush(); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (insecure_randrange(100) == 0) { |
|
|
|
if (InsecureRandRange(100) == 0) { |
|
|
|
// Every 100 iterations, change the cache stack.
|
|
|
|
// Every 100 iterations, change the cache stack.
|
|
|
|
if (stack.size() > 0 && insecure_randbool() == 0) { |
|
|
|
if (stack.size() > 0 && InsecureRandBool() == 0) { |
|
|
|
stack.back()->Flush(); |
|
|
|
stack.back()->Flush(); |
|
|
|
delete stack.back(); |
|
|
|
delete stack.back(); |
|
|
|
stack.pop_back(); |
|
|
|
stack.pop_back(); |
|
|
|
} |
|
|
|
} |
|
|
|
if (stack.size() == 0 || (stack.size() < 4 && insecure_randbool())) { |
|
|
|
if (stack.size() == 0 || (stack.size() < 4 && InsecureRandBool())) { |
|
|
|
CCoinsView* tip = &base; |
|
|
|
CCoinsView* tip = &base; |
|
|
|
if (stack.size() > 0) { |
|
|
|
if (stack.size() > 0) { |
|
|
|
tip = stack.back(); |
|
|
|
tip = stack.back(); |
|
|
|