MCPcopy Create free account
hub / github.com/bitcoin/bitcoin / SimulationTest

Method SimulationTest

src/test/coins_tests.cpp:123–283  ·  view source on GitHub ↗

This is a large randomized insert/remove simulation test on a variable-size stack of caches on top of CCoinsViewTest. It will randomly create/update/delete Coin entries to a tip of caches, with txids picked from a limited list of random 256-bit hashes. Occasionally, a new tip is added to the stack of caches, or the tip is flushed and removed. During the process, booleans are kept to make sure th

Source from the content-addressed store, hash-verified

121// otherwise we'll hit an assertion in BatchWrite.
122//
123void SimulationTest(CCoinsView* base, bool fake_best_block)
124{
125 // Various coverage trackers.
126 bool removed_all_caches = false;
127 bool reached_4_caches = false;
128 bool added_an_entry = false;
129 bool added_an_unspendable_entry = false;
130 bool removed_an_entry = false;
131 bool updated_an_entry = false;
132 bool found_an_entry = false;
133 bool missed_an_entry = false;
134 bool uncached_an_entry = false;
135 bool flushed_without_erase = false;
136
137 // A simple map to track what we expect the cache stack to represent.
138 std::map<COutPoint, Coin> result;
139
140 // The cache stack.
141 std::vector<std::unique_ptr<CCoinsViewCacheTest>> stack; // A stack of CCoinsViewCaches on top.
142 stack.push_back(std::make_unique<CCoinsViewCacheTest>(base)); // Start with one cache.
143
144 // Use a limited set of random transaction ids, so we do test overwriting entries.
145 std::vector<Txid> txids;
146 txids.resize(NUM_SIMULATION_ITERATIONS / 8);
147 for (unsigned int i = 0; i < txids.size(); i++) {
148 txids[i] = Txid::FromUint256(m_rng.rand256());
149 }
150
151 for (unsigned int i = 0; i < NUM_SIMULATION_ITERATIONS; i++) {
152 // Do a random modification.
153 {
154 auto txid = txids[m_rng.randrange(txids.size())]; // txid we're going to modify in this iteration.
155 Coin& coin = result[COutPoint(txid, 0)];
156
157 // Determine whether to test HaveCoin before or after Access* (or both). As these functions
158 // can influence each other's behaviour by pulling things into the cache, all combinations
159 // are tested.
160 bool test_havecoin_before = m_rng.randbits(2) == 0;
161 bool test_havecoin_after = m_rng.randbits(2) == 0;
162
163 bool result_havecoin = test_havecoin_before ? stack.back()->HaveCoin(COutPoint(txid, 0)) : false;
164
165 // Infrequently, test usage of AccessByTxid instead of AccessCoin - the
166 // former just delegates to the latter and returns the first unspent in a txn.
167 const Coin& entry = (m_rng.randrange(500) == 0) ?
168 AccessByTxid(*stack.back(), txid) : stack.back()->AccessCoin(COutPoint(txid, 0));
169 BOOST_CHECK(coin == entry);
170
171 if (test_havecoin_before) {
172 BOOST_CHECK(result_havecoin == !entry.IsSpent());
173 }
174
175 if (test_havecoin_after) {
176 bool ret = stack.back()->HaveCoin(COutPoint(txid, 0));
177 BOOST_CHECK(ret == !entry.IsSpent());
178 }
179
180 if (m_rng.randrange(5) == 0 || coin.IsSpent()) {

Callers

nothing calls this directly

Calls 15

RandMoneyFunction · 0.85
rand256Method · 0.80
randrangeMethod · 0.80
randbitsMethod · 0.80
IsUnspendableMethod · 0.80
randboolMethod · 0.80
AddCoinMethod · 0.80
SpendCoinMethod · 0.80
rand32Method · 0.80
UncacheMethod · 0.80
HaveCoinInCacheMethod · 0.80

Tested by

no test coverage detected