diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index b63b4efd7a..8f1a14d92b 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -192,9 +192,11 @@ static bool extractSignals(const llmq::CQuorumManager& qman, const CBlock& block std::optional CMNHFManager::ProcessBlock(const CBlock& block, const CBlockIndex* const pindex, bool fJustCheck, BlockValidationState& state) { + assert(m_qman); + try { std::vector new_signals; - if (!extractSignals(*Assert(llmq::quorumManager), block, pindex, new_signals, state)) { + if (!extractSignals(*m_qman, block, pindex, new_signals, state)) { // state is set inside extractSignals return std::nullopt; } @@ -244,9 +246,11 @@ std::optional CMNHFManager::ProcessBlock(const CBlock& bl bool CMNHFManager::UndoBlock(const CBlock& block, const CBlockIndex* const pindex) { + assert(m_qman); + std::vector excluded_signals; BlockValidationState state; - if (!extractSignals(*Assert(llmq::quorumManager), block, pindex, excluded_signals, state)) { + if (!extractSignals(*m_qman, block, pindex, excluded_signals, state)) { LogPrintf("CMNHFManager::%s: failed to extract signals\n", __func__); return false; } @@ -350,6 +354,13 @@ void CMNHFManager::AddSignal(const CBlockIndex* const pindex, int bit) AddToCache(signals, pindex); } +void CMNHFManager::ConnectManagers(gsl::not_null qman) +{ + // Do not allow double-initialization + assert(m_qman == nullptr); + m_qman = qman; +} + std::string MNHFTx::ToString() const { return strprintf("MNHFTx(versionBit=%d, quorumHash=%s, sig=%s)", diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index cb045b267b..53425d60ab 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -6,6 +6,7 @@ #define BITCOIN_EVO_MNHFTX_H #include +#include #include #include #include @@ -99,6 +100,7 @@ class CMNHFManager : public AbstractEHFManager { private: CEvoDB& m_evoDb; + llmq::CQuorumManager* m_qman{nullptr}; static constexpr size_t MNHFCacheSize = 1000; Mutex cs_cache; @@ -115,17 +117,22 @@ public: /** * Every new block should be processed when Tip() is updated by calling of CMNHFManager::ProcessBlock. * This function actually does only validate EHF transaction for this block and update internal caches/evodb state + * + * @pre Caller must ensure that LLMQContext has been initialized and the llmq::CQuorumManager pointer has been + * set by calling ConnectManagers() for this CMNHFManager instance */ std::optional ProcessBlock(const CBlock& block, const CBlockIndex* const pindex, bool fJustCheck, BlockValidationState& state); /** * Every undo block should be processed when Tip() is updated by calling of CMNHFManager::UndoBlock - * This function actually does nothing at the moment, because status of ancestor block is already know. + * This function actually does nothing at the moment, because status of ancestor block is already known. * Although it should be still called to do some sanity checks + * + * @pre Caller must ensure that LLMQContext has been initialized and the llmq::CQuorumManager pointer has been + * set by calling ConnectManagers() for this CMNHFManager instance */ bool UndoBlock(const CBlock& block, const CBlockIndex* const pindex); - // Implements interface Signals GetSignalsStage(const CBlockIndex* const pindexPrev) override; @@ -133,6 +140,22 @@ public: * Helper that used in Unit Test to forcely setup EHF signal for specific block */ void AddSignal(const CBlockIndex* const pindex, int bit) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); + + /** + * Set llmq::CQuorumManager pointer. + * + * Separated from constructor to allow LLMQContext to use CMNHFManager in read-only capacity. + * Required to mutate state. + */ + void ConnectManagers(gsl::not_null qman); + + /** + * Reset llmq::CQuorumManager pointer. + * + * @pre Must be called before LLMQContext (containing llmq::CQuorumManager) is destroyed. + */ + void DisconnectManagers() { m_qman = nullptr; }; + private: void AddToCache(const Signals& signals, const CBlockIndex* const pindex); diff --git a/src/init.cpp b/src/init.cpp index 461b9397e3..afc9d52993 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -339,9 +339,10 @@ void PrepareShutdown(NodeContext& node) } pblocktree.reset(); node.chain_helper.reset(); - if (node.llmq_ctx) { - node.llmq_ctx.reset(); + if (node.mnhf_manager) { + node.mnhf_manager->DisconnectManagers(); } + node.llmq_ctx.reset(); llmq::quorumSnapshotManager.reset(); node.mempool->DisconnectManagers(); node.dmnman.reset(); @@ -1973,6 +1974,8 @@ bool AppInitMain(const CoreContext& context, NodeContext& node, interfaces::Bloc node.llmq_ctx.reset(); node.llmq_ctx = std::make_unique(chainman.ActiveChainstate(), *node.connman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, *node.mempool, node.mn_activeman.get(), *node.mn_sync, node.peerman, /* unit_tests = */ false, /* wipe = */ fReset || fReindexChainState); + // Enable CMNHFManager::{Process, Undo}Block + node.mnhf_manager->ConnectManagers(node.llmq_ctx->qman); // Have to start it early to let VerifyDB check ChainLock signatures in coinbase node.llmq_ctx->Start(); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 6b22c8b5e7..f52d97a12a 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -119,6 +119,7 @@ void DashTestSetup(NodeContext& node, const CChainParams& chainparams) #endif // ENABLE_WALLET node.llmq_ctx = std::make_unique(chainstate, *node.connman, *node.dmnman, *node.evodb, *node.mn_metaman, *node.mnhf_manager, *node.sporkman, *node.mempool, /* mn_activeman = */ nullptr, *node.mn_sync, node.peerman, /* unit_tests = */ true, /* wipe = */ false); + Assert(node.mnhf_manager)->ConnectManagers(node.llmq_ctx->qman); node.chain_helper = std::make_unique(*node.cpoolman, *node.dmnman, *node.mnhf_manager, *node.govman, *(node.llmq_ctx->quorum_block_processor), chainparams.GetConsensus(), *node.mn_sync, *node.sporkman, *(node.llmq_ctx->clhandler), *(node.llmq_ctx->qman)); } @@ -128,6 +129,7 @@ void DashTestSetupClose(NodeContext& node) node.chain_helper.reset(); node.llmq_ctx->Interrupt(); node.llmq_ctx->Stop(); + Assert(node.mnhf_manager)->DisconnectManagers(); node.llmq_ctx.reset(); #ifdef ENABLE_WALLET node.coinjoin_loader.reset();