19#include <boost/test/unit_test.hpp> 
   38    std::map<COutPoint, Coin> map_;
 
   43        std::map<COutPoint, Coin>::const_iterator it = map_.find(outpoint);
 
   44        if (it == map_.end()) {
 
   59        for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end(); ) {
 
   62                map_[it->first] = it->second.coin;
 
   65                    map_.erase(it->first);
 
   71            hashBestBlock_ = hashBlock;
 
   86        for (
const auto& entry : cacheCoins) {
 
   87            ret += entry.second.coin.DynamicMemoryUsage();
 
  121    bool removed_all_caches = 
false;
 
  122    bool reached_4_caches = 
false;
 
  123    bool added_an_entry = 
false;
 
  124    bool added_an_unspendable_entry = 
false;
 
  125    bool removed_an_entry = 
false;
 
  126    bool updated_an_entry = 
false;
 
  127    bool found_an_entry = 
false;
 
  128    bool missed_an_entry = 
false;
 
  129    bool uncached_an_entry = 
false;
 
  132    std::map<COutPoint, Coin> result;
 
  135    std::vector<CCoinsViewCacheTest*> stack; 
 
  136    stack.push_back(
new CCoinsViewCacheTest(base)); 
 
  139    std::vector<uint256> txids;
 
  141    for (
unsigned int i = 0; i < txids.size(); i++) {
 
  157            bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(
COutPoint(txid, 0)) : 
false;
 
  162            if (test_havecoin_after) {
 
  163                bool ret = stack.back()->HaveCoin(
COutPoint(txid, 0));
 
  174                    added_an_unspendable_entry = 
true;
 
  177                    (coin.
IsSpent() ? added_an_entry : updated_an_entry) = 
true;
 
  182                removed_an_entry = 
true;
 
  192            stack[cacheid]->Uncache(out);
 
  193            uncached_an_entry |= !stack[cacheid]->HaveCoinInCache(out);
 
  198            for (
const auto& entry : result) {
 
  199                bool have = stack.back()->HaveCoin(entry.first);
 
  200                const Coin& coin = stack.back()->AccessCoin(entry.first);
 
  204                    missed_an_entry = 
true;
 
  206                    BOOST_CHECK(stack.back()->HaveCoinInCache(entry.first));
 
  207                    found_an_entry = 
true;
 
  210            for (
const CCoinsViewCacheTest *test : stack) {
 
  219                if (fake_best_block) stack[flushIndex]->SetBestBlock(
InsecureRand256());
 
  235                if (stack.size() > 0) {
 
  238                    removed_all_caches = 
true;
 
  240                stack.push_back(
new CCoinsViewCacheTest(tip));
 
  241                if (stack.size() == 4) {
 
  242                    reached_4_caches = 
true;
 
  249    while (stack.size() > 0) {
 
  277typedef std::map<COutPoint, std::tuple<CTransaction,CTxUndo,Coin>> 
UtxoData;
 
  283    if (utxoSetIt == utxoSet.end()) {
 
  284        utxoSetIt = utxoSet.begin();
 
  286    auto utxoDataIt = 
utxoData.find(*utxoSetIt);
 
  302    bool spent_a_duplicate_coinbase = 
false;
 
  304    std::map<COutPoint, Coin> result;
 
  308    std::vector<CCoinsViewCacheTest*> stack; 
 
  309    stack.push_back(
new CCoinsViewCacheTest(&base)); 
 
  312    std::set<COutPoint> coinbase_coins;
 
  313    std::set<COutPoint> disconnected_coins;
 
  314    std::set<COutPoint> duplicate_coins;
 
  315    std::set<COutPoint> utxoset;
 
  321        if (randiter % 20 < 19) {
 
  325            tx.
vout[0].nValue = i; 
 
  331            if (randiter % 20 < 2 || coinbase_coins.size() < 10) {
 
  338                    disconnected_coins.erase(utxod->first);
 
  340                    duplicate_coins.insert(utxod->first);
 
  353                if (randiter % 20 == 2 && disconnected_coins.size()) {
 
  356                    prevout = tx.
vin[0].prevout;
 
  357                    if (!
CTransaction(tx).IsCoinBase() && !utxoset.count(prevout)) {
 
  358                        disconnected_coins.erase(utxod->first);
 
  363                    if (utxoset.count(utxod->first)) {
 
  365                        assert(duplicate_coins.count(utxod->first));
 
  367                    disconnected_coins.erase(utxod->first);
 
  373                    prevout = utxod->first;
 
  376                    tx.
vin[0].prevout = prevout;
 
  380                old_coin = result[prevout];
 
  382                result[prevout].
Clear();
 
  384                utxoset.erase(prevout);
 
  388                if (duplicate_coins.count(prevout)) {
 
  389                    spent_a_duplicate_coinbase = 
true;
 
  403            utxoset.insert(outpoint);
 
  406            utxoData.emplace(outpoint, std::make_tuple(tx,undo,old_coin));
 
  407        } 
else if (utxoset.size()) {
 
  412            CTxUndo &undo = std::get<1>(utxod->second);
 
  413            Coin &orig_coin = std::get<2>(utxod->second);
 
  417            result[utxod->first].Clear();
 
  420                result[tx.
vin[0].prevout] = orig_coin;
 
  426            BOOST_CHECK(stack.back()->SpendCoin(utxod->first));
 
  434            disconnected_coins.insert(utxod->first);
 
  437            utxoset.erase(utxod->first);
 
  439                utxoset.insert(tx.
vin[0].prevout);
 
  444            for (
const auto& entry : result) {
 
  445                bool have = stack.back()->HaveCoin(entry.first);
 
  446                const Coin& coin = stack.back()->AccessCoin(entry.first);
 
  479                if (stack.size() > 0) {
 
  482                stack.push_back(
new CCoinsViewCacheTest(tip));
 
  488    while (stack.size() > 0) {
 
  533        BOOST_CHECK_MESSAGE(
false, 
"We should have thrown");
 
  534    } 
catch (
const std::ios_base::failure&) {
 
  539    uint64_t x = 3000000000ULL;
 
  546        BOOST_CHECK_MESSAGE(
false, 
"We should have thrown");
 
  547    } 
catch (
const std::ios_base::failure&) {
 
  571    if (value != 
SPENT) {
 
  588    auto inserted = map.emplace(
OUTPOINT, std::move(entry));
 
  590    return inserted.first->second.coin.DynamicMemoryUsage();
 
  596    if (it == map.end()) {
 
  600        if (it->second.coin.IsSpent()) {
 
  603            value = it->second.coin.out.nValue;
 
  605        flags = it->second.flags;
 
  635    test.
cache.SelfTest();
 
  686    test.
cache.SelfTest();
 
  741        output.
nValue = modify_value;
 
  743        test.
cache.SelfTest();
 
  745    } 
catch (std::logic_error&) {
 
  759template <
typename... Args>
 
  804        test.
cache.SelfTest();
 
  806    } 
catch (std::logic_error&) {
 
  878                    CheckWriteCoins(parent_value, child_value, parent_value, parent_flags, child_flags, parent_flags);
 
int64_t CAmount
Amount in satoshis (Can be negative)
CCoinsView that adds a memory cache for transactions to another CCoinsView.
unsigned int GetCacheSize() const
Calculate the size of the cache (in number of transaction outputs)
size_t DynamicMemoryUsage() const
Calculate the size of the cache (in bytes)
CCoinsView backed by the coin database (chainstate/)
Abstract view on the open txout dataset.
virtual bool GetCoin(const COutPoint &outpoint, Coin &coin) const
Retrieve the Coin (unspent transaction output) for a given outpoint.
virtual bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock)
Do a bulk modification (multiple Coin changes + BestBlock change).
virtual uint256 GetBestBlock() const
Retrieve the block hash whose state this CCoinsView currently represents.
Double ended buffer combining vector and stream-like interfaces.
An outpoint - a combination of a transaction hash and an index n into its vout.
bool IsUnspendable() const
Returns whether the script is guaranteed to fail at execution, regardless of the initial stack.
The basic transaction that is broadcasted on the network and contained in blocks.
const std::vector< CTxIn > vin
An output of a transaction.
Undo information for a CTransaction.
std::vector< Coin > vprevout
CTxOut out
unspent transaction output
bool IsSpent() const
Either this coin never existed (see e.g.
uint32_t nHeight
at which height this containing transaction was included in the active block chain
unsigned int fCoinBase
whether containing transaction was a coinbase
CCoinsViewCacheTest cache
SingleEntryCacheTest(CAmount base_value, CAmount cache_value, char cache_flags)
void assign(size_type n, const T &val)
static const int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
const Coin & AccessByTxid(const CCoinsViewCache &view, const uint256 &txid)
Utility function to find any unspent output with a given txid.
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher > CCoinsMap
static void CheckAddCoin(Args &&... args)
static const COutPoint OUTPOINT
static const CAmount ABSENT
void WriteCoinsViewEntry(CCoinsView &view, CAmount value, char flags)
static const CAmount VALUE2
static const CAmount SPENT
int ApplyTxInUndo(Coin &&undo, CCoinsViewCache &view, const COutPoint &out)
Restore the UTXO in a Coin at a given COutPoint.
static const unsigned int NUM_SIMULATION_ITERATIONS
std::map< COutPoint, std::tuple< CTransaction, CTxUndo, Coin > > UtxoData
static void CheckAddCoinBase(CAmount base_value, CAmount cache_value, CAmount modify_value, CAmount expected_value, char cache_flags, char expected_flags, bool coinbase)
void UpdateCoins(const CTransaction &tx, CCoinsViewCache &inputs, CTxUndo &txundo, int nHeight)
static void CheckAccessCoin(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
static void SetCoinsValue(CAmount value, Coin &coin)
void CheckWriteCoins(CAmount parent_value, CAmount child_value, CAmount expected_value, char parent_flags, char child_flags, char expected_flags)
static const CAmount VALUE1
static const char NO_ENTRY
void GetCoinsMapEntry(const CCoinsMap &map, CAmount &value, char &flags)
BOOST_AUTO_TEST_CASE(coins_cache_simulation_test)
static const auto ABSENT_FLAGS
static const CAmount VALUE3
static void CheckSpendCoins(CAmount base_value, CAmount cache_value, CAmount expected_value, char cache_flags, char expected_flags)
static size_t InsertCoinsMapEntry(CCoinsMap &map, CAmount value, char flags)
void SimulationTest(CCoinsView *base, bool fake_best_block)
UtxoData::iterator FindRandomFrom(const std::set< COutPoint > &utxoSet)
static const auto CLEAN_FLAGS
static const CAmount FAIL
BOOST_AUTO_TEST_SUITE_END()
static size_t DynamicUsage(const int8_t &v)
Dynamic memory usage for built-in types is zero.
bool operator==(const CNetAddr &a, const CNetAddr &b)
#define BOOST_FIXTURE_TEST_SUITE(a, b)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
bool g_mock_deterministic_tests
Flag to make GetRand in random.h return the same number.
@ ZEROS
Seed with a compile time constant of zeros.
static uint64_t InsecureRandRange(uint64_t range)
static uint256 InsecureRand256()
static void SeedInsecureRand(SeedRand seed=SeedRand::SEED)
static uint64_t InsecureRandBits(int bits)
static uint32_t InsecureRand32()
static bool InsecureRandBool()
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< unsigned char > ParseHex(const char *psz)
A Coin in one level of the coins database caching hierarchy.
@ FRESH
FRESH means the parent cache does not have this coin or that it is a spent coin in the parent cache.
@ DIRTY
DIRTY means the CCoinsCacheEntry is potentially different from the version in the parent cache.
A mutable version of CTransaction.
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
std::vector< CTxOut > vout