Skip to content

Commit c49628d

Browse files
UdjinM6PastaPastaPasta
authored andcommitted
fix: should not notify about mnlist changes while ConnectBlock isn't done yet (dashpay#5711)
## Issue being fixed or feature implemented `ConnectBlock` can fail after `ProcessSpecialTxsInBlock`, we shouldn't be notifying too early. Same for `DisconnectBlock` but that's less of an issue imo. ## What was done? Move notifications to the end of `ConnectBlock`/`DisconnectBlock`. There is no `connman` in `CChainState` and I don't want to pass it in updates struct so I changed `NotifyMasternodeListChanged` and used `connman` from `CDSNotificationInterface` instead. ## How Has This Been Tested? run unit test, run testnet qt wallet ## Breaking Changes ## Checklist: - [x] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have made corresponding changes to the documentation - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_
1 parent 259ad31 commit c49628d

10 files changed

+48
-24
lines changed

src/dsnotificationinterface.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ void CDSNotificationInterface::BlockDisconnected(const std::shared_ptr<const CBl
118118
CCoinJoin::BlockDisconnected(pblock, pindexDisconnected);
119119
}
120120

121-
void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman)
121+
void CDSNotificationInterface::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff)
122122
{
123123
CMNAuth::NotifyMasternodeListChanged(undo, oldMNList, diff, connman);
124124
govman.UpdateCachesAndClean();

src/dsnotificationinterface.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class CDSNotificationInterface : public CValidationInterface
3636
void TransactionRemovedFromMempool(const CTransactionRef& ptx, MemPoolRemovalReason reason) override;
3737
void BlockConnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindex) override;
3838
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock, const CBlockIndex* pindexDisconnected) override;
39-
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman) override;
39+
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) override;
4040
void NotifyChainLock(const CBlockIndex* pindex, const std::shared_ptr<const llmq::CChainLockSig>& clsig) override;
4141

4242
private:

src/evo/deterministicmns.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,7 @@ void CDeterministicMNList::RemoveMN(const uint256& proTxHash)
594594
mnInternalIdMap = mnInternalIdMap.erase(dmn->GetInternalId());
595595
}
596596

597-
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck)
597+
bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindex, BlockValidationState& state, const CCoinsViewCache& view, bool fJustCheck, std::optional<MNListUpdates>& updatesRet)
598598
{
599599
AssertLockHeld(cs_main);
600600

@@ -641,10 +641,8 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null<co
641641
return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "failed-dmn-block");
642642
}
643643

644-
// Don't hold cs while calling signals
645644
if (diff.HasChanges()) {
646-
GetMainSignals().NotifyMasternodeListChanged(false, oldList, diff, connman);
647-
uiInterface.NotifyMasternodeListChanged(newList, pindex);
645+
updatesRet = {newList, oldList, diff};
648646
}
649647

650648
if (nHeight == consensusParams.DIP0003EnforcementHeight) {
@@ -660,7 +658,7 @@ bool CDeterministicMNManager::ProcessBlock(const CBlock& block, gsl::not_null<co
660658
return true;
661659
}
662660

663-
bool CDeterministicMNManager::UndoBlock(gsl::not_null<const CBlockIndex*> pindex)
661+
bool CDeterministicMNManager::UndoBlock(gsl::not_null<const CBlockIndex*> pindex, std::optional<MNListUpdates>& updatesRet)
664662
{
665663
int nHeight = pindex->nHeight;
666664
uint256 blockHash = pindex->GetBlockHash();
@@ -684,8 +682,7 @@ bool CDeterministicMNManager::UndoBlock(gsl::not_null<const CBlockIndex*> pindex
684682

685683
if (diff.HasChanges()) {
686684
auto inversedDiff = curList.BuildDiff(prevList);
687-
GetMainSignals().NotifyMasternodeListChanged(true, curList, inversedDiff, connman);
688-
uiInterface.NotifyMasternodeListChanged(prevList, pindex->pprev);
685+
updatesRet = {curList, prevList, inversedDiff};
689686
}
690687

691688
const auto& consensusParams = Params().GetConsensus();

src/evo/deterministicmns.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,13 @@ constexpr int llmq_max_blocks() {
565565
return max_blocks;
566566
}
567567

568+
struct MNListUpdates
569+
{
570+
CDeterministicMNList old_list;
571+
CDeterministicMNList new_list;
572+
CDeterministicMNListDiff diff;
573+
};
574+
568575
class CDeterministicMNManager
569576
{
570577
static constexpr int DISK_SNAPSHOT_PERIOD = 576; // once per day
@@ -596,8 +603,8 @@ class CDeterministicMNManager
596603
~CDeterministicMNManager() = default;
597604

598605
bool ProcessBlock(const CBlock& block, gsl::not_null<const CBlockIndex*> pindex, BlockValidationState& state,
599-
const CCoinsViewCache& view, bool fJustCheck) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
600-
bool UndoBlock(gsl::not_null<const CBlockIndex*> pindex) LOCKS_EXCLUDED(cs);
606+
const CCoinsViewCache& view, bool fJustCheck, std::optional<MNListUpdates>& updatesRet) EXCLUSIVE_LOCKS_REQUIRED(cs_main) LOCKS_EXCLUDED(cs);
607+
bool UndoBlock(gsl::not_null<const CBlockIndex*> pindex, std::optional<MNListUpdates>& updatesRet) LOCKS_EXCLUDED(cs);
601608

602609
void UpdatedBlockTip(gsl::not_null<const CBlockIndex*> pindex) LOCKS_EXCLUDED(cs);
603610

src/evo/specialtxman.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ static bool UndoSpecialTx(const CTransaction& tx, const CBlockIndex* pindex)
133133
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHFManager& mnhfManager,
134134
llmq::CQuorumBlockProcessor& quorum_block_processor, const llmq::CChainLocksHandler& chainlock_handler,
135135
const Consensus::Params& consensusParams, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots,
136-
BlockValidationState& state)
136+
BlockValidationState& state, std::optional<MNListUpdates>& updatesRet)
137137
{
138138
AssertLockHeld(cs_main);
139139

@@ -181,7 +181,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CM
181181
nTimeQuorum += nTime3 - nTime2;
182182
LogPrint(BCLog::BENCHMARK, " - quorumBlockProcessor: %.2fms [%.2fs]\n", 0.001 * (nTime3 - nTime2), nTimeQuorum * 0.000001);
183183

184-
if (!deterministicMNManager->ProcessBlock(block, pindex, state, view, fJustCheck)) {
184+
if (!deterministicMNManager->ProcessBlock(block, pindex, state, view, fJustCheck, updatesRet)) {
185185
// pass the state returned by the function above
186186
return false;
187187
}
@@ -231,7 +231,7 @@ bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CM
231231
return true;
232232
}
233233

234-
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHFManager& mnhfManager, llmq::CQuorumBlockProcessor& quorum_block_processor)
234+
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHFManager& mnhfManager, llmq::CQuorumBlockProcessor& quorum_block_processor, std::optional<MNListUpdates>& updatesRet)
235235
{
236236
AssertLockHeld(cs_main);
237237

@@ -256,7 +256,7 @@ bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHF
256256
return false;
257257
}
258258

259-
if (!deterministicMNManager->UndoBlock(pindex)) {
259+
if (!deterministicMNManager->UndoBlock(pindex, updatesRet)) {
260260
return false;
261261
}
262262

src/evo/specialtxman.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
#include <sync.h>
1010
#include <threadsafety.h>
1111

12+
#include <optional>
13+
1214
class BlockValidationState;
1315
class CBlock;
1416
class CBlockIndex;
1517
class CCoinsViewCache;
1618
class CMNHFManager;
1719
class TxValidationState;
20+
struct MNListUpdates;
1821
namespace llmq {
1922
class CQuorumBlockProcessor;
2023
class CChainLocksHandler;
@@ -30,9 +33,9 @@ bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const
3033
bool ProcessSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHFManager& mnhfManager,
3134
llmq::CQuorumBlockProcessor& quorum_block_processor, const llmq::CChainLocksHandler& chainlock_handler,
3235
const Consensus::Params& consensusParams, const CCoinsViewCache& view, bool fJustCheck, bool fCheckCbTxMerleRoots,
33-
BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
36+
BlockValidationState& state, std::optional<MNListUpdates>& updatesRet) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
3437
bool UndoSpecialTxsInBlock(const CBlock& block, const CBlockIndex* pindex, CMNHFManager& mnhfManager,
35-
llmq::CQuorumBlockProcessor& quorum_block_processor) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
38+
llmq::CQuorumBlockProcessor& quorum_block_processor, std::optional<MNListUpdates>& updatesRet) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
3639
bool CheckCreditPoolDiffForBlock(const CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams,
3740
const CAmount blockSubsidy, BlockValidationState& state);
3841

src/validation.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include <masternode/payments.h>
5353
#include <masternode/sync.h>
5454

55+
#include <evo/deterministicmns.h>
5556
#include <evo/evodb.h>
5657
#include <evo/mnhftx.h>
5758
#include <evo/specialtx.h>
@@ -1731,7 +1732,8 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
17311732
std::vector<std::pair<CAddressUnspentKey, CAddressUnspentValue> > addressUnspentIndex;
17321733
std::vector<std::pair<CSpentIndexKey, CSpentIndexValue> > spentIndex;
17331734

1734-
if (!UndoSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor)) {
1735+
std::optional<MNListUpdates> mnlist_updates_opt{std::nullopt};
1736+
if (!UndoSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor, mnlist_updates_opt)) {
17351737
error("DisconnectBlock(): UndoSpecialTxsInBlock failed");
17361738
return DISCONNECT_FAILED;
17371739
}
@@ -1847,6 +1849,12 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
18471849
view.SetBestBlock(pindex->pprev->GetBlockHash());
18481850
m_evoDb.WriteBestBlock(pindex->pprev->GetBlockHash());
18491851

1852+
if (mnlist_updates_opt.has_value()) {
1853+
auto mnlu = mnlist_updates_opt.value();
1854+
GetMainSignals().NotifyMasternodeListChanged(true, mnlu.old_list, mnlu.diff);
1855+
uiInterface.NotifyMasternodeListChanged(mnlu.new_list, pindex->pprev);
1856+
}
1857+
18501858
auto finish = Now<SteadyMilliseconds>();
18511859
auto diff = finish - start;
18521860
statsClient.timing("DisconnectBlock_ms", count_milliseconds(diff), 1.0f);
@@ -2210,7 +2218,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
22102218
bool fDIP0001Active_context = pindex->nHeight >= Params().GetConsensus().DIP0001Height;
22112219

22122220
// MUST process special txes before updating UTXO to ensure consistency between mempool and block processing
2213-
if (!ProcessSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor, *m_clhandler, m_params.GetConsensus(), view, fJustCheck, fScriptChecks, state)) {
2221+
std::optional<MNListUpdates> mnlist_updates_opt{std::nullopt};
2222+
if (!ProcessSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor, *m_clhandler, m_params.GetConsensus(), view, fJustCheck, fScriptChecks, state, mnlist_updates_opt)) {
22142223
return error("ConnectBlock(DASH): ProcessSpecialTxsInBlock for block %s failed with %s",
22152224
pindex->GetBlockHash().ToString(), state.ToString());
22162225
}
@@ -2470,6 +2479,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
24702479
view.SetBestBlock(pindex->GetBlockHash());
24712480
m_evoDb.WriteBestBlock(pindex->GetBlockHash());
24722481

2482+
if (mnlist_updates_opt.has_value()) {
2483+
auto mnlu = mnlist_updates_opt.value();
2484+
GetMainSignals().NotifyMasternodeListChanged(false, mnlu.old_list, mnlu.diff);
2485+
uiInterface.NotifyMasternodeListChanged(mnlu.new_list, pindex);
2486+
}
2487+
24732488
int64_t nTime8 = GetTimeMicros(); nTimeCallbacks += nTime8 - nTime5;
24742489
LogPrint(BCLog::BENCHMARK, " - Callbacks: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime8 - nTime5), nTimeCallbacks * MICRO, nTimeCallbacks * MILLI / nBlocksTotal);
24752490

@@ -4838,7 +4853,8 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
48384853

48394854
// MUST process special txes before updating UTXO to ensure consistency between mempool and block processing
48404855
BlockValidationState state;
4841-
if (!ProcessSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor, *m_clhandler, m_params.GetConsensus(), inputs, false /*fJustCheck*/, false /*fScriptChecks*/, state)) {
4856+
std::optional<MNListUpdates> mnlist_updates_opt{std::nullopt};
4857+
if (!ProcessSpecialTxsInBlock(block, pindex, m_mnhfManager, *m_quorum_block_processor, *m_clhandler, m_params.GetConsensus(), inputs, false /*fJustCheck*/, false /*fScriptChecks*/, state, mnlist_updates_opt)) {
48424858
return error("RollforwardBlock(DASH): ProcessSpecialTxsInBlock for block %s failed with %s",
48434859
pindex->GetBlockHash().ToString(), state.ToString());
48444860
}

src/validationinterface.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ void CMainSignals::NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecover
310310
sig->GetHash().ToString());
311311
}
312312

313-
void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman) {
313+
void CMainSignals::NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {
314314
LOG_EVENT("%s: notify mn list changed undo=%d", __func__, undo);
315-
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyMasternodeListChanged(undo, oldMNList, diff, connman); });
315+
m_internals->Iterate([&](CValidationInterface& callbacks) { callbacks.NotifyMasternodeListChanged(undo, oldMNList, diff); });
316316
}

src/validationinterface.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ class CValidationInterface {
165165
virtual void NotifyGovernanceObject(const std::shared_ptr<const CGovernanceObject>& object) {}
166166
virtual void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef& currentTx, const CTransactionRef& previousTx) {}
167167
virtual void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig>& sig) {}
168-
virtual void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman) {}
168+
virtual void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff) {}
169169
/**
170170
* Notifies listeners of the new active block chain on-disk.
171171
*
@@ -232,7 +232,7 @@ class CMainSignals {
232232
void NotifyGovernanceObject(const std::shared_ptr<const CGovernanceObject>& object);
233233
void NotifyInstantSendDoubleSpendAttempt(const CTransactionRef &currentTx, const CTransactionRef &previousTx);
234234
void NotifyRecoveredSig(const std::shared_ptr<const llmq::CRecoveredSig> &sig);
235-
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff, CConnman& connman);
235+
void NotifyMasternodeListChanged(bool undo, const CDeterministicMNList& oldMNList, const CDeterministicMNListDiff& diff);
236236
void ChainStateFlushed(const CBlockLocator &);
237237
void BlockChecked(const CBlock&, const BlockValidationState&);
238238
void NewPoWValidBlock(const CBlockIndex *, const std::shared_ptr<const CBlock>&);

test/lint/lint-circular-dependencies.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=(
105105
"llmq/debug -> llmq/dkgsessionhandler -> llmq/dkgsession -> llmq/debug"
106106
"llmq/utils -> validation -> llmq/utils"
107107
"evo/mnhftx -> validation -> evo/mnhftx"
108+
"evo/deterministicmns -> validation -> evo/deterministicmns"
108109
)
109110

110111
EXIT_CODE=0

0 commit comments

Comments
 (0)