15#include <boost/test/unit_test.hpp>
21#include <unordered_set>
26std::shared_ptr<ThreadPool> MakeStartedThreadPool()
28 auto pool{std::make_shared<ThreadPool>(
"fetch_test")};
33CBlock CreateBlock() noexcept
35 static constexpr auto NUM_TXS{100};
38 coinbase.
vin.emplace_back();
43 for (
const auto i : std::views::iota(1, NUM_TXS)) {
46 tx.
vin.emplace_back(txid, 0);
59 std::unordered_set<Txid, SaltedCoinsCacheHasher> txids{};
60 txids.reserve(block.
vtx.size() - 1);
61 for (
const auto& tx : block.
vtx | std::views::drop(1)) {
62 for (
const auto& in : tx->
vin) {
63 if (txids.contains(in.prevout.hash))
continue;
66 cache.EmplaceCoinInternalDANGER(in.prevout, std::move(coin));
77 std::unordered_set<Txid, SaltedCoinsCacheHasher> txids{};
78 txids.reserve(block.
vtx.size() - 1);
80 for (
const auto& tx : block.
vtx) {
81 if (tx->IsCoinBase()) {
84 for (
const auto& in : tx->
vin) {
85 const auto& outpoint{in.prevout};
87 const auto& second{cache.
AccessCoin(outpoint)};
90 BOOST_CHECK_NE(txids.contains(outpoint.hash), have);
101BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests)
105 const auto block{CreateBlock()};
106 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
107 PopulateView(block,
db);
110 const auto reset_guard{view.StartFetching(block)};
111 const auto& outpoint{block.
vtx[1]->vin[0].prevout};
115 BOOST_CHECK(!main_cache.HaveCoinInCache(outpoint));
117 CheckCache(block, view);
119 for (
const auto& tx : block.
vtx) {
120 for (
const auto& in : tx->
vin) {
121 BOOST_CHECK(!main_cache.HaveCoinInCache(in.prevout));
128 BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
133 const auto block{CreateBlock()};
134 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
136 PopulateView(block, main_cache);
138 const auto reset_guard{view.StartFetching(block)};
139 CheckCache(block, view);
141 const auto& outpoint{block.
vtx[1]->vin[0].prevout};
145 BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
152 const auto block{CreateBlock()};
153 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
154 PopulateView(block,
db);
157 PopulateView(block, main_cache,
true);
159 const auto reset_guard{view.StartFetching(block)};
160 for (
const auto& tx : block.
vtx) {
161 for (
const auto& in : tx->
vin) {
162 const auto& c{view.AccessCoin(in.prevout)};
174 const auto block{CreateBlock()};
175 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
178 const auto reset_guard{view.StartFetching(block)};
179 for (
const auto& tx : block.
vtx) {
180 for (
const auto& in : tx->
vin) {
181 const auto& c{view.AccessCoin(in.prevout)};
195 coinbase.
vin.emplace_back();
197 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
202 main_cache.EmplaceCoinInternalDANGER(
COutPoint{outpoint}, std::move(coin));
205 const auto reset_guard{view.StartFetching(block)};
212 BOOST_CHECK(view.AccessCoin(missing_outpoint).IsSpent());
213 BOOST_CHECK(!view.HaveCoinInCache(missing_outpoint));
221 const auto block{CreateBlock()};
222 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
224 PopulateView(block, main_cache);
226 std::vector<COutPoint> fetched_inputs;
227 std::unordered_set<Txid, SaltedCoinsCacheHasher> txids;
228 txids.reserve(block.
vtx.size() - 1);
229 for (
const auto& tx : block.
vtx | std::views::drop(1)) {
230 for (
const auto& input : tx->
vin) {
231 if (!txids.contains(input.prevout.hash)) fetched_inputs.push_back(input.prevout);
235 BOOST_REQUIRE_GE(fetched_inputs.size(), 2U);
238 const auto reset_guard{view.StartFetching(block)};
240 const auto& out_of_order_input{fetched_inputs[1]};
241 BOOST_CHECK(!view.HaveCoinInCache(out_of_order_input));
242 BOOST_CHECK(!view.AccessCoin(out_of_order_input).IsSpent());
243 BOOST_CHECK(view.HaveCoinInCache(out_of_order_input));
245 CheckCache(block, view);
253 const auto block{CreateBlock()};
254 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
256 PopulateView(block, main_cache);
259 for (
const bool use_flush : {
false,
true,
false}) {
261 const auto reset_guard{view.StartFetching(block)};
262 CheckCache(block, view);
275BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests_noworkers)
280 const auto block{CreateBlock()};
281 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
283 PopulateView(block, main_cache);
284 auto thread_pool{std::make_shared<ThreadPool>(
"fetch_none")};
286 const auto reset_guard{view.StartFetching(block)};
287 CheckCache(block, view);
293 const auto block{CreateBlock()};
294 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
296 PopulateView(block, main_cache);
298 auto thread_pool{std::make_shared<ThreadPool>(
"fetch_intr")};
300 thread_pool->Interrupt();
302 const auto reset_guard{view.StartFetching(block)};
303 CheckCache(block, view);
static constexpr int32_t DEFAULT_PREVOUTFETCH_THREADS
std::vector< CTransactionRef > vtx
CCoinsView that adds a memory cache for transactions to another CCoinsView.
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
bool HaveCoinInCache(const COutPoint &outpoint) const
Check if we have the given utxo already loaded in this cache.
const Coin & AccessCoin(const COutPoint &output) const
Return a reference to Coin in the cache, or coinEmpty if not found.
CCoinsView backed by the coin database (chainstate/)
Pure abstract view on the open txout dataset.
virtual std::optional< Coin > GetCoin(const COutPoint &outpoint) const =0
Retrieve the Coin (unspent transaction output) for a given outpoint.
virtual bool HaveCoin(const COutPoint &outpoint) const =0
Just check whether a given outpoint is unspent.
An outpoint - a combination of a transaction hash and an index n into its vout.
CTxOut out
unspent transaction output
CCoinsViewCache subclass that asynchronously fetches most block input prevouts in parallel during Con...
static transaction_identifier FromUint256(const uint256 &id)
static const uint256 ZERO
BOOST_AUTO_TEST_CASE(fetch_inputs_from_db)
BOOST_AUTO_TEST_SUITE_END()
BOOST_CHECK_GT(excessive_headers.size(), MAX_HEADERS_SIZE)
BOOST_CHECK_EQUAL(headers.FindFirst("key"), "value")
#define BOOST_CHECK(expr)
static CTransactionRef MakeTransactionRef(Tx &&txIn)
A mutable version of CTransaction.
Txid GetHash() const
Compute the hash of this CMutableTransaction.