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);
80 for (
const auto&
cs : manager.m_chainstates) {
81 cs->ClearBlockIndexCandidates();
84 for (
const auto&
cs : manager.m_chainstates) {
85 cs->PopulateBlockIndexCandidates();
116 m_node.validation_signals->SyncWithValidationInterfaceQueue();
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();
176 auto apply{[&](
bool cached_is_ibd,
bool loading_blocks,
bool tip_exists,
bool enough_work,
bool tip_recent) {
178 chainman.ResetChainstates();
179 chainman.InitializeChainstate(m_node.mempool.get());
183 chainman.
m_cached_is_ibd.store(cached_is_ibd, std::memory_order_relaxed);
187 tip.
nTime = (recent_time - (tip_recent ? 0h : 100h)).time_since_epoch().count();
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());
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();
423 m_node.validation_signals->SyncWithValidationInterfaceQueue();
425 chainman.ResetChainstates();
431 .notifications = *
m_node.notifications,
432 .signals =
m_node.validation_signals.get(),
436 .blocks_dir =
m_args.GetBlocksDirPath(),
447 m_node.chainman = std::make_unique<ChainstateManager>(*
Assert(
m_node.shutdown_signal), chainman_opts, blockman_opts);
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;
552 reload_all_block_indexes();
612 auto* child{m_node.chainman->ActiveChain().Tip()};
613 auto* parent{child->pprev};
614 auto* grand_parent{parent->pprev};
620 m_node.chainman->LoadBlockIndex();
635 this->SetupSnapshot();
665 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
668 this->LoadVerifyActivateChainstate();
689 "Ensure we can mine blocks on top of the initialized snapshot chainstate");
706 this->SetupSnapshot();
715 m_node.notifications->m_shutdown_on_fatal_error =
false;
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));
742 fs::path snapshot_invalid_dir =
gArgs.GetDataDirNet() /
"chainstate_snapshot_INVALID";
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);
791 m_node.notifications->m_shutdown_on_fatal_error =
false;
796 return validation_chainstate.
CoinsTip());
804 fs::path snapshot_chainstate_dir =
gArgs.GetDataDirNet() /
"chainstate_snapshot";
809 res =
WITH_LOCK(
::cs_main,
return chainman.MaybeValidateSnapshot(validation_chainstate, unvalidated_cs));
817 BOOST_CHECK(!chainman.m_chainstates[0]->SnapshotBase());
819 BOOST_CHECK(chainman.m_chainstates[1]->SnapshotBase());
822 fs::path snapshot_invalid_dir =
gArgs.GetDataDirNet() /
"chainstate_snapshot_INVALID";
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");
856template <
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) {
883 const auto result{get_opts(
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"}));
BOOST_FIXTURE_TEST_CASE(util_CheckValue, CheckValueTest)
arith_uint256 UintToArith256(const uint256 &a)
@ BLOCK_FAILED_CHILD
Unused flag that was previously set when descending from failed block.
@ BLOCK_FAILED_VALID
stage after last reached validness failed
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
bool ParseParameters(int argc, const char *const argv[], std::string &error)
Non-refcounted RAII wrapper for FILE*.
The block chain is a tree shaped structure starting with the genesis block at the root,...
CBlockIndex * pprev
pointer to the index of the predecessor of this block
uint64_t m_chain_tx_count
arith_uint256 nChainWork
(memory only) Total amount of work (expected number of hashes) in the chain up to and including this ...
uint256 GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
const uint256 * phashBlock
pointer to the hash of the block, if any. Memory is owned by this CBlockIndex
CBlockIndex * Tip() const
Returns the index entry for the tip of this chain, or nullptr if none.
void SetTip(CBlockIndex &block)
Set/initialize a chain with a given tip.
int Height() const
Return the maximal height in the chain.
std::optional< AssumeutxoData > AssumeutxoForHeight(int height) const
CCoinsView that adds a memory cache for transactions to another CCoinsView.
void AddCoin(const COutPoint &outpoint, Coin &&coin, bool possible_overwrite)
Add a coin.
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs).
void SetBestBlock(const uint256 &hashBlock)
bool HaveCoin(const COutPoint &outpoint) const override
An outpoint - a combination of a transaction hash and an index n into its vout.
Chainstate stores and provides an API to update our local knowledge of the current best chain.
size_t m_coinstip_cache_size_bytes
The cache size of the in-memory coins view.
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
bool LoadChainTip() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Update the chain tip based on database information, i.e.
size_t m_coinsdb_cache_size_bytes
The cache size of the on-disk coins view.
kernel::ChainstateRole GetRole() const EXCLUSIVE_LOCKS_REQUIRED(void InitCoinsDB(size_t cache_size_bytes, bool in_memory, bool should_wipe)
Initialize the CoinsViews UTXO set database management data structures.
const std::optional< uint256 > m_from_snapshot_blockhash
The blockhash which is the base of the snapshot this chainstate was created from.
bool DisconnectTip(BlockValidationState &state, DisconnectedBlockTransactions *disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main
Disconnect m_chain's tip.
std::set< CBlockIndex *, node::CBlockIndexWorkComparator > setBlockIndexCandidates
The set of all CBlockIndex entries that have as much work as our current tip or more,...
CoinsCacheSizeState GetCoinsCacheSizeState() EXCLUSIVE_LOCKS_REQUIRED(CoinsCacheSizeState GetCoinsCacheSizeState(size_t max_coins_cache_size_bytes, size_t max_mempool_size_bytes) EXCLUSIVE_LOCKS_REQUIRED(std::string ToString() EXCLUSIVE_LOCKS_REQUIRED(RecursiveMutex * MempoolMutex() const LOCK_RETURNED(m_mempool -> cs)
Indirection necessary to make lock annotations work with an optional mempool.
Interface for managing multiple Chainstate objects, where each chainstate is associated with chainsta...
kernel::ChainstateManagerOpts Options
Chainstate * HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Return historical chainstate targeting a specific block, if any.
SnapshotCompletionResult MaybeValidateSnapshot(Chainstate &validated_cs, Chainstate &unvalidated_cs) EXCLUSIVE_LOCKS_REQUIRED(Chainstate CurrentChainstate)() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Return current chainstate targeting the most-work, network tip.
bool IsInitialBlockDownload() const noexcept
Check whether we are doing an initial block download (synchronizing from disk or network).
size_t m_total_coinstip_cache
RecursiveMutex & GetMutex() const LOCK_RETURNED(
Alias for cs_main.
CBlockIndex * ActiveTip() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
Chainstate & ActiveChainstate() const
size_t m_total_coinsdb_cache
int ActiveHeight() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
const arith_uint256 & MinimumChainWork() const
void UpdateIBDStatus() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Update and possibly latch the IBD status.
bool LoadBlockIndex() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Load the block tree and coins database from disk, initializing state if we're running with -reindex.
CChain & ActiveChain() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex())
std::atomic_bool m_cached_is_ibd
Whether initial block download (IBD) is ongoing.
void ResetBlockSequenceCounters() EXCLUSIVE_LOCKS_REQUIRED(
node::BlockManager m_blockman
CTxOut out
unspent transaction output
uint32_t nHeight
at which height this containing transaction was included in the active block chain
DisconnectedBlockTransactions.
256-bit unsigned big integer.
A base class defining functions for notifying about certain kernel events.
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
std::atomic< bool > m_importing
kernel::BlockManagerOpts Options
void assign(size_type n, const T &val)
static transaction_identifier FromUint256(const uint256 &id)
static const uint256 ZERO
static std::optional< uint256 > FromHex(std::string_view str)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
BOOST_FIXTURE_TEST_SUITE(cuckoocache_tests, BasicTestingSetup)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
static const unsigned int MAX_DISCONNECTED_TX_POOL_BYTES
Maximum bytes for transactions to store for processing during reorg.
util::Result< void > ApplyArgsManOptions(const ArgsManager &args, BlockManager::Options &opts)
std::optional< fs::path > FindAssumeutxoChainstateDir(const fs::path &data_dir)
Return a path to the snapshot-based chainstate dir, if one exists.
std::optional< uint256 > ReadSnapshotBaseBlockhash(fs::path chaindir)
bilingual_str ErrorString(const Result< T > &result)
#define BOOST_CHECK_EQUAL(v1, v2)
#define BOOST_CHECK(expr)
std::shared_ptr< const CTransaction > CTransactionRef
uint64_t ReadCompactSize(Stream &is, bool range_check=true)
Decode a CompactSize-encoded variable-length integer.
ArgsManager m_args
Test-specific arguments and settings.
Testing setup that performs all steps up until right before ChainstateManager gets initialized.
kernel::CacheSizes m_kernel_cache_sizes
bool m_block_tree_db_in_memory
Application-specific storage settings.
std::tuple< Chainstate *, Chainstate * > SetupSnapshot()
ChainstateManager & SimulateNodeRestart()
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
void mineBlocks(int num_blocks)
Mine a series of new blocks on the active chain.
std::vector< CTransactionRef > m_coinbase_txns
TestChain100Setup(ChainType chain_type=ChainType::REGTEST, TestOpts={})
Testing setup that configures a complete environment.
std::chrono::seconds max_tip_age
If the tip is older than this, the node is considered to be in initial block download.
Notifications & notifications
const CChainParams & chainparams
#define WITH_LOCK(cs, code)
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.
#define ASSERT_DEBUG_LOG(message)
transaction_identifier< false > Txid
Txid commits to all transaction fields except the witness.
consteval auto _(util::TranslatedLiteral str)
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
T Now()
Return the current time point cast to the given precision.
@ VALIDATED
Every block in the chain has been validated.
@ UNVALIDATED
Blocks after an assumeutxo snapshot have been validated but the snapshot itself has not been validate...
@ INVALID
The assumeutxo snapshot failed validation.
BOOST_FIXTURE_TEST_CASE(chainstatemanager, TestChain100Setup)
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.
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.