mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-02-07 06:01:22 +00:00
Change ChainstateRole parameter passed to wallets and indexes. Wallets and indexes need to know whether chainstate is historical and whether it is fully validated. They should not be aware of the assumeutxo snapshot validation process.
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::ALWAYS);
|
|
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()
|