Branch data Line data Source code
1 : : // Copyright (c) 2020 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 <boost/test/unit_test.hpp>
6 : : #include <consensus/validation.h>
7 : : #include <primitives/block.h>
8 : : #include <scheduler.h>
9 : : #include <test/util/setup_common.h>
10 : : #include <util/check.h>
11 : : #include <kernel/chain.h>
12 : : #include <validationinterface.h>
13 : :
14 : : #include <atomic>
15 : : #include <memory>
16 : :
17 : : BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, ChainTestingSetup)
18 : :
19 : 250000 : struct TestSubscriberNoop final : public CValidationInterface {
20 : 4968 : void BlockChecked(const std::shared_ptr<const CBlock>&, const BlockValidationState&) override {}
21 : : };
22 : :
23 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(unregister_validation_interface_race)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
24 : : {
25 : 1 : std::atomic<bool> generate{true};
26 : :
27 : : // Start thread to generate notifications
28 : 2 : std::thread gen{[&] {
29 : 1 : BlockValidationState state_dummy;
30 [ + + ]: 10302 : while (generate) {
31 [ + - + - ]: 20602 : m_node.validation_signals->BlockChecked(std::make_shared<const CBlock>(), state_dummy);
32 : : }
33 : 2 : }};
34 : :
35 : : // Start thread to consume notifications
36 : 2 : std::thread sub{[&] {
37 : : // keep going for about 1 sec, which is 250k iterations
38 [ + + ]: 250001 : for (int i = 0; i < 250000; i++) {
39 : 250000 : auto sub = std::make_shared<TestSubscriberNoop>();
40 [ + - + - ]: 500000 : m_node.validation_signals->RegisterSharedValidationInterface(sub);
41 [ + - + - : 750000 : m_node.validation_signals->UnregisterSharedValidationInterface(sub);
+ - ]
42 : 250000 : }
43 : : // tell the other thread we are done
44 : 1 : generate = false;
45 [ + - ]: 2 : }};
46 : :
47 [ + - ]: 1 : gen.join();
48 [ + - ]: 1 : sub.join();
49 [ + - + - ]: 2 : BOOST_CHECK(!generate);
50 : 1 : }
51 : :
52 : : class TestInterface : public CValidationInterface
53 : : {
54 : : public:
55 : 1 : TestInterface(ValidationSignals& signals, std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr)
56 : 1 : : m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy)), m_signals{signals}
57 : : {
58 : 1 : }
59 : 1 : virtual ~TestInterface()
60 : 1 : {
61 [ + - ]: 1 : if (m_on_destroy) m_on_destroy();
62 : 1 : }
63 : 1 : void BlockChecked(const std::shared_ptr<const CBlock>& block, const BlockValidationState& state) override
64 : : {
65 [ + - ]: 1 : if (m_on_call) m_on_call();
66 : 1 : }
67 : 1 : void Call()
68 : : {
69 [ + - ]: 1 : BlockValidationState state;
70 [ + - + - ]: 2 : m_signals.BlockChecked(std::make_shared<const CBlock>(), state);
71 : 1 : }
72 : : std::function<void()> m_on_call;
73 : : std::function<void()> m_on_destroy;
74 : : ValidationSignals& m_signals;
75 : : };
76 : :
77 : : // Regression test to ensure UnregisterAllValidationInterfaces calls don't
78 : : // destroy a validation interface while it is being called. Bug:
79 : : // https://github.com/bitcoin/bitcoin/pull/18551
80 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(unregister_all_during_call)
+ - + - -
+ + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- + - + -
+ - + - +
- + - - +
+ - + - +
- + - + -
+ - - + +
- ]
81 : : {
82 : 1 : bool destroyed = false;
83 : 1 : auto shared{std::make_shared<TestInterface>(
84 : 1 : *m_node.validation_signals,
85 : 2 : [&] {
86 : : // First call should decrements reference count 2 -> 1
87 : 1 : m_node.validation_signals->UnregisterAllValidationInterfaces();
88 [ + - ]: 2 : BOOST_CHECK(!destroyed);
89 : : // Second call should not decrement reference count 1 -> 0
90 : 1 : m_node.validation_signals->UnregisterAllValidationInterfaces();
91 [ + - ]: 2 : BOOST_CHECK(!destroyed);
92 : 1 : },
93 : 2 : [&] { destroyed = true; })};
94 [ + - + - ]: 2 : m_node.validation_signals->RegisterSharedValidationInterface(shared);
95 [ + - + - : 2 : BOOST_CHECK(shared.use_count() == 2);
+ - ]
96 [ + - ]: 1 : shared->Call();
97 [ + - + - : 2 : BOOST_CHECK(shared.use_count() == 1);
+ - ]
98 [ + - + - ]: 2 : BOOST_CHECK(!destroyed);
99 : 1 : shared.reset();
100 [ + - + - : 2 : BOOST_CHECK(destroyed);
- + ]
101 : 1 : }
102 : :
103 : : BOOST_AUTO_TEST_SUITE_END()
|