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 : :
16 : : BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, ChainTestingSetup)
17 : :
18 : 250000 : struct TestSubscriberNoop final : public CValidationInterface {
19 : 2888 : void BlockChecked(const CBlock&, const BlockValidationState&) override {}
20 : : };
21 : :
22 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(unregister_validation_interface_race)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
23 : : {
24 : 1 : std::atomic<bool> generate{true};
25 : :
26 : : // Start thread to generate notifications
27 : 2 : std::thread gen{[&] {
28 : 1 : const CBlock block_dummy;
29 : 1 : BlockValidationState state_dummy;
30 [ + + ]: 6014 : while (generate) {
31 [ + - ]: 6013 : m_node.validation_signals->BlockChecked(block_dummy, 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 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 : CBlock block;
70 [ + - ]: 1 : BlockValidationState state;
71 [ + - ]: 1 : m_signals.BlockChecked(block, state);
72 : 1 : }
73 : : std::function<void()> m_on_call;
74 : : std::function<void()> m_on_destroy;
75 : : ValidationSignals& m_signals;
76 : : };
77 : :
78 : : // Regression test to ensure UnregisterAllValidationInterfaces calls don't
79 : : // destroy a validation interface while it is being called. Bug:
80 : : // https://github.com/bitcoin/bitcoin/pull/18551
81 [ + - + - : 7 : BOOST_AUTO_TEST_CASE(unregister_all_during_call)
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- + - + -
+ - + - +
- ]
82 : : {
83 : 1 : bool destroyed = false;
84 : 1 : auto shared{std::make_shared<TestInterface>(
85 : 1 : *m_node.validation_signals,
86 : 2 : [&] {
87 : : // First call should decrements reference count 2 -> 1
88 : 1 : m_node.validation_signals->UnregisterAllValidationInterfaces();
89 [ + - ]: 2 : BOOST_CHECK(!destroyed);
90 : : // Second call should not decrement reference count 1 -> 0
91 : 1 : m_node.validation_signals->UnregisterAllValidationInterfaces();
92 [ + - ]: 2 : BOOST_CHECK(!destroyed);
93 : 1 : },
94 : 2 : [&] { destroyed = true; })};
95 [ + - + - ]: 2 : m_node.validation_signals->RegisterSharedValidationInterface(shared);
96 [ + - + - : 2 : BOOST_CHECK(shared.use_count() == 2);
+ - ]
97 [ + - ]: 1 : shared->Call();
98 [ + - + - : 2 : BOOST_CHECK(shared.use_count() == 1);
+ - ]
99 [ + - + - ]: 2 : BOOST_CHECK(!destroyed);
100 : 1 : shared.reset();
101 [ + - + - : 2 : BOOST_CHECK(destroyed);
- + ]
102 : 1 : }
103 : :
104 : : BOOST_AUTO_TEST_SUITE_END()
|