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