Bitcoin Core 30.99.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
20BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests)
21
22namespace {
23
24CBlock 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)) {
35 tx.vin.emplace_back(txid, 0);
36 block.vtx.push_back(MakeTransactionRef(tx));
37 }
38
39 return block;
40}
41
42void 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
58void 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
81BOOST_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
108BOOST_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.
126BOOST_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
147BOOST_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
Definition: block.h:74
std::vector< CTransactionRef > vtx
Definition: block.h:77
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:367
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
Definition: coins.cpp:325
bool HaveCoinInCache(const COutPoint &outpoint) const
Check if we have the given utxo already loaded in this cache.
Definition: coins.cpp:193
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
Definition: coins.cpp:179
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:35
Abstract view on the open txout dataset.
Definition: coins.h:307
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: coins.cpp:17
virtual bool HaveCoin(const COutPoint &outpoint) const
Just check whether a given outpoint is unspent.
Definition: coins.cpp:28
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
CAmount nValue
Definition: transaction.h:142
A UTXO entry.
Definition: coins.h:34
CTxOut out
unspent transaction output
Definition: coins.h:37
CCoinsViewCache overlay that avoids populating/mutating parent cache layers on cache misses.
Definition: coins.h:538
static transaction_identifier FromUint256(const uint256 &id)
256-bit opaque blob.
Definition: uint256.h:195
static const uint256 ONE
Definition: uint256.h:204
BOOST_AUTO_TEST_CASE(fetch_inputs_from_db)
BOOST_AUTO_TEST_SUITE_END()
#define BOOST_CHECK_EQUAL(v1, v2)
Definition: object.cpp:17
#define BOOST_CHECK(expr)
Definition: object.cpp:16
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:404
A mutable version of CTransaction.
Definition: transaction.h:358
std::vector< CTxIn > vin
Definition: transaction.h:359