16#include <boost/test/unit_test.hpp>
22#include <unordered_set>
27std::shared_ptr<ThreadPool> MakeStartedThreadPool()
29 auto pool{std::make_shared<ThreadPool>(
"fetch_test")};
34CBlock CreateBlock() noexcept
36 static constexpr auto NUM_TXS{100};
39 coinbase.
vin.emplace_back();
44 for (
const auto i : std::views::iota(1, NUM_TXS)) {
47 tx.
vin.emplace_back(txid, 0);
60 std::unordered_set<Txid, SaltedTxidHasher> txids{};
61 txids.reserve(block.
vtx.size() - 1);
62 for (
const auto& tx : block.
vtx | std::views::drop(1)) {
63 for (
const auto& in : tx->
vin) {
64 if (txids.contains(in.prevout.hash))
continue;
67 cache.EmplaceCoinInternalDANGER(
COutPoint{in.prevout}, std::move(coin));
78 std::unordered_set<Txid, SaltedTxidHasher> txids{};
79 txids.reserve(block.
vtx.size() - 1);
81 for (
const auto& tx : block.
vtx) {
82 if (tx->IsCoinBase()) {
85 for (
const auto& in : tx->
vin) {
86 const auto& outpoint{in.prevout};
88 const auto& second{cache.
AccessCoin(outpoint)};
91 BOOST_CHECK_NE(txids.contains(outpoint.hash), have);
102BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests)
106 const auto block{CreateBlock()};
107 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
108 PopulateView(block,
db);
111 const auto reset_guard{view.StartFetching(block)};
112 const auto& outpoint{block.
vtx[1]->vin[0].prevout};
116 BOOST_CHECK(!main_cache.HaveCoinInCache(outpoint));
118 CheckCache(block, view);
120 for (
const auto& tx : block.
vtx) {
121 for (
const auto& in : tx->
vin) {
122 BOOST_CHECK(!main_cache.HaveCoinInCache(in.prevout));
129 BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
134 const auto block{CreateBlock()};
135 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
137 PopulateView(block, main_cache);
139 const auto reset_guard{view.StartFetching(block)};
140 CheckCache(block, view);
142 const auto& outpoint{block.
vtx[1]->vin[0].prevout};
146 BOOST_CHECK(!main_cache.PeekCoin(outpoint).has_value());
153 const auto block{CreateBlock()};
154 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
155 PopulateView(block,
db);
158 PopulateView(block, main_cache,
true);
160 const auto reset_guard{view.StartFetching(block)};
161 for (
const auto& tx : block.
vtx) {
162 for (
const auto& in : tx->
vin) {
163 const auto& c{view.AccessCoin(in.prevout)};
175 const auto block{CreateBlock()};
176 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
179 const auto reset_guard{view.StartFetching(block)};
180 for (
const auto& tx : block.
vtx) {
181 for (
const auto& in : tx->
vin) {
182 const auto& c{view.AccessCoin(in.prevout)};
196 coinbase.
vin.emplace_back();
198 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
203 main_cache.EmplaceCoinInternalDANGER(
COutPoint{outpoint}, std::move(coin));
206 const auto reset_guard{view.StartFetching(block)};
213 BOOST_CHECK(view.AccessCoin(missing_outpoint).IsSpent());
214 BOOST_CHECK(!view.HaveCoinInCache(missing_outpoint));
222 const auto block{CreateBlock()};
223 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
225 PopulateView(block, main_cache);
227 std::vector<COutPoint> fetched_inputs;
228 std::unordered_set<Txid, SaltedTxidHasher> txids;
229 txids.reserve(block.
vtx.size() - 1);
230 for (
const auto& tx : block.
vtx | std::views::drop(1)) {
231 for (
const auto& input : tx->
vin) {
232 if (!txids.contains(input.prevout.hash)) fetched_inputs.push_back(input.prevout);
236 BOOST_REQUIRE_GE(fetched_inputs.size(), 2U);
239 const auto reset_guard{view.StartFetching(block)};
241 const auto& out_of_order_input{fetched_inputs[1]};
242 BOOST_CHECK(!view.HaveCoinInCache(out_of_order_input));
243 BOOST_CHECK(!view.AccessCoin(out_of_order_input).IsSpent());
244 BOOST_CHECK(view.HaveCoinInCache(out_of_order_input));
246 CheckCache(block, view);
254 const auto block{CreateBlock()};
255 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
257 PopulateView(block, main_cache);
260 for (
const bool use_flush : {
false,
true,
false}) {
262 const auto reset_guard{view.StartFetching(block)};
263 CheckCache(block, view);
276BOOST_AUTO_TEST_SUITE(coinsviewoverlay_tests_noworkers)
281 const auto block{CreateBlock()};
282 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
284 PopulateView(block, main_cache);
285 auto thread_pool{std::make_shared<ThreadPool>(
"fetch_none")};
287 const auto reset_guard{view.StartFetching(block)};
288 CheckCache(block, view);
294 const auto block{CreateBlock()};
295 CCoinsViewDB db{{.path =
"", .cache_bytes = 1_MiB, .memory_only =
true}, {}};
297 PopulateView(block, main_cache);
299 auto thread_pool{std::make_shared<ThreadPool>(
"fetch_intr")};
301 thread_pool->Interrupt();
303 const auto reset_guard{view.StartFetching(block)};
304 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.