Skip to content

Commit 4660170

Browse files
PastaPastaPastaogabrielides
authored andcommitted
Merge pull request dashpay#5726 from UdjinM6/bp_18742_28150
backport: bitcoin#18742, bitcoin#28150
1 parent 330c5f9 commit 4660170

File tree

5 files changed

+76
-35
lines changed

5 files changed

+76
-35
lines changed

src/rpc/mining.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -955,7 +955,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request)
955955
return result;
956956
}
957957

958-
class submitblock_StateCatcher : public CValidationInterface
958+
class submitblock_StateCatcher final : public CValidationInterface
959959
{
960960
public:
961961
uint256 hash;
@@ -1016,17 +1016,17 @@ static UniValue submitblock(const JSONRPCRequest& request)
10161016
}
10171017

10181018
bool new_block;
1019-
submitblock_StateCatcher sc(block.GetHash());
1020-
RegisterValidationInterface(&sc);
1019+
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
1020+
RegisterSharedValidationInterface(sc);
10211021
bool accepted = chainman.ProcessNewBlock(Params(), blockptr, /* fForceProcessing */ true, /* fNewBlock */ &new_block);
1022-
UnregisterValidationInterface(&sc);
1022+
UnregisterSharedValidationInterface(sc);
10231023
if (!new_block && accepted) {
10241024
return "duplicate";
10251025
}
1026-
if (!sc.found) {
1026+
if (!sc->found) {
10271027
return "inconclusive";
10281028
}
1029-
return BIP22ValidationResult(sc.state);
1029+
return BIP22ValidationResult(sc->state);
10301030
}
10311031

10321032
static UniValue submitheader(const JSONRPCRequest& request)

src/test/validation_block_tests.cpp

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ static const std::vector<unsigned char> V_OP_TRUE{OP_TRUE};
4040

4141
BOOST_FIXTURE_TEST_SUITE(validation_block_tests, MinerTestingSetup)
4242

43-
struct TestSubscriber : public CValidationInterface {
43+
struct TestSubscriber final : public CValidationInterface {
4444
uint256 m_expected_tip;
4545

4646
explicit TestSubscriber(uint256 tip) : m_expected_tip(tip) {}
@@ -179,8 +179,8 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
179179
LOCK(cs_main);
180180
initial_tip = ::ChainActive().Tip();
181181
}
182-
TestSubscriber sub(initial_tip->GetBlockHash());
183-
RegisterValidationInterface(&sub);
182+
auto sub = std::make_shared<TestSubscriber>(initial_tip->GetBlockHash());
183+
RegisterSharedValidationInterface(sub);
184184

185185
// create a bunch of threads that repeatedly process a block generated above at random
186186
// this will create parallelism and randomness inside validation - the ValidationInterface
@@ -208,14 +208,12 @@ BOOST_AUTO_TEST_CASE(processnewblock_signals_ordering)
208208
for (auto& t : threads) {
209209
t.join();
210210
}
211-
while (GetMainSignals().CallbacksPending() > 0) {
212-
UninterruptibleSleep(std::chrono::milliseconds{100});
213-
}
211+
SyncWithValidationInterfaceQueue();
214212

215-
UnregisterValidationInterface(&sub);
213+
UnregisterSharedValidationInterface(sub);
216214

217215
LOCK(cs_main);
218-
BOOST_CHECK_EQUAL(sub.m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
216+
BOOST_CHECK_EQUAL(sub->m_expected_tip, ::ChainActive().Tip()->GetBlockHash());
219217
}
220218

221219
/**

src/test/validationinterface_tests.cpp

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,41 @@
1010
#include <util/check.h>
1111
#include <validationinterface.h>
1212

13-
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, TestingSetup)
13+
BOOST_FIXTURE_TEST_SUITE(validationinterface_tests, ChainTestingSetup)
14+
15+
struct TestSubscriberNoop final : public CValidationInterface {
16+
void BlockChecked(const CBlock&, const BlockValidationState&) override {}
17+
};
18+
19+
BOOST_AUTO_TEST_CASE(unregister_validation_interface_race)
20+
{
21+
std::atomic<bool> generate{true};
22+
23+
// Start thread to generate notifications
24+
std::thread gen{[&] {
25+
const CBlock block_dummy;
26+
const BlockValidationState state_dummy;
27+
while (generate) {
28+
GetMainSignals().BlockChecked(block_dummy, state_dummy);
29+
}
30+
}};
31+
32+
// Start thread to consume notifications
33+
std::thread sub{[&] {
34+
// keep going for about 1 sec, which is 250k iterations
35+
for (int i = 0; i < 250000; i++) {
36+
auto sub = std::make_shared<TestSubscriberNoop>();
37+
RegisterSharedValidationInterface(sub);
38+
UnregisterSharedValidationInterface(sub);
39+
}
40+
// tell the other thread we are done
41+
generate = false;
42+
}};
43+
44+
gen.join();
45+
sub.join();
46+
BOOST_CHECK(!generate);
47+
}
1448

1549
class TestInterface : public CValidationInterface
1650
{

src/validationinterface.cpp

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,26 @@ struct MainSignalsInstance {
9494

9595
static CMainSignals g_signals;
9696

97-
void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler) {
97+
void CMainSignals::RegisterBackgroundSignalScheduler(CScheduler& scheduler)
98+
{
9899
assert(!m_internals);
99100
m_internals.reset(new MainSignalsInstance(&scheduler));
100101
}
101102

102-
void CMainSignals::UnregisterBackgroundSignalScheduler() {
103+
void CMainSignals::UnregisterBackgroundSignalScheduler()
104+
{
103105
m_internals.reset(nullptr);
104106
}
105107

106-
void CMainSignals::FlushBackgroundCallbacks() {
108+
void CMainSignals::FlushBackgroundCallbacks()
109+
{
107110
if (m_internals) {
108111
m_internals->m_schedulerClient.EmptyQueue();
109112
}
110113
}
111114

112-
size_t CMainSignals::CallbacksPending() {
115+
size_t CMainSignals::CallbacksPending()
116+
{
113117
if (!m_internals) return 0;
114118
return m_internals->m_schedulerClient.CallbacksPending();
115119
}
@@ -119,10 +123,11 @@ CMainSignals& GetMainSignals()
119123
return g_signals;
120124
}
121125

122-
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> pwalletIn) {
123-
// Each connection captures pwalletIn to ensure that each callback is
124-
// executed before pwalletIn is destroyed. For more details see #18338.
125-
g_signals.m_internals->Register(std::move(pwalletIn));
126+
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks)
127+
{
128+
// Each connection captures the shared_ptr to ensure that each callback is
129+
// executed before the subscriber is destroyed. For more details see #18338.
130+
g_signals.m_internals->Register(std::move(callbacks));
126131
}
127132

128133
void RegisterValidationInterface(CValidationInterface* callbacks)
@@ -137,24 +142,28 @@ void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> c
137142
UnregisterValidationInterface(callbacks.get());
138143
}
139144

140-
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
145+
void UnregisterValidationInterface(CValidationInterface* callbacks)
146+
{
141147
if (g_signals.m_internals) {
142-
g_signals.m_internals->Unregister(pwalletIn);
148+
g_signals.m_internals->Unregister(callbacks);
143149
}
144150
}
145151

146-
void UnregisterAllValidationInterfaces() {
152+
void UnregisterAllValidationInterfaces()
153+
{
147154
if (!g_signals.m_internals) {
148155
return;
149156
}
150157
g_signals.m_internals->Clear();
151158
}
152159

153-
void CallFunctionInValidationInterfaceQueue(std::function<void ()> func) {
160+
void CallFunctionInValidationInterfaceQueue(std::function<void()> func)
161+
{
154162
g_signals.m_internals->m_schedulerClient.AddToProcessQueue(std::move(func));
155163
}
156164

157-
void SyncWithValidationInterfaceQueue() {
165+
void SyncWithValidationInterfaceQueue()
166+
{
158167
AssertLockNotHeld(cs_main);
159168
// Block until the validation queue drains
160169
std::promise<void> promise;

src/validationinterface.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,20 @@ namespace llmq {
3333
class CRecoveredSig;
3434
} // namespace llmq
3535

36-
// These functions dispatch to one or all registered wallets
37-
38-
/** Register a wallet to receive updates from core */
39-
void RegisterValidationInterface(CValidationInterface* pwalletIn);
40-
/** Unregister a wallet from core */
41-
void UnregisterValidationInterface(CValidationInterface* pwalletIn);
42-
/** Unregister all wallets from core */
36+
/** Register subscriber */
37+
void RegisterValidationInterface(CValidationInterface* callbacks);
38+
/** Unregister subscriber. DEPRECATED. This is not safe to use when the RPC server or main message handler thread is running. */
39+
void UnregisterValidationInterface(CValidationInterface* callbacks);
40+
/** Unregister all subscribers */
4341
void UnregisterAllValidationInterfaces();
4442

4543
// Alternate registration functions that release a shared_ptr after the last
4644
// notification is sent. These are useful for race-free cleanup, since
4745
// unregistration is nonblocking and can return before the last notification is
4846
// processed.
47+
/** Register subscriber */
4948
void RegisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);
49+
/** Unregister subscriber */
5050
void UnregisterSharedValidationInterface(std::shared_ptr<CValidationInterface> callbacks);
5151

5252
/**

0 commit comments

Comments
 (0)