mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-02 17:56:16 +00:00
This prepares the addition of `FORCE_SYNC`. `empty_cache` in `FlushStateToDisk` was moved up to be reusable and `FlushStateMode::FORCE_FLUSH` was used as a placeholder before we properly split the two new states. `log_utxocache_flush.py` was regenerated and the alignment adjusted for the wider `FlushStateMode` values. Co-authored-by: Pieter Wuille <pieter@wuille.net> Co-authored-by: optout <13562139+optout21@users.noreply.github.com>
105 lines
4.0 KiB
C++
105 lines
4.0 KiB
C++
// Copyright (c) The Bitcoin Core developers
|
|
// Distributed under the MIT software license, see the accompanying
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
#include <test/util/setup_common.h>
|
|
#include <validation.h>
|
|
#include <validationinterface.h>
|
|
|
|
#include <boost/test/unit_test.hpp>
|
|
|
|
using kernel::ChainstateRole;
|
|
|
|
// Taken from validation.cpp
|
|
static constexpr auto DATABASE_WRITE_INTERVAL_MIN{50min};
|
|
static constexpr auto DATABASE_WRITE_INTERVAL_MAX{70min};
|
|
|
|
BOOST_AUTO_TEST_SUITE(chainstate_write_tests)
|
|
|
|
BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
|
|
{
|
|
struct TestSubscriber final : CValidationInterface {
|
|
bool m_did_flush{false};
|
|
void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
|
|
{
|
|
m_did_flush = true;
|
|
}
|
|
};
|
|
|
|
const auto sub{std::make_shared<TestSubscriber>()};
|
|
m_node.validation_signals->RegisterSharedValidationInterface(sub);
|
|
auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
|
|
BlockValidationState state_dummy{};
|
|
|
|
// The first periodic flush sets m_next_write and does not flush
|
|
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
|
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
|
BOOST_CHECK(!sub->m_did_flush);
|
|
|
|
// The periodic flush interval is between 50 and 70 minutes (inclusive)
|
|
SetMockTime(GetTime<std::chrono::minutes>() + DATABASE_WRITE_INTERVAL_MIN - 1min);
|
|
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
|
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
|
BOOST_CHECK(!sub->m_did_flush);
|
|
|
|
SetMockTime(GetTime<std::chrono::minutes>() + DATABASE_WRITE_INTERVAL_MAX);
|
|
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
|
|
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
|
BOOST_CHECK(sub->m_did_flush);
|
|
}
|
|
|
|
// Test that we do PERIODIC flushes inside ActivateBestChain.
|
|
// This is necessary for reindex-chainstate to be able to periodically flush
|
|
// before reaching chain tip.
|
|
BOOST_FIXTURE_TEST_CASE(write_during_multiblock_activation, TestChain100Setup)
|
|
{
|
|
struct TestSubscriber final : CValidationInterface
|
|
{
|
|
const CBlockIndex* m_tip{nullptr};
|
|
const CBlockIndex* m_flushed_at_block{nullptr};
|
|
void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
|
|
{
|
|
m_flushed_at_block = m_tip;
|
|
}
|
|
void UpdatedBlockTip(const CBlockIndex* block_index, const CBlockIndex*, bool) override {
|
|
m_tip = block_index;
|
|
}
|
|
};
|
|
|
|
auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
|
|
BlockValidationState state_dummy{};
|
|
|
|
// Pop two blocks from the tip
|
|
const CBlockIndex* tip{chainstate.m_chain.Tip()};
|
|
CBlockIndex* second_from_tip{tip->pprev};
|
|
|
|
{
|
|
LOCK2(m_node.chainman->GetMutex(), chainstate.MempoolMutex());
|
|
chainstate.DisconnectTip(state_dummy, nullptr);
|
|
chainstate.DisconnectTip(state_dummy, nullptr);
|
|
}
|
|
|
|
BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip());
|
|
|
|
// Set m_next_write to current time
|
|
chainstate.FlushStateToDisk(state_dummy, FlushStateMode::FORCE_FLUSH);
|
|
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
|
// The periodic flush interval is between 50 and 70 minutes (inclusive)
|
|
// The next call to a PERIODIC write will flush
|
|
SetMockTime(GetMockTime() + DATABASE_WRITE_INTERVAL_MAX);
|
|
|
|
const auto sub{std::make_shared<TestSubscriber>()};
|
|
m_node.validation_signals->RegisterSharedValidationInterface(sub);
|
|
|
|
// ActivateBestChain back to tip
|
|
chainstate.ActivateBestChain(state_dummy, nullptr);
|
|
BOOST_CHECK_EQUAL(tip, chainstate.m_chain.Tip());
|
|
// Check that we flushed inside ActivateBestChain while we were at the
|
|
// second block from tip, since FlushStateToDisk is called with PERIODIC
|
|
// inside the outer loop.
|
|
m_node.validation_signals->SyncWithValidationInterfaceQueue();
|
|
BOOST_CHECK_EQUAL(sub->m_flushed_at_block, second_from_tip);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_SUITE_END()
|