diff --git a/src/bench/rpc_blockchain.cpp b/src/bench/rpc_blockchain.cpp index 5a39e3393411..cb6b058a7b90 100644 --- a/src/bench/rpc_blockchain.cpp +++ b/src/bench/rpc_blockchain.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include @@ -43,9 +42,9 @@ struct TestBlockAndIndex { static void BlockToJsonVerbose(benchmark::Bench& bench) { TestBlockAndIndex data; - const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx; + const llmq::CInstantSendManager& isman = *data.testing_setup->m_node.isman; bench.run([&] { - auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, *llmq_ctx.isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); ankerl::nanobench::doNotOptimizeAway(univalue); }); } @@ -55,8 +54,8 @@ BENCHMARK(BlockToJsonVerbose, benchmark::PriorityLevel::HIGH); static void BlockToJsonVerboseWrite(benchmark::Bench& bench) { TestBlockAndIndex data; - const LLMQContext& llmq_ctx = *data.testing_setup->m_node.llmq_ctx; - auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, *llmq_ctx.isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); + const llmq::CInstantSendManager& isman = *data.testing_setup->m_node.isman; + auto univalue = blockToJSON(data.testing_setup->m_node.chainman->m_blockman, data.block, &data.blockindex, &data.blockindex, *data.testing_setup->m_node.chainlocks, isman, TxVerbosity::SHOW_DETAILS_AND_PREVOUT); bench.run([&] { auto str = univalue.write(); ankerl::nanobench::doNotOptimizeAway(str); diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index 24eb5965c26d..1ebd86bae1c5 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -93,11 +94,13 @@ int main(int argc, char* argv[]) ChainstateManager chainman{chainman_opts}; CMasternodeMetaMan metaman; - std::unique_ptr evodb; - std::unique_ptr dmnman; + CEvoDB evodb{util::DbWrapperParams{.path = gArgs.GetDataDirNet(), .memory = false, .wipe = false}}; + CDeterministicMNManager dmnman{evodb, metaman}; CMasternodeSync mn_sync{std::make_unique()}; CSporkManager sporkman; chainlock::Chainlocks chainlocks(sporkman); + // TODO: remove isman from bitcoin-chainstate and make it nullable for node::ChainstateLoadOptions same as mempool + llmq::CInstantSendManager isman{sporkman, util::DbWrapperParams{.path = gArgs.GetDataDirNet(), .memory = false, .wipe = false}}; std::unique_ptr llmq_ctx; std::unique_ptr chain_helper; @@ -107,8 +110,7 @@ int main(int argc, char* argv[]) cache_sizes.coins_db = 2 << 22; cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22); node::ChainstateLoadOptions options; - options.mn_metaman = &metaman; - options.sporkman = &sporkman; + options.isman = &isman; options.chainlocks = &chainlocks; options.mn_sync = &mn_sync; options.data_dir = gArgs.GetDataDirNet(); @@ -119,7 +121,7 @@ int main(int argc, char* argv[]) std::cerr << "Failed to load Chain state from your datadir." << std::endl; goto epilogue; } else { - std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options, *evodb); + std::tie(status, error) = node::VerifyLoadedChainstate(chainman, options, evodb); if (status != node::ChainstateLoadStatus::SUCCESS) { std::cerr << "Failed to verify loaded Chain state from your datadir." << std::endl; goto epilogue; @@ -278,6 +280,4 @@ int main(int argc, char* argv[]) // Tear down Dash kernel objects before kernel::~Context(). chain_helper.reset(); llmq_ctx.reset(); - dmnman.reset(); - evodb.reset(); } diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index 9412607e93a0..7bcd66d40c6e 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -84,6 +84,10 @@ std::optional> CChainstateH return std::make_pair(::SerializeHash(*islock), islock->txid); } +bool CChainstateHelper::IsInstantSendEnabled() const { return isman.IsInstantSendEnabled(); } + +bool CChainstateHelper::IsInstantSendLocked(const uint256& hash) const { return isman.IsLocked(hash); } + bool CChainstateHelper::IsInstantSendWaitingForTx(const uint256& hash) const { return isman.IsWaitingForTx(hash); } bool CChainstateHelper::RemoveConflictingISLockByTx(const CTransaction& tx) diff --git a/src/evo/chainhelper.h b/src/evo/chainhelper.h index eac183777ba1..0036475fd282 100644 --- a/src/evo/chainhelper.h +++ b/src/evo/chainhelper.h @@ -78,6 +78,8 @@ class CChainstateHelper /** Passthrough functions to CInstantSendManager */ std::optional> ConflictingISLockIfAny(const CTransaction& tx) const; + bool IsInstantSendEnabled() const; + bool IsInstantSendLocked(const uint256& hash) const; bool IsInstantSendWaitingForTx(const uint256& hash) const; bool RemoveConflictingISLockByTx(const CTransaction& tx); diff --git a/src/init.cpp b/src/init.cpp index 61b8ed7501ef..d083d168270f 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -429,13 +429,12 @@ void PrepareShutdown(NodeContext& node) chainstate->ResetCoinsViews(); } } - // The mempool holds raw pointers to dmnman and llmq_ctx->isman, so it has to - // let go of them before either manager is destroyed. - if (node.mempool) { - node.mempool->DisconnectManagers(); - } + // The mempool holds raw pointers to dmnman and isman, so it must be + // destroyed before either manager. + node.mempool.reset(); node.chain_helper.reset(); node.llmq_ctx.reset(); + node.isman.reset(); node.dmnman.reset(); node.evodb.reset(); } @@ -900,7 +899,7 @@ static void PeriodicStats(NodeContext& node) assert(::g_stats_client->active()); ChainstateManager& chainman = *Assert(node.chainman); const CTxMemPool& mempool = *Assert(node.mempool); - const llmq::CInstantSendManager& isman = *Assert(node.llmq_ctx->isman); + const llmq::CInstantSendManager& isman = *Assert(node.isman); chainman.ActiveChainstate().ForceFlushStateToDisk(); const auto maybe_stats = WITH_LOCK(::cs_main, return GetUTXOStats(&chainman.ActiveChainstate().CoinsDB(), chainman.m_blockman, /*hash_type=*/CoinStatsHashType::NONE, node.rpc_interruption_point, chainman.ActiveChain().Tip(), /*index_requested=*/true)); if (maybe_stats.has_value()) { @@ -1949,7 +1948,30 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("* Using %.1f MiB for in-memory UTXO set (plus up to %.1f MiB of unused mempool space)\n", cache_sizes.coins * (1.0 / 1024 / 1024), mempool_opts.max_size_bytes * (1.0 / 1024 / 1024)); for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { - node.mempool = std::make_unique(mempool_opts); + // On a retry iteration the previous instances still hold the on-disk + // database locks, so release them before opening the databases again. + node.mempool.reset(); + node.isman.reset(); + node.dmnman.reset(); + node.evodb.reset(); + auto catch_exceptions = [](auto&& f) { + try { + return f(); + } catch (const std::exception& e) { + LogPrintf("%s\n", e.what()); + return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database")); + } + }; + auto [status, error] = catch_exceptions([&]() -> node::ChainstateLoadResult { + node.evodb = std::make_unique(util::DbWrapperParams{.path = args.GetDataDirNet(), .memory = false, .wipe = node::fReindex || fReindexChainState}); + node.dmnman = std::make_unique(*node.evodb, *node.mn_metaman); + node.isman = std::make_unique(*node.sporkman, util::DbWrapperParams{.path = args.GetDataDirNet(), .memory = false, .wipe = node::fReindex || fReindexChainState}); + + mempool_opts.dmnman = node.dmnman.get(); + mempool_opts.isman = node.isman.get(); + node.mempool = std::make_unique(mempool_opts); + return {node::ChainstateLoadStatus::SUCCESS, {}}; + }); const ChainstateManager::Options chainman_opts{ .chainparams = chainparams, @@ -1968,9 +1990,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.mn_sync = std::make_unique(std::make_unique(*node.connman, *node.netfulfilledman)); node::ChainstateLoadOptions options; - options.mempool = Assert(node.mempool.get()); - options.mn_metaman = Assert(node.mn_metaman.get()); - options.sporkman = Assert(node.sporkman.get()); options.chainlocks = Assert(node.chainlocks.get()); options.mn_sync = Assert(node.mn_sync.get()); options.data_dir = args.GetDataDirNet(); @@ -2000,15 +2019,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) uiInterface.InitMessage(_("Loading block index…").translated); const auto load_block_index_start_time{SteadyClock::now()}; - auto catch_exceptions = [](auto&& f) { - try { - return f(); - } catch (const std::exception& e) { - LogPrintf("%s\n", e.what()); - return std::make_tuple(node::ChainstateLoadStatus::FAILURE, _("Error opening block database")); - } - }; - auto [status, error] = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options, node.evodb, node.dmnman, node.llmq_ctx, node.chain_helper); }); + if (status == node::ChainstateLoadStatus::SUCCESS) { + options.mempool = Assert(node.mempool.get()); + options.isman = Assert(node.isman.get()); + std::tie(status, error) = catch_exceptions([&]{ return LoadChainstate(chainman, cache_sizes, options, *node.evodb, *node.dmnman, node.llmq_ctx, node.chain_helper); }); + } if (status == node::ChainstateLoadStatus::SUCCESS) { uiInterface.InitMessage(_("Verifying blocks…").translated); if (chainman.m_blockman.m_have_pruned && options.check_blocks > MIN_BLOCKS_TO_KEEP) { @@ -2083,7 +2098,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Will init later in ThreadImport node.active_ctx = std::make_unique(*node.llmq_ctx->bls_worker, chainman, *node.connman, *node.dmnman, *node.govman, *node.chain_helper->superblocks, - *node.sporkman, *node.chainlocks, *node.mempool, *node.clhandler, *node.llmq_ctx->isman, + *node.sporkman, *node.chainlocks, *node.mempool, *node.clhandler, *node.isman, *node.llmq_ctx->qman, *node.llmq_ctx->qsnapman, *node.llmq_ctx->sigman, *node.mn_sync, operator_sk, dash_db_params, quorums_watch); RegisterValidationInterface(node.active_ctx.get()); @@ -2093,12 +2108,21 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) RegisterValidationInterface(node.observer_ctx.get()); } + assert(!node.cj_walletman); +#ifdef ENABLE_WALLET + if (!node.active_ctx) { + // Only constructed in wallet-enabled builds; stays null otherwise, must check before use + node.cj_walletman = CJWalletManager::make(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, *node.mn_sync, + *node.isman, !ignores_incoming_txs); + } +#endif + assert(!node.peerman); node.peerman = PeerManager::make(*node.connman, *node.addrman, node.banman.get(), *node.dstxman, chainman, *node.mempool, *node.mn_metaman, *node.mn_sync, *node.sporkman, *node.chainlocks, *node.clhandler, node.active_ctx ? node.active_ctx->nodeman.get() : nullptr, - node.dmnman, node.cj_walletman, node.llmq_ctx, ignores_incoming_txs); + *node.dmnman, node.cj_walletman.get(), *node.isman, *node.llmq_ctx, ignores_incoming_txs); RegisterValidationInterface(node.peerman.get()); node.ds_notification_interface = std::make_unique( @@ -2108,7 +2132,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 7d: Setup other Dash services - node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->isman, node.active_ctx ? node.active_ctx->is_signer.get() : nullptr, *node.llmq_ctx->sigman, *node.llmq_ctx->qman, *node.chainlocks, chainman, *node.mempool, *node.mn_sync)); + node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.isman, node.active_ctx ? node.active_ctx->is_signer.get() : nullptr, *node.llmq_ctx->sigman, *node.llmq_ctx->qman, *node.chainlocks, chainman, *node.mempool, *node.mn_sync)); node.peerman->AddExtraHandler(std::make_unique(node.peerman.get(), *node.llmq_ctx->sigman, node.active_ctx ? node.active_ctx->shareman.get() : nullptr, *node.sporkman)); { @@ -2140,16 +2164,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (node.active_ctx) { auto cj_server = std::make_unique(node.peerman.get(), chainman, *node.connman, *node.dmnman, *node.dstxman, *node.mn_metaman, - *node.mempool, *node.active_ctx->nodeman, *node.mn_sync, *node.llmq_ctx->isman); + *node.mempool, *node.active_ctx->nodeman, *node.mn_sync, *node.isman); node.active_ctx->SetCJServer(cj_server.get()); node.peerman->AddExtraHandler(std::move(cj_server)); - } else { - assert(!node.cj_walletman); - // Only constructed in wallet-enabled builds; stays null otherwise, must check before use -#ifdef ENABLE_WALLET - node.cj_walletman = CJWalletManager::make(chainman, *node.dmnman, *node.mn_metaman, *node.mempool, *node.mn_sync, - *node.llmq_ctx->isman, !ignores_incoming_txs); -#endif } if (node.cj_walletman) { @@ -2386,7 +2403,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // Seed InstantSend tip-height cache; NetInstantSend receives future // updates via CValidationInterface but misses InitializeCurrentBlockTip. // TODO: move cache updates from NetInstantSend to g_ds_notification due to specific of Tip's processing - node.llmq_ctx->isman->CacheTipHeight(WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip())); + node.isman->CacheTipHeight(WITH_LOCK(::cs_main, return chainman.ActiveChain().Tip())); { // Get all UTXOs for each MN collateral in one go so that we can fill coin cache early diff --git a/src/kernel/mempool_options.h b/src/kernel/mempool_options.h index fe2fb0543ba3..93384bb8e7c1 100644 --- a/src/kernel/mempool_options.h +++ b/src/kernel/mempool_options.h @@ -15,6 +15,11 @@ #include class CBlockPolicyEstimator; +class CDeterministicMNManager; + +namespace llmq { +class CInstantSendManager; +} // namespace llmq /** Default for -maxmempool, maximum megabytes of mempool memory usage */ static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300}; @@ -32,6 +37,10 @@ namespace kernel { struct MemPoolOptions { /* Used to estimate appropriate transaction fees. */ CBlockPolicyEstimator* estimator{nullptr}; + /* Used to validate special transactions; required, must outlive the mempool. */ + CDeterministicMNManager* dmnman{nullptr}; + /* Used to protect InstantSend-locked transactions; required, must outlive the mempool. */ + llmq::CInstantSendManager* isman{nullptr}; /* The ratio used to determine how often sanity checks will run. */ int check_ratio{0}; int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000}; diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index f144f5e5db84..b961a0a7ec89 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -5,24 +5,22 @@ #include #include -#include #include #include #include #include #include -LLMQContext::LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, CSporkManager& sporkman, - ChainstateManager& chainman, const util::DbWrapperParams& db_params, int8_t bls_threads, - int16_t worker_count, int64_t max_recsigs_age) : +LLMQContext::LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, ChainstateManager& chainman, + const util::DbWrapperParams& db_params, int8_t bls_threads, int16_t worker_count, + int64_t max_recsigs_age) : bls_worker{std::make_shared()}, qsnapman{std::make_unique(evo_db)}, quorum_block_processor{ std::make_unique(chainman, dmnman, evo_db, *qsnapman, bls_threads)}, qman{std::make_unique(*bls_worker, dmnman, evo_db, *quorum_block_processor, *qsnapman, chainman, db_params)}, - sigman{std::make_unique(*qman, db_params, max_recsigs_age)}, - isman{std::make_unique(sporkman, db_params)} + sigman{std::make_unique(*qman, db_params, max_recsigs_age)} { // Have to start it early to let VerifyDB check ChainLock signatures in coinbase bls_worker->Start(worker_count); diff --git a/src/llmq/context.h b/src/llmq/context.h index 8ffc38dfa529..9033967bfc95 100644 --- a/src/llmq/context.h +++ b/src/llmq/context.h @@ -13,11 +13,9 @@ class CBLSWorker; class ChainstateManager; class CDeterministicMNManager; class CEvoDB; -class CSporkManager; class PeerManager; namespace llmq { -class CInstantSendManager; class CQuorumBlockProcessor; class CQuorumManager; class CQuorumSnapshotManager; @@ -32,9 +30,9 @@ struct LLMQContext { LLMQContext() = delete; LLMQContext(const LLMQContext&) = delete; LLMQContext& operator=(const LLMQContext&) = delete; - explicit LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, CSporkManager& sporkman, - ChainstateManager& chainman, const util::DbWrapperParams& db_params, int8_t bls_threads, - int16_t worker_count, int64_t max_recsigs_age); + explicit LLMQContext(CDeterministicMNManager& dmnman, CEvoDB& evo_db, ChainstateManager& chainman, + const util::DbWrapperParams& db_params, int8_t bls_threads, int16_t worker_count, + int64_t max_recsigs_age); ~LLMQContext(); /** Guaranteed if LLMQContext is initialized then all members are valid too @@ -48,7 +46,6 @@ struct LLMQContext { const std::unique_ptr quorum_block_processor; const std::unique_ptr qman; const std::unique_ptr sigman; - const std::unique_ptr isman; }; #endif // BITCOIN_LLMQ_CONTEXT_H diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 0e265c36bb2c..3c164a07de41 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -570,9 +570,10 @@ class PeerManagerImpl final : public PeerManager CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, chainlock::ChainlockHandler& clhandler, CActiveMasternodeManager* nodeman, - const std::unique_ptr& dmnman, - const std::unique_ptr& cj_walletman, - const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); + CDeterministicMNManager& dmnman, + CJWalletManager* cj_walletman, + llmq::CInstantSendManager& isman, + LLMQContext& llmq_ctx, bool ignore_incoming_txs); ~PeerManagerImpl() { @@ -807,9 +808,10 @@ class PeerManagerImpl final : public PeerManager CTxMemPool& m_mempool; std::unique_ptr m_txreconciliation; CActiveMasternodeManager* const m_nodeman; //!< null if non-masternode mode; non-null implies masternode mode - const std::unique_ptr& m_dmnman; - const std::unique_ptr& m_cj_walletman; - const std::unique_ptr& m_llmq_ctx; + CDeterministicMNManager& m_dmnman; + CJWalletManager* const m_cj_walletman; //!< null in masternode mode and in wallet-disabled builds + llmq::CInstantSendManager& m_isman; + LLMQContext& m_llmq_ctx; CMasternodeMetaMan& m_mn_metaman; CMasternodeSync& m_mn_sync; CSporkManager& m_sporkman; @@ -867,7 +869,7 @@ class PeerManagerImpl final : public PeerManager */ bool BlockRequestAllowed(const CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main); bool AlreadyHaveBlock(const uint256& block_hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); - void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv, llmq::CInstantSendManager& isman) EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); + void ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!m_most_recent_block_mutex); /** * Validation logic for compact filters request handling. @@ -2039,11 +2041,12 @@ std::unique_ptr PeerManager::make(CConnman& connman, AddrMan& addrm CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, chainlock::ChainlockHandler& clhandler, CActiveMasternodeManager* nodeman, - const std::unique_ptr& dmnman, - const std::unique_ptr& cj_walletman, - const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) + CDeterministicMNManager& dmnman, + CJWalletManager* cj_walletman, + llmq::CInstantSendManager& isman, + LLMQContext& llmq_ctx, bool ignore_incoming_txs) { - return std::make_unique(connman, addrman, banman, dstxman, chainman, pool, mn_metaman, mn_sync, sporkman, chainlocks, clhandler, nodeman, dmnman, cj_walletman, llmq_ctx, ignore_incoming_txs); + return std::make_unique(connman, addrman, banman, dstxman, chainman, pool, mn_metaman, mn_sync, sporkman, chainlocks, clhandler, nodeman, dmnman, cj_walletman, isman, llmq_ctx, ignore_incoming_txs); } PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* banman, @@ -2053,9 +2056,10 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* ba const chainlock::Chainlocks& chainlocks, chainlock::ChainlockHandler& clhandler, CActiveMasternodeManager* nodeman, - const std::unique_ptr& dmnman, - const std::unique_ptr& cj_walletman, - const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs) + CDeterministicMNManager& dmnman, + CJWalletManager* cj_walletman, + llmq::CInstantSendManager& isman, + LLMQContext& llmq_ctx, bool ignore_incoming_txs) : m_chainparams(chainman.GetParams()), m_connman(connman), m_addrman(addrman), @@ -2066,6 +2070,7 @@ PeerManagerImpl::PeerManagerImpl(CConnman& connman, AddrMan& addrman, BanMan* ba m_nodeman(nodeman), m_dmnman(dmnman), m_cj_walletman(cj_walletman), + m_isman(isman), m_llmq_ctx(llmq_ctx), m_mn_metaman(mn_metaman), m_mn_sync(mn_sync), @@ -2319,8 +2324,8 @@ bool PeerManagerImpl::AlreadyHave(const CInv& inv) // crafted invalid DSTX-es and potentially cause high load cheaply, because // corresponding checks in ProcessMessage won't let it to send DSTX-es too often. bool fIgnoreRecentRejects = inv.IsMsgDstx() || - m_llmq_ctx->isman->IsWaitingForTx(inv.hash) || - m_llmq_ctx->isman->IsLocked(inv.hash); + m_isman.IsWaitingForTx(inv.hash) || + m_isman.IsLocked(inv.hash); return (!fIgnoreRecentRejects && m_recent_rejects.contains(inv.hash)) || (inv.IsMsgDstx() && static_cast(m_dstxman.GetDSTX(inv.hash))) || @@ -2351,15 +2356,15 @@ bool PeerManagerImpl::AlreadyHave(const CInv& inv) return false; case MSG_QUORUM_FINAL_COMMITMENT: - return m_llmq_ctx->quorum_block_processor->HasMineableCommitment(inv.hash); + return m_llmq_ctx.quorum_block_processor->HasMineableCommitment(inv.hash); case MSG_QUORUM_RECOVERED_SIG: // TODO: move it to NetSigning - return m_llmq_ctx->sigman->AlreadyHave(inv); + return m_llmq_ctx.sigman->AlreadyHave(inv); case MSG_CLSIG: return m_clhandler.AlreadyHave(inv); // TODO: move it to NetInstantSend case MSG_ISDLOCK: - return m_llmq_ctx->isman->AlreadyHave(inv); + return m_isman.AlreadyHave(inv); case MSG_PLATFORM_BAN: return m_mn_metaman.AlreadyHavePlatformBan(inv.hash); @@ -2652,7 +2657,7 @@ void PeerManagerImpl::RelayAddress(NodeId originator, } } -void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv, llmq::CInstantSendManager& isman) +void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& inv) { std::shared_ptr a_recent_block; std::shared_ptr a_recent_compact_block; @@ -2773,7 +2778,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv& m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::TX, *pblock->vtx[pair.first])); } for (PairType &pair : merkleBlock.vMatchedTxn) { - auto islock = isman.GetInstantSendLockByTxid(pair.second); + auto islock = m_isman.GetInstantSendLockByTxid(pair.second); if (islock != nullptr) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::ISDLOCK, *islock)); } @@ -2936,7 +2941,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic if (!push && (inv.type == MSG_QUORUM_FINAL_COMMITMENT)) { llmq::CFinalCommitment o; - if (m_llmq_ctx->quorum_block_processor->GetMineableCommitmentByHash( + if (m_llmq_ctx.quorum_block_processor->GetMineableCommitmentByHash( inv.hash, o)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QFCOMMITMENT, o)); push = true; @@ -2945,7 +2950,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic if (!push && (inv.type == MSG_QUORUM_RECOVERED_SIG)) { llmq::CRecoveredSig o; - if (m_llmq_ctx->sigman->GetRecoveredSigForGetData(inv.hash, o)) { + if (m_llmq_ctx.sigman->GetRecoveredSigForGetData(inv.hash, o)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QSIGREC, o)); push = true; } @@ -2961,7 +2966,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic if (!push && inv.type == MSG_ISDLOCK) { instantsend::InstantSendLock o; - if (m_llmq_ctx->isman->GetInstantSendLockByHash(inv.hash, o)) { + if (m_isman.GetInstantSendLockByHash(inv.hash, o)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::ISDLOCK, o)); push = true; } @@ -2996,7 +3001,7 @@ void PeerManagerImpl::ProcessGetData(CNode& pfrom, Peer& peer, const std::atomic if (it != peer.m_getdata_requests.end() && !pfrom.fPauseSend) { const CInv &inv = *it++; if (inv.IsGenBlkMsg()) { - ProcessGetBlockData(pfrom, peer, inv, *m_llmq_ctx->isman); + ProcessGetBlockData(pfrom, peer, inv); } // else: If the first item on the queue is an unknown type, we erase it // and continue processing the queue on the next call. @@ -3737,7 +3742,7 @@ MessageProcessingResult PeerManagerImpl::ProcessPlatformBanMessage(NodeId node, MessageProcessingResult ret{}; ret.m_to_erase = CInv{MSG_PLATFORM_BAN, hash}; - const auto list = Assert(m_dmnman)->GetListAtChainTip(); + const auto list = m_dmnman.GetListAtChainTip(); auto dmn = list.GetMN(ban_msg.m_protx_hash); if (!dmn) { // small P2P penalty (1), as the evonode may have very recently been removed @@ -3765,7 +3770,7 @@ MessageProcessingResult PeerManagerImpl::ProcessPlatformBanMessage(NodeId node, } Consensus::LLMQType llmq_type = m_chainparams.GetConsensus().llmqTypePlatform; - auto quorum = m_llmq_ctx->qman->GetQuorum(llmq_type, ban_msg.m_quorum_hash); + auto quorum = m_llmq_ctx.qman->GetQuorum(llmq_type, ban_msg.m_quorum_hash); if (!quorum) { LogPrintf("PLATFORMBAN -- hash: %s protx_hash: %s missing quorum_hash: %s llmq_type: %d\n", hash.ToString(), ban_msg.m_protx_hash.ToString(), ban_msg.m_quorum_hash.ToString(), std23::to_underlying(llmq_type)); ret.m_error = MisbehavingError{100}; @@ -4101,8 +4106,8 @@ void PeerManagerImpl::ProcessMessage( // Tell our peer that he should send us CoinJoin queue messages m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDDSQUEUE, true)); // Tell our peer that he should send us intra-quorum messages - const auto tip_mn_list = Assert(m_dmnman)->GetListAtChainTip(); - if (m_llmq_ctx->qman->IsWatching() && m_connman.IsMasternodeQuorumNode(&pfrom, tip_mn_list)) { + const auto tip_mn_list = m_dmnman.GetListAtChainTip(); + if (m_llmq_ctx.qman->IsWatching() && m_connman.IsMasternodeQuorumNode(&pfrom, tip_mn_list)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QWATCH)); } } @@ -4757,7 +4762,7 @@ void PeerManagerImpl::ProcessMessage( // Process custom logic, no matter if tx will be accepted to mempool later or not if (nInvType == MSG_DSTX) { uint256 hashTx = tx.GetHash(); - const auto result = ValidateDSTX(*m_dmnman, m_dstxman, m_chainman, m_mn_metaman, m_mempool, dstx, hashTx); + const auto result = ValidateDSTX(m_dmnman, m_dstxman, m_chainman, m_mn_metaman, m_mempool, dstx, hashTx); if (result.do_return) { if (result.score != DSTXValidationScore::NONE) { Misbehaving(*peer, static_cast(result.score), "invalid dstx"); @@ -4859,7 +4864,7 @@ void PeerManagerImpl::ProcessMessage( // parents so avoid re-requesting it from other peers. m_recent_rejects.insert(tx.GetHash()); ForgetTx(tx.GetHash()); - m_llmq_ctx->isman->TransactionIsRemoved(ptx); + m_isman.TransactionIsRemoved(ptx); } } else { m_recent_rejects.insert(tx.GetHash()); @@ -4891,7 +4896,7 @@ void PeerManagerImpl::ProcessMessage( pfrom.GetId(), state.ToString()); MaybePunishNodeForTx(pfrom.GetId(), state); - m_llmq_ctx->isman->TransactionIsRemoved(ptx); + m_isman.TransactionIsRemoved(ptx); } return; } @@ -5463,7 +5468,7 @@ void PeerManagerImpl::ProcessMessage( CSimplifiedMNListDiff mnListDiff; std::string strError; - if (BuildSimplifiedMNListDiff(*m_dmnman, m_chainman, *m_llmq_ctx->quorum_block_processor, *m_llmq_ctx->qman, + if (BuildSimplifiedMNListDiff(m_dmnman, m_chainman, *m_llmq_ctx.quorum_block_processor, *m_llmq_ctx.qman, cmd.baseBlockHash, cmd.blockHash, mnListDiff, strError)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::MNLISTDIFF, mnListDiff)); @@ -5513,7 +5518,7 @@ void PeerManagerImpl::ProcessMessage( llmq::CQuorumRotationInfo quorumRotationInfoRet; std::string strError; bool use_legacy_construction = pfrom.GetCommonVersion() < EFFICIENT_QRINFO_VERSION;; - if (BuildQuorumRotationInfo(*m_dmnman, *m_llmq_ctx->qsnapman, m_chainman, *m_llmq_ctx->qman, *m_llmq_ctx->quorum_block_processor, cmd, use_legacy_construction, quorumRotationInfoRet, strError)) { + if (BuildQuorumRotationInfo(m_dmnman, *m_llmq_ctx.qsnapman, m_chainman, *m_llmq_ctx.qman, *m_llmq_ctx.quorum_block_processor, cmd, use_legacy_construction, quorumRotationInfoRet, strError)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QUORUMROTATIONINFO, quorumRotationInfoRet)); } else { strError = strprintf("getquorumrotationinfo failed for size(baseBlockHashes)=%d, blockRequestHash=%s. error=%s", cmd.baseBlockHashes.size(), cmd.blockRequestHash.ToString(), strError); @@ -5618,8 +5623,8 @@ void PeerManagerImpl::ProcessMessage( if (m_cj_walletman) { PostProcessMessage(m_cj_walletman->processMessage(pfrom, m_chainman.ActiveChainstate(), m_connman, m_mempool, msg_type, vRecv), pfrom.GetId()); } - PostProcessMessage(CMNAuth::ProcessMessage(pfrom, peer->m_their_services, m_connman, m_mn_metaman, m_nodeman, m_mn_sync, m_dmnman->GetListAtChainTip(), msg_type, vRecv), pfrom.GetId()); - PostProcessMessage(m_llmq_ctx->quorum_block_processor->ProcessMessage( + PostProcessMessage(CMNAuth::ProcessMessage(pfrom, peer->m_their_services, m_connman, m_mn_metaman, m_nodeman, m_mn_sync, m_dmnman.GetListAtChainTip(), msg_type, vRecv), pfrom.GetId()); + PostProcessMessage(m_llmq_ctx.quorum_block_processor->ProcessMessage( pfrom, msg_type, vRecv, [this, &pfrom](const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!::cs_main) { return WITH_LOCK(::cs_main, @@ -5649,7 +5654,7 @@ void PeerManagerImpl::ProcessMessage( Misbehaving(*peer, UNREQUESTED_OBJECT_MISBEHAVIOR_SCORE, "unrequested clsig"); return; } - PostProcessMessage(m_clhandler.ProcessNewChainLock(pfrom.GetId(), clsig, *m_llmq_ctx->qman, + PostProcessMessage(m_clhandler.ProcessNewChainLock(pfrom.GetId(), clsig, *m_llmq_ctx.qman, clsig_inv.hash), pfrom.GetId()); } @@ -6137,8 +6142,6 @@ bool PeerManagerImpl::SendMessages(CNode* pto) { AssertLockHeld(g_msgproc_mutex); - assert(m_llmq_ctx); - const bool is_masternode = m_nodeman != nullptr; PeerRef peer = GetPeerRef(pto->GetId()); @@ -6468,7 +6471,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto) tx_relay->m_tx_inventory_known_filter.insert(hash); queueAndMaybePushInv(CInv(nInvType, hash)); - const auto islock = m_llmq_ctx->isman->GetInstantSendLockByTxid(hash); + const auto islock = m_isman.GetInstantSendLockByTxid(hash); if (islock == nullptr) continue; uint256 isLockHash{::SerializeHash(*islock)}; tx_relay->m_tx_inventory_known_filter.insert(isLockHash); diff --git a/src/net_processing.h b/src/net_processing.h index 761da8001c07..8fceb9bcd295 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -33,6 +33,9 @@ namespace chainlock { class Chainlocks; class ChainlockHandler; } // namespace chainlock +namespace llmq { +class CInstantSendManager; +} // namespace llmq /** Default for -maxorphantxsize, maximum size in megabytes the orphan map can grow before entries are removed */ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS_SIZE = 10; // this allows around 100 TXs of max size (and many more of normal size) @@ -156,9 +159,10 @@ class PeerManager : public CValidationInterface, public NetEventsInterface, publ const chainlock::Chainlocks& chainlocks, chainlock::ChainlockHandler& clhandler, CActiveMasternodeManager* nodeman, - const std::unique_ptr& dmnman, - const std::unique_ptr& cj_walletman, - const std::unique_ptr& llmq_ctx, bool ignore_incoming_txs); + CDeterministicMNManager& dmnman, + CJWalletManager* cj_walletman, + llmq::CInstantSendManager& isman, + LLMQContext& llmq_ctx, bool ignore_incoming_txs); virtual ~PeerManager() { } /** diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 87c91b2dcfa6..b0ceaf9dea67 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -139,34 +138,28 @@ static bool RecoverSnapshotCleanup(CEvoDB& evodb, const fs::path& data_dir, bili // to ChainstateManager::InitializeChainstate(). static ChainstateLoadResult CompleteChainstateInitialization(ChainstateManager& chainman, const CacheSizes& cache_sizes, const ChainstateLoadOptions& options, CEvoDB& evodb, - std::unique_ptr& dmnman, + CDeterministicMNManager& dmnman, std::unique_ptr& llmq_ctx, std::unique_ptr& chain_helper) EXCLUSIVE_LOCKS_REQUIRED(::cs_main) { const bool to_wipe_data = options.reindex || options.reindex_chainstate; - dmnman.reset(); - dmnman = std::make_unique(evodb, *options.mn_metaman); - auto& pblocktree{chainman.m_blockman.m_block_tree_db}; // new CBlockTreeDB tries to delete the existing file, which // fails if it's still open from the previous loop. Close it first: pblocktree.reset(); pblocktree.reset(new CBlockTreeDB(cache_sizes.block_tree_db, options.block_tree_db_in_memory, options.reindex)); - // Initialize llmq_ctx and connection to mempool + // Initialize llmq_ctx llmq_ctx.reset(); - llmq_ctx = std::make_unique(*dmnman, evodb, *options.sporkman, chainman, + llmq_ctx = std::make_unique(dmnman, evodb, chainman, util::DbWrapperParams{.path = options.data_dir, .memory = options.dash_dbs_in_memory, .wipe = to_wipe_data}, options.bls_threads, options.worker_count, options.max_recsigs_age); - if (options.mempool) { - options.mempool->ConnectManagers(dmnman.get(), llmq_ctx->isman.get()); - } // Initialize chain_helper chain_helper.reset(); - chain_helper = std::make_unique(evodb, *dmnman, *options.mn_sync, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor), + chain_helper = std::make_unique(evodb, dmnman, *options.mn_sync, *options.isman, *(llmq_ctx->quorum_block_processor), *(llmq_ctx->qsnapman), chainman, chainman.GetConsensus(), *options.chainlocks, *(llmq_ctx->qman)); @@ -287,7 +280,7 @@ static ChainstateLoadResult CompleteChainstateInitialization(ChainstateManager& } // Check if nVersion-first migration is needed and perform it - if (dmnman->IsMigrationRequired() && !dmnman->MigrateLegacyDiffs(chainman.ActiveChainstate().m_chain.Tip())) { + if (dmnman.IsMigrationRequired() && !dmnman.MigrateLegacyDiffs(chainman.ActiveChainstate().m_chain.Tip())) { return {ChainstateLoadStatus::FAILURE, _("Failed to upgrade Evo database")}; } @@ -300,12 +293,11 @@ static ChainstateLoadResult CompleteChainstateInitialization(ChainstateManager& } ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, - const ChainstateLoadOptions& options, std::unique_ptr& evodb, - std::unique_ptr& dmnman, std::unique_ptr& llmq_ctx, + const ChainstateLoadOptions& options, CEvoDB& evodb, + CDeterministicMNManager& dmnman, std::unique_ptr& llmq_ctx, std::unique_ptr& chain_helper) { - assert(options.mn_metaman); - assert(options.sporkman); + assert(options.isman); assert(options.chainlocks); assert(options.mn_sync); @@ -326,15 +318,9 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize LOCK(cs_main); - evodb.reset(); - // TODO: pass DbWrapperParams as options instead multiple params - evodb = std::make_unique(util::DbWrapperParams{ - .path = options.data_dir, - .memory = options.dash_dbs_in_memory, - .wipe = options.reindex || options.reindex_chainstate}); if (!options.dash_dbs_in_memory && !options.reindex && !options.reindex_chainstate) { bilingual_str recovery_error; - if (!RecoverSnapshotCleanup(*evodb, options.data_dir, recovery_error)) { + if (!RecoverSnapshotCleanup(evodb, options.data_dir, recovery_error)) { return {ChainstateLoadStatus::FAILURE, recovery_error}; } } @@ -342,12 +328,13 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize chainman.m_total_coinsdb_cache = cache_sizes.coins_db; // Load the fully validated chainstate. - chainman.InitializeChainstate(options.mempool, *evodb, chain_helper); + chainman.InitializeChainstate(options.mempool, evodb, chain_helper); - // Wiping the shared EvoDB above erased the SNAPSHOT best-block marker that - // ActivateExistingSnapshot() requires, so a persisted snapshot chainstate can - // no longer be revived. Discard it here rather than letting startup fail with - // advice ("reindex") the user has just followed, which would never recover. + // On a reindex the caller hands us a freshly wiped EvoDB, without the + // SNAPSHOT best-block marker that ActivateExistingSnapshot() requires, so a + // persisted snapshot chainstate can no longer be revived. Discard it here + // rather than letting startup fail with advice ("reindex") the user has + // just followed, which would never recover. if ((options.reindex || options.reindex_chainstate) && !DeleteSnapshotChainstateFromDisk()) { return {ChainstateLoadStatus::FAILURE, _("Failed to remove the snapshot chainstate directory. Remove it manually before restarting.")}; @@ -359,7 +346,7 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize return {ChainstateLoadStatus::FAILURE, snapshot_error}; } - auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options, *evodb, dmnman, + auto [init_status, init_error] = CompleteChainstateInitialization(chainman, cache_sizes, options, evodb, dmnman, llmq_ctx, chain_helper); if (init_status != ChainstateLoadStatus::SUCCESS) { return {init_status, init_error}; @@ -379,14 +366,8 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize // Do nothing; expected case. } else if (snapshot_completion == SnapshotCompletionResult::SUCCESS) { LogPrintf("[snapshot] cleaning up unneeded background chainstate, then reinitializing\n"); - // The mempool holds raw pointers to dmnman and llmq_ctx->isman, so it has to - // let go of them before either manager is destroyed. - if (options.mempool) { - options.mempool->DisconnectManagers(); - } chain_helper.reset(); llmq_ctx.reset(); - dmnman.reset(); if (!chainman.ValidatedSnapshotCleanup()) { return {ChainstateLoadStatus::FAILURE_FATAL, Untranslated("Background chainstate cleanup failed unexpectedly.")}; } @@ -398,13 +379,13 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize assert(!chainman.IsSnapshotActive()); assert(!chainman.IsSnapshotValidated()); - chainman.InitializeChainstate(options.mempool, *evodb, chain_helper); + chainman.InitializeChainstate(options.mempool, evodb, chain_helper); // A reload of the block index is required to recompute setBlockIndexCandidates // for the fully validated chainstate. chainman.ActiveChainstate().ClearBlockIndexCandidates(); - std::tie(init_status, init_error) = CompleteChainstateInitialization(chainman, cache_sizes, options, *evodb, + std::tie(init_status, init_error) = CompleteChainstateInitialization(chainman, cache_sizes, options, evodb, dmnman, llmq_ctx, chain_helper); if (init_status != ChainstateLoadStatus::SUCCESS) { return {init_status, init_error}; diff --git a/src/node/chainstate.h b/src/node/chainstate.h index 98c0ea9f7511..675afe3cc1b4 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -21,12 +21,11 @@ class CDeterministicMNManager; class CEvoDB; class ChainstateManager; class CMasternodeSync; -class CMasternodeMetaMan; -class CSporkManager; class CTxMemPool; struct LLMQContext; namespace chainlock { class Chainlocks; } +namespace llmq { class CInstantSendManager; } namespace node { @@ -34,8 +33,7 @@ struct CacheSizes; struct ChainstateLoadOptions { CTxMemPool* mempool{nullptr}; - CMasternodeMetaMan* mn_metaman{nullptr}; - CSporkManager* sporkman{nullptr}; + llmq::CInstantSendManager* isman{nullptr}; chainlock::Chainlocks* chainlocks{nullptr}; const CMasternodeSync* mn_sync{nullptr}; fs::path data_dir; @@ -83,12 +81,12 @@ using ChainstateLoadResult = std::tuple; * * LoadChainstate returns a (status code, error string) tuple. * - * The evodb, dmnman, llmq_ctx and chain_helper arguments are outputs: any - * instance they hold is destroyed and replaced with a freshly constructed one. + * The llmq_ctx and chain_helper arguments are outputs: any instance they hold + * is destroyed and replaced with a freshly constructed one. */ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSizes& cache_sizes, - const ChainstateLoadOptions& options, std::unique_ptr& evodb, - std::unique_ptr& dmnman, std::unique_ptr& llmq_ctx, + const ChainstateLoadOptions& options, CEvoDB& evodb, + CDeterministicMNManager& dmnman, std::unique_ptr& llmq_ctx, std::unique_ptr& chain_helper); ChainstateLoadResult VerifyLoadedChainstate(ChainstateManager& chainman, const ChainstateLoadOptions& options, CEvoDB& evodb, std::function notify_bls_state = nullptr); diff --git a/src/node/context.cpp b/src/node/context.cpp index 335f34a22947..24687782ee5b 100644 --- a/src/node/context.cpp +++ b/src/node/context.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include diff --git a/src/node/context.h b/src/node/context.h index b0d839603418..ce9a384ecdb6 100644 --- a/src/node/context.h +++ b/src/node/context.h @@ -58,6 +58,7 @@ class Loader; } // namespace interfaces namespace llmq { +class CInstantSendManager; struct ObserverContext; } // namespace llmq @@ -102,6 +103,7 @@ struct NodeContext { std::unique_ptr evodb; std::unique_ptr chain_helper; std::unique_ptr dmnman; + std::unique_ptr isman; std::unique_ptr govman; std::unique_ptr mn_metaman; std::unique_ptr mn_sync; diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 14b9fd4a204b..4900dcf785af 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -546,10 +546,10 @@ class LLMQImpl : public LLMQ } InstantSendCounts getInstantSendCounts() override { - if (!context().llmq_ctx || !context().llmq_ctx->isman) { + if (!context().isman) { return {}; } - const auto counts{context().llmq_ctx->isman->GetCounts()}; + const auto counts{context().isman->GetCounts()}; return { .m_verified = counts.m_verified, .m_unverified = counts.m_unverified, @@ -648,10 +648,10 @@ class LLMQImpl : public LLMQ } std::vector getInstantSendLock(const uint256& txid) override { - if (!context().llmq_ctx || !context().llmq_ctx->isman) { + if (!context().isman) { return {}; } - const auto islock{context().llmq_ctx->isman->GetInstantSendLockByTxid(txid)}; + const auto islock{context().isman->GetInstantSendLockByTxid(txid)}; if (!islock) { return {}; } @@ -1383,8 +1383,8 @@ class ChainImpl : public Chain } bool isInstantSendLockedTx(const uint256& hash) override { - if (m_node.llmq_ctx == nullptr || m_node.llmq_ctx->isman == nullptr) return false; - return m_node.llmq_ctx->isman->IsLocked(hash); + if (m_node.isman == nullptr) return false; + return m_node.isman->IsLocked(hash); } bool hasChainLock(int height, const uint256& hash) override { diff --git a/src/node/miner.cpp b/src/node/miner.cpp index 34225a6d0daa..c4ad5451d76b 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -76,7 +75,6 @@ BlockAssembler::BlockAssembler(Chainstate& chainstate, const NodeContext& node, m_evoDb(*Assert(node.evodb)), m_chainlocks(*Assert(node.chainlocks)), m_clhandler(*Assert(node.clhandler)), - m_isman(*Assert(Assert(node.llmq_ctx)->isman)), chainparams(chainstate.m_chainman.GetParams()), m_mempool(mempool), m_quorum_block_processor(*Assert(Assert(node.llmq_ctx)->quorum_block_processor)), @@ -396,7 +394,7 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa } const auto& txid = it->GetTx().GetHash(); - if (!m_isman.IsInstantSendEnabled() || m_isman.IsLocked(txid)) { + if (!m_chain_helper.IsInstantSendEnabled() || m_chain_helper.IsInstantSendLocked(txid)) { continue; } diff --git a/src/node/miner.h b/src/node/miner.h index 465929be17dc..dfa24cfcb55d 100644 --- a/src/node/miner.h +++ b/src/node/miner.h @@ -34,7 +34,6 @@ class ChainlockHandler; } // namespace chainlock namespace Consensus { struct Params; }; namespace llmq { -class CInstantSendManager; class CQuorumBlockProcessor; class CQuorumManager; } // namespace llmq @@ -174,7 +173,6 @@ class BlockAssembler CEvoDB& m_evoDb; const chainlock::Chainlocks& m_chainlocks; chainlock::ChainlockHandler& m_clhandler; - llmq::CInstantSendManager& m_isman; const CChainParams& chainparams; const CTxMemPool* const m_mempool; const llmq::CQuorumBlockProcessor& m_quorum_block_processor; diff --git a/src/rest.cpp b/src/rest.cpp index 90a8dc7bca6a..4cb2859b360b 100644 --- a/src/rest.cpp +++ b/src/rest.cpp @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -138,21 +137,21 @@ static ChainstateManager* GetChainman(const CoreContext& context, HTTPRequest* r * Get the node context LLMQContext. * * @param[in] req The HTTP request, whose status code will be set if node - * context LLMQContext is not found. - * @returns Pointer to the LLMQContext or nullptr if none found. + * context InstantSend manager is not found. + * @returns Pointer to the InstantSend manager or nullptr if none found. */ -static LLMQContext* GetLLMQContext(const CoreContext& context, HTTPRequest* req) +static llmq::CInstantSendManager* GetInstantSendManager(const CoreContext& context, HTTPRequest* req) { auto node_context = GetContext(context); - if (!node_context || !node_context->llmq_ctx) { + if (!node_context || !node_context->isman) { RESTERR(req, HTTP_INTERNAL_SERVER_ERROR, strprintf("%s:%d (%s)\n" - "Internal bug detected: LLMQ context not found!\n" + "Internal bug detected: InstantSend manager not found!\n" "You may report this issue here: %s\n", __FILE__, __LINE__, __func__, PACKAGE_BUGREPORT)); return nullptr; } - return node_context->llmq_ctx.get(); + return node_context->isman.get(); } RESTResponseFormat ParseDataFormat(std::string& param, const std::string& strReq) @@ -364,10 +363,10 @@ static bool rest_block(const CoreContext& context, const NodeContext* const node = GetNodeContext(context, req); if (!node || !node->chainlocks) return false; - const LLMQContext* llmq_ctx = GetLLMQContext(context, req); - if (!llmq_ctx) return false; + const llmq::CInstantSendManager* isman = GetInstantSendManager(context, req); + if (!isman) return false; - UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, *node->chainlocks, *llmq_ctx->isman, tx_verbosity); + UniValue objBlock = blockToJSON(chainman.m_blockman, block, tip, pblockindex, *node->chainlocks, *isman, tx_verbosity); std::string strJSON = objBlock.write() + "\n"; req->WriteHeader("Content-Type", "application/json"); req->WriteReply(HTTP_OK, strJSON); @@ -688,8 +687,8 @@ static bool rest_mempool(const CoreContext& context, HTTPRequest* req, const std switch (rf) { case RESTResponseFormat::JSON: { - const LLMQContext* llmq_ctx = GetLLMQContext(context, req); - if (!llmq_ctx) return false; + const llmq::CInstantSendManager* isman = GetInstantSendManager(context, req); + if (!isman) return false; std::string str_json; if (param == "contents") { @@ -716,9 +715,9 @@ static bool rest_mempool(const CoreContext& context, HTTPRequest* req, const std if (verbose && mempool_sequence) { return RESTERR(req, HTTP_BAD_REQUEST, "Verbose results cannot contain mempool sequence values. (hint: set \"verbose=false\")"); } - str_json = MempoolToJSON(*mempool, llmq_ctx->isman.get(), verbose, mempool_sequence).write() + "\n"; + str_json = MempoolToJSON(*mempool, isman, verbose, mempool_sequence).write() + "\n"; } else { - str_json = MempoolInfoToJSON(*mempool, *llmq_ctx->isman).write() + "\n"; + str_json = MempoolInfoToJSON(*mempool, *isman).write() + "\n"; } req->WriteHeader("Content-Type", "application/json"); diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index bb0be4e11df4..34f41736bbaf 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -57,7 +57,6 @@ #include #include #include -#include #include @@ -1061,7 +1060,7 @@ static RPCHelpMan getblock() return strHex; } - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); CHECK_NONFATAL(node.chainlocks); TxVerbosity tx_verbosity; if (verbosity == 1) { @@ -1072,7 +1071,7 @@ static RPCHelpMan getblock() tx_verbosity = TxVerbosity::SHOW_DETAILS_AND_PREVOUT; } - return blockToJSON(chainman.m_blockman, block, tip, pblockindex, *node.chainlocks, *llmq_ctx.isman, tx_verbosity); + return blockToJSON(chainman.m_blockman, block, tip, pblockindex, *node.chainlocks, isman, tx_verbosity); }, }; } @@ -2414,7 +2413,7 @@ static RPCHelpMan getspecialtxes() LOCK(cs_main); const CTxMemPool& mempool = EnsureMemPool(node); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); CHECK_NONFATAL(node.chainlocks); const uint256 blockhash(ParseHashV(request.params[0], "blockhash")); @@ -2474,7 +2473,7 @@ static RPCHelpMan getspecialtxes() case 2 : { UniValue objTx(UniValue::VOBJ); - TxToJSON(*tx, blockhash, mempool, chainman.ActiveChainstate(), *node.chainlocks, *llmq_ctx.isman, node.spent_index.get(), objTx); + TxToJSON(*tx, blockhash, mempool, chainman.ActiveChainstate(), *node.chainlocks, isman, node.spent_index.get(), objTx); result.push_back(objTx); break; } diff --git a/src/rpc/mempool.cpp b/src/rpc/mempool.cpp index 5f8bca5db3ef..d433c04f13e7 100644 --- a/src/rpc/mempool.cpp +++ b/src/rpc/mempool.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include @@ -402,9 +401,9 @@ static RPCHelpMan getrawmempool() const NodeContext& node = EnsureAnyNodeContext(request.context); const CTxMemPool& mempool = EnsureMemPool(node); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); - return MempoolToJSON(mempool, llmq_ctx.isman.get(), fVerbose, include_mempool_sequence); + return MempoolToJSON(mempool, &isman, fVerbose, include_mempool_sequence); }, }; } @@ -461,12 +460,12 @@ static RPCHelpMan getmempoolancestors() return o; } else { UniValue o(UniValue::VOBJ); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); for (CTxMemPool::txiter ancestorIt : setAncestors) { const CTxMemPoolEntry &e = *ancestorIt; const uint256& _hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); - entryToJSON(mempool, info, e, llmq_ctx.isman.get()); + entryToJSON(mempool, info, e, &isman); o.pushKV(_hash.ToString(), info); } return o; @@ -529,12 +528,12 @@ static RPCHelpMan getmempooldescendants() return o; } else { UniValue o(UniValue::VOBJ); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); for (CTxMemPool::txiter descendantIt : setDescendants) { const CTxMemPoolEntry &e = *descendantIt; const uint256& _hash = e.GetTx().GetHash(); UniValue info(UniValue::VOBJ); - entryToJSON(mempool, info, e, llmq_ctx.isman.get()); + entryToJSON(mempool, info, e, &isman); o.pushKV(_hash.ToString(), info); } return o; @@ -573,8 +572,8 @@ static RPCHelpMan getmempoolentry() const CTxMemPoolEntry &e = *it; UniValue info(UniValue::VOBJ); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - entryToJSON(mempool, info, e, llmq_ctx.isman.get()); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); + entryToJSON(mempool, info, e, &isman); return info; }, }; @@ -707,8 +706,8 @@ static RPCHelpMan getmempoolinfo() { const NodeContext& node = EnsureAnyNodeContext(request.context); const CTxMemPool& mempool = EnsureMemPool(node); - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); - return MempoolInfoToJSON(mempool, *llmq_ctx.isman); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); + return MempoolInfoToJSON(mempool, isman); }, }; } diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 4a003a8d6593..9d55adcc00cb 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -57,7 +57,6 @@ #include #include #include -#include #include #include @@ -434,13 +433,13 @@ static RPCHelpMan getrawtransaction() return EncodeHexTx(*tx); } - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); const CTxMemPool& mempool = EnsureMemPool(node); CHECK_NONFATAL(node.chainlocks); UniValue result(UniValue::VOBJ); if (blockindex) result.pushKV("in_active_chain", in_active_chain); - TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, *llmq_ctx.isman, node.spent_index.get(), result); + TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, isman, node.spent_index.get(), result); return result; }, }; @@ -495,7 +494,7 @@ static RPCHelpMan getrawtransactionmulti() { const NodeContext& node{EnsureAnyNodeContext(request.context)}; const ChainstateManager& chainman{EnsureChainman(node)}; - const LLMQContext& llmq_ctx{EnsureLLMQContext(node)}; + const llmq::CInstantSendManager& isman{EnsureInstantSendManager(node)}; CHECK_NONFATAL(node.chainlocks); CTxMemPool& mempool{EnsureMemPool(node)}; @@ -531,7 +530,7 @@ static RPCHelpMan getrawtransactionmulti() { result.pushKV(txid_str, "None"); } else if (fVerbose) { UniValue tx_data{UniValue::VOBJ}; - TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, *llmq_ctx.isman, node.spent_index.get(), tx_data); + TxToJSON(*tx, hash_block, mempool, chainman.ActiveChainstate(), *node.chainlocks, isman, node.spent_index.get(), tx_data); result.pushKV(txid_str, tx_data); } else { result.pushKV(txid_str, EncodeHexTx(*tx)); @@ -591,11 +590,11 @@ static RPCHelpMan getislocks() throw JSONRPCError(RPC_INVALID_PARAMETER, "Up to 100 txids only"); } - const LLMQContext& llmq_ctx = EnsureLLMQContext(node); + const llmq::CInstantSendManager& isman = EnsureInstantSendManager(node); for (const auto idx : util::irange(txids.size())) { const uint256 txid(ParseHashV(txids[idx], "txid")); - if (const instantsend::InstantSendLockPtr islock = llmq_ctx.isman->GetInstantSendLockByTxid(txid); islock != nullptr) { + if (const instantsend::InstantSendLockPtr islock = isman.GetInstantSendLockByTxid(txid); islock != nullptr) { UniValue objIS(UniValue::VOBJ); objIS.pushKV("txid", islock->txid.ToString()); UniValue inputs(UniValue::VARR); diff --git a/src/rpc/server_util.cpp b/src/rpc/server_util.cpp index 60d24077736e..8c041ee20993 100644 --- a/src/rpc/server_util.cpp +++ b/src/rpc/server_util.cpp @@ -123,6 +123,14 @@ LLMQContext& EnsureAnyLLMQContext(const CoreContext& context) return EnsureLLMQContext(EnsureAnyNodeContext(context)); } +llmq::CInstantSendManager& EnsureInstantSendManager(const NodeContext& node) +{ + if (!node.isman) { + throw JSONRPCError(RPC_INTERNAL_ERROR, "Node InstantSend manager not found"); + } + return *node.isman; +} + CConnman& EnsureConnman(const NodeContext& node) { if (!node.connman) { diff --git a/src/rpc/server_util.h b/src/rpc/server_util.h index 81e330817f7c..4b50bc8dde3a 100644 --- a/src/rpc/server_util.h +++ b/src/rpc/server_util.h @@ -15,6 +15,9 @@ class ChainstateManager; class PeerManager; class BanMan; struct LLMQContext; +namespace llmq { +class CInstantSendManager; +} // namespace llmq namespace node { struct NodeContext; } // namespace node @@ -32,6 +35,7 @@ CBlockPolicyEstimator& EnsureFeeEstimator(const node::NodeContext& node); CBlockPolicyEstimator& EnsureAnyFeeEstimator(const CoreContext& context); LLMQContext& EnsureLLMQContext(const node::NodeContext& node); LLMQContext& EnsureAnyLLMQContext(const CoreContext& context); +llmq::CInstantSendManager& EnsureInstantSendManager(const node::NodeContext& node); CConnman& EnsureConnman(const node::NodeContext& node); PeerManager& EnsurePeerman(const node::NodeContext& node); diff --git a/src/test/coinjoin_inouts_tests.cpp b/src/test/coinjoin_inouts_tests.cpp index 0753a9f56d88..5cd3c8921474 100644 --- a/src/test/coinjoin_inouts_tests.cpp +++ b/src/test/coinjoin_inouts_tests.cpp @@ -219,7 +219,7 @@ BOOST_AUTO_TEST_CASE(server_signfinaltx_nonparticipant_cannot_abort_session) TestableCoinJoinServer server(m_node.peerman.get(), *Assert(m_node.chainman), *Assert(m_node.connman), *Assert(m_node.dmnman), *Assert(m_node.dstxman), *Assert(m_node.mn_metaman), *Assert(m_node.mempool), mn_activeman, *Assert(m_node.mn_sync), - *Assert(m_node.llmq_ctx->isman)); + *Assert(m_node.isman)); // Seed an active signing session with one participant. That participant's // addr is deliberately not registered with connman -- a session-wide @@ -257,7 +257,7 @@ BOOST_AUTO_TEST_CASE(server_signfinaltx_participant_oversized_count_is_rejected_ TestableCoinJoinServer server(m_node.peerman.get(), *Assert(m_node.chainman), *Assert(m_node.connman), *Assert(m_node.dmnman), *Assert(m_node.dstxman), *Assert(m_node.mn_metaman), *Assert(m_node.mempool), mn_activeman, *Assert(m_node.mn_sync), - *Assert(m_node.llmq_ctx->isman)); + *Assert(m_node.isman)); // Same setup, but this time the oversized DSSIGNFINALTX comes from the // session participant itself. It must still be rejected without materializing @@ -298,7 +298,7 @@ struct InOutsChecker : CCoinJoinBaseSession BOOST_AUTO_TEST_CASE(validation_uses_session_denom_snapshot) { Chainstate& chainstate{Assert(m_node.chainman)->ActiveChainstate()}; - const auto& isman{*Assert(m_node.llmq_ctx->isman)}; + const auto& isman{*Assert(m_node.isman)}; const auto& mempool{*Assert(m_node.mempool)}; const int session_denom{CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination())}; diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index 2e4d117ab182..6e9339bd0c7a 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -1285,9 +1285,6 @@ void FuncTestMempoolReorg(TestChainSetup& setup) auto tx_reg = CreateProRegTxExternalCollateral(chainman, utxos, 1, collateralOutpoint, scriptPayout, ownerKey, operatorKey, collateralKey, setup.coinbaseKey); CTxMemPool testPool{MemPoolOptionsForTest(setup.m_node)}; - if (setup.m_node.dmnman) { - testPool.ConnectManagers(setup.m_node.dmnman.get(), setup.m_node.llmq_ctx->isman.get()); - } TestMemPoolEntryHelper entry; LOCK2(cs_main, testPool.cs); @@ -1372,8 +1369,6 @@ void FuncTestMempoolProTxKeyChangedConflictChain(TestChainSetup& setup) auto tx_revoke = CreateProUpRevTx(chainman, utxos, proTxHash, operatorKey, setup.coinbaseKey); CTxMemPool testPool{MemPoolOptionsForTest(setup.m_node)}; - BOOST_REQUIRE(setup.m_node.dmnman); - testPool.ConnectManagers(setup.m_node.dmnman.get(), setup.m_node.llmq_ctx->isman.get()); TestMemPoolEntryHelper entry; LOCK2(cs_main, testPool.cs); @@ -1415,9 +1410,6 @@ void FuncTestMempoolDualProregtx(TestChainSetup& setup) auto tx_reg2 = CreateProRegTxExternalCollateral(chainman, utxos, 2, collateralOutpoint, scriptPayout, ownerKey, operatorKey, collateralKey, setup.coinbaseKey); CTxMemPool testPool{MemPoolOptionsForTest(setup.m_node)}; - if (setup.m_node.dmnman) { - testPool.ConnectManagers(setup.m_node.dmnman.get(), setup.m_node.llmq_ctx->isman.get()); - } TestMemPoolEntryHelper entry; LOCK2(cs_main, testPool.cs); diff --git a/src/test/interfaces_tests.cpp b/src/test/interfaces_tests.cpp index d96112dbca1e..2e3f1e414ff8 100644 --- a/src/test/interfaces_tests.cpp +++ b/src/test/interfaces_tests.cpp @@ -358,7 +358,7 @@ BOOST_AUTO_TEST_CASE(getInstantSendLock) constexpr const char* REGTEST_SPORK_PRIVKEY{"cP4EKFyJsHT39LDqgdcB43Y3YXjNyjb5Fuas1GQSeAtjnZWmZEQK"}; auto node{interfaces::MakeNode(m_node)}; - auto& isman{*Assert(m_node.llmq_ctx)->isman}; + auto& isman{*Assert(m_node.isman)}; auto islock{std::make_shared()}; islock->inputs.emplace_back(uint256::ONE, 0); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index a370cb1072ea..e1f6a8efcd52 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -70,6 +70,7 @@ #include #include #include +#include #include #include #include @@ -131,8 +132,8 @@ std::unique_ptr MakePeerManager(CConnman& connman, bool ignore_incoming_txs) { return PeerManager::make(connman, *node.addrman, banman, *node.dstxman, *node.chainman, *node.mempool, *node.mn_metaman, - *node.mn_sync, *node.sporkman, *node.chainlocks, *node.clhandler, /*nodeman=*/nullptr, node.dmnman, node.cj_walletman, - node.llmq_ctx, ignore_incoming_txs); + *node.mn_sync, *node.sporkman, *node.chainlocks, *node.clhandler, /*nodeman=*/nullptr, *node.dmnman, node.cj_walletman.get(), + *node.isman, *node.llmq_ctx, ignore_incoming_txs); } struct NetworkSetup @@ -221,6 +222,8 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve m_node.sporkman = std::make_unique(); m_node.chainlocks = std::make_unique(*m_node.sporkman); m_node.evodb = std::make_unique(util::DbWrapperParams{.path = m_node.args->GetDataDirNet(), .memory = m_dash_dbs_in_memory, .wipe = true}); + m_node.dmnman = std::make_unique(*m_node.evodb, *m_node.mn_metaman); + m_node.isman = std::make_unique(*m_node.sporkman, util::DbWrapperParams{.path = m_node.args->GetDataDirNet(), .memory = m_dash_dbs_in_memory, .wipe = true}); static bool noui_connected = false; if (!noui_connected) { @@ -235,7 +238,9 @@ BasicTestingSetup::~BasicTestingSetup() { SetMockTime(0s); // Reset mocktime for following tests LogInstance().DisconnectTestLogger(); - // Close disk-backed EvoDB before deleting its data directory. + // Close the disk-backed databases before deleting their data directory. + m_node.isman.reset(); + m_node.dmnman.reset(); m_node.evodb.reset(); fs::remove_all(m_path_root); gArgs.ClearArgs(); @@ -300,8 +305,7 @@ node::ChainstateLoadOptions ChainTestingSetup::ChainstateLoadOptionsForTest() { node::ChainstateLoadOptions options; options.mempool = Assert(m_node.mempool.get()); - options.mn_metaman = Assert(m_node.mn_metaman.get()); - options.sporkman = Assert(m_node.sporkman.get()); + options.isman = Assert(m_node.isman.get()); options.chainlocks = Assert(m_node.chainlocks.get()); options.mn_sync = Assert(m_node.mn_sync.get()); options.data_dir = Assert(m_node.args)->GetDataDirNet(); @@ -322,9 +326,26 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() { auto& chainman{*Assert(m_node.chainman)}; - const node::ChainstateLoadOptions options{ChainstateLoadOptionsForTest()}; + node::ChainstateLoadOptions options{ChainstateLoadOptionsForTest()}; + + if (options.reindex || options.reindex_chainstate) { + // A reindex wipes the Dash databases at open, which AppInitMain does by + // recreating them together with the mempool bound to them. Mirror that + // here, including the chainlock handler that references the mempool. + m_node.clhandler.reset(); + m_node.mempool.reset(); + m_node.isman.reset(); + m_node.dmnman.reset(); + m_node.evodb.reset(); + m_node.evodb = std::make_unique(util::DbWrapperParams{.path = m_node.args->GetDataDirNet(), .memory = m_dash_dbs_in_memory, .wipe = true}); + m_node.dmnman = std::make_unique(*m_node.evodb, *m_node.mn_metaman); + m_node.isman = std::make_unique(*m_node.sporkman, util::DbWrapperParams{.path = m_node.args->GetDataDirNet(), .memory = m_dash_dbs_in_memory, .wipe = true}); + m_node.mempool = std::make_unique(MemPoolOptionsForTest(m_node)); + m_node.clhandler = std::make_unique(*m_node.chainlocks, chainman, *m_node.mempool, *m_node.mn_sync); + options = ChainstateLoadOptionsForTest(); + } - auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options, m_node.evodb, m_node.dmnman, m_node.llmq_ctx, + auto [status, error] = LoadChainstate(chainman, m_cache_sizes, options, *m_node.evodb, *m_node.dmnman, m_node.llmq_ctx, m_node.chain_helper); assert(status == node::ChainstateLoadStatus::SUCCESS); @@ -358,7 +379,7 @@ TestingSetup::TestingSetup( #ifdef ENABLE_WALLET // The test suite doesn't use masternode mode, so we may initialize it m_node.cj_walletman = CJWalletManager::make(*m_node.chainman, *m_node.dmnman, *m_node.mn_metaman, *m_node.mempool, - *m_node.mn_sync, *m_node.llmq_ctx->isman, /*relay_txes=*/true); + *m_node.mn_sync, *m_node.isman, /*relay_txes=*/true); assert(m_node.cj_walletman); // WalletInit::Construct()-like logic needed for wallet tests that run on @@ -410,12 +431,8 @@ TestingSetup::~TestingSetup() // in init.cpp). Keep this defensive for fixtures that construct govman. m_node.govman.reset(); - if (m_node.mempool) { - m_node.mempool->DisconnectManagers(); - } m_node.chain_helper.reset(); m_node.llmq_ctx.reset(); - m_node.dmnman.reset(); } TestChain100Setup::TestChain100Setup( diff --git a/src/test/util/txmempool.cpp b/src/test/util/txmempool.cpp index ce3d85e83d57..23aff3f2e2d4 100644 --- a/src/test/util/txmempool.cpp +++ b/src/test/util/txmempool.cpp @@ -18,6 +18,8 @@ CTxMemPool::Options MemPoolOptionsForTest(const NodeContext& node) { CTxMemPool::Options mempool_opts{ .estimator = node.fee_estimator.get(), + .dmnman = node.dmnman.get(), + .isman = node.isman.get(), // Default to always checking mempool regardless of // chainparams.DefaultConsistencyChecks for tests .check_ratio = 1, diff --git a/src/test/validation_chainstatemanager_tests.cpp b/src/test/validation_chainstatemanager_tests.cpp index 901a3f094f65..50a8f8dc1145 100644 --- a/src/test/validation_chainstatemanager_tests.cpp +++ b/src/test/validation_chainstatemanager_tests.cpp @@ -58,25 +58,18 @@ static void DashChainstateSetup(ChainstateManager& chainman, bool llmq_dbs_wipe) { node.llmq_ctx.reset(); - node.llmq_ctx = std::make_unique(*node.dmnman, *node.evodb, *Assert(node.sporkman.get()), chainman, + node.llmq_ctx = std::make_unique(*node.dmnman, *node.evodb, chainman, util::DbWrapperParams{.path = node.args->GetDataDirNet(), .memory = llmq_dbs_in_memory, .wipe = llmq_dbs_wipe}, llmq::DEFAULT_BLSCHECK_THREADS, llmq::DEFAULT_WORKER_COUNT, llmq::DEFAULT_MAX_RECOVERED_SIGS_AGE); - if (node.mempool) { - node.mempool->ConnectManagers(node.dmnman.get(), node.llmq_ctx->isman.get()); - } - // Initialize chain_helper node.chain_helper.reset(); - node.chain_helper = std::make_unique(*node.evodb, *node.dmnman, *Assert(node.mn_sync), *(node.llmq_ctx->isman), *(node.llmq_ctx->quorum_block_processor), + node.chain_helper = std::make_unique(*node.evodb, *node.dmnman, *Assert(node.mn_sync), *Assert(node.isman), *(node.llmq_ctx->quorum_block_processor), *(node.llmq_ctx->qsnapman), chainman, chainman.GetConsensus(), *Assert(node.chainlocks), *(node.llmq_ctx->qman)); } static void DashChainstateSetupClose(node::NodeContext& node) { - if (node.mempool) { - node.mempool->DisconnectManagers(); - } node.chain_helper.reset(); node.llmq_ctx.reset(); } @@ -89,7 +82,6 @@ BOOST_AUTO_TEST_CASE(chainstatemanager) ChainstateManager& manager = *m_node.chainman; CTxMemPool& mempool = *m_node.mempool; CEvoDB& evodb = *m_node.evodb; - m_node.dmnman = std::make_unique(evodb, *Assert(m_node.mn_metaman.get())); std::vector chainstates; BOOST_CHECK(!manager.SnapshotBlockhash().has_value()); @@ -1223,7 +1215,7 @@ BOOST_FIXTURE_TEST_CASE(chainstatemanager_snapshot_missing_base_fails_load, Snap { ASSERT_DEBUG_LOG("missing from the block index"); std::tie(status, error) = node::LoadChainstate(chainman, m_cache_sizes, ChainstateLoadOptionsForTest(), - m_node.evodb, m_node.dmnman, m_node.llmq_ctx, + *m_node.evodb, *m_node.dmnman, m_node.llmq_ctx, m_node.chain_helper); } BOOST_CHECK(status == node::ChainstateLoadStatus::FAILURE); diff --git a/src/txmempool.cpp b/src/txmempool.cpp index 58c03b3baa6f..001d4de0500a 100644 --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -423,6 +423,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee, CTxMemPool::CTxMemPool(const Options& opts) : m_check_ratio{opts.check_ratio}, minerPolicyEstimator{opts.estimator}, + m_dmnman{*Assert(opts.dmnman)}, + m_isman{*Assert(opts.isman)}, m_max_size_bytes{opts.max_size_bytes}, m_expiry{opts.expiry}, m_incremental_relay_feerate{opts.incremental_relay_feerate}, @@ -438,21 +440,6 @@ CTxMemPool::CTxMemPool(const Options& opts) _clear(); //lock free clear } -void CTxMemPool::ConnectManagers(gsl::not_null dmnman, gsl::not_null isman) -{ - // Do not allow double-initialization - assert(m_dmnman.load(std::memory_order_acquire) == nullptr); - m_dmnman.store(dmnman, std::memory_order_release); - assert(m_isman.load(std::memory_order_acquire) == nullptr); - m_isman.store(isman, std::memory_order_release); -} - -void CTxMemPool::DisconnectManagers() -{ - m_dmnman.store(nullptr, std::memory_order_release); - m_isman.store(nullptr, std::memory_order_release); -} - bool CTxMemPool::isSpent(const COutPoint& outpoint) const { LOCK(cs); @@ -523,9 +510,7 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces // Invalid ProTxes should never get this far because transactions should be // fully checked by AcceptToMemoryPool() at this point, so we just assume that // everything is fine here. - if (auto dmnman = m_dmnman.load(std::memory_order_acquire); dmnman) { - addUncheckedProTx(*dmnman, newit, tx); - } + addUncheckedProTx(newit, tx); } void CTxMemPool::addAddressIndex(const CTxMemPoolEntry& entry, const CCoinsViewCache& view) @@ -651,8 +636,7 @@ void CTxMemPool::removeSpentIndex(const uint256 txhash) } } -void CTxMemPool::addUncheckedProTx(CDeterministicMNManager& dmnman, indexed_transaction_set::iterator& newit, - const CTransaction& tx) +void CTxMemPool::addUncheckedProTx(indexed_transaction_set::iterator& newit, const CTransaction& tx) { const uint256 tx_hash{tx.GetHash()}; if (tx.nType == TRANSACTION_PROVIDER_REGISTER) { @@ -686,7 +670,7 @@ void CTxMemPool::addUncheckedProTx(CDeterministicMNManager& dmnman, indexed_tran auto proTx = *Assert(GetTxPayload(tx)); mapProTxRefs.emplace(proTx.proTxHash, tx_hash); mapProTxBlsPubKeyHashes.emplace(proTx.pubKeyOperator.GetHash(), tx_hash); - auto dmn = Assert(dmnman.GetListAtChainTip().GetMN(proTx.proTxHash)); + auto dmn = Assert(m_dmnman.GetListAtChainTip().GetMN(proTx.proTxHash)); newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator); if (dmn->pdmnState->pubKeyOperator != proTx.pubKeyOperator) { newit->isKeyChangeProTx = true; @@ -694,7 +678,7 @@ void CTxMemPool::addUncheckedProTx(CDeterministicMNManager& dmnman, indexed_tran } else if (tx.nType == TRANSACTION_PROVIDER_UPDATE_REVOKE) { auto proTx = *Assert(GetTxPayload(tx)); mapProTxRefs.emplace(proTx.proTxHash, tx_hash); - auto dmn = Assert(dmnman.GetListAtChainTip().GetMN(proTx.proTxHash)); + auto dmn = Assert(m_dmnman.GetListAtChainTip().GetMN(proTx.proTxHash)); newit->validForProTxKey = ::SerializeHash(dmn->pdmnState->pubKeyOperator); if (dmn->pdmnState->pubKeyOperator.Get() != CBLSPublicKey()) { newit->isKeyChangeProTx = true; @@ -736,9 +720,7 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason) } else vTxHashes.clear(); - if (m_dmnman.load(std::memory_order_acquire)) { - removeUncheckedProTx(it->GetTx()); - } + removeUncheckedProTx(it->GetTx()); totalTxSize -= it->GetTxSize(); m_total_fee -= it->GetFee(); @@ -957,8 +939,6 @@ void CTxMemPool::removeProTxCollateralConflicts(const CTransaction &tx, const CO void CTxMemPool::removeProTxSpentCollateralConflicts(const CTransaction &tx) { - auto dmnman = Assert(m_dmnman.load(std::memory_order_acquire)); - // Remove TXs that refer to a MN for which the collateral was spent auto removeSpentCollateralConflict = [&](const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(cs) { // Can't use equal_range here as every call to removeRecursive might invalidate iterators @@ -979,7 +959,7 @@ void CTxMemPool::removeProTxSpentCollateralConflicts(const CTransaction &tx) } } }; - auto mnList = dmnman->GetListAtChainTip(); + auto mnList = m_dmnman.GetListAtChainTip(); for (const auto& in : tx.vin) { auto collateralIt = mapProTxCollaterals.find(in.prevout); if (collateralIt != mapProTxCollaterals.end()) { @@ -1114,9 +1094,7 @@ void CTxMemPool::removeForBlock(const std::vector& vtx, unsigne RemoveStaged(stage, true, MemPoolRemovalReason::BLOCK); } removeConflicts(*tx); - if (m_dmnman.load(std::memory_order_acquire)) { - removeProTxConflicts(*tx); - } + removeProTxConflicts(*tx); ClearPrioritisation(tx->GetHash()); } lastRollingFeeUpdate = GetTime(); @@ -1418,8 +1396,7 @@ bool CTxMemPool::existsProviderTxCrossSchemeConflict(const CTransaction& tx) con // encoding the masternode already holds in the list fails CheckSpecialTx // before reaching the mempool. Probing here would wrongly block updates // for one member of a pre-activation cross-scheme pair. - auto dmnman = Assert(m_dmnman.load(std::memory_order_acquire)); - if (auto dmn = dmnman->GetListAtChainTip().GetMN(opt_proTx->proTxHash); + if (auto dmn = m_dmnman.GetListAtChainTip().GetMN(opt_proTx->proTxHash); dmn && opt_proTx->pubKeyOperator == dmn->pdmnState->pubKeyOperator) { return false; } @@ -1429,8 +1406,6 @@ bool CTxMemPool::existsProviderTxCrossSchemeConflict(const CTransaction& tx) con } bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const { - auto dmnman = Assert(m_dmnman.load(std::memory_order_acquire)); - LOCK(cs); auto hasKeyChangeInMempool = [&](const uint256& proTxHash) EXCLUSIVE_LOCKS_REQUIRED(cs) { @@ -1504,7 +1479,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const { auto& proTx = *opt_proTx; // this method should only be called with validated ProTxs - auto dmn = dmnman->GetListAtChainTip().GetMN(proTx.proTxHash); + auto dmn = m_dmnman.GetListAtChainTip().GetMN(proTx.proTxHash); if (!dmn) { LogPrint(BCLog::MEMPOOL, "%s: ERROR: Masternode is not in the list, proTxHash: %s\n", __func__, proTx.proTxHash.ToString()); return true; // i.e. failed to find validated ProTx == conflict @@ -1526,7 +1501,7 @@ bool CTxMemPool::existsProviderTxConflict(const CTransaction &tx) const { } auto& proTx = *opt_proTx; // this method should only be called with validated ProTxs - auto dmn = dmnman->GetListAtChainTip().GetMN(proTx.proTxHash); + auto dmn = m_dmnman.GetListAtChainTip().GetMN(proTx.proTxHash); if (!dmn) { LogPrint(BCLog::MEMPOOL, "%s: ERROR: Masternode is not in the list, proTxHash: %s\n", __func__, proTx.proTxHash.ToString()); return true; // i.e. failed to find validated ProTx == conflict @@ -1675,12 +1650,11 @@ void CTxMemPool::RemoveStaged(setEntries &stage, bool updateDescendants, MemPool int CTxMemPool::Expire(std::chrono::seconds time) { AssertLockHeld(cs); - auto isman = Assert(m_isman.load(std::memory_order_acquire)); indexed_transaction_set::index::type::iterator it = mapTx.get().begin(); setEntries toremove; while (it != mapTx.get().end() && it->GetTime() < time) { // locked txes do not expire until mined and have sufficient confirmations - if (isman->IsLocked(it->GetTx().GetHash())) { + if (m_isman.IsLocked(it->GetTx().GetHash())) { it++; continue; } diff --git a/src/txmempool.h b/src/txmempool.h index 564aa5c0ef15..c0dcd0f1a360 100644 --- a/src/txmempool.h +++ b/src/txmempool.h @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -448,8 +447,8 @@ class CTxMemPool const int m_check_ratio; //!< Value n means that 1 times in n we check. std::atomic nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation CBlockPolicyEstimator* const minerPolicyEstimator; - std::atomic m_dmnman{nullptr}; - std::atomic m_isman{nullptr}; + CDeterministicMNManager& m_dmnman; + llmq::CInstantSendManager& m_isman; uint64_t totalTxSize GUARDED_BY(cs); //!< sum of all mempool tx' byte sizes CAmount m_total_fee GUARDED_BY(cs); //!< sum of all mempool tx's fees (NOT modified fee) @@ -610,21 +609,6 @@ class CTxMemPool */ explicit CTxMemPool(const Options& opts); - /** - * Set CDeterministicMNManager and CInstantSendManager pointers. - * - * Separated from constructor as it's initialized after CTxMemPool - * is created. Required for ProTx processing. - */ - void ConnectManagers(gsl::not_null dmnman, gsl::not_null isman); - - /** - * Reset CDeterministicMNManager and CInstantSendManager pointers. - * - * @pre Must be called before CDeterministicMNManager and CInstantSendManager are destroyed. - */ - void DisconnectManagers(); - /** * If sanity-checking is turned on, check makes sure the pool is * consistent (does not contain two transactions that spend the same inputs, @@ -781,10 +765,7 @@ class CTxMemPool */ void TrimToSize(size_t sizelimit, std::vector* pvNoSpendsRemaining = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs); - /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. - * @pre Caller must ensure that CInstantSendManager exists and has been set using - * ConnectManagers() for InstantSend awareness - */ + /** Expire all transaction (and their dependencies) in the mempool older than time. Return the number of removed transactions. */ int Expire(std::chrono::seconds time) EXCLUSIVE_LOCKS_REQUIRED(cs); /** @@ -835,10 +816,6 @@ class CTxMemPool TxMempoolInfo info(const uint256& hash) const; std::vector infoAll() const; - /** - * @pre Caller must ensure that CDeterministicMNManager exists and has been - * set using ConnectManagers() for the CTxMemPool instance. - */ bool existsProviderTxConflict(const CTransaction &tx) const; /** @@ -939,8 +916,7 @@ class CTxMemPool /** * addUnchecked extension for Dash-specific transactions (ProTx). */ - void addUncheckedProTx(CDeterministicMNManager& dmnman, indexed_transaction_set::iterator& newit, - const CTransaction& tx); + void addUncheckedProTx(indexed_transaction_set::iterator& newit, const CTransaction& tx); /** Before calling removeUnchecked for a given transaction, * UpdateForRemoveFromMempool must be called on the entire (dependent) set