5 #include <chainparams.h> 30 #include <boost/test/unit_test.hpp> 72 const uint256 snapshot_blockhash = active_tip->GetBlockHash();
75 1 << 23,
true,
false);
78 c2.InitCoinsCache(1 << 23);
79 c2.CoinsTip().SetBestBlock(active_tip->GetBlockHash());
80 for (
const auto&
cs : manager.m_chainstates) {
81 cs->ClearBlockIndexCandidates();
84 for (
const auto&
cs : manager.m_chainstates) {
85 cs->PopulateBlockIndexCandidates();
124 size_t max_cache = 10000;
128 std::vector<Chainstate*> chainstates;
133 chainstates.push_back(&c1);
136 c1.InitCoinsCache(1 << 23);
137 manager.MaybeRebalanceCaches();
147 chainstates.push_back(&c2);
149 1 << 23,
true,
false);
162 c2.InitCoinsCache(1 << 23);
163 manager.MaybeRebalanceCaches();
168 BOOST_CHECK_CLOSE(
double(c2.m_coinstip_cache_size_bytes), max_cache * 0.95, 1);
169 BOOST_CHECK_CLOSE(
double(c2.m_coinsdb_cache_size_bytes), max_cache * 0.95, 1);
176 auto apply{[&](
bool cached_is_ibd,
bool loading_blocks,
bool tip_exists,
bool enough_work,
bool tip_recent) {
178 chainman.ResetChainstates();
181 const auto recent_time{Now<NodeSeconds>() - chainman.m_options.max_tip_age};
183 chainman.m_cached_is_ibd.store(cached_is_ibd, std::memory_order_relaxed);
184 chainman.m_blockman.m_importing = loading_blocks;
186 tip.
nChainWork = chainman.MinimumChainWork() - (enough_work ? 0 : 1);
187 tip.
nTime = (recent_time - (tip_recent ? 0h : 100h)).time_since_epoch().count();
188 chainman.ActiveChain().SetTip(tip);
190 assert(!chainman.ActiveChain().Tip());
192 chainman.UpdateIBDStatus();
195 for (
const bool cached_is_ibd : {
false,
true}) {
196 for (
const bool loading_blocks : {
false,
true}) {
197 for (
const bool tip_exists : {
false,
true}) {
198 for (
const bool enough_work : {
false,
true}) {
199 for (
const bool tip_recent : {
false,
true}) {
200 apply(cached_is_ibd, loading_blocks, tip_exists, enough_work, tip_recent);
201 const bool expected_ibd = cached_is_ibd && (loading_blocks || !tip_exists || !enough_work || !tip_recent);
220 .coins_db_in_memory =
false,
221 .block_tree_db_in_memory =
false,
238 size_t initial_total_coins{100};
245 size_t total_coins{0};
265 constexpr
int snapshot_height = 110;
268 initial_total_coins += 10;
341 int chains_tested{0};
343 for (
const auto& chainstate : chainman.m_chainstates) {
344 BOOST_TEST_MESSAGE(
"Checking coins in " << chainstate->ToString());
350 size_t total_coins{0};
367 constexpr
size_t new_coins{100};
372 size_t coins_in_active{0};
373 size_t coins_in_background{0};
374 size_t coins_missing_from_background{0};
376 for (
const auto& chainstate : chainman.m_chainstates) {
377 BOOST_TEST_MESSAGE(
"Checking coins in " << chainstate->ToString());
383 if (coinscache.HaveCoin(op)) {
384 (is_background ? coins_in_background : coins_in_active)++;
385 }
else if (is_background) {
386 coins_missing_from_background++;
402 loaded_snapshot_blockhash);
403 return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
414 BOOST_TEST_MESSAGE(
"Simulating node restart");
417 for (
const auto&
cs : chainman.m_chainstates) {
418 if (
cs->CanFlushToDisk())
cs->ForceFlushStateToDisk();
425 chainman.ResetChainstates();
434 const BlockManager::Options blockman_opts{
435 .chainparams = chainman_opts.chainparams,
437 .notifications = chainman_opts.notifications,
456 this->SetupSnapshot();
477 const int expected_assumed_valid{20};
478 const int last_assumed_valid_idx{111};
479 const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid;
490 auto reload_all_block_indexes = [&]() {
496 for (
const auto&
cs : chainman.m_chainstates) {
497 cs->ClearBlockIndexCandidates();
501 for (
const auto&
cs : chainman.m_chainstates) {
502 cs->PopulateBlockIndexCandidates();
508 reload_all_block_indexes();
517 if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {
520 index->m_chain_tx_count = 0;
526 if (i == (assumed_valid_start_idx - 1)) {
527 validated_tip = index;
530 if (i == last_assumed_valid_idx - 1) {
531 assumed_base = index;
542 cs2.m_chain.SetTip(*assumed_base);
552 reload_all_block_indexes();
600 BOOST_CHECK_EQUAL(cs2.setBlockIndexCandidates.size(), num_indexes - last_assumed_valid_idx + 1);
613 auto* parent{child->pprev};
614 auto* grand_parent{parent->pprev};
635 this->SetupSnapshot();
665 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
668 this->LoadVerifyActivateChainstate();
671 LOCK(chainman_restarted.GetMutex());
680 BOOST_CHECK(chainman_restarted.CurrentChainstate().m_from_snapshot_blockhash);
683 BOOST_CHECK_EQUAL(chainman_restarted.ActiveTip()->GetBlockHash(), snapshot_tip_hash);
685 BOOST_CHECK_EQUAL(chainman_restarted.HistoricalChainstate()->m_chain.Height(), 109);
689 "Ensure we can mine blocks on top of the initialized snapshot chainstate");
692 LOCK(chainman_restarted.GetMutex());
706 this->SetupSnapshot();
725 res =
WITH_LOCK(::
cs_main,
return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
738 res =
WITH_LOCK(::
cs_main,
return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
752 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
756 this->LoadVerifyActivateChainstate();
776 "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
786 auto chainstates = this->SetupSnapshot();
787 Chainstate& validation_chainstate = *std::get<0>(chainstates);
788 Chainstate& unvalidated_cs = *std::get<1>(chainstates);
796 return validation_chainstate.
CoinsTip());
800 badcoin.out.scriptPubKey.assign(m_rng.randbits(6), 0);
809 res =
WITH_LOCK(::
cs_main,
return chainman.MaybeValidateSnapshot(validation_chainstate, unvalidated_cs));
814 LOCK(chainman.GetMutex());
817 BOOST_CHECK(!chainman.m_chainstates[0]->SnapshotBase());
819 BOOST_CHECK(chainman.m_chainstates[1]->SnapshotBase());
830 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
834 this->LoadVerifyActivateChainstate();
847 "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
856 template <
typename Options>
858 const std::vector<const char*>&
args)
860 const auto argv{
Cat({
"ignore"},
args)};
873 auto get_opts = [&](
const std::vector<const char*>&
args) {
878 .notifications = notifications};
882 auto get_valid_opts = [&](
const std::vector<const char*>&
args) {
889 BOOST_CHECK(!get_valid_opts({}).assumed_valid_block);
895 std::string assume_valid{
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
899 BOOST_CHECK(!get_opts({
"-assumevalid=01234567890123456789012345678901234567890123456789012345678901234"}));
902 BOOST_CHECK(!get_valid_opts({}).minimum_chain_work);
907 std::string minimum_chainwork{
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
911 BOOST_CHECK(!get_opts({
"-minimumchainwork=01234567890123456789012345678901234567890123456789012345678901234"}));
std::shared_ptr< const CTransaction > CTransactionRef
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
node::BlockManager m_blockman
A single BlockManager instance is shared across each constructed chainstate to avoid duplicating bloc...
const std::optional< uint256 > m_from_snapshot_blockhash
The blockhash which is the base of the snapshot this chainstate was created from. ...
Testing setup that performs all steps up until right before ChainstateManager gets initialized...
fs::path path
Location in the filesystem where leveldb data will be stored.
kernel::CacheSizes m_kernel_cache_sizes
The assumeutxo snapshot failed validation.
std::unique_ptr< node::Warnings > warnings
Manages all the node warnings.
std::set< CBlockIndex *, node::CBlockIndexWorkComparator > setBlockIndexCandidates
The set of all CBlockIndex entries that have as much work as our current tip or more, and transaction data needed to be validated (with BLOCK_VALID_TRANSACTIONS for each block and its parents back to the genesis block or an assumeutxo snapshot block).
Unused flag that was previously set when descending from failed block.
util::SignalInterrupt * shutdown_signal
Interrupt object used to track whether node shutdown was requested.
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
bool m_block_tree_db_in_memory
util::Result< Options > SetOptsFromArgs(ArgsManager &args_man, Options opts, const std::vector< const char *> &args)
Helper function to parse args into args_man and return the result of applying them to opts...
ArgsManager m_args
Test-specific arguments and settings.
std::optional< uint256 > ReadSnapshotBaseBlockhash(fs::path chaindir)
size_t m_coinsdb_cache_size_bytes
The cache size of the on-disk coins view.
ChainstateManager & SimulateNodeRestart()
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
std::atomic< int > exit_status
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
All parent headers found, difficulty matches, timestamp >= median previous.
std::tuple< Chainstate *, Chainstate * > SetupSnapshot()
int Height() const
Return the maximal height in the chain.
CTxOut out
unspent transaction output
const CChainParams & chainparams
std::unique_ptr< ValidationSignals > validation_signals
Issues calls about blocks and transactions.
stage after last reached validness failed
std::vector< CTransactionRef > m_coinbase_txns
An options struct for ChainstateManager, more ergonomically referred to as ChainstateManager::Options...
bool ParseParameters(int argc, const char *const argv[], std::string &error)
size_t m_total_coinsdb_cache
The total number of bytes available for us to use across all leveldb coins databases.
util::Result< void > ApplyArgsManOptions(const ArgsManager &args, BlockManager::Options &opts)
CChain m_chain
The current chain of blockheaders we consult and build on.
static const unsigned int MAX_DISCONNECTED_TX_POOL_BYTES
Maximum bytes for transactions to store for processing during reorg.
consteval auto _(util::TranslatedLiteral str)
Non-refcounted RAII wrapper for FILE*.
void SetTip(CBlockIndex &block)
Set/initialize a chain with a given tip.
arith_uint256 UintToArith256(const uint256 &a)
std::unique_ptr< CTxMemPool > mempool
uint256 GetBlockHash() const
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs)
static bool exists(const path &p)
bool DisconnectTip(BlockValidationState &state, DisconnectedBlockTransactions *disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main
Disconnect m_chain's tip.
fs::path GetDataDirNet() const
Get data directory path with appended network identifier.
Blocks after an assumeutxo snapshot have been validated but the snapshot itself has not been validate...
Chainstate stores and provides an API to update our local knowledge of the current best chain...
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_FIXTURE_TEST_CASE(chainstatemanager, TestChain100Setup)
Basic tests for ChainstateManager.
uint64_t m_chain_tx_count
(memory only) Number of transactions in the chain up to and including this block. ...
fs::path GetBlocksDirPath() const
Get blocks directory path.
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Load the block tree and coins database from disk, initializing state if we're running with -reindex...
BOOST_AUTO_TEST_SUITE_END()
static std::optional< uint256 > FromHex(std::string_view str)
static const uint256 ZERO
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate &validated_cs, Chainstate &unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(Chainstate & CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Try to validate an assumeutxo snapshot by using a validated historical chainstate targeted at the sna...
void mineBlocks(int num_blocks)
Mine a series of new blocks on the active chain.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
Every block in the chain has been validated.
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
#define ASSERT_DEBUG_LOG(message)
An outpoint - a combination of a transaction hash and an index n into its vout.
A base class defining functions for notifying about certain kernel events.
size_t m_total_coinstip_cache
The total number of bytes available for us to use across all in-memory coins caches.
DisconnectedBlockTransactions.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
256-bit unsigned big integer.
void AddCoin(const COutPoint &outpoint, Coin &&coin, bool possible_overwrite)
Add a coin.
#define BOOST_CHECK_EQUAL(v1, v2)
The block chain is a tree shaped structure starting with the genesis block at the root...
const CChainParams & Params()
Return the currently selected parameters.
static transaction_identifier FromUint256(const uint256 &id)
static bool CreateAndActivateUTXOSnapshot(TestingSetup *fixture, F malleation=NoMalleation, bool reset_chainstate=false, bool in_memory_chainstate=false)
Create and activate a UTXO snapshot, optionally providing a function to malleate the snapshot...
std::unique_ptr< KernelNotifications > notifications
Issues blocking calls about sync status, errors and warnings.
void ResetBlockSequenceCounters() EXCLUSIVE_LOCKS_REQUIRED(
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Application-specific storage settings.
std::optional< fs::path > FindAssumeutxoChainstateDir(const fs::path &data_dir)
Return a path to the snapshot-based chainstate dir, if one exists.
bilingual_str ErrorString(const Result< T > &result)
size_t m_coinstip_cache_size_bytes
The cache size of the in-memory coins view.
Chainstate & ActiveChainstate() const
Alternatives to CurrentChainstate() used by older code to query latest chainstate information without...
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Chainstate * HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Return historical chainstate targeting a specific block, if any.
std::optional< AssumeutxoData > AssumeutxoForHeight(int height) const
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
std::function< bool()> shutdown_request
Function to request a shutdown.
std::unique_ptr< ChainstateManager > chainman
Testing setup that configures a complete environment.
#define Assert(val)
Identity function.
#define BOOST_CHECK(expr)
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.