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 <validationinterface.h> # 12 : : # 13 : : BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup) # 14 : : # 15 : : struct TestSubscriberNoop final : public CValidationInterface { # 16 : 528 : void BlockChecked(const CBlock&, const BlockValidationState&) override {} # 17 : : }; # 18 : : # 19 : : BOOST_AUTO_TEST_CASE(unregister_validation_interface_race) # 20 : 1 : { # 21 : 1 : std::atomic<bool> generate{true}; # 22 : : # 23 : : // Start thread to generate notifications # 24 : 1 : std::thread gen{[&] { # 25 : 1 : const CBlock block_dummy; # 26 : 1 : BlockValidationState state_dummy; # 27 [ + + ]: 2512 : while (generate) { # 28 : 2511 : GetMainSignals().BlockChecked(block_dummy, state_dummy); # 29 : 2511 : } # 30 : 1 : }}; # 31 : : # 32 : : // Start thread to consume notifications # 33 : 1 : std::thread sub{[&] { # 34 : : // keep going for about 1 sec, which is 250k iterations # 35 [ + + ]: 250001 : for (int i = 0; i < 250000; i++) { # 36 : 250000 : auto sub = std::make_shared<TestSubscriberNoop>(); # 37 : 250000 : RegisterSharedValidationInterface(sub); # 38 : 250000 : UnregisterSharedValidationInterface(sub); # 39 : 250000 : } # 40 : : // tell the other thread we are done # 41 : 1 : generate = false; # 42 : 1 : }}; # 43 : : # 44 : 1 : gen.join(); # 45 : 1 : sub.join(); # 46 : 1 : BOOST_CHECK(!generate); # 47 : 1 : } # 48 : : # 49 : : class TestInterface : public CValidationInterface # 50 : : { # 51 : : public: # 52 : : TestInterface(std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr) # 53 : : : m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy)) # 54 : 1 : { # 55 : 1 : } # 56 : : virtual ~TestInterface() # 57 : 1 : { # 58 [ + - ]: 1 : if (m_on_destroy) m_on_destroy(); # 59 : 1 : } # 60 : : void BlockChecked(const CBlock& block, const BlockValidationState& state) override # 61 : 1 : { # 62 [ + - ]: 1 : if (m_on_call) m_on_call(); # 63 : 1 : } # 64 : : static void Call() # 65 : 1 : { # 66 : 1 : CBlock block; # 67 : 1 : BlockValidationState state; # 68 : 1 : GetMainSignals().BlockChecked(block, state); # 69 : 1 : } # 70 : : std::function<void()> m_on_call; # 71 : : std::function<void()> m_on_destroy; # 72 : : }; # 73 : : # 74 : : // Regression test to ensure UnregisterAllValidationInterfaces calls don't # 75 : : // destroy a validation interface while it is being called. Bug: # 76 : : // https://github.com/bitcoin/bitcoin/pull/18551 # 77 : : BOOST_AUTO_TEST_CASE(unregister_all_during_call) # 78 : 1 : { # 79 : 1 : bool destroyed = false; # 80 : 1 : RegisterSharedValidationInterface(std::make_shared<TestInterface>( # 81 : 1 : [&] { # 82 : : // First call should decrements reference count 2 -> 1 # 83 : 1 : UnregisterAllValidationInterfaces(); # 84 : 1 : BOOST_CHECK(!destroyed); # 85 : : // Second call should not decrement reference count 1 -> 0 # 86 : 1 : UnregisterAllValidationInterfaces(); # 87 : 1 : BOOST_CHECK(!destroyed); # 88 : 1 : }, # 89 : 1 : [&] { destroyed = true; })); # 90 : 1 : TestInterface::Call(); # 91 : 1 : BOOST_CHECK(destroyed); # 92 : 1 : } # 93 : : # 94 : : BOOST_AUTO_TEST_SUITE_END()