Bitcoin Core  31.0.0
P2P Digital Currency
coinsviewoverlay_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <coins.h>
6 #include <primitives/block.h>
9 #include <txdb.h>
10 #include <uint256.h>
11 #include <util/byte_units.h>
12 #include <util/hasher.h>
13 
14 #include <boost/test/unit_test.hpp>
15 
16 #include <cstdint>
17 #include <cstring>
18 #include <ranges>
19 
20 BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests)
21 
22 namespace {
23 
24 CBlock CreateBlock() noexcept
25 {
26  static constexpr auto NUM_TXS{100};
27  CBlock block;
28  CMutableTransaction coinbase;
29  coinbase.vin.emplace_back();
30  block.vtx.push_back(MakeTransactionRef(coinbase));
31 
32  for (const auto i : std::views::iota(1, NUM_TXS)) {
34  Txid txid{Txid::FromUint256(uint256(i))};
35  tx.vin.emplace_back(txid, 0);
36  block.vtx.push_back(MakeTransactionRef(tx));
37  }
38 
39  return block;
40 }
41 
42 void PopulateView(const CBlock& block, CCoinsView& view, bool spent = false)
43 {
44  CCoinsViewCache cache{&view};
45  cache.SetBestBlock(uint256::ONE);
46 
47  for (const auto& tx : block.vtx | std::views::drop(1)) {
48  for (const auto& in : tx->vin) {
49  Coin coin{};
50  if (!spent) coin.out.nValue = 1;
51  cache.EmplaceCoinInternalDANGER(COutPoint{in.prevout}, std::move(coin));
52  }
53  }
54 
55  cache.Flush();
56 }
57 
58 void CheckCache(const CBlock& block, const CCoinsViewCache& cache)
59 {
60  uint32_t counter{0};
61 
62  for (const auto& tx : block.vtx) {
63  if (tx->IsCoinBase()) {
64  BOOST_CHECK(!cache.HaveCoinInCache(tx->vin[0].prevout));
65  } else {
66  for (const auto& in : tx->vin) {
67  const auto& outpoint{in.prevout};
68  const auto& first{cache.AccessCoin(outpoint)};
69  const auto& second{cache.AccessCoin(outpoint)};
70  BOOST_CHECK_EQUAL(&first, &second);
71  ++counter;
72  BOOST_CHECK(cache.HaveCoinInCache(outpoint));
73  }
74  }
75  }
76  BOOST_CHECK_EQUAL(cache.GetCacheSize(), counter);
77 }
78 
79 } // namespace
80 
81 BOOST_AUTO_TEST_CASE(fetch_inputs_from_db)
82 {
83  const auto block{CreateBlock()};
84  CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
85  PopulateView(block, db);
86  CCoinsViewCache main_cache{&db};
87  CoinsViewOverlay view{&main_cache};
88  const auto& outpoint{block.vtx[1]->vin[0].prevout};
89 
90  BOOST_CHECK(view.HaveCoin(outpoint));
91  BOOST_CHECK(view.GetCoin(outpoint).has_value());
92  BOOST_CHECK(!main_cache.HaveCoinInCache(outpoint));
93 
94  CheckCache(block, view);
95  // Check that no coins have been moved up to main cache from db
96  for (const auto& tx : block.vtx) {
97  for (const auto& in : tx->vin) {
98  BOOST_CHECK(!main_cache.HaveCoinInCache(in.prevout));
99  }
100  }
101 
102  view.SetBestBlock(uint256::ONE);
103  BOOST_CHECK(view.SpendCoin(outpoint));
104  view.Flush();
105  BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
106 }
107 
108 BOOST_AUTO_TEST_CASE(fetch_inputs_from_cache)
109 {
110  const auto block{CreateBlock()};
111  CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
112  CCoinsViewCache main_cache{&db};
113  PopulateView(block, main_cache);
114  CoinsViewOverlay view{&main_cache};
115  CheckCache(block, view);
116 
117  const auto& outpoint{block.vtx[1]->vin[0].prevout};
118  view.SetBestBlock(uint256::ONE);
119  BOOST_CHECK(view.SpendCoin(outpoint));
120  view.Flush();
121  BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
122 }
123 
124 // Test for the case where a block spends coins that are spent in the cache, but
125 // the spentness has not been flushed to the db.
126 BOOST_AUTO_TEST_CASE(fetch_no_double_spend)
127 {
128  const auto block{CreateBlock()};
129  CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
130  PopulateView(block, db);
131  CCoinsViewCache main_cache{&db};
132  // Add all inputs as spent already in cache
133  PopulateView(block, main_cache, /*spent=*/true);
134  CoinsViewOverlay view{&main_cache};
135  for (const auto& tx : block.vtx) {
136  for (const auto& in : tx->vin) {
137  const auto& c{view.AccessCoin(in.prevout)};
138  BOOST_CHECK(c.IsSpent());
139  BOOST_CHECK(!view.HaveCoin(in.prevout));
140  BOOST_CHECK(!view.GetCoin(in.prevout));
141  }
142  }
143  // Coins are not added to the view, even though they exist unspent in the parent db
144  BOOST_CHECK_EQUAL(view.GetCacheSize(), 0);
145 }
146 
147 BOOST_AUTO_TEST_CASE(fetch_no_inputs)
148 {
149  const auto block{CreateBlock()};
150  CCoinsViewDB db{{.path = "", .cache_bytes = 1_MiB, .memory_only = true}, {}};
151  CCoinsViewCache main_cache{&db};
152  CoinsViewOverlay view{&main_cache};
153  for (const auto& tx : block.vtx) {
154  for (const auto& in : tx->vin) {
155  const auto& c{view.AccessCoin(in.prevout)};
156  BOOST_CHECK(c.IsSpent());
157  BOOST_CHECK(!view.HaveCoin(in.prevout));
158  BOOST_CHECK(!view.GetCoin(in.prevout));
159  }
160  }
161  BOOST_CHECK_EQUAL(view.GetCacheSize(), 0);
162 }
163 
165 
CAmount nValue
Definition: transaction.h:142
static const uint256 ONE
Definition: uint256.h:204
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
Definition: coins.cpp:179
A UTXO entry.
Definition: coins.h:34
Definition: block.h:73
std::vector< CTxIn > vin
Definition: transaction.h:359
CTxOut out
unspent transaction output
Definition: coins.h:38
bool HaveCoinInCache(const COutPoint &outpoint) const
Check if we have the given utxo already loaded in this cache.
Definition: coins.cpp:193
CCoinsViewCache overlay that avoids populating/mutating parent cache layers on cache misses...
Definition: coins.h:538
BOOST_AUTO_TEST_CASE(fetch_inputs_from_db)
virtual bool HaveCoin(const COutPoint &outpoint) const
Just check whether a given outpoint is unspent.
Definition: coins.cpp:28
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
Definition: coins.cpp:325
Abstract view on the open txout dataset.
Definition: coins.h:307
BOOST_AUTO_TEST_SUITE_END()
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
256-bit opaque blob.
Definition: uint256.h:195
std::vector< CTransactionRef > vtx
Definition: block.h:77
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
static transaction_identifier FromUint256(const uint256 &id)
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:34
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:17
A mutable version of CTransaction.
Definition: transaction.h:357
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:367
#define BOOST_CHECK(expr)
Definition: object.cpp:16