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 89 : BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup) 14 : 15 500000 : struct TestSubscriberNoop final : public CValidationInterface { 16 2768 : void BlockChecked(const CBlock&, const BlockValidationState&) override {} 17 : }; 18 : 19 95 : BOOST_AUTO_TEST_CASE(unregister_validation_interface_race) 20 : { 21 1 : std::atomic<bool> generate{true}; 22 : 23 : // Start thread to generate notifications 24 2 : std::thread gen{[&] { 25 1 : const CBlock block_dummy; 26 1 : BlockValidationState state_dummy; 27 12908 : while (generate) { 28 12907 : GetMainSignals().BlockChecked(block_dummy, state_dummy); 29 : } 30 1 : }}; 31 : 32 : // Start thread to consume notifications 33 2 : 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 2 : TestInterface(std::function<void()> on_call = nullptr, std::function<void()> on_destroy = nullptr) 53 1 : : m_on_call(std::move(on_call)), m_on_destroy(std::move(on_destroy)) 54 2 : { 55 2 : } 56 2 : virtual ~TestInterface() 57 2 : { 58 1 : if (m_on_destroy) m_on_destroy(); 59 2 : } 60 1 : void BlockChecked(const CBlock& block, const BlockValidationState& state) override 61 : { 62 1 : if (m_on_call) m_on_call(); 63 1 : } 64 1 : static void Call() 65 : { 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 95 : BOOST_AUTO_TEST_CASE(unregister_all_during_call) 78 : { 79 1 : bool destroyed = false; 80 2 : RegisterSharedValidationInterface(std::make_shared<TestInterface>( 81 2 : [&] { 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 2 : [&] { destroyed = true; })); 90 1 : TestInterface::Call(); 91 1 : BOOST_CHECK(destroyed); 92 1 : } 93 : 94 89 : BOOST_AUTO_TEST_SUITE_END()