Line data Source code
1 : // Copyright (c) 2018-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 <boost/test/unit_test.hpp>
6 :
7 : #include <chainparams.h>
8 : #include <consensus/merkle.h>
9 : #include <consensus/validation.h>
10 : #include <miner.h>
11 : #include <pow.h>
12 : #include <random.h>
13 : #include <script/standard.h>
14 : #include <test/util/setup_common.h>
15 : #include <util/time.h>
16 : #include <validation.h>
17 : #include <validationinterface.h>
18 :
19 : #include <thread>
20 :
21 89 : static const std::vector<unsigned char> V_OP_TRUE{OP_TRUE};
22 :
23 : namespace validation_block_tests {
24 6 : struct MinerTestingSetup : public RegTestingSetup {
25 : std::shared_ptr<CBlock> Block(const uint256& prev_hash);
26 : std::shared_ptr<const CBlock> GoodBlock(const uint256& prev_hash);
27 : std::shared_ptr<const CBlock> BadBlock(const uint256& prev_hash);
28 : std::shared_ptr<CBlock> FinalizeBlock(std::shared_ptr<CBlock> pblock);
29 : void BuildChain(const uint256& root, int height, const unsigned int invalid_rate, const unsigned int branch_rate, const unsigned int max_size, std::vector<std::shared_ptr<const CBlock>>& blocks);
30 : };
31 : } // namespace validation_block_tests
32 :
33 89 : BOOST_FIXTURE_TEST_SUITE(validation_block_tests, MinerTestingSetup)
34 :
35 : struct TestSubscriber final : public CValidationInterface {
36 : uint256 m_expected_tip;
37 :
38 2 : explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
39 :
40 26 : void UpdatedBlockTip(const CBlockIndex* pindexNew, const CBlockIndex* pindexFork, bool fInitialDownload) override
41 : {
42 26 : BOOST_CHECK_EQUAL(m_expected_tip, pindexNew->GetBlockHash());
43 26 : }
44 :
45 26 : void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override
46 : {
47 26 : BOOST_CHECK_EQUAL(m_expected_tip, block->hashPrevBlock);
48 26 : BOOST_CHECK_EQUAL(m_expected_tip, pindex->pprev->GetBlockHash());
49 :
50 26 : m_expected_tip = block->GetHash();
51 26 : }
52 :
53 0 : void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override
54 : {
55 0 : BOOST_CHECK_EQUAL(m_expected_tip, block->GetHash());
56 0 : BOOST_CHECK_EQUAL(m_expected_tip, pindex->GetBlockHash());
57 :
58 0 : m_expected_tip = block->hashPrevBlock;
59 0 : }
60 : };
61 :
62 932 : std::shared_ptr<CBlock> MinerTestingSetup::Block(const uint256& prev_hash)
63 : {
64 : static int i = 0;
65 932 : static uint64_t time = Params().GenesisBlock().nTime;
66 :
67 932 : CScript pubKey;
68 932 : pubKey << i++ << OP_TRUE;
69 :
70 932 : auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(pubKey);
71 932 : auto pblock = std::make_shared<CBlock>(ptemplate->block);
72 932 : pblock->hashPrevBlock = prev_hash;
73 932 : pblock->nTime = ++time;
74 :
75 932 : pubKey.clear();
76 : {
77 932 : WitnessV0ScriptHash witness_program;
78 932 : CSHA256().Write(&V_OP_TRUE[0], V_OP_TRUE.size()).Finalize(witness_program.begin());
79 932 : pubKey << OP_0 << ToByteVector(witness_program);
80 932 : }
81 :
82 : // Make the coinbase transaction with two outputs:
83 : // One zero-value one that has a unique pubkey to make sure that blocks at the same height can have a different hash
84 : // Another one that has the coinbase reward in a P2WSH with OP_TRUE as witness program to make it easy to spend
85 932 : CMutableTransaction txCoinbase(*pblock->vtx[0]);
86 932 : txCoinbase.vout.resize(2);
87 932 : txCoinbase.vout[1].scriptPubKey = pubKey;
88 932 : txCoinbase.vout[1].nValue = txCoinbase.vout[0].nValue;
89 932 : txCoinbase.vout[0].nValue = 0;
90 932 : txCoinbase.vin[0].scriptWitness.SetNull();
91 932 : pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
92 :
93 : return pblock;
94 932 : }
95 :
96 932 : std::shared_ptr<CBlock> MinerTestingSetup::FinalizeBlock(std::shared_ptr<CBlock> pblock)
97 : {
98 932 : LOCK(cs_main); // For LookupBlockIndex
99 932 : GenerateCoinbaseCommitment(*pblock, LookupBlockIndex(pblock->hashPrevBlock), Params().GetConsensus());
100 :
101 932 : pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
102 :
103 1894 : while (!CheckProofOfWork(pblock->GetHash(), pblock->nBits, Params().GetConsensus())) {
104 962 : ++(pblock->nNonce);
105 : }
106 :
107 932 : return pblock;
108 932 : }
109 :
110 : // construct a valid block
111 895 : std::shared_ptr<const CBlock> MinerTestingSetup::GoodBlock(const uint256& prev_hash)
112 : {
113 895 : return FinalizeBlock(Block(prev_hash));
114 0 : }
115 :
116 : // construct an invalid block (but with a valid header)
117 37 : std::shared_ptr<const CBlock> MinerTestingSetup::BadBlock(const uint256& prev_hash)
118 : {
119 37 : auto pblock = Block(prev_hash);
120 :
121 37 : CMutableTransaction coinbase_spend;
122 37 : coinbase_spend.vin.push_back(CTxIn(COutPoint(pblock->vtx[0]->GetHash(), 0), CScript(), 0));
123 37 : coinbase_spend.vout.push_back(pblock->vtx[0]->vout[0]);
124 :
125 37 : CTransactionRef tx = MakeTransactionRef(coinbase_spend);
126 37 : pblock->vtx.push_back(tx);
127 :
128 37 : auto ret = FinalizeBlock(pblock);
129 37 : return ret;
130 37 : }
131 :
132 174 : void MinerTestingSetup::BuildChain(const uint256& root, int height, const unsigned int invalid_rate, const unsigned int branch_rate, const unsigned int max_size, std::vector<std::shared_ptr<const CBlock>>& blocks)
133 : {
134 174 : if (height <= 0 || blocks.size() >= max_size) return;
135 :
136 174 : bool gen_invalid = InsecureRandRange(100) < invalid_rate;
137 174 : bool gen_fork = InsecureRandRange(100) < branch_rate;
138 :
139 174 : const std::shared_ptr<const CBlock> pblock = gen_invalid ? BadBlock(root) : GoodBlock(root);
140 174 : blocks.push_back(pblock);
141 174 : if (!gen_invalid) {
142 137 : BuildChain(pblock->GetHash(), height - 1, invalid_rate, branch_rate, max_size, blocks);
143 137 : }
144 :
145 174 : if (gen_fork) {
146 19 : blocks.push_back(GoodBlock(root));
147 19 : BuildChain(blocks.back()->GetHash(), height - 1, invalid_rate, branch_rate, max_size, blocks);
148 19 : }
149 174 : }
150 :
151 95 : BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
152 : {
153 : // build a large-ish chain that's likely to have some forks
154 1 : std::vector<std::shared_ptr<const CBlock>> blocks;
155 19 : while (blocks.size() < 50) {
156 18 : blocks.clear();
157 18 : BuildChain(Params().GenesisBlock().GetHash(), 100, 15, 10, 500, blocks);
158 : }
159 :
160 1 : bool ignored;
161 1 : BlockValidationState state;
162 1 : std::vector<CBlockHeader> headers;
163 58 : std::transform(blocks.begin(), blocks.end(), std::back_inserter(headers), [](std::shared_ptr<const CBlock> b) { return b->GetBlockHeader(); });
164 :
165 : // Process all the headers so we understand the toplogy of the chain
166 2 : BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlockHeaders(headers, state, Params()));
167 :
168 : // Connect the genesis block and drain any outstanding events
169 2 : BOOST_CHECK(Assert(m_node.chainman)->ProcessNewBlock(Params(), std::make_shared<CBlock>(Params().GenesisBlock()), true, &ignored));
170 1 : SyncWithValidationInterfaceQueue();
171 :
172 : // subscribe to events (this subscriber will validate event ordering)
173 : const CBlockIndex* initial_tip = nullptr;
174 : {
175 1 : LOCK(cs_main);
176 1 : initial_tip = ::ChainActive().Tip();
177 1 : }
178 1 : auto sub = std::make_shared<TestSubscriber>(initial_tip->GetBlockHash());
179 1 : RegisterSharedValidationInterface(sub);
180 :
181 : // create a bunch of threads that repeatedly process a block generated above at random
182 : // this will create parallelism and randomness inside validation - the ValidationInterface
183 : // will subscribe to events generated during block validation and assert on ordering invariance
184 1 : std::vector<std::thread> threads;
185 11 : for (int i = 0; i < 10; i++) {
186 20 : threads.emplace_back([&]() {
187 10 : bool ignored;
188 10 : FastRandomContext insecure;
189 10010 : for (int i = 0; i < 1000; i++) {
190 10000 : auto block = blocks[insecure.randrange(blocks.size() - 1)];
191 20000 : Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, &ignored);
192 10000 : }
193 :
194 : // to make sure that eventually we process the full chain - do it here
195 580 : for (auto block : blocks) {
196 570 : if (block->vtx.size() == 1) {
197 960 : bool processed = Assert(m_node.chainman)->ProcessNewBlock(Params(), block, true, &ignored);
198 480 : assert(processed);
199 480 : }
200 570 : }
201 10 : });
202 : }
203 :
204 11 : for (auto& t : threads) {
205 10 : t.join();
206 : }
207 1 : SyncWithValidationInterfaceQueue();
208 :
209 1 : UnregisterSharedValidationInterface(sub);
210 :
211 1 : LOCK(cs_main);
212 1 : BOOST_CHECK_EQUAL(sub->m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
213 1 : }
214 :
215 : /**
216 : * Test that mempool updates happen atomically with reorgs.
217 : *
218 : * This prevents RPC clients, among others, from retrieving immediately-out-of-date mempool data
219 : * during large reorgs.
220 : *
221 : * The test verifies this by creating a chain of `num_txs` blocks, matures their coinbases, and then
222 : * submits txns spending from their coinbase to the mempool. A fork chain is then processed,
223 : * invalidating the txns and evicting them from the mempool.
224 : *
225 : * We verify that the mempool updates atomically by polling it continuously
226 : * from another thread during the reorg and checking that its size only changes
227 : * once. The size changing exactly once indicates that the polling thread's
228 : * view of the mempool is either consistent with the chain state before reorg,
229 : * or consistent with the chain state after the reorg, and not just consistent
230 : * with some intermediate state during the reorg.
231 : */
232 95 : BOOST_AUTO_TEST_CASE(mempool_locks_reorg)
233 : {
234 1 : bool ignored;
235 741 : auto ProcessBlock = [&](std::shared_ptr<const CBlock> block) -> bool {
236 1480 : return Assert(m_node.chainman)->ProcessNewBlock(Params(), block, /* fForceProcessing */ true, /* fNewBlock */ &ignored);
237 0 : };
238 :
239 : // Process all mined blocks
240 1 : BOOST_REQUIRE(ProcessBlock(std::make_shared<CBlock>(Params().GenesisBlock())));
241 1 : auto last_mined = GoodBlock(Params().GenesisBlock().GetHash());
242 1 : BOOST_REQUIRE(ProcessBlock(last_mined));
243 :
244 : // Run the test multiple times
245 4 : for (int test_runs = 3; test_runs > 0; --test_runs) {
246 3 : BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
247 :
248 : // Later on split from here
249 3 : const uint256 split_hash{last_mined->hashPrevBlock};
250 :
251 : // Create a bunch of transactions to spend the miner rewards of the
252 : // most recent blocks
253 3 : std::vector<CTransactionRef> txs;
254 69 : for (int num_txs = 22; num_txs > 0; --num_txs) {
255 66 : CMutableTransaction mtx;
256 66 : mtx.vin.push_back(CTxIn{COutPoint{last_mined->vtx[0]->GetHash(), 1}, CScript{}});
257 66 : mtx.vin[0].scriptWitness.stack.push_back(V_OP_TRUE);
258 66 : mtx.vout.push_back(last_mined->vtx[0]->vout[1]);
259 66 : mtx.vout[0].nValue -= 1000;
260 66 : txs.push_back(MakeTransactionRef(mtx));
261 :
262 66 : last_mined = GoodBlock(last_mined->GetHash());
263 66 : BOOST_REQUIRE(ProcessBlock(last_mined));
264 66 : }
265 :
266 : // Mature the inputs of the txs
267 303 : for (int j = COINBASE_MATURITY; j > 0; --j) {
268 300 : last_mined = GoodBlock(last_mined->GetHash());
269 300 : BOOST_REQUIRE(ProcessBlock(last_mined));
270 : }
271 :
272 : // Mine a reorg (and hold it back) before adding the txs to the mempool
273 3 : const uint256 tip_init{last_mined->GetHash()};
274 :
275 3 : std::vector<std::shared_ptr<const CBlock>> reorg;
276 3 : last_mined = GoodBlock(split_hash);
277 3 : reorg.push_back(last_mined);
278 372 : for (size_t j = COINBASE_MATURITY + txs.size() + 1; j > 0; --j) {
279 369 : last_mined = GoodBlock(last_mined->GetHash());
280 369 : reorg.push_back(last_mined);
281 : }
282 :
283 : // Add the txs to the tx pool
284 : {
285 3 : LOCK(cs_main);
286 3 : TxValidationState state;
287 3 : std::list<CTransactionRef> plTxnReplaced;
288 69 : for (const auto& tx : txs) {
289 66 : BOOST_REQUIRE(AcceptToMemoryPool(
290 : *m_node.mempool,
291 : state,
292 : tx,
293 : &plTxnReplaced,
294 : /* bypass_limits */ false,
295 : /* nAbsurdFee */ 0));
296 : }
297 3 : }
298 :
299 : // Check that all txs are in the pool
300 : {
301 3 : LOCK(m_node.mempool->cs);
302 3 : BOOST_CHECK_EQUAL(m_node.mempool->mapTx.size(), txs.size());
303 3 : }
304 :
305 : // Run a thread that simulates an RPC caller that is polling while
306 : // validation is doing a reorg
307 6 : std::thread rpc_thread{[&]() {
308 : // This thread is checking that the mempool either contains all of
309 : // the transactions invalidated by the reorg, or none of them, and
310 : // not some intermediate amount.
311 3 : while (true) {
312 6092758 : LOCK(m_node.mempool->cs);
313 6092758 : if (m_node.mempool->mapTx.size() == 0) {
314 : // We are done with the reorg
315 3 : break;
316 : }
317 : // Internally, we might be in the middle of the reorg, but
318 : // externally the reorg to the most-proof-of-work chain should
319 : // be atomic. So the caller assumes that the returned mempool
320 : // is consistent. That is, it has all txs that were there
321 : // before the reorg.
322 6092755 : assert(m_node.mempool->mapTx.size() == txs.size());
323 6092755 : continue;
324 6092758 : }
325 3 : LOCK(cs_main);
326 : // We are done with the reorg, so the tip must have changed
327 3 : assert(tip_init != ::ChainActive().Tip()->GetBlockHash());
328 3 : }};
329 :
330 : // Submit the reorg in this thread to invalidate and remove the txs from the tx pool
331 375 : for (const auto& b : reorg) {
332 372 : ProcessBlock(b);
333 : }
334 : // Check that the reorg was eventually successful
335 3 : BOOST_CHECK_EQUAL(last_mined->GetHash(), ::ChainActive().Tip()->GetBlockHash());
336 :
337 : // We can join the other thread, which returns when the reorg was successful
338 3 : rpc_thread.join();
339 3 : }
340 1 : }
341 :
342 95 : BOOST_AUTO_TEST_CASE(witness_commitment_index)
343 : {
344 1 : CScript pubKey;
345 1 : pubKey << 1 << OP_TRUE;
346 1 : auto ptemplate = BlockAssembler(*m_node.mempool, Params()).CreateNewBlock(pubKey);
347 1 : CBlock pblock = ptemplate->block;
348 :
349 1 : CTxOut witness;
350 1 : witness.scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT);
351 1 : witness.scriptPubKey[0] = OP_RETURN;
352 1 : witness.scriptPubKey[1] = 0x24;
353 1 : witness.scriptPubKey[2] = 0xaa;
354 1 : witness.scriptPubKey[3] = 0x21;
355 1 : witness.scriptPubKey[4] = 0xa9;
356 1 : witness.scriptPubKey[5] = 0xed;
357 :
358 : // A witness larger than the minimum size is still valid
359 1 : CTxOut min_plus_one = witness;
360 1 : min_plus_one.scriptPubKey.resize(MINIMUM_WITNESS_COMMITMENT + 1);
361 :
362 1 : CTxOut invalid = witness;
363 1 : invalid.scriptPubKey[0] = OP_VERIFY;
364 :
365 1 : CMutableTransaction txCoinbase(*pblock.vtx[0]);
366 1 : txCoinbase.vout.resize(4);
367 1 : txCoinbase.vout[0] = witness;
368 1 : txCoinbase.vout[1] = witness;
369 1 : txCoinbase.vout[2] = min_plus_one;
370 1 : txCoinbase.vout[3] = invalid;
371 1 : pblock.vtx[0] = MakeTransactionRef(std::move(txCoinbase));
372 :
373 1 : BOOST_CHECK_EQUAL(GetWitnessCommitmentIndex(pblock), 2);
374 1 : }
375 89 : BOOST_AUTO_TEST_SUITE_END()
|