chainstate_write_tests.cpp raw

   1  // Copyright (c) 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 <test/util/setup_common.h>
   6  #include <test/util/time.h>
   7  #include <validation.h>
   8  #include <validationinterface.h>
   9  
  10  #include <boost/test/unit_test.hpp>
  11  
  12  using kernel::ChainstateRole;
  13  
  14  // Taken from validation.cpp
  15  static constexpr auto DATABASE_WRITE_INTERVAL_MIN{50min};
  16  static constexpr auto DATABASE_WRITE_INTERVAL_MAX{70min};
  17  
  18  BOOST_AUTO_TEST_SUITE(chainstate_write_tests)
  19  
  20  BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
  21  {
  22      struct TestSubscriber final : CValidationInterface {
  23          bool m_did_flush{false};
  24          void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
  25          {
  26              m_did_flush = true;
  27          }
  28      };
  29  
  30      const auto sub{std::make_shared<TestSubscriber>()};
  31      m_node.validation_signals->RegisterSharedValidationInterface(sub);
  32      auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
  33      BlockValidationState state_dummy{};
  34      FakeNodeClock clock{};
  35  
  36      // The first periodic flush sets m_next_write and does not flush
  37      chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
  38      m_node.validation_signals->SyncWithValidationInterfaceQueue();
  39      BOOST_CHECK(!sub->m_did_flush);
  40  
  41      // The periodic flush interval is between 50 and 70 minutes (inclusive)
  42      clock += DATABASE_WRITE_INTERVAL_MIN - 1min;
  43      chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
  44      m_node.validation_signals->SyncWithValidationInterfaceQueue();
  45      BOOST_CHECK(!sub->m_did_flush);
  46  
  47      clock += DATABASE_WRITE_INTERVAL_MAX;
  48      chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
  49      m_node.validation_signals->SyncWithValidationInterfaceQueue();
  50      BOOST_CHECK(sub->m_did_flush);
  51  }
  52  
  53  // Test that we do PERIODIC flushes inside ActivateBestChain.
  54  // This is necessary for reindex-chainstate to be able to periodically flush
  55  // before reaching chain tip.
  56  BOOST_FIXTURE_TEST_CASE(write_during_multiblock_activation, TestChain100Setup)
  57  {
  58      struct TestSubscriber final : CValidationInterface
  59      {
  60          const CBlockIndex* m_tip{nullptr};
  61          const CBlockIndex* m_flushed_at_block{nullptr};
  62          void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
  63          {
  64              m_flushed_at_block = m_tip;
  65          }
  66          void UpdatedBlockTip(const CBlockIndex* block_index, const CBlockIndex*, bool) override {
  67              m_tip = block_index;
  68          }
  69      };
  70  
  71      auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
  72      BlockValidationState state_dummy{};
  73  
  74      // Pop two blocks from the tip
  75      const CBlockIndex* tip{chainstate.m_chain.Tip()};
  76      CBlockIndex* second_from_tip{tip->pprev};
  77  
  78      {
  79          LOCK2(m_node.chainman->GetMutex(), chainstate.MempoolMutex());
  80          chainstate.DisconnectTip(state_dummy, nullptr);
  81          chainstate.DisconnectTip(state_dummy, nullptr);
  82      }
  83  
  84      BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip());
  85  
  86      // Set m_next_write to current time
  87      chainstate.FlushStateToDisk(state_dummy, FlushStateMode::FORCE_FLUSH);
  88      BOOST_CHECK_EQUAL(WITH_LOCK(::cs_main, return chainstate.GetLastFlushedBlock()), second_from_tip->pprev);
  89      m_node.validation_signals->SyncWithValidationInterfaceQueue();
  90      // The periodic flush interval is between 50 and 70 minutes (inclusive)
  91      // The next call to a PERIODIC write will flush
  92      m_clock += DATABASE_WRITE_INTERVAL_MAX;
  93  
  94      const auto sub{std::make_shared<TestSubscriber>()};
  95      m_node.validation_signals->RegisterSharedValidationInterface(sub);
  96  
  97      // ActivateBestChain back to tip
  98      chainstate.ActivateBestChain(state_dummy, nullptr);
  99      BOOST_CHECK_EQUAL(tip, chainstate.m_chain.Tip());
 100      // Check that we flushed inside ActivateBestChain while we were at the
 101      // second block from tip, since FlushStateToDisk is called with PERIODIC
 102      // inside the outer loop.
 103      m_node.validation_signals->SyncWithValidationInterfaceQueue();
 104      BOOST_CHECK_EQUAL(sub->m_flushed_at_block, second_from_tip);
 105      BOOST_CHECK_EQUAL(WITH_LOCK(::cs_main, return chainstate.GetLastFlushedBlock()), second_from_tip);
 106  }
 107  
 108  BOOST_AUTO_TEST_SUITE_END()
 109