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 <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 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(chainstate_write_interval, TestingSetup)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
21 : : {
22 : 2 : struct TestSubscriber final : CValidationInterface {
23 : : bool m_did_flush{false};
24 : 1 : void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
25 : : {
26 : 1 : m_did_flush = true;
27 : 1 : }
28 : : };
29 : :
30 : 1 : const auto sub{std::make_shared<TestSubscriber>()};
31 [ + - + - ]: 2 : m_node.validation_signals->RegisterSharedValidationInterface(sub);
32 [ - + + - ]: 1 : auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
33 [ + - ]: 1 : BlockValidationState state_dummy{};
34 [ + - ]: 1 : NodeClockContext clock_ctx{};
35 : :
36 : : // The first periodic flush sets m_next_write and does not flush
37 [ + - ]: 1 : chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
38 [ + - ]: 1 : m_node.validation_signals->SyncWithValidationInterfaceQueue();
39 [ + - + - ]: 1 : BOOST_CHECK(!sub->m_did_flush);
40 : :
41 : : // The periodic flush interval is between 50 and 70 minutes (inclusive)
42 [ + - ]: 1 : clock_ctx += DATABASE_WRITE_INTERVAL_MIN - 1min;
43 [ + - ]: 1 : chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
44 [ + - ]: 1 : m_node.validation_signals->SyncWithValidationInterfaceQueue();
45 [ + - + - : 2 : BOOST_CHECK(!sub->m_did_flush);
+ - ]
46 : :
47 [ + - ]: 1 : clock_ctx += DATABASE_WRITE_INTERVAL_MAX;
48 [ + - ]: 1 : chainstate.FlushStateToDisk(state_dummy, FlushStateMode::PERIODIC);
49 [ + - ]: 1 : m_node.validation_signals->SyncWithValidationInterfaceQueue();
50 [ + - + - ]: 2 : BOOST_CHECK(sub->m_did_flush);
51 [ + - ]: 2 : }
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 [ + - + - : 7 : BOOST_FIXTURE_TEST_CASE(write_during_multiblock_activation, TestChain100Setup)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
57 : : {
58 : 2 : struct TestSubscriber final : CValidationInterface
59 : : {
60 : : const CBlockIndex* m_tip{nullptr};
61 : : const CBlockIndex* m_flushed_at_block{nullptr};
62 : 1 : void ChainStateFlushed(const ChainstateRole&, const CBlockLocator&) override
63 : : {
64 : 1 : m_flushed_at_block = m_tip;
65 : 1 : }
66 : 2 : void UpdatedBlockTip(const CBlockIndex* block_index, const CBlockIndex*, bool) override {
67 : 2 : m_tip = block_index;
68 : 2 : }
69 : : };
70 : :
71 [ - + ]: 1 : auto& chainstate{Assert(m_node.chainman)->ActiveChainstate()};
72 [ - + ]: 1 : BlockValidationState state_dummy{};
73 : :
74 : : // Pop two blocks from the tip
75 [ - + ]: 1 : const CBlockIndex* tip{chainstate.m_chain.Tip()};
76 : 1 : CBlockIndex* second_from_tip{tip->pprev};
77 : :
78 : 1 : {
79 [ + - + - : 2 : LOCK2(m_node.chainman->GetMutex(), chainstate.MempoolMutex());
+ - ]
80 [ + - ]: 1 : chainstate.DisconnectTip(state_dummy, nullptr);
81 [ + - ]: 1 : chainstate.DisconnectTip(state_dummy, nullptr);
82 [ + - ]: 1 : }
83 : :
84 [ + - - + : 2 : BOOST_CHECK_EQUAL(second_from_tip->pprev, chainstate.m_chain.Tip());
+ - ]
85 : :
86 : : // Set m_next_write to current time
87 [ + - ]: 1 : chainstate.FlushStateToDisk(state_dummy, FlushStateMode::FORCE_FLUSH);
88 [ + - ]: 1 : m_node.validation_signals->SyncWithValidationInterfaceQueue();
89 : : // The periodic flush interval is between 50 and 70 minutes (inclusive)
90 : : // The next call to a PERIODIC write will flush
91 [ + - + - ]: 1 : SetMockTime(GetMockTime() + DATABASE_WRITE_INTERVAL_MAX);
92 : :
93 [ + - ]: 1 : const auto sub{std::make_shared<TestSubscriber>()};
94 [ + - + - ]: 2 : m_node.validation_signals->RegisterSharedValidationInterface(sub);
95 : :
96 : : // ActivateBestChain back to tip
97 [ + - ]: 1 : chainstate.ActivateBestChain(state_dummy, nullptr);
98 [ + - - + : 2 : BOOST_CHECK_EQUAL(tip, chainstate.m_chain.Tip());
+ - ]
99 : : // Check that we flushed inside ActivateBestChain while we were at the
100 : : // second block from tip, since FlushStateToDisk is called with PERIODIC
101 : : // inside the outer loop.
102 [ + - ]: 1 : m_node.validation_signals->SyncWithValidationInterfaceQueue();
103 [ + - + - : 1 : BOOST_CHECK_EQUAL(sub->m_flushed_at_block, second_from_tip);
+ - ]
104 : 2 : }
105 : :
106 : : BOOST_AUTO_TEST_SUITE_END()
|