5#include <chainparams.h>
31#include <boost/test/unit_test.hpp>
73 const uint256 snapshot_blockhash = active_tip->GetBlockHash();
79 c2.InitCoinsCache(8_MiB);
81 for (
const auto&
cs : manager.m_chainstates) {
82 cs->ClearBlockIndexCandidates();
85 for (
const auto&
cs : manager.m_chainstates) {
86 cs->PopulateBlockIndexCandidates();
117 m_node.validation_signals->SyncWithValidationInterfaceQueue();
122 auto& manager{*
Assert(m_node.chainman)};
124 auto& snapshot{
WITH_LOCK(
::cs_main,
return manager.AddChainstate(std::make_unique<Chainstate>(
nullptr, manager.m_blockman, manager,
uint256::ONE)))};
134 size_t max_cache = 10000;
138 std::vector<Chainstate*> chainstates;
143 chainstates.push_back(&c1);
146 c1.InitCoinsCache(8_MiB);
147 manager.MaybeRebalanceCaches();
157 chainstates.push_back(&c2);
172 c2.InitCoinsCache(8_MiB);
173 manager.MaybeRebalanceCaches();
186 auto apply{[&](
bool cached_is_ibd,
bool loading_blocks,
bool tip_exists,
bool enough_work,
bool tip_recent) {
188 chainman.ResetChainstates();
189 chainman.InitializeChainstate(m_node.mempool.get());
193 chainman.
m_cached_is_ibd.store(cached_is_ibd, std::memory_order_relaxed);
197 tip.
nTime = (recent_time - (tip_recent ? 0h : 100h)).time_since_epoch().count();
205 for (
const bool cached_is_ibd : {
false,
true}) {
206 for (
const bool loading_blocks : {
false,
true}) {
207 for (
const bool tip_exists : {
false,
true}) {
208 for (
const bool enough_work : {
false,
true}) {
209 for (
const bool tip_recent : {
false,
true}) {
210 apply(cached_is_ibd, loading_blocks, tip_exists, enough_work, tip_recent);
211 const bool expected_ibd = cached_is_ibd && (loading_blocks || !tip_exists || !enough_work || !tip_recent);
230 .coins_db_in_memory =
false,
231 .block_tree_db_in_memory =
false,
248 size_t initial_total_coins{100};
255 size_t total_coins{0};
270 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
this));
275 constexpr int snapshot_height = 110;
278 initial_total_coins += 10;
281 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
298 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
303 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
308 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
313 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
319 BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(
this));
351 int chains_tested{0};
353 for (
const auto& chainstate : chainman.m_chainstates) {
354 BOOST_TEST_MESSAGE(
"Checking coins in " << chainstate->ToString());
360 size_t total_coins{0};
377 constexpr size_t new_coins{100};
382 size_t coins_in_active{0};
383 size_t coins_in_background{0};
384 size_t coins_missing_from_background{0};
386 for (
const auto& chainstate : chainman.m_chainstates) {
387 BOOST_TEST_MESSAGE(
"Checking coins in " << chainstate->ToString());
394 (is_background ? coins_in_background : coins_in_active)++;
395 }
else if (is_background) {
396 coins_missing_from_background++;
407 BOOST_REQUIRE(!CreateAndActivateUTXOSnapshot(
this));
412 loaded_snapshot_blockhash);
413 return std::make_tuple(&validation_chainstate, &snapshot_chainstate);
424 BOOST_TEST_MESSAGE(
"Simulating node restart");
427 for (
const auto&
cs : chainman.m_chainstates) {
428 if (
cs->CanFlushToDisk())
cs->ForceFlushStateToDisk();
433 m_node.validation_signals->SyncWithValidationInterfaceQueue();
435 chainman.ResetChainstates();
441 .notifications = *
m_node.notifications,
442 .signals =
m_node.validation_signals.get(),
446 .blocks_dir =
m_args.GetBlocksDirPath(),
457 m_node.chainman = std::make_unique<ChainstateManager>(*
Assert(
m_node.shutdown_signal), chainman_opts, blockman_opts);
466 this->SetupSnapshot();
487 const int expected_assumed_valid{20};
488 const int last_assumed_valid_idx{111};
489 const int assumed_valid_start_idx = last_assumed_valid_idx - expected_assumed_valid;
500 auto reload_all_block_indexes = [&]() {
506 for (
const auto&
cs : chainman.m_chainstates) {
507 cs->ClearBlockIndexCandidates();
511 for (
const auto&
cs : chainman.m_chainstates) {
512 cs->PopulateBlockIndexCandidates();
518 reload_all_block_indexes();
527 if (i < last_assumed_valid_idx && i >= assumed_valid_start_idx) {
530 index->m_chain_tx_count = 0;
536 if (i == (assumed_valid_start_idx - 1)) {
537 validated_tip = index;
540 if (i == last_assumed_valid_idx - 1) {
541 assumed_base = index;
562 reload_all_block_indexes();
615 auto* child{m_node.chainman->ActiveChain().Tip()};
616 auto* parent{child->pprev};
617 auto* grand_parent{parent->pprev};
623 m_node.chainman->LoadBlockIndex();
655 BOOST_REQUIRE(chainstate.InvalidateBlock(state, block99));
658 for (
int i = 0; i < 2; ++i) {
659 CreateAndProcessBlock({}, coinbase_script);
666 BOOST_REQUIRE(fork_block99->
pprev == block98);
668 BOOST_REQUIRE(fork_block100->
pprev == fork_block99);
674 chainman.RecalculateBestHeader();
676 chainstate.ActivateBestChain(state);
688 BOOST_REQUIRE(chainstate.InvalidateBlock(state, block98));
706 chainman.RecalculateBestHeader();
708 chainstate.ActivateBestChain(state);
726 this->SetupSnapshot();
756 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
759 this->LoadVerifyActivateChainstate();
780 "Ensure we can mine blocks on top of the initialized snapshot chainstate");
797 this->SetupSnapshot();
806 m_node.notifications->m_shutdown_on_fatal_error =
false;
816 res =
WITH_LOCK(
::cs_main,
return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
829 res =
WITH_LOCK(
::cs_main,
return chainman.MaybeValidateSnapshot(validated_cs, active_cs));
833 fs::path snapshot_invalid_dir =
gArgs.
GetDataDirNet() /
"chainstate_snapshot_INVALID";
843 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
847 this->LoadVerifyActivateChainstate();
867 "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
877 auto chainstates = this->SetupSnapshot();
878 Chainstate& validation_chainstate = *std::get<0>(chainstates);
879 Chainstate& unvalidated_cs = *std::get<1>(chainstates);
882 m_node.notifications->m_shutdown_on_fatal_error =
false;
887 return validation_chainstate.
CoinsTip());
900 res =
WITH_LOCK(
::cs_main,
return chainman.MaybeValidateSnapshot(validation_chainstate, unvalidated_cs));
908 BOOST_CHECK(!chainman.m_chainstates[0]->SnapshotBase());
910 BOOST_CHECK(chainman.m_chainstates[1]->SnapshotBase());
913 fs::path snapshot_invalid_dir =
gArgs.
GetDataDirNet() /
"chainstate_snapshot_INVALID";
921 BOOST_TEST_MESSAGE(
"Performing Load/Verify/Activate of chainstate");
925 this->LoadVerifyActivateChainstate();
938 "Ensure we can mine blocks on top of the \"new\" IBD chainstate");
947template <
typename Options>
949 const std::vector<const char*>&
args)
951 const auto argv{
Cat({
"ignore"},
args)};
964 auto get_opts = [&](
const std::vector<const char*>&
args) {
969 .notifications = notifications};
973 auto get_valid_opts = [&](
const std::vector<const char*>&
args) {
974 const auto result{get_opts(
args)};
980 BOOST_CHECK(!get_valid_opts({}).assumed_valid_block);
986 std::string assume_valid{
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
990 BOOST_CHECK(!get_opts({
"-assumevalid=01234567890123456789012345678901234567890123456789012345678901234"}));
993 BOOST_CHECK(!get_valid_opts({}).minimum_chain_work);
998 std::string minimum_chainwork{
"0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"};
1001 BOOST_CHECK(!get_opts({
"-minimumchainwork=xyz"}));
1002 BOOST_CHECK(!get_opts({
"-minimumchainwork=01234567890123456789012345678901234567890123456789012345678901234"}));
1005 BOOST_CHECK_EQUAL(get_valid_opts({
"-prevoutfetchthreads=0"}).prevoutfetch_threads_num, 0);
1006 BOOST_CHECK_EQUAL(get_valid_opts({
"-prevoutfetchthreads=3"}).prevoutfetch_threads_num, 3);
1008 BOOST_CHECK(!get_opts({
"-prevoutfetchthreads=-1"}));
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.
constexpr int32_t DEFAULT_PREVOUTFETCH_THREADS
#define Assert(val)
Identity function.
bool ParseParameters(int argc, const char *const argv[], std::string &error) EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
fs::path GetDataDirNet() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get data directory path with appended network identifier.
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.
void SetBestBlock(const uint256 &block_hash)
unsigned int GetCacheSize() const
Size of the cache (in number of transaction outputs).
bool HaveCoin(const COutPoint &outpoint) const override
An outpoint - a combination of a transaction hash and an index n into its vout.
Serialized script, used inside transaction inputs and outputs.
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,...
bool PreciousBlock(BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(bool InvalidateBlock(BlockValidationState &state, CBlockIndex *pindex) LOCKS_EXCLUDED(void SetBlockFailureFlags(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(void ResetBlockFailureFlags(CBlockIndex *pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Mark a block as precious and reorganize.
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.
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
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.
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.
constexpr arith_uint256()=default
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()
constexpr 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
std::vector< unsigned char > ToByteVector(const T &in)
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)
#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.
constexpr int32_t MAX_PREVOUTFETCH_THREADS
Maximum number of dedicated threads allowed for prefetching block input prevouts.
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.