coinstatsindex_tests.cpp raw
1 // Copyright (c) 2020-present 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 <chain.h>
6 #include <chainparams.h>
7 #include <coins.h>
8 #include <consensus/validation.h>
9 #include <index/coinstatsindex.h>
10 #include <interfaces/chain.h>
11 #include <kernel/coinstats.h>
12 #include <kernel/types.h>
13 #include <key.h>
14 #include <primitives/block.h>
15 #include <primitives/transaction.h>
16 #include <script/script.h>
17 #include <sync.h>
18 #include <test/util/setup_common.h>
19 #include <test/util/validation.h>
20 #include <util/check.h>
21 #include <validation.h>
22
23 #include <boost/test/unit_test.hpp>
24
25 #include <memory>
26 #include <optional>
27 #include <span>
28 #include <vector>
29
30 using kernel::ChainstateRole;
31
32 BOOST_AUTO_TEST_SUITE(coinstatsindex_tests)
33
34 BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
35 {
36 CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1_MiB, true};
37 BOOST_REQUIRE(coin_stats_index.Init());
38
39 const CBlockIndex* block_index;
40 {
41 LOCK(cs_main);
42 block_index = m_node.chainman->ActiveChain().Tip();
43 }
44
45 // CoinStatsIndex should not be found before it is started.
46 BOOST_CHECK(!coin_stats_index.LookUpStats(*block_index));
47
48 // BlockUntilSyncedToCurrentChain should return false before CoinStatsIndex
49 // is started.
50 BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
51
52 coin_stats_index.Sync();
53
54 // Check that CoinStatsIndex works for genesis block.
55 const CBlockIndex* genesis_block_index;
56 {
57 LOCK(cs_main);
58 genesis_block_index = m_node.chainman->ActiveChain().Genesis();
59 }
60 BOOST_CHECK(coin_stats_index.LookUpStats(*genesis_block_index));
61
62 // Check that CoinStatsIndex updates with new blocks.
63 BOOST_CHECK(coin_stats_index.LookUpStats(*block_index));
64
65 const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
66 std::vector<CMutableTransaction> noTxns;
67 CreateAndProcessBlock(noTxns, script_pub_key);
68
69 // Let the CoinStatsIndex to catch up again.
70 BOOST_CHECK(coin_stats_index.BlockUntilSyncedToCurrentChain());
71
72 const CBlockIndex* new_block_index;
73 {
74 LOCK(cs_main);
75 new_block_index = m_node.chainman->ActiveChain().Tip();
76 }
77 BOOST_CHECK(coin_stats_index.LookUpStats(*new_block_index));
78
79 BOOST_CHECK(block_index != new_block_index);
80
81 // Shutdown sequence (c.f. Shutdown() in init.cpp)
82 coin_stats_index.Stop();
83 }
84
85 // Test shutdown between BlockConnected and ChainStateFlushed notifications,
86 // make sure index is not corrupted and is able to reload.
87 BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
88 {
89 Chainstate& chainstate = Assert(m_node.chainman)->ActiveChainstate();
90 const CChainParams& params = Params();
91 {
92 CoinStatsIndex index{interfaces::MakeChain(m_node), 1_MiB};
93 BOOST_REQUIRE(index.Init());
94 index.Sync();
95 std::shared_ptr<const CBlock> new_block;
96 CBlockIndex* new_block_index = nullptr;
97 {
98 const CScript script_pub_key{CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG};
99 const CBlock block = this->CreateBlock({}, script_pub_key);
100
101 new_block = std::make_shared<CBlock>(block);
102
103 LOCK(cs_main);
104 BlockValidationState state;
105 BOOST_CHECK(CheckBlock(block, state, params.GetConsensus()));
106 BOOST_CHECK(m_node.chainman->AcceptBlock(new_block, state, &new_block_index, true, nullptr, nullptr, true));
107 CCoinsViewCache view(&chainstate.CoinsTip());
108 BOOST_CHECK(chainstate.ConnectBlock(block, state, new_block_index, view));
109 }
110 // Send block connected notification, then stop the index without
111 // sending a chainstate flushed notification. Prior to #24138, this
112 // would cause the index to be corrupted and fail to reload.
113 ValidationInterfaceTest::BlockConnected(ChainstateRole{}, index, new_block, new_block_index);
114 index.Stop();
115 }
116
117 {
118 CoinStatsIndex index{interfaces::MakeChain(m_node), 1_MiB};
119 BOOST_REQUIRE(index.Init());
120 // Make sure the index can be loaded.
121 BOOST_REQUIRE(index.StartBackgroundSync());
122 index.Stop();
123 }
124 }
125
126 BOOST_AUTO_TEST_SUITE_END()
127