Bitcoin Core  25.99.0
P2P Digital Currency
coinstatsindex_tests.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-2022 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <chainparams.h>
6 #include <index/coinstatsindex.h>
7 #include <interfaces/chain.h>
8 #include <kernel/coinstats.h>
10 #include <test/util/validation.h>
11 #include <util/time.h>
12 #include <validation.h>
13 
14 #include <boost/test/unit_test.hpp>
15 
16 #include <chrono>
17 
18 BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)
19 
20 static void IndexWaitSynced(BaseIndex& index)
21 {
22  // Allow the CoinStatsIndex to catch up with the block index that is syncing
23  // in a background thread.
24  const auto timeout = GetTime<std::chrono::seconds>() + 120s;
25  while (!index.BlockUntilSyncedToCurrentChain()) {
26  BOOST_REQUIRE(timeout > GetTime<std::chrono::milliseconds>());
27  UninterruptibleSleep(100ms);
28  }
29 }
30 
31 BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
32 {
33  CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
34 
35  const CBlockIndex* block_index;
36  {
37  LOCK(cs_main);
38  block_index = m_node.chainman->ActiveChain().Tip();
39  }
40 
41  // CoinStatsIndex should not be found before it is started.
42  BOOST_CHECK(!coin_stats_index.LookUpStats(*block_index));
43 
44  // BlockUntilSyncedToCurrentChain should return false before CoinStatsIndex
45  // is started.
46  BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
47 
48  BOOST_REQUIRE(coin_stats_index.Start());
49 
50  IndexWaitSynced(coin_stats_index);
51 
52  // Check that CoinStatsIndex works for genesis block.
53  const CBlockIndex* genesis_block_index;
54  {
55  LOCK(cs_main);
56  genesis_block_index = m_node.chainman->ActiveChain().Genesis();
57  }
58  BOOST_CHECK(coin_stats_index.LookUpStats(*genesis_block_index));
59 
60  // Check that CoinStatsIndex updates with new blocks.
61  BOOST_CHECK(coin_stats_index.LookUpStats(*block_index));
62 
63  const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
64  std::vector<CMutableTransaction> noTxns;
65  CreateAndProcessBlock(noTxns, script_pub_key);
66 
67  // Let the CoinStatsIndex to catch up again.
68  BOOST_CHECK(coin_stats_index.BlockUntilSyncedToCurrentChain());
69 
70  const CBlockIndex* new_block_index;
71  {
72  LOCK(cs_main);
73  new_block_index = m_node.chainman->ActiveChain().Tip();
74  }
75  BOOST_CHECK(coin_stats_index.LookUpStats(*new_block_index));
76 
77  BOOST_CHECK(block_index != new_block_index);
78 
79  // It is not safe to stop and destroy the index until it finishes handling
80  // the last BlockConnected notification. The BlockUntilSyncedToCurrentChain()
81  // call above is sufficient to ensure this, but the
82  // SyncWithValidationInterfaceQueue() call below is also needed to ensure
83  // TSAN always sees the test thread waiting for the notification thread, and
84  // avoid potential false positive reports.
86 
87  // Shutdown sequence (c.f. Shutdown() in init.cpp)
88  coin_stats_index.Stop();
89 }
90 
91 // Test shutdown between BlockConnected and ChainStateFlushed notifications,
92 // make sure index is not corrupted and is able to reload.
93 BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
94 {
95  Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate();
96  const CChainParams& params = Params();
97  {
99  BOOST_REQUIRE(index.Start());
100  IndexWaitSynced(index);
101  std::shared_ptr<const CBlock> new_block;
102  CBlockIndex* new_block_index = nullptr;
103  {
104  const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
105  const CBlock block = this->CreateBlock({}, script_pub_key, chainstate);
106 
107  new_block = std::make_shared<CBlock>(block);
108 
109  LOCK(cs_main);
110  BlockValidationState state;
111  BOOST_CHECK(CheckBlock(block, state, params.GetConsensus()));
112  BOOST_CHECK(chainstate.AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr, true));
113  CCoinsViewCache view(&chainstate.CoinsTip());
114  BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view));
115  }
116  // Send block connected notification, then stop the index without
117  // sending a chainstate flushed notification. Prior to #24138, this
118  // would cause the index to be corrupted and fail to reload.
119  ValidationInterfaceTest::BlockConnected(index, new_block, new_block_index);
120  index.Stop();
121  }
122 
123  {
125  // Make sure the index can be loaded.
126  BOOST_REQUIRE(index.Start());
127  index.Stop();
128  }
129 }
130 
node::NodeContext m_node
Definition: bitcoin-gui.cpp:37
const CChainParams & Params()
Return the currently selected parameters.
#define Assert(val)
Identity function.
Definition: check.h:73
Base class for indices of blockchain data.
Definition: base.h:34
Definition: block.h:69
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:151
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:77
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:89
CCoinsView that adds a memory cache for transactions to another CCoinsView.
Definition: coins.h:230
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:411
Chainstate stores and provides an API to update our local knowledge of the current best chain.
Definition: validation.h:459
DisconnectResult DisconnectBlock(const CBlock &block, const CBlockIndex *pindex, CCoinsViewCache &view) EXCLUSIVE_LOCKS_REQUIRED(boo ConnectBlock)(const CBlock &block, BlockValidationState &state, CBlockIndex *pindex, CCoinsViewCache &view, bool fJustCheck=false) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Apply the effects of this block (with given index) on the UTXO set represented by coins.
Definition: validation.h:703
bool ActivateBestChain(BlockValidationState &state, std::shared_ptr< const CBlock > pblock=nullptr) LOCKS_EXCLUDED(bool AcceptBlock(const std::shared_ptr< const CBlock > &pblock, BlockValidationState &state, CBlockIndex **ppindex, bool fRequested, const FlatFilePos *dbp, bool *fNewBlock, bool min_pow_checked) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Find the best known block, and make it the tip of the block chain.
Definition: validation.h:698
CCoinsViewCache & CoinsTip() EXCLUSIVE_LOCKS_REQUIRED(
Definition: validation.h:571
CoinStatsIndex maintains statistics on the UTXO set.
static void BlockConnected(CValidationInterface &obj, const std::shared_ptr< const CBlock > &block, const CBlockIndex *pindex)
Definition: validation.cpp:25
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
static void IndexWaitSynced(BaseIndex &index)
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
BOOST_AUTO_TEST_SUITE(cuckoocache_tests)
Test Suite for CuckooCache.
BOOST_AUTO_TEST_SUITE_END()
std::unique_ptr< Chain > MakeChain(node::NodeContext &node)
Return implementation of Chain interface.
Definition: interfaces.cpp:799
#define BOOST_CHECK(expr)
Definition: object.cpp:17
std::vector< unsigned char > ToByteVector(const T &in)
Definition: script.h:63
@ OP_CHECKSIG
Definition: script.h:186
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
Definition: setup_common.h:129
std::unique_ptr< ChainstateManager > chainman
Definition: context.h:56
#define LOCK(cs)
Definition: sync.h:258
void UninterruptibleSleep(const std::chrono::microseconds &n)
Definition: time.cpp:23
bool CheckBlock(const CBlock &block, BlockValidationState &state, const Consensus::Params &consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
Functions for validating blocks and updating the block tree.
void SyncWithValidationInterfaceQueue()
This is a synonym for the following, which asserts certain locks are not held: std::promise<void> pro...