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