Skip to content

Commit 67023e9

Browse files
committed
Merge #9725: CValidationInterface Cleanups
b1a6d4c Take a CTransactionRef in AddToWalletIfInvolvingMe to avoid a copy (Matt Corallo) 1c95e2f Use std::shared_ptr instead of boost::shared_ptr in ScriptForMining (Matt Corallo) 91f1e6c Remove dead-code tracking of requests for blocks we generated (Matt Corallo) acad82f Add override to functions using CValidationInterface methods (Matt Corallo) e6d5e6c Hold cs_wallet for whole block [dis]connection processing (Matt Corallo) 461e49f SyncTransaction->TxAddedToMempool/BlockConnected/Disconnected (Matt Corallo) f404334 Handle SyncTransaction in ActivateBestChain instead of ConnectTrace (Matt Corallo) a147687 Keep conflictedTxs in ConnectTrace per-block (Matt Corallo) d3167ba Handle conflicted transactions directly in ConnectTrace (Matt Corallo) 29e6e23 Make ConnectTrace::blocksConnected private, hide behind accessors (Matt Corallo) 822000c Add pblock to connectTrace at the end of ConnectTip, not start (Matt Corallo) f5e9a01 Include missing #include in zmqnotificationinterface.h (Matt Corallo) Tree-SHA512: 8893d47559da3b28d2ef7359768547cba8a4b43b6f891d80f5848f995a84b1517bfb0f706fdc8cd43f09a1350349eb440d9724a59363ab517dfcc4fcb31b2018
2 parents e183ea2 + b1a6d4c commit 67023e9

10 files changed

+197
-135
lines changed

src/net_processing.cpp

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -744,21 +744,23 @@ PeerLogicValidation::PeerLogicValidation(CConnman* connmanIn) : connman(connmanI
744744
recentRejects.reset(new CRollingBloomFilter(120000, 0.000001));
745745
}
746746

747-
void PeerLogicValidation::SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock) {
748-
if (nPosInBlock == CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK)
749-
return;
750-
747+
void PeerLogicValidation::BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex, const std::vector<CTransactionRef>& vtxConflicted) {
751748
LOCK(cs_main);
752749

753750
std::vector<uint256> vOrphanErase;
754-
// Which orphan pool entries must we evict?
755-
for (size_t j = 0; j < tx.vin.size(); j++) {
756-
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
757-
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
758-
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
759-
const CTransaction& orphanTx = *(*mi)->second.tx;
760-
const uint256& orphanHash = orphanTx.GetHash();
761-
vOrphanErase.push_back(orphanHash);
751+
752+
for (const CTransactionRef& ptx : pblock->vtx) {
753+
const CTransaction& tx = *ptx;
754+
755+
// Which orphan pool entries must we evict?
756+
for (size_t j = 0; j < tx.vin.size(); j++) {
757+
auto itByPrev = mapOrphanTransactionsByPrev.find(tx.vin[j].prevout);
758+
if (itByPrev == mapOrphanTransactionsByPrev.end()) continue;
759+
for (auto mi = itByPrev->second.begin(); mi != itByPrev->second.end(); ++mi) {
760+
const CTransaction& orphanTx = *(*mi)->second.tx;
761+
const uint256& orphanHash = orphanTx.GetHash();
762+
vOrphanErase.push_back(orphanHash);
763+
}
762764
}
763765
}
764766

src/net_processing.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,10 +30,10 @@ class PeerLogicValidation : public CValidationInterface {
3030
public:
3131
PeerLogicValidation(CConnman* connmanIn);
3232

33-
virtual void SyncTransaction(const CTransaction& tx, const CBlockIndex* pindex, int nPosInBlock);
34-
virtual void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload);
35-
virtual void BlockChecked(const CBlock& block, const CValidationState& state);
36-
virtual void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock);
33+
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexConnected, const std::vector<CTransactionRef>& vtxConflicted) override;
34+
void UpdatedBlockTip(const CBlockIndex *pindexNew, const CBlockIndex *pindexFork, bool fInitialDownload) override;
35+
void BlockChecked(const CBlock& block, const CValidationState& state) override;
36+
void NewPoWValidBlock(const CBlockIndex *pindex, const std::shared_ptr<const CBlock>& pblock) override;
3737
};
3838

3939
struct CNodeStateStats {

src/rpc/mining.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include <stdint.h>
2828

2929
#include <boost/assign/list_of.hpp>
30-
#include <boost/shared_ptr.hpp>
3130

3231
#include <univalue.h>
3332

@@ -95,7 +94,7 @@ UniValue getnetworkhashps(const JSONRPCRequest& request)
9594
return GetNetworkHashPS(request.params.size() > 0 ? request.params[0].get_int() : 120, request.params.size() > 1 ? request.params[1].get_int() : -1);
9695
}
9796

98-
UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
97+
UniValue generateBlocks(std::shared_ptr<CReserveScript> coinbaseScript, int nGenerate, uint64_t nMaxTries, bool keepScript)
9998
{
10099
static const int nInnerLoopCount = 0x10000;
101100
int nHeightStart = 0;
@@ -167,7 +166,7 @@ UniValue generate(const JSONRPCRequest& request)
167166
nMaxTries = request.params[1].get_int();
168167
}
169168

170-
boost::shared_ptr<CReserveScript> coinbaseScript;
169+
std::shared_ptr<CReserveScript> coinbaseScript;
171170
GetMainSignals().ScriptForMining(coinbaseScript);
172171

173172
// If the keypool is exhausted, no script is returned at all. Catch this.
@@ -208,7 +207,7 @@ UniValue generatetoaddress(const JSONRPCRequest& request)
208207
if (!address.IsValid())
209208
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
210209

211-
boost::shared_ptr<CReserveScript> coinbaseScript(new CReserveScript());
210+
std::shared_ptr<CReserveScript> coinbaseScript = std::make_shared<CReserveScript>();
212211
coinbaseScript->reserveScript = GetScriptForDestination(address.Get());
213212

214213
return generateBlocks(coinbaseScript, nGenerate, nMaxTries, false);
@@ -710,7 +709,7 @@ class submitblock_StateCatcher : public CValidationInterface
710709
submitblock_StateCatcher(const uint256 &hashIn) : hash(hashIn), found(false), state() {}
711710

712711
protected:
713-
virtual void BlockChecked(const CBlock& block, const CValidationState& stateIn) {
712+
void BlockChecked(const CBlock& block, const CValidationState& stateIn) override {
714713
if (block.GetHash() != hash)
715714
return;
716715
found = true;

src/validation.cpp

Lines changed: 75 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -154,39 +154,6 @@ namespace {
154154
std::set<int> setDirtyFileInfo;
155155
} // anon namespace
156156

157-
/* Use this class to start tracking transactions that are removed from the
158-
* mempool and pass all those transactions through SyncTransaction when the
159-
* object goes out of scope. This is currently only used to call SyncTransaction
160-
* on conflicts removed from the mempool during block connection. Applied in
161-
* ActivateBestChain around ActivateBestStep which in turn calls:
162-
* ConnectTip->removeForBlock->removeConflicts
163-
*/
164-
class MemPoolConflictRemovalTracker
165-
{
166-
private:
167-
std::vector<CTransactionRef> conflictedTxs;
168-
CTxMemPool &pool;
169-
170-
public:
171-
MemPoolConflictRemovalTracker(CTxMemPool &_pool) : pool(_pool) {
172-
pool.NotifyEntryRemoved.connect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
173-
}
174-
175-
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
176-
if (reason == MemPoolRemovalReason::CONFLICT) {
177-
conflictedTxs.push_back(txRemoved);
178-
}
179-
}
180-
181-
~MemPoolConflictRemovalTracker() {
182-
pool.NotifyEntryRemoved.disconnect(boost::bind(&MemPoolConflictRemovalTracker::NotifyEntryRemoved, this, _1, _2));
183-
for (const auto& tx : conflictedTxs) {
184-
GetMainSignals().SyncTransaction(*tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
185-
}
186-
conflictedTxs.clear();
187-
}
188-
};
189-
190157
CBlockIndex* FindForkInGlobalIndex(const CChain& chain, const CBlockLocator& locator)
191158
{
192159
// Find the first block the caller has in the main chain
@@ -982,7 +949,7 @@ bool AcceptToMemoryPoolWorker(CTxMemPool& pool, CValidationState& state, const C
982949
}
983950
}
984951

985-
GetMainSignals().SyncTransaction(tx, NULL, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
952+
GetMainSignals().TransactionAddedToMempool(ptx);
986953

987954
return true;
988955
}
@@ -2153,7 +2120,8 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
21532120
CBlockIndex *pindexDelete = chainActive.Tip();
21542121
assert(pindexDelete);
21552122
// Read block from disk.
2156-
CBlock block;
2123+
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
2124+
CBlock& block = *pblock;
21572125
if (!ReadBlockFromDisk(block, pindexDelete, chainparams.GetConsensus()))
21582126
return AbortNode(state, "Failed to read block");
21592127
// Apply the block atomically to the chain state.
@@ -2195,9 +2163,7 @@ bool static DisconnectTip(CValidationState& state, const CChainParams& chainpara
21952163
UpdateTip(pindexDelete->pprev, chainparams);
21962164
// Let wallets know transactions went from 1-confirmed to
21972165
// 0-confirmed or conflicted:
2198-
for (const auto& tx : block.vtx) {
2199-
GetMainSignals().SyncTransaction(*tx, pindexDelete->pprev, CMainSignals::SYNC_TRANSACTION_NOT_IN_BLOCK);
2200-
}
2166+
GetMainSignals().BlockDisconnected(pblock);
22012167
return true;
22022168
}
22032169

@@ -2207,36 +2173,92 @@ static int64_t nTimeFlush = 0;
22072173
static int64_t nTimeChainState = 0;
22082174
static int64_t nTimePostConnect = 0;
22092175

2176+
struct PerBlockConnectTrace {
2177+
CBlockIndex* pindex = NULL;
2178+
std::shared_ptr<const CBlock> pblock;
2179+
std::shared_ptr<std::vector<CTransactionRef>> conflictedTxs;
2180+
PerBlockConnectTrace() : conflictedTxs(std::make_shared<std::vector<CTransactionRef>>()) {}
2181+
};
22102182
/**
22112183
* Used to track blocks whose transactions were applied to the UTXO state as a
22122184
* part of a single ActivateBestChainStep call.
2185+
*
2186+
* This class also tracks transactions that are removed from the mempool as
2187+
* conflicts (per block) and can be used to pass all those transactions
2188+
* through SyncTransaction.
2189+
*
2190+
* This class assumes (and asserts) that the conflicted transactions for a given
2191+
* block are added via mempool callbacks prior to the BlockConnected() associated
2192+
* with those transactions. If any transactions are marked conflicted, it is
2193+
* assumed that an associated block will always be added.
2194+
*
2195+
* This class is single-use, once you call GetBlocksConnected() you have to throw
2196+
* it away and make a new one.
22132197
*/
2214-
struct ConnectTrace {
2215-
std::vector<std::pair<CBlockIndex*, std::shared_ptr<const CBlock> > > blocksConnected;
2198+
class ConnectTrace {
2199+
private:
2200+
std::vector<PerBlockConnectTrace> blocksConnected;
2201+
CTxMemPool &pool;
2202+
2203+
public:
2204+
ConnectTrace(CTxMemPool &_pool) : blocksConnected(1), pool(_pool) {
2205+
pool.NotifyEntryRemoved.connect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
2206+
}
2207+
2208+
~ConnectTrace() {
2209+
pool.NotifyEntryRemoved.disconnect(boost::bind(&ConnectTrace::NotifyEntryRemoved, this, _1, _2));
2210+
}
2211+
2212+
void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {
2213+
assert(!blocksConnected.back().pindex);
2214+
assert(pindex);
2215+
assert(pblock);
2216+
blocksConnected.back().pindex = pindex;
2217+
blocksConnected.back().pblock = std::move(pblock);
2218+
blocksConnected.emplace_back();
2219+
}
2220+
2221+
std::vector<PerBlockConnectTrace>& GetBlocksConnected() {
2222+
// We always keep one extra block at the end of our list because
2223+
// blocks are added after all the conflicted transactions have
2224+
// been filled in. Thus, the last entry should always be an empty
2225+
// one waiting for the transactions from the next block. We pop
2226+
// the last entry here to make sure the list we return is sane.
2227+
assert(!blocksConnected.back().pindex);
2228+
assert(blocksConnected.back().conflictedTxs->empty());
2229+
blocksConnected.pop_back();
2230+
return blocksConnected;
2231+
}
2232+
2233+
void NotifyEntryRemoved(CTransactionRef txRemoved, MemPoolRemovalReason reason) {
2234+
assert(!blocksConnected.back().pindex);
2235+
if (reason == MemPoolRemovalReason::CONFLICT) {
2236+
blocksConnected.back().conflictedTxs->emplace_back(std::move(txRemoved));
2237+
}
2238+
}
22162239
};
22172240

22182241
/**
22192242
* Connect a new block to chainActive. pblock is either NULL or a pointer to a CBlock
22202243
* corresponding to pindexNew, to bypass loading it again from disk.
22212244
*
2222-
* The block is always added to connectTrace (either after loading from disk or by copying
2223-
* pblock) - if that is not intended, care must be taken to remove the last entry in
2224-
* blocksConnected in case of failure.
2245+
* The block is added to connectTrace if connection succeeds.
22252246
*/
22262247
bool static ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace)
22272248
{
22282249
assert(pindexNew->pprev == chainActive.Tip());
22292250
// Read block from disk.
22302251
int64_t nTime1 = GetTimeMicros();
2252+
std::shared_ptr<const CBlock> pthisBlock;
22312253
if (!pblock) {
22322254
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
2233-
connectTrace.blocksConnected.emplace_back(pindexNew, pblockNew);
22342255
if (!ReadBlockFromDisk(*pblockNew, pindexNew, chainparams.GetConsensus()))
22352256
return AbortNode(state, "Failed to read block");
2257+
pthisBlock = pblockNew;
22362258
} else {
2237-
connectTrace.blocksConnected.emplace_back(pindexNew, pblock);
2259+
pthisBlock = pblock;
22382260
}
2239-
const CBlock& blockConnecting = *connectTrace.blocksConnected.back().second;
2261+
const CBlock& blockConnecting = *pthisBlock;
22402262
// Apply the block atomically to the chain state.
22412263
int64_t nTime2 = GetTimeMicros(); nTimeReadFromDisk += nTime2 - nTime1;
22422264
int64_t nTime3;
@@ -2270,6 +2292,8 @@ bool static ConnectTip(CValidationState& state, const CChainParams& chainparams,
22702292
int64_t nTime6 = GetTimeMicros(); nTimePostConnect += nTime6 - nTime5; nTimeTotal += nTime6 - nTime1;
22712293
LogPrint(BCLog::BENCH, " - Connect postprocess: %.2fms [%.2fs]\n", (nTime6 - nTime5) * 0.001, nTimePostConnect * 0.000001);
22722294
LogPrint(BCLog::BENCH, "- Connect block: %.2fms [%.2fs]\n", (nTime6 - nTime1) * 0.001, nTimeTotal * 0.000001);
2295+
2296+
connectTrace.BlockConnected(pindexNew, std::move(pthisBlock));
22732297
return true;
22742298
}
22752299

@@ -2388,8 +2412,6 @@ static bool ActivateBestChainStep(CValidationState& state, const CChainParams& c
23882412
state = CValidationState();
23892413
fInvalidFound = true;
23902414
fContinue = false;
2391-
// If we didn't actually connect the block, don't notify listeners about it
2392-
connectTrace.blocksConnected.pop_back();
23932415
break;
23942416
} else {
23952417
// A system error occurred (disk space, database error, ...).
@@ -2461,18 +2483,11 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
24612483
break;
24622484

24632485
const CBlockIndex *pindexFork;
2464-
ConnectTrace connectTrace;
24652486
bool fInitialDownload;
24662487
{
24672488
LOCK(cs_main);
2468-
{ // TODO: Temporarily ensure that mempool removals are notified before
2469-
// connected transactions. This shouldn't matter, but the abandoned
2470-
// state of transactions in our wallet is currently cleared when we
2471-
// receive another notification and there is a race condition where
2472-
// notification of a connected conflict might cause an outside process
2473-
// to abandon a transaction and then have it inadvertently cleared by
2474-
// the notification that the conflicted transaction was evicted.
2475-
MemPoolConflictRemovalTracker mrt(mempool);
2489+
ConnectTrace connectTrace(mempool); // Destructed before cs_main is unlocked
2490+
24762491
CBlockIndex *pindexOldTip = chainActive.Tip();
24772492
if (pindexMostWork == NULL) {
24782493
pindexMostWork = FindMostWorkChain();
@@ -2495,16 +2510,9 @@ bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams,
24952510
pindexFork = chainActive.FindFork(pindexOldTip);
24962511
fInitialDownload = IsInitialBlockDownload();
24972512

2498-
// throw all transactions though the signal-interface
2499-
2500-
} // MemPoolConflictRemovalTracker destroyed and conflict evictions are notified
2501-
2502-
// Transactions in the connected block are notified
2503-
for (const auto& pair : connectTrace.blocksConnected) {
2504-
assert(pair.second);
2505-
const CBlock& block = *(pair.second);
2506-
for (unsigned int i = 0; i < block.vtx.size(); i++)
2507-
GetMainSignals().SyncTransaction(*block.vtx[i], pair.first, i);
2513+
for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) {
2514+
assert(trace.pblock && trace.pindex);
2515+
GetMainSignals().BlockConnected(trace.pblock, trace.pindex, *trace.conflictedTxs);
25082516
}
25092517
}
25102518
// When we reach this point, we switched to a new tip (stored in pindexNewTip).

src/validationinterface.cpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,42 @@ CMainSignals& GetMainSignals()
1414

1515
void RegisterValidationInterface(CValidationInterface* pwalletIn) {
1616
g_signals.UpdatedBlockTip.connect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
17-
g_signals.SyncTransaction.connect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
17+
g_signals.TransactionAddedToMempool.connect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
18+
g_signals.BlockConnected.connect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
19+
g_signals.BlockDisconnected.connect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
1820
g_signals.UpdatedTransaction.connect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
1921
g_signals.SetBestChain.connect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
2022
g_signals.Inventory.connect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
2123
g_signals.Broadcast.connect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
2224
g_signals.BlockChecked.connect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
2325
g_signals.ScriptForMining.connect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
24-
g_signals.BlockFound.connect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
2526
g_signals.NewPoWValidBlock.connect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
2627
}
2728

2829
void UnregisterValidationInterface(CValidationInterface* pwalletIn) {
29-
g_signals.BlockFound.disconnect(boost::bind(&CValidationInterface::ResetRequestCount, pwalletIn, _1));
3030
g_signals.ScriptForMining.disconnect(boost::bind(&CValidationInterface::GetScriptForMining, pwalletIn, _1));
3131
g_signals.BlockChecked.disconnect(boost::bind(&CValidationInterface::BlockChecked, pwalletIn, _1, _2));
3232
g_signals.Broadcast.disconnect(boost::bind(&CValidationInterface::ResendWalletTransactions, pwalletIn, _1, _2));
3333
g_signals.Inventory.disconnect(boost::bind(&CValidationInterface::Inventory, pwalletIn, _1));
3434
g_signals.SetBestChain.disconnect(boost::bind(&CValidationInterface::SetBestChain, pwalletIn, _1));
3535
g_signals.UpdatedTransaction.disconnect(boost::bind(&CValidationInterface::UpdatedTransaction, pwalletIn, _1));
36-
g_signals.SyncTransaction.disconnect(boost::bind(&CValidationInterface::SyncTransaction, pwalletIn, _1, _2, _3));
36+
g_signals.TransactionAddedToMempool.disconnect(boost::bind(&CValidationInterface::TransactionAddedToMempool, pwalletIn, _1));
37+
g_signals.BlockConnected.disconnect(boost::bind(&CValidationInterface::BlockConnected, pwalletIn, _1, _2, _3));
38+
g_signals.BlockDisconnected.disconnect(boost::bind(&CValidationInterface::BlockDisconnected, pwalletIn, _1));
3739
g_signals.UpdatedBlockTip.disconnect(boost::bind(&CValidationInterface::UpdatedBlockTip, pwalletIn, _1, _2, _3));
3840
g_signals.NewPoWValidBlock.disconnect(boost::bind(&CValidationInterface::NewPoWValidBlock, pwalletIn, _1, _2));
3941
}
4042

4143
void UnregisterAllValidationInterfaces() {
42-
g_signals.BlockFound.disconnect_all_slots();
4344
g_signals.ScriptForMining.disconnect_all_slots();
4445
g_signals.BlockChecked.disconnect_all_slots();
4546
g_signals.Broadcast.disconnect_all_slots();
4647
g_signals.Inventory.disconnect_all_slots();
4748
g_signals.SetBestChain.disconnect_all_slots();
4849
g_signals.UpdatedTransaction.disconnect_all_slots();
49-
g_signals.SyncTransaction.disconnect_all_slots();
50+
g_signals.TransactionAddedToMempool.disconnect_all_slots();
51+
g_signals.BlockConnected.disconnect_all_slots();
52+
g_signals.BlockDisconnected.disconnect_all_slots();
5053
g_signals.UpdatedBlockTip.disconnect_all_slots();
5154
g_signals.NewPoWValidBlock.disconnect_all_slots();
5255
}

0 commit comments

Comments
 (0)