Line data Source code
1 : // Copyright (c) 2019-2020 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 <consensus/validation.h>
7 : #include <random.h>
8 : #include <sync.h>
9 : #include <test/util/setup_common.h>
10 : #include <uint256.h>
11 : #include <validation.h>
12 : #include <validationinterface.h>
13 :
14 : #include <vector>
15 :
16 : #include <boost/test/unit_test.hpp>
17 :
18 89 : BOOST_FIXTURE_TEST_SUITE(validation_chainstatemanager_tests, TestingSetup)
19 :
20 : //! Basic tests for ChainstateManager.
21 : //!
22 : //! First create a legacy (IBD) chainstate, then create a snapshot chainstate.
23 95 : BOOST_AUTO_TEST_CASE(chainstatemanager)
24 : {
25 1 : ChainstateManager manager;
26 1 : CTxMemPool mempool;
27 1 : std::vector<CChainState*> chainstates;
28 1 : const CChainParams& chainparams = Params();
29 :
30 : // Create a legacy (IBD) chainstate.
31 : //
32 2 : CChainState& c1 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool));
33 1 : chainstates.push_back(&c1);
34 1 : c1.InitCoinsDB(
35 : /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
36 2 : WITH_LOCK(::cs_main, c1.InitCoinsCache(1 << 23));
37 :
38 1 : BOOST_CHECK(!manager.IsSnapshotActive());
39 1 : BOOST_CHECK(!manager.IsSnapshotValidated());
40 1 : BOOST_CHECK(!manager.IsBackgroundIBD(&c1));
41 1 : auto all = manager.GetAll();
42 1 : BOOST_CHECK_EQUAL_COLLECTIONS(all.begin(), all.end(), chainstates.begin(), chainstates.end());
43 :
44 1 : auto& active_chain = manager.ActiveChain();
45 1 : BOOST_CHECK_EQUAL(&active_chain, &c1.m_chain);
46 :
47 1 : BOOST_CHECK_EQUAL(manager.ActiveHeight(), -1);
48 :
49 1 : auto active_tip = manager.ActiveTip();
50 1 : auto exp_tip = c1.m_chain.Tip();
51 1 : BOOST_CHECK_EQUAL(active_tip, exp_tip);
52 :
53 1 : auto& validated_cs = manager.ValidatedChainstate();
54 1 : BOOST_CHECK_EQUAL(&validated_cs, &c1);
55 :
56 : // Create a snapshot-based chainstate.
57 : //
58 2 : CChainState& c2 = *WITH_LOCK(::cs_main, return &manager.InitializeChainstate(mempool, GetRandHash()));
59 1 : chainstates.push_back(&c2);
60 1 : c2.InitCoinsDB(
61 : /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
62 2 : WITH_LOCK(::cs_main, c2.InitCoinsCache(1 << 23));
63 : // Unlike c1, which doesn't have any blocks. Gets us different tip, height.
64 1 : c2.LoadGenesisBlock(chainparams);
65 1 : BlockValidationState _;
66 1 : BOOST_CHECK(c2.ActivateBestChain(_, chainparams, nullptr));
67 :
68 1 : BOOST_CHECK(manager.IsSnapshotActive());
69 1 : BOOST_CHECK(!manager.IsSnapshotValidated());
70 1 : BOOST_CHECK(manager.IsBackgroundIBD(&c1));
71 1 : BOOST_CHECK(!manager.IsBackgroundIBD(&c2));
72 1 : auto all2 = manager.GetAll();
73 1 : BOOST_CHECK_EQUAL_COLLECTIONS(all2.begin(), all2.end(), chainstates.begin(), chainstates.end());
74 :
75 1 : auto& active_chain2 = manager.ActiveChain();
76 1 : BOOST_CHECK_EQUAL(&active_chain2, &c2.m_chain);
77 :
78 1 : BOOST_CHECK_EQUAL(manager.ActiveHeight(), 0);
79 :
80 1 : auto active_tip2 = manager.ActiveTip();
81 1 : auto exp_tip2 = c2.m_chain.Tip();
82 1 : BOOST_CHECK_EQUAL(active_tip2, exp_tip2);
83 :
84 : // Ensure that these pointers actually correspond to different
85 : // CCoinsViewCache instances.
86 1 : BOOST_CHECK(exp_tip != exp_tip2);
87 :
88 1 : auto& validated_cs2 = manager.ValidatedChainstate();
89 1 : BOOST_CHECK_EQUAL(&validated_cs2, &c1);
90 :
91 1 : auto& validated_chain = manager.ValidatedChain();
92 1 : BOOST_CHECK_EQUAL(&validated_chain, &c1.m_chain);
93 :
94 1 : auto validated_tip = manager.ValidatedTip();
95 1 : exp_tip = c1.m_chain.Tip();
96 1 : BOOST_CHECK_EQUAL(validated_tip, exp_tip);
97 :
98 : // Let scheduler events finish running to avoid accessing memory that is going to be unloaded
99 1 : SyncWithValidationInterfaceQueue();
100 :
101 2 : WITH_LOCK(::cs_main, manager.Unload());
102 1 : }
103 :
104 : //! Test rebalancing the caches associated with each chainstate.
105 95 : BOOST_AUTO_TEST_CASE(chainstatemanager_rebalance_caches)
106 : {
107 1 : ChainstateManager manager;
108 1 : CTxMemPool mempool;
109 1 : size_t max_cache = 10000;
110 1 : manager.m_total_coinsdb_cache = max_cache;
111 1 : manager.m_total_coinstip_cache = max_cache;
112 :
113 1 : std::vector<CChainState*> chainstates;
114 :
115 : // Create a legacy (IBD) chainstate.
116 : //
117 2 : CChainState& c1 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool));
118 1 : chainstates.push_back(&c1);
119 1 : c1.InitCoinsDB(
120 : /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
121 :
122 : {
123 1 : LOCK(::cs_main);
124 1 : c1.InitCoinsCache(1 << 23);
125 1 : c1.CoinsTip().SetBestBlock(InsecureRand256());
126 1 : manager.MaybeRebalanceCaches();
127 1 : }
128 :
129 1 : BOOST_CHECK_EQUAL(c1.m_coinstip_cache_size_bytes, max_cache);
130 1 : BOOST_CHECK_EQUAL(c1.m_coinsdb_cache_size_bytes, max_cache);
131 :
132 : // Create a snapshot-based chainstate.
133 : //
134 2 : CChainState& c2 = *WITH_LOCK(cs_main, return &manager.InitializeChainstate(mempool, GetRandHash()));
135 1 : chainstates.push_back(&c2);
136 1 : c2.InitCoinsDB(
137 : /* cache_size_bytes */ 1 << 23, /* in_memory */ true, /* should_wipe */ false);
138 :
139 : {
140 1 : LOCK(::cs_main);
141 1 : c2.InitCoinsCache(1 << 23);
142 1 : c2.CoinsTip().SetBestBlock(InsecureRand256());
143 1 : manager.MaybeRebalanceCaches();
144 1 : }
145 :
146 : // Since both chainstates are considered to be in initial block download,
147 : // the snapshot chainstate should take priority.
148 1 : BOOST_CHECK_CLOSE(c1.m_coinstip_cache_size_bytes, max_cache * 0.05, 1);
149 1 : BOOST_CHECK_CLOSE(c1.m_coinsdb_cache_size_bytes, max_cache * 0.05, 1);
150 1 : BOOST_CHECK_CLOSE(c2.m_coinstip_cache_size_bytes, max_cache * 0.95, 1);
151 1 : BOOST_CHECK_CLOSE(c2.m_coinsdb_cache_size_bytes, max_cache * 0.95, 1);
152 1 : }
153 :
154 89 : BOOST_AUTO_TEST_SUITE_END()
|