chainstate_write_tests.cpp raw

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