From b4199583d6c9bea6bf78b677a627d5374f79bb5f Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Sun, 17 May 2026 14:00:06 +0700 Subject: [PATCH 01/13] refactor: drop useless GovernanceSignerParent --- src/governance/core_write.cpp | 4 ++-- src/governance/governance.h | 25 ++++++++++++------------- src/governance/net_governance.cpp | 2 ++ src/governance/signing.cpp | 3 ++- src/governance/signing.h | 24 +++--------------------- src/qt/proposallist.cpp | 1 + src/qt/proposalresume.cpp | 6 +++--- test/lint/lint-circular-dependencies.py | 1 - 8 files changed, 25 insertions(+), 41 deletions(-) diff --git a/src/governance/core_write.cpp b/src/governance/core_write.cpp index 3fab5b078030..9093ec2748fc 100644 --- a/src/governance/core_write.cpp +++ b/src/governance/core_write.cpp @@ -2,10 +2,10 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include - -#include +#include #include #include diff --git a/src/governance/governance.h b/src/governance/governance.h index bce031abede0..457fb488852f 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -7,8 +7,7 @@ #include #include -#include - +#include #include #include @@ -231,7 +230,7 @@ class GovernanceStore // // Governance Manager : Contains all proposals for the budget // -class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent +class CGovernanceManager : public GovernanceStore { friend class CGovernanceObject; @@ -271,7 +270,7 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent ~CGovernanceManager(); // Basic initialization and querying - bool IsValid() const override { return is_valid; } + bool IsValid() const { return is_valid; } bool LoadCache(bool load_cache) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); @@ -286,7 +285,7 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent bool AreRateChecksEnabled() const { return fRateChecksEnabled; } // Getters/Setters - int GetCachedBlockHeight() const override { return nCachedBlockHeight; } + int GetCachedBlockHeight() const { return nCachedBlockHeight; } int64_t GetLastDiffTime() const { return nTimeLastDiff; } std::vector GetCurrentVotes(const uint256& nParentHash, const COutPoint& mnCollateralOutpointFilter) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); @@ -303,7 +302,7 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent */ bool ConfirmInventoryRequest(const CInv& inv) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) override + bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); void RelayObject(const CGovernanceObject& obj) EXCLUSIVE_LOCKS_REQUIRED(!cs_relay); @@ -315,13 +314,13 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); // Signer interface - bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false) override + bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::shared_ptr FindGovernanceObjectByDataHash(const uint256& nDataHash) override + std::shared_ptr FindGovernanceObjectByDataHash(const uint256& nDataHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::vector> GetApprovedProposals(const CDeterministicMNList& tip_mn_list) override + std::vector> GetApprovedProposals(const CDeterministicMNList& tip_mn_list) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - void AddGovernanceObject(CGovernanceObject& govobj, const std::string& peer_str) override + void AddGovernanceObject(CGovernanceObject& govobj, const std::string& peer_str) EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); // Superblocks @@ -336,7 +335,7 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent // Thread-safe accessors bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, - int nBlockHeight) override + int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); bool HaveObjectForHash(const uint256& nHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); @@ -346,11 +345,11 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent EXCLUSIVE_LOCKS_REQUIRED(!cs_store); bool SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::shared_ptr FindGovernanceObject(const uint256& nHash) override + std::shared_ptr FindGovernanceObject(const uint256& nHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); int GetVoteCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::vector> GetActiveTriggers() const override + std::vector> GetActiveTriggers() const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); void AddPostponedObject(const CGovernanceObject& govobj) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); diff --git a/src/governance/net_governance.cpp b/src/governance/net_governance.cpp index 852175d05b36..72e903170aa9 100644 --- a/src/governance/net_governance.cpp +++ b/src/governance/net_governance.cpp @@ -7,7 +7,9 @@ #include #include #include +#include #include +#include #include #include #include diff --git a/src/governance/signing.cpp b/src/governance/signing.cpp index 173860b1aa19..d89c6d72204b 100644 --- a/src/governance/signing.cpp +++ b/src/governance/signing.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -22,7 +23,7 @@ namespace { constexpr std::chrono::seconds GOVERNANCE_FUDGE_WINDOW{2h}; } // anonymous namespace -GovernanceSigner::GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, GovernanceSignerParent& govman, +GovernanceSigner::GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, CGovernanceManager& govman, const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, const CMasternodeSync& mn_sync) : m_connman{connman}, diff --git a/src/governance/signing.h b/src/governance/signing.h index 6f4d3884bd09..9675c86898f5 100644 --- a/src/governance/signing.h +++ b/src/governance/signing.h @@ -20,36 +20,18 @@ class CConnman; class CDeterministicMNList; class CDeterministicMNManager; class CGovernanceException; +class CGovernanceManager; class CGovernanceVote; class ChainstateManager; class CMasternodeSync; enum vote_outcome_enum_t : int; -class GovernanceSignerParent -{ -public: - virtual ~GovernanceSignerParent() = default; - - virtual bool IsValid() const = 0; - virtual bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, - std::shared_ptr& pSuperblockRet, int nBlockHeight) = 0; - virtual bool MasternodeRateCheck(const CGovernanceObject& govobj, bool fUpdateFailStatus = false) = 0; - virtual bool ProcessVoteAndRelay(const CGovernanceVote& vote, CGovernanceException& exception, CConnman& connman) = 0; - virtual int GetCachedBlockHeight() const = 0; - virtual std::shared_ptr FindGovernanceObject(const uint256& nHash) = 0; - virtual std::shared_ptr FindGovernanceObjectByDataHash(const uint256& nDataHash) = 0; - virtual std::vector> GetActiveTriggers() const = 0; - virtual std::vector> GetApprovedProposals( - const CDeterministicMNList& tip_mn_list) = 0; - virtual void AddGovernanceObject(CGovernanceObject& govobj, const std::string& peer_str) = 0; -}; - class GovernanceSigner { private: CConnman& m_connman; CDeterministicMNManager& m_dmnman; - GovernanceSignerParent& m_govman; + CGovernanceManager& m_govman; const CActiveMasternodeManager& m_mn_activeman; const ChainstateManager& m_chainman; const CMasternodeSync& m_mn_sync; @@ -61,7 +43,7 @@ class GovernanceSigner GovernanceSigner() = delete; GovernanceSigner(const GovernanceSigner&) = delete; GovernanceSigner& operator=(const GovernanceSigner&) = delete; - explicit GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, GovernanceSignerParent& govman, + explicit GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, CGovernanceManager& govman, const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, const CMasternodeSync& mn_sync); ~GovernanceSigner(); diff --git a/src/qt/proposallist.cpp b/src/qt/proposallist.cpp index 27241a021726..7b69e03f7479 100644 --- a/src/qt/proposallist.cpp +++ b/src/qt/proposallist.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include diff --git a/src/qt/proposalresume.cpp b/src/qt/proposalresume.cpp index 6b1fcd641563..51243d676d0d 100644 --- a/src/qt/proposalresume.cpp +++ b/src/qt/proposalresume.cpp @@ -6,13 +6,13 @@ #include #include +#include +#include +#include #include #include -#include -#include - #include #include #include diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index cb3f4c80e89a..fb9e2644d7d0 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -38,7 +38,6 @@ "evo/smldiff -> llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> evo/smldiff", "evo/specialtxman -> validation -> evo/specialtxman", "governance/classes -> governance/object -> governance/governance -> governance/classes", - "governance/governance -> governance/signing -> governance/object -> governance/governance", "instantsend/instantsend -> node/blockstorage -> validation -> txmempool -> instantsend/instantsend", "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor", "llmq/commitment -> llmq/utils -> llmq/snapshot -> llmq/commitment", From 095497aa59ec13d14b138850ae2e30a9ea229e66 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 18 May 2026 01:14:10 +0700 Subject: [PATCH 02/13] refactor: extract SuperblockManager from CGovernanceManager --- src/Makefile.am | 2 + src/active/context.cpp | 6 +- src/active/context.h | 6 +- src/evo/chainhelper.cpp | 14 +- src/evo/chainhelper.h | 15 +- src/governance/governance.cpp | 354 ++--------------------- src/governance/governance.h | 51 +--- src/governance/signing.cpp | 10 +- src/governance/signing.h | 9 +- src/governance/superblock.cpp | 262 +++++++++++++++++ src/governance/superblock.h | 94 ++++++ src/init.cpp | 12 +- src/masternode/payments.cpp | 20 +- src/masternode/payments.h | 19 +- src/node/chainstate.cpp | 6 +- src/node/chainstate.h | 3 - src/node/interfaces.cpp | 5 +- src/rpc/masternode.cpp | 15 +- src/test/util/setup_common.cpp | 6 +- test/functional/feature_governance_cl.py | 2 +- 20 files changed, 481 insertions(+), 430 deletions(-) create mode 100644 src/governance/superblock.cpp create mode 100644 src/governance/superblock.h diff --git a/src/Makefile.am b/src/Makefile.am index a0eca537b48d..31e1b158461b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -237,6 +237,7 @@ BITCOIN_CORE_H = \ governance/net_governance.h \ governance/object.h \ governance/signing.h \ + governance/superblock.h \ governance/validators.h \ governance/vote.h \ governance/votedb.h \ @@ -527,6 +528,7 @@ libbitcoin_node_a_SOURCES = \ governance/net_governance.cpp \ governance/object.cpp \ governance/signing.cpp \ + governance/superblock.cpp \ governance/validators.cpp \ governance/vote.cpp \ governance/votedb.cpp \ diff --git a/src/active/context.cpp b/src/active/context.cpp index c89162df6a7e..4479c6653fa8 100644 --- a/src/active/context.cpp +++ b/src/active/context.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,8 @@ #include ActiveContext::ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman, CConnman& connman, - CDeterministicMNManager& dmnman, CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, + CDeterministicMNManager& dmnman, CGovernanceManager& govman, + governance::SuperblockManager& superblocks, CMasternodeMetaMan& mn_metaman, CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, CTxMemPool& mempool, chainlock::ChainlockHandler& clhandler, llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumManager& qman, @@ -40,7 +42,7 @@ ActiveContext::ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman dkgdbgman{std::make_unique(dmnman, qsnapman, chainman)}, qdkgsman{std::make_unique(dmnman, qsnapman, chainman, sporkman, db_params, quorums_watch)}, shareman{std::make_unique(connman, chainman, sigman, *nodeman, qman, sporkman)}, - gov_signer{std::make_unique(connman, dmnman, govman, *nodeman, chainman, mn_sync)}, + gov_signer{std::make_unique(connman, dmnman, govman, superblocks, *nodeman, chainman, mn_sync)}, ehf_sighandler{std::make_unique(chainman, sigman, *shareman, qman)}, cl_signer{std::make_unique(chainman.ActiveChainstate(), chainlocks, clhandler, isman, qman, sigman, *shareman, mn_sync)}, diff --git a/src/active/context.h b/src/active/context.h index 44b71abc8af7..af41ec7bfc84 100644 --- a/src/active/context.h +++ b/src/active/context.h @@ -31,6 +31,9 @@ class Chainlocks; class ChainlockHandler; class ChainLockSigner; } // namespace chainlock +namespace governance { +class SuperblockManager; +} // namespace governance namespace instantsend { class InstantSendSigner; } // namespace instantsend @@ -55,7 +58,8 @@ struct ActiveContext final : public llmq::QuorumRole, public CValidationInterfac ActiveContext(const ActiveContext&) = delete; ActiveContext& operator=(const ActiveContext&) = delete; explicit ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman, CConnman& connman, - CDeterministicMNManager& dmnman, CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, + CDeterministicMNManager& dmnman, CGovernanceManager& govman, + governance::SuperblockManager& superblocks, CMasternodeMetaMan& mn_metaman, CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, CTxMemPool& mempool, chainlock::ChainlockHandler& clhandler, llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumManager& qman, diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index 63c6fdafd2a7..bffb8d1e43fc 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -10,20 +10,22 @@ #include #include #include +#include #include #include #include -CChainstateHelper::CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, CGovernanceManager& govman, - llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, - llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync, - const chainlock::Chainlocks& chainlocks, const llmq::CQuorumManager& qman) : +CChainstateHelper::CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, llmq::CInstantSendManager& isman, + llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, + const ChainstateManager& chainman, const Consensus::Params& consensus_params, + const CMasternodeSync& mn_sync, const chainlock::Chainlocks& chainlocks, + const llmq::CQuorumManager& qman) : isman{isman}, credit_pool_manager{std::make_unique(evodb, chainman)}, m_chainlocks{chainlocks}, ehf_manager{std::make_unique(evodb, chainman, qman)}, - mn_payments{std::make_unique(dmnman, govman, chainman, consensus_params, mn_sync)}, + superblocks{std::make_unique()}, + mn_payments{std::make_unique(dmnman, *superblocks, chainman, consensus_params, mn_sync)}, special_tx{std::make_unique(*credit_pool_manager, dmnman, *ehf_manager, qblockman, qsnapman, chainman, consensus_params, chainlocks, qman)} {} diff --git a/src/evo/chainhelper.h b/src/evo/chainhelper.h index ec129d30df2b..08e5d8eb482b 100644 --- a/src/evo/chainhelper.h +++ b/src/evo/chainhelper.h @@ -13,7 +13,6 @@ class CBlockIndex; class CCreditPoolManager; class CDeterministicMNManager; class CEvoDB; -class CGovernanceManager; class ChainstateManager; class CMasternodeSync; class CMNHFManager; @@ -25,6 +24,9 @@ struct CCreditPool; namespace chainlock { class Chainlocks; } // namespace chainlock +namespace governance { +class SuperblockManager; +} // namespace governance namespace Consensus { struct Params; } // namespace Consensus @@ -43,6 +45,7 @@ class CChainstateHelper const std::unique_ptr credit_pool_manager; const chainlock::Chainlocks& m_chainlocks; const std::unique_ptr ehf_manager; + const std::unique_ptr superblocks; const std::unique_ptr mn_payments; const std::unique_ptr special_tx; @@ -50,11 +53,11 @@ class CChainstateHelper CChainstateHelper() = delete; CChainstateHelper(const CChainstateHelper&) = delete; CChainstateHelper& operator=(const CChainstateHelper&) = delete; - explicit CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, CGovernanceManager& govman, - llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, - llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync, - const chainlock::Chainlocks& chainlocks, const llmq::CQuorumManager& qman); + explicit CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, llmq::CInstantSendManager& isman, + llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, + const ChainstateManager& chainman, const Consensus::Params& consensus_params, + const CMasternodeSync& mn_sync, const chainlock::Chainlocks& chainlocks, + const llmq::CQuorumManager& qman); ~CChainstateHelper(); /** Passthrough functions to chainlock::Chainlocks */ diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index b79a6b532ed2..77b3e0cc006e 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -67,21 +68,22 @@ GovernanceStore::GovernanceStore() : CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman, + governance::SuperblockManager& superblocks, const std::unique_ptr& dmnman, CMasternodeSync& mn_sync) : m_db{std::make_unique("governance.dat", "magicGovernanceCache")}, m_mn_metaman{mn_metaman}, m_chainman{chainman}, + m_superblocks{superblocks}, m_dmnman{dmnman}, m_mn_sync{mn_sync}, cmapVoteToObject{MAX_CACHE_SIZE}, - mapPostponedObjects{}, - mapTrigger{} + mapPostponedObjects{} { } CGovernanceManager::~CGovernanceManager() { - if (!is_valid) return; + if (!is_loaded) return; m_db->Store(*this); } @@ -89,12 +91,13 @@ bool CGovernanceManager::LoadCache(bool load_cache) { AssertLockNotHeld(cs_store); assert(m_db != nullptr); - is_valid = load_cache ? m_db->Load(*this) : m_db->Store(*this); - if (is_valid && load_cache) { + is_loaded = load_cache ? m_db->Load(*this) : m_db->Store(*this); + if (is_loaded && load_cache) { CheckAndRemove(); InitOnLoad(); } - return is_valid; + m_superblocks.SetLoaded(is_loaded); + return is_loaded; } void CGovernanceManager::RelayObject(const CGovernanceObject& obj) @@ -302,7 +305,8 @@ void CGovernanceManager::AddGovernanceObjectInternal(CGovernanceObject& insert_o LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Before trigger block, GetDataAsPlainString = %s, nObjectType = %d\n", Assert(govobj)->GetDataAsPlainString(), std23::to_underlying(govobj->GetObjectType())); - if (govobj->GetObjectType() == GovernanceObject::TRIGGER && !AddNewTrigger(nHash)) { + if (govobj->GetObjectType() == GovernanceObject::TRIGGER && + !m_superblocks.AddTrigger(govobj, nCachedBlockHeight)) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s\n", nHash.ToString()); govobj->PrepareDeletion(GetTime().count()); return; @@ -359,7 +363,7 @@ void CGovernanceManager::CheckAndRemove() ScopedLockBool guard(cs_store, fRateChecksEnabled, false); // Clean up any expired or invalid triggers - CleanAndRemoveTriggers(); + m_superblocks.Clean(nCachedBlockHeight); const auto nNow = GetTime(); for (auto it = mapObjects.begin(); it != mapObjects.end();) { @@ -412,6 +416,9 @@ void CGovernanceManager::CheckAndRemove() } mapErasedGovernanceObjects.insert(std::make_pair(nHash, nTimeExpired)); + if (pObj->GetObjectType() == GovernanceObject::TRIGGER) { + m_superblocks.RemoveTrigger(nHash); + } mapObjects.erase(it++); } else { if (pObj->GetObjectType() == GovernanceObject::PROPOSAL) { @@ -962,23 +969,6 @@ void CGovernanceManager::RebuildIndexes() } } -void CGovernanceManager::AddCachedTriggers() -{ - AssertLockHeld(cs_store); - - int64_t nNow = GetTime().count(); - - for (auto& [_, govobj] : mapObjects) { - if (Assert(govobj)->GetObjectType() != GovernanceObject::TRIGGER) { - continue; - } - - if (!AddNewTrigger(govobj->GetHash())) { - govobj->PrepareDeletion(nNow); - } - } -} - void CGovernanceManager::InitOnLoad() { { @@ -986,7 +976,14 @@ void CGovernanceManager::InitOnLoad() const auto start{SteadyClock::now()}; LogPrintf("Preparing masternode indexes and governance triggers...\n"); RebuildIndexes(); - AddCachedTriggers(); + + const int64_t nNow = GetTime().count(); + for (auto& [_, govobj] : mapObjects) { + if (Assert(govobj)->GetObjectType() != GovernanceObject::TRIGGER) continue; + if (!m_superblocks.AddTrigger(govobj, nCachedBlockHeight)) { + govobj->PrepareDeletion(nNow); + } + } LogPrintf("Masternode indexes and governance triggers prepared %dms\n", Ticks(SteadyClock::now() - start)); } @@ -1016,7 +1013,7 @@ void CGovernanceManager::Clear() setAdditionalRelayObjects.clear(); m_requested_hash_time.clear(); fRateChecksEnabled = true; - mapTrigger.clear(); + m_superblocks.Clear(); } std::string GovernanceStore::ToString() const @@ -1075,7 +1072,7 @@ void CGovernanceManager::UpdatedBlockTip(const CBlockIndex* pindex) CheckPostponedObjects(); - ExecuteBestSuperblock(Assert(m_dmnman)->GetListAtChainTip(), pindex->nHeight); + m_superblocks.ExecuteBestSuperblock(Assert(m_dmnman)->GetListAtChainTip(), pindex->nHeight); } std::vector CGovernanceManager::GetOrphanVoteObjectHashes() @@ -1158,307 +1155,6 @@ void CGovernanceManager::RemoveInvalidVotes() lastMNListForVotingKeys = std::make_shared(tip_mn_list); } -/** - * Add Governance Object - */ - -bool CGovernanceManager::AddNewTrigger(uint256 nHash) -{ - AssertLockHeld(cs_store); - - // IF WE ALREADY HAVE THIS HASH, RETURN - if (mapTrigger.count(nHash)) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Already have hash, nHash = %s, count = %d, size = %s\n", - __func__, nHash.GetHex(), mapTrigger.count(nHash), mapTrigger.size()); - return false; - } - - CSuperblock_sptr pSuperblock; - try { - auto pGovObj = FindGovernanceObjectInternal(nHash); - if (!pGovObj) { - throw std::runtime_error("CSuperblock: Failed to find Governance Object"); - } - pSuperblock = std::make_shared(*pGovObj, nHash); - } catch (std::exception& e) { - LogPrintf("CGovernanceManager::%s -- Error creating superblock: %s\n", __func__, e.what()); - return false; - } catch (...) { - LogPrintf("CGovernanceManager::%s -- Unknown Error creating superblock\n", __func__); - return false; - } - - pSuperblock->SetStatus(SeenObjectStatus::Valid); - - mapTrigger.insert(std::make_pair(nHash, pSuperblock)); - - return !pSuperblock->IsExpired(GetCachedBlockHeight()); -} - -/** - * - * Clean And Remove - * - */ - -void CGovernanceManager::CleanAndRemoveTriggers() -{ - AssertLockHeld(cs_store); - - // Remove triggers that are invalid or expired - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- mapTrigger.size() = %d\n", __func__, mapTrigger.size()); - - for (auto it = mapTrigger.begin(); it != mapTrigger.end();) { - bool remove = false; - std::shared_ptr pObj = nullptr; - const CSuperblock_sptr& pSuperblock = it->second; - if (!pSuperblock) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- nullptr superblock\n", __func__); - remove = true; - } else { - pObj = FindGovernanceObjectInternal(it->first); - if (!pObj || pObj->GetObjectType() != GovernanceObject::TRIGGER) { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or non-trigger superblock\n", __func__); - pSuperblock->SetStatus(SeenObjectStatus::ErrorInvalid); - } - - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- superblock status = %d\n", __func__, - std23::to_underlying(pSuperblock->GetStatus())); - switch (pSuperblock->GetStatus()) { - case SeenObjectStatus::ErrorInvalid: - case SeenObjectStatus::Unknown: - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Unknown or invalid trigger found\n", __func__); - remove = true; - break; - case SeenObjectStatus::Valid: - case SeenObjectStatus::Executed: { - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Valid trigger found\n", __func__); - if (pSuperblock->IsExpired(GetCachedBlockHeight())) { - // update corresponding object - pObj->SetExpired(); - remove = true; - } - break; - } - default: - break; - } - } - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- %smarked for removal\n", __func__, remove ? "" : "NOT "); - - if (remove) { - std::string strDataAsPlainString = "nullptr"; - if (pObj) { - strDataAsPlainString = pObj->GetDataAsPlainString(); - // mark corresponding object for deletion - pObj->PrepareDeletion(GetTime().count()); - } - LogPrint(BCLog::GOBJECT, "CGovernanceManager::%s -- Removing trigger object %s\n", __func__, - strDataAsPlainString); - // delete the trigger - mapTrigger.erase(it++); - } else { - ++it; - } - } -} - -/** - * Get Active Triggers - * - * - Look through triggers and scan for active ones - * - Return the triggers in a list - */ -std::vector CGovernanceManager::GetActiveTriggers() const -{ - AssertLockNotHeld(cs_store); - LOCK(cs_store); - return GetActiveTriggersInternal(); -} - -std::vector CGovernanceManager::GetActiveTriggersInternal() const -{ - AssertLockHeld(cs_store); - std::vector vecResults; - - // LOOK AT THESE OBJECTS AND COMPILE A VALID LIST OF TRIGGERS - for (const auto& [nHash, pSuperblock] : mapTrigger) { - auto pObj = FindConstGovernanceObjectInternal(nHash); - if (pObj) { - vecResults.push_back(pSuperblock); - } - } - - return vecResults; -} - -bool CGovernanceManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) -{ - AssertLockNotHeld(cs_store); - LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight); - if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { - return false; - } - - LOCK(cs_store); - // GET ALL ACTIVE TRIGGERS - std::vector vecTriggers = GetActiveTriggersInternal(); - - LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- vecTriggers.size() = %d\n", vecTriggers.size()); - - for (const auto& pSuperblock : vecTriggers) { - if (!pSuperblock) { - LogPrintf("IsSuperblockTriggered -- Non-superblock found, continuing\n"); - continue; - } - - auto pObj = FindGovernanceObjectInternal(pSuperblock->GetGovernanceObjHash()); - if (!pObj) { - LogPrintf("IsSuperblockTriggered -- pObj == nullptr, continuing\n"); - continue; - } - - LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- data = %s\n", pObj->GetDataAsPlainString()); - - // note : 12.1 - is epoch calculation correct? - - if (nBlockHeight != pSuperblock->GetBlockHeight()) { - LogPrint(BCLog::GOBJECT, /* Continued */ - "IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, " - "continuing\n", - nBlockHeight, pSuperblock->GetBlockHeight()); - continue; - } - - // MAKE SURE THIS TRIGGER IS ACTIVE VIA FUNDING CACHE FLAG - - pObj->UpdateSentinelVariables(tip_mn_list); - - if (pObj->IsSetCachedFunding()) { - LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = true, returning true\n"); - return true; - } else { - LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = false, continuing\n"); - } - } - - return false; -} - -bool CGovernanceManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, - int nBlockHeight) -{ - AssertLockNotHeld(cs_store); - LOCK(cs_store); - return GetBestSuperblockInternal(tip_mn_list, pSuperblockRet, nBlockHeight); -} - -bool CGovernanceManager::GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, - CSuperblock_sptr& pSuperblockRet, int nBlockHeight) -{ - if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { - return false; - } - - AssertLockHeld(cs_store); - std::vector vecTriggers = GetActiveTriggersInternal(); - int nYesCount = 0; - - for (const auto& pSuperblock : vecTriggers) { - if (!pSuperblock || nBlockHeight != pSuperblock->GetBlockHeight()) { - continue; - } - - auto pObj = FindGovernanceObjectInternal(pSuperblock->GetGovernanceObjHash()); - if (!pObj) { - continue; - } - - // DO WE HAVE A NEW WINNER? - - int nTempYesCount = pObj->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); - if (nTempYesCount > nYesCount) { - nYesCount = nTempYesCount; - pSuperblockRet = pSuperblock; - } - } - - return nYesCount > 0; -} - -bool CGovernanceManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, - std::vector& voutSuperblockRet) -{ - LOCK(cs_store); - - // GET THE BEST SUPERBLOCK FOR THIS BLOCK HEIGHT - - CSuperblock_sptr pSuperblock; - if (!GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { - LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Can't find superblock for height %d\n", nBlockHeight); - return false; - } - - // make sure it's empty, just in case - voutSuperblockRet.clear(); - - // GET SUPERBLOCK OUTPUTS - - // Superblock payments will be appended to the end of the coinbase vout vector - - // TODO: How many payments can we add before things blow up? - // Consider at least following limits: - // - max coinbase tx size - // - max "budget" available - for (int i = 0; i < pSuperblock->CountPayments(); i++) { - CGovernancePayment payment; - if (pSuperblock->GetPayment(i, payment)) { - // SET COINBASE OUTPUT TO SUPERBLOCK SETTING - - CTxOut txout = CTxOut(payment.nAmount, payment.script); - voutSuperblockRet.push_back(txout); - - // PRINT NICE LOG OUTPUT FOR SUPERBLOCK PAYMENT - - CTxDestination dest; - ExtractDestination(payment.script, dest); - - LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- NEW Superblock: output %d (addr %s, amount %d.%08d)\n", - i, EncodeDestination(dest), payment.nAmount / COIN, payment.nAmount % COIN); - } else { - LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Payment not found\n"); - } - } - - return true; -} - -bool CGovernanceManager::IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, - const CTransaction& txNew, int nBlockHeight, CAmount blockReward) -{ - // GET BEST SUPERBLOCK, SHOULD MATCH - LOCK(cs_store); - - CSuperblock_sptr pSuperblock; - if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { - return pSuperblock->IsValid(active_chain, txNew, nBlockHeight, blockReward); - } - - return false; -} - -void CGovernanceManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) -{ - AssertLockHeld(cs_store); - - CSuperblock_sptr pSuperblock; - if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { - // All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid, - // tip wouldn't be updated if anything was wrong. Mark this trigger as executed. - pSuperblock->SetExecuted(); - } -} - std::vector> CGovernanceManager::GetApprovedProposals( const CDeterministicMNList& tip_mn_list) { diff --git a/src/governance/governance.h b/src/governance/governance.h index 457fb488852f..4ac8629f7d7b 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -41,6 +41,11 @@ class CMasternodeMetaMan; class CMasternodeSync; class CSuperblock; +namespace governance +{ +class SuperblockManager; +} // namespace governance + class UniValue; using CSuperblock_sptr = std::shared_ptr; @@ -240,10 +245,11 @@ class CGovernanceManager : public GovernanceStore private: const std::unique_ptr m_db; - bool is_valid{false}; + bool is_loaded{false}; CMasternodeMetaMan& m_mn_metaman; const ChainstateManager& m_chainman; + governance::SuperblockManager& m_superblocks; const std::unique_ptr& m_dmnman; CMasternodeSync& m_mn_sync; @@ -255,7 +261,6 @@ class CGovernanceManager : public GovernanceStore std::set setAdditionalRelayObjects; std::map m_requested_hash_time; bool fRateChecksEnabled{true}; - std::map> mapTrigger; mutable Mutex cs_relay; std::vector m_relay_invs GUARDED_BY(cs_relay); @@ -266,11 +271,13 @@ class CGovernanceManager : public GovernanceStore CGovernanceManager& operator=(const CGovernanceManager&) = delete; explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman, - const std::unique_ptr& dmnman, CMasternodeSync& mn_sync); + governance::SuperblockManager& superblocks, + const std::unique_ptr& dmnman, + CMasternodeSync& mn_sync); ~CGovernanceManager(); // Basic initialization and querying - bool IsValid() const { return is_valid; } + bool IsValid() const { return is_loaded; } bool LoadCache(bool load_cache) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); @@ -323,20 +330,7 @@ class CGovernanceManager : public GovernanceStore void AddGovernanceObject(CGovernanceObject& govobj, const std::string& peer_str) EXCLUSIVE_LOCKS_REQUIRED(!cs_store, !cs_relay); - // Superblocks - bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, - std::vector& voutSuperblockRet) - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, - const CTransaction& txNew, int nBlockHeight, CAmount blockReward) - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - // Thread-safe accessors - bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, - int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); bool HaveObjectForHash(const uint256& nHash) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); bool HaveVoteForHash(const uint256& nHash) const @@ -349,8 +343,6 @@ class CGovernanceManager : public GovernanceStore EXCLUSIVE_LOCKS_REQUIRED(!cs_store); int GetVoteCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::vector> GetActiveTriggers() const - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); void AddPostponedObject(const CGovernanceObject& govobj) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); @@ -388,13 +380,8 @@ class CGovernanceManager : public GovernanceStore // Internal counterparts to "Thread-safe accessors" void AddPostponedObjectInternal(const CGovernanceObject& govobj) EXCLUSIVE_LOCKS_REQUIRED(cs_store); - bool GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& pSuperblockRet, - int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(cs_store); std::shared_ptr FindGovernanceObjectInternal(const uint256& nHash) EXCLUSIVE_LOCKS_REQUIRED(cs_store); - std::vector> GetActiveTriggersInternal() const - EXCLUSIVE_LOCKS_REQUIRED(cs_store); std::shared_ptr FindConstGovernanceObjectInternal(const uint256& nHash) const EXCLUSIVE_LOCKS_REQUIRED(cs_store); @@ -416,28 +403,12 @@ class CGovernanceManager : public GovernanceStore void InitOnLoad() EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - /* - * Trigger Management (formerly CGovernanceTriggerManager) - * - Track governance objects which are triggers - * - After triggers are activated and executed, they can be removed - */ - bool AddNewTrigger(uint256 nHash) - EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void CleanAndRemoveTriggers() - EXCLUSIVE_LOCKS_REQUIRED(cs_store); - - void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void CheckOrphanVotes(CGovernanceObject& govobj) EXCLUSIVE_LOCKS_REQUIRED(cs_store, !cs_relay); void RebuildIndexes() EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void AddCachedTriggers() - EXCLUSIVE_LOCKS_REQUIRED(cs_store); - void RemoveInvalidVotes() EXCLUSIVE_LOCKS_REQUIRED(cs_store); }; diff --git a/src/governance/signing.cpp b/src/governance/signing.cpp index d89c6d72204b..24675729cb4b 100644 --- a/src/governance/signing.cpp +++ b/src/governance/signing.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -24,11 +25,12 @@ constexpr std::chrono::seconds GOVERNANCE_FUDGE_WINDOW{2h}; } // anonymous namespace GovernanceSigner::GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, CGovernanceManager& govman, - const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, - const CMasternodeSync& mn_sync) : + governance::SuperblockManager& superblocks, const CActiveMasternodeManager& mn_activeman, + const ChainstateManager& chainman, const CMasternodeSync& mn_sync) : m_connman{connman}, m_dmnman{dmnman}, m_govman{govman}, + m_superblocks{superblocks}, m_mn_activeman{mn_activeman}, m_chainman{chainman}, m_mn_sync{mn_sync} @@ -214,7 +216,7 @@ void GovernanceSigner::VoteGovernanceTriggers(const std::optionalGetGovernanceObjHash()); if (!govobj) { @@ -292,7 +294,7 @@ void GovernanceSigner::UpdatedBlockTip(const CBlockIndex* pindex) const auto trigger_opt = CreateGovernanceTrigger(sb_opt); VoteGovernanceTriggers(trigger_opt); CSuperblock_sptr pSuperblock; - if (m_govman.GetBestSuperblock(m_dmnman.GetListAtChainTip(), pSuperblock, pindex->nHeight)) { + if (m_superblocks.GetBestSuperblock(m_dmnman.GetListAtChainTip(), pSuperblock, pindex->nHeight)) { ResetVotedFundingTrigger(); } } diff --git a/src/governance/signing.h b/src/governance/signing.h index 9675c86898f5..995b53502462 100644 --- a/src/governance/signing.h +++ b/src/governance/signing.h @@ -26,12 +26,17 @@ class ChainstateManager; class CMasternodeSync; enum vote_outcome_enum_t : int; +namespace governance { +class SuperblockManager; +} + class GovernanceSigner { private: CConnman& m_connman; CDeterministicMNManager& m_dmnman; CGovernanceManager& m_govman; + governance::SuperblockManager& m_superblocks; const CActiveMasternodeManager& m_mn_activeman; const ChainstateManager& m_chainman; const CMasternodeSync& m_mn_sync; @@ -44,8 +49,8 @@ class GovernanceSigner GovernanceSigner(const GovernanceSigner&) = delete; GovernanceSigner& operator=(const GovernanceSigner&) = delete; explicit GovernanceSigner(CConnman& connman, CDeterministicMNManager& dmnman, CGovernanceManager& govman, - const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman, - const CMasternodeSync& mn_sync); + governance::SuperblockManager& superblocks, const CActiveMasternodeManager& mn_activeman, + const ChainstateManager& chainman, const CMasternodeSync& mn_sync); ~GovernanceSigner(); void UpdatedBlockTip(const CBlockIndex* pindex); diff --git a/src/governance/superblock.cpp b/src/governance/superblock.cpp new file mode 100644 index 000000000000..36f169467027 --- /dev/null +++ b/src/governance/superblock.cpp @@ -0,0 +1,262 @@ +// Copyright (c) 2014-2025 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace governance { + +bool SuperblockManager::AddTrigger(std::shared_ptr obj, int cachedHeight) +{ + AssertLockNotHeld(cs_sb); + if (!obj) return false; + + uint256 nHash = obj->GetHash(); + + LOCK(cs_sb); + if (m_triggers.count(nHash)) { + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Already have hash, nHash = %s, size = %s\n", + __func__, nHash.GetHex(), m_triggers.size()); + return false; + } + + CSuperblock_sptr pSuperblock; + try { + pSuperblock = std::make_shared(*obj, nHash); + } catch (std::exception& e) { + LogPrintf("SuperblockManager::%s -- Error creating superblock: %s\n", __func__, e.what()); + return false; + } catch (...) { + LogPrintf("SuperblockManager::%s -- Unknown Error creating superblock\n", __func__); + return false; + } + + pSuperblock->SetStatus(SeenObjectStatus::Valid); + m_triggers.emplace(nHash, TriggerEntry{pSuperblock, std::move(obj)}); + + return !pSuperblock->IsExpired(cachedHeight); +} + +void SuperblockManager::RemoveTrigger(const uint256& hash) +{ + LOCK(cs_sb); + m_triggers.erase(hash); +} + +void SuperblockManager::Clean(int cachedHeight) +{ + AssertLockNotHeld(cs_sb); + LOCK(cs_sb); + + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- m_triggers.size() = %d\n", __func__, m_triggers.size()); + + for (auto it = m_triggers.begin(); it != m_triggers.end();) { + bool remove = false; + const auto& [sb, obj] = it->second; + + if (!sb) { + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- nullptr superblock\n", __func__); + remove = true; + } else { + if (!obj || obj->GetObjectType() != GovernanceObject::TRIGGER) { + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Unknown or non-trigger superblock\n", __func__); + sb->SetStatus(SeenObjectStatus::ErrorInvalid); + } + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- superblock status = %d\n", __func__, + std23::to_underlying(sb->GetStatus())); + switch (sb->GetStatus()) { + case SeenObjectStatus::ErrorInvalid: + case SeenObjectStatus::Unknown: + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Unknown or invalid trigger found\n", __func__); + remove = true; + break; + case SeenObjectStatus::Valid: + case SeenObjectStatus::Executed: + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Valid trigger found\n", __func__); + if (sb->IsExpired(cachedHeight)) { + if (obj) obj->SetExpired(); + remove = true; + } + break; + default: + break; + } + } + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- %smarked for removal\n", __func__, + remove ? "" : "NOT "); + + if (remove) { + std::string strDataAsPlainString = "nullptr"; + if (obj) { + strDataAsPlainString = obj->GetDataAsPlainString(); + obj->PrepareDeletion(GetTime().count()); + } + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Removing trigger object %s\n", __func__, + strDataAsPlainString); + it = m_triggers.erase(it); + } else { + ++it; + } + } +} + +void SuperblockManager::Clear() +{ + LOCK(cs_sb); + m_triggers.clear(); +} + +std::vector SuperblockManager::GetActiveTriggers() const +{ + LOCK(cs_sb); + std::vector vecResults; + vecResults.reserve(m_triggers.size()); + for (const auto& [_, entry] : m_triggers) { + if (entry.sb && entry.obj) { + vecResults.push_back(entry.sb); + } + } + return vecResults; +} + +bool SuperblockManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, + CSuperblock_sptr& sbRet, int nBlockHeight) const +{ + LOCK(cs_sb); + return GetBestSuperblockInternal(tip_mn_list, sbRet, nBlockHeight); +} + +bool SuperblockManager::GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, + CSuperblock_sptr& sbRet, int nBlockHeight) const +{ + AssertLockHeld(cs_sb); + if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { + return false; + } + + int nYesCount = 0; + for (const auto& [_, entry] : m_triggers) { + if (!entry.sb || !entry.obj || nBlockHeight != entry.sb->GetBlockHeight()) { + continue; + } + int nTempYesCount = entry.obj->GetAbsoluteYesCount(tip_mn_list, VOTE_SIGNAL_FUNDING); + if (nTempYesCount > nYesCount) { + nYesCount = nTempYesCount; + sbRet = entry.sb; + } + } + return nYesCount > 0; +} + +bool SuperblockManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) +{ + LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- Start nBlockHeight = %d\n", nBlockHeight); + if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { + return false; + } + + LOCK(cs_sb); + + LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- m_triggers.size() = %d\n", m_triggers.size()); + + for (const auto& [_, entry] : m_triggers) { + if (!entry.sb) { + LogPrintf("IsSuperblockTriggered -- Non-superblock found, continuing\n"); + continue; + } + if (!entry.obj) { + LogPrintf("IsSuperblockTriggered -- pObj == nullptr, continuing\n"); + continue; + } + + LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- data = %s\n", entry.obj->GetDataAsPlainString()); + + if (nBlockHeight != entry.sb->GetBlockHeight()) { + LogPrint(BCLog::GOBJECT, /* Continued */ + "IsSuperblockTriggered -- block height doesn't match nBlockHeight = %d, blockStart = %d, " + "continuing\n", + nBlockHeight, entry.sb->GetBlockHeight()); + continue; + } + + entry.obj->UpdateSentinelVariables(tip_mn_list); + + if (entry.obj->IsSetCachedFunding()) { + LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = true, returning true\n"); + return true; + } else { + LogPrint(BCLog::GOBJECT, "IsSuperblockTriggered -- fCacheFunding = false, continuing\n"); + } + } + + return false; +} + +bool SuperblockManager::IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, + const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const +{ + LOCK(cs_sb); + CSuperblock_sptr pSuperblock; + if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { + return pSuperblock->IsValid(active_chain, txNew, nBlockHeight, blockReward); + } + return false; +} + +bool SuperblockManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, + std::vector& voutSuperblockRet) const +{ + LOCK(cs_sb); + + CSuperblock_sptr pSuperblock; + if (!GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { + LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Can't find superblock for height %d\n", nBlockHeight); + return false; + } + + voutSuperblockRet.clear(); + + // TODO: How many payments can we add before things blow up? + // Consider at least following limits: + // - max coinbase tx size + // - max "budget" available + for (int i = 0; i < pSuperblock->CountPayments(); i++) { + CGovernancePayment payment; + if (pSuperblock->GetPayment(i, payment)) { + voutSuperblockRet.emplace_back(payment.nAmount, payment.script); + + CTxDestination dest; + ExtractDestination(payment.script, dest); + + LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- NEW Superblock: output %d (addr %s, amount %d.%08d)\n", + i, EncodeDestination(dest), payment.nAmount / COIN, payment.nAmount % COIN); + } else { + LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Payment not found\n"); + } + } + + return true; +} + +void SuperblockManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) +{ + LOCK(cs_sb); + CSuperblock_sptr pSuperblock; + if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { + // All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid, + // tip wouldn't be updated if anything was wrong. Mark this trigger as executed. + pSuperblock->SetExecuted(); + } +} + +} // namespace governance diff --git a/src/governance/superblock.h b/src/governance/superblock.h new file mode 100644 index 000000000000..cbc42ea71ed4 --- /dev/null +++ b/src/governance/superblock.h @@ -0,0 +1,94 @@ +// Copyright (c) 2014-2025 The Dash Core developers +// Distributed under the MIT/X11 software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_GOVERNANCE_SUPERBLOCK_H +#define BITCOIN_GOVERNANCE_SUPERBLOCK_H + +#include +#include +#include + +#include +#include +#include +#include + +class CChain; +class CDeterministicMNList; +class CGovernanceObject; +class CSuperblock; +class CTransaction; +class CTxOut; + +using CSuperblock_sptr = std::shared_ptr; + +namespace governance { + +/** + * Owns the set of active superblock triggers. Trigger lifecycle is fully + * owned here; CGovernanceManager pushes new TRIGGER objects in via + * AddTrigger() and notifies us via RemoveTrigger() when it erases the + * underlying object from its store. Each entry holds a strong reference + * to the underlying CGovernanceObject so we never look it up by hash. + */ +class SuperblockManager +{ +public: + bool IsValid() const { return m_loaded; } + void SetLoaded(bool loaded) { m_loaded = loaded; } + + /** Register a TRIGGER governance object. Returns true if the resulting + * trigger is live (not already height-expired). */ + bool AddTrigger(std::shared_ptr obj, int cachedHeight) + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + /** Single-direction notification from CGovernanceManager when it erases + * a TRIGGER object from its store. */ + void RemoveTrigger(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + /** Prune triggers that are invalid or height-expired. Calls + * PrepareDeletion() on the underlying object so CGovernanceManager + * picks it up on its own sweep. */ + void Clean(int cachedHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + void Clear() EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + std::vector GetActiveTriggers() const EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, + CSuperblock_sptr& sbRet, int nBlockHeight) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, + const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, + std::vector& voutSuperblockRet) const + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + + void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) + EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + +private: + struct TriggerEntry { + CSuperblock_sptr sb; + std::shared_ptr obj; + }; + + bool GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, + CSuperblock_sptr& sbRet, int nBlockHeight) const + EXCLUSIVE_LOCKS_REQUIRED(cs_sb); + + mutable Mutex cs_sb; + std::atomic m_loaded{false}; + std::map m_triggers GUARDED_BY(cs_sb); +}; + +} // namespace governance + +#endif // BITCOIN_GOVERNANCE_SUPERBLOCK_H diff --git a/src/init.cpp b/src/init.cpp index 113bd4c9f025..449ea075f11b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -370,9 +370,9 @@ void PrepareShutdown(NodeContext& node) // and reset all to nullptr. node.observer_ctx.reset(); node.active_ctx.reset(); + node.govman.reset(); node.mn_sync.reset(); node.sporkman.reset(); - node.govman.reset(); node.netfulfilledman.reset(); node.mn_metaman.reset(); @@ -1959,7 +1959,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) assert(!node.mempool); assert(!node.chainman); - assert(!node.govman); assert(!node.mn_sync); const int mempool_check_ratio = std::clamp(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0, 1000000); @@ -1979,8 +1978,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) */ node.mn_sync = std::make_unique(std::make_unique(*node.connman, *node.netfulfilledman)); - node.govman = std::make_unique(*node.mn_metaman, *node.chainman, node.dmnman, *node.mn_sync); - const bool fReset = fReindex; bilingual_str strLoadError; @@ -1990,7 +1987,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) try { maybe_load_error = LoadChainstate(fReset, chainman, - *node.govman, *node.mn_metaman, *node.mn_sync, *node.sporkman, @@ -2173,6 +2169,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) node.clhandler = std::make_unique(*node.chainlocks, chainman, *node.mempool, *node.mn_sync); RegisterValidationInterface(node.clhandler.get()); + assert(!node.govman); + node.govman = std::make_unique(*node.mn_metaman, *node.chainman, *node.chain_helper->superblocks, node.dmnman, *node.mn_sync); + assert(!node.peerman); node.peerman = PeerManager::make(chainparams, *node.connman, *node.addrman, node.banman.get(), *node.dstxman, chainman, *node.mempool, *node.mn_metaman, *node.mn_sync, @@ -2199,7 +2198,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) return InitError(_("Invalid masternodeblsprivkey. Please see documentation.")); } // Will init later in ThreadImport - node.active_ctx = std::make_unique(*node.llmq_ctx->bls_worker, chainman, *node.connman, *node.dmnman, *node.govman, *node.mn_metaman, + node.active_ctx = std::make_unique(*node.llmq_ctx->bls_worker, chainman, *node.connman, *node.dmnman, + *node.govman, *node.chain_helper->superblocks, *node.mn_metaman, *node.sporkman, *node.chainlocks, *node.mempool, *node.clhandler, *node.llmq_ctx->isman, *node.llmq_ctx->quorum_block_processor, *node.llmq_ctx->qman, *node.llmq_ctx->qsnapman, *node.llmq_ctx->sigman, *node.mn_sync, operator_sk, dash_db_params, quorums_watch); diff --git a/src/masternode/payments.cpp b/src/masternode/payments.cpp index 01a379b1d1b8..22a69be94177 100644 --- a/src/masternode/payments.cpp +++ b/src/masternode/payments.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -232,7 +232,7 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo return false; } - if (!m_mn_sync.IsSynced() || !m_govman.IsValid()) { + if (!m_mn_sync.IsSynced() || !m_superblocks.IsValid()) { LogPrint(BCLog::MNPAYMENTS, "CMNPaymentsProcessor::%s -- WARNING! Not enough data, checked superblock max bounds only\n", __func__); // not enough data for full checks but at least we know that the superblock limits were honored. // We rely on the network to have followed the correct chain in this case @@ -245,7 +245,7 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo const auto tip_mn_list = m_dmnman.GetListAtChainTip(); - if (!m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { + if (!m_superblocks.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { // we are on a valid superblock height but a superblock was not triggered // revert to block reward limits in this case if(!isBlockRewardValueMet) { @@ -256,7 +256,7 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo } // this actually also checks for correct payees and not only amount - if (!m_govman.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, *block.vtx[0], nBlockHeight, blockReward)) { + if (!m_superblocks.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, *block.vtx[0], nBlockHeight, blockReward)) { // triggered but invalid? that's weird LogPrintf("CMNPaymentsProcessor::%s -- ERROR! Invalid superblock detected at height %d: %s", __func__, nBlockHeight, block.vtx[0]->ToString()); /* Continued */ // should NOT allow invalid superblocks, when superblocks are enabled @@ -280,7 +280,7 @@ bool CMNPaymentsProcessor::IsBlockPayeeValid(const CTransaction& txNew, const CB return false; } - if (!m_mn_sync.IsSynced() || !m_govman.IsValid()) { + if (!m_mn_sync.IsSynced() || !m_superblocks.IsValid()) { // governance data is either incomplete or non-existent LogPrint(BCLog::MNPAYMENTS, "CMNPaymentsProcessor::%s -- WARNING! Not enough data, skipping superblock payee checks\n", __func__); return true; // not an error @@ -300,9 +300,9 @@ bool CMNPaymentsProcessor::IsBlockPayeeValid(const CTransaction& txNew, const CB if (!check_superblock) return true; const auto tip_mn_list = m_dmnman.GetListAtChainTip(); - if (m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { - if (m_govman.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, txNew, nBlockHeight, - blockSubsidy + feeReward)) { + if (m_superblocks.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { + if (m_superblocks.IsValidSuperblock(m_chainman.ActiveChain(), tip_mn_list, txNew, nBlockHeight, + blockSubsidy + feeReward)) { LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Valid superblock at height %d: %s", /* Continued */ __func__, nBlockHeight, txNew.ToString()); // continue validation, should also pay MN @@ -326,9 +326,9 @@ void CMNPaymentsProcessor::FillBlockPayments(CMutableTransaction& txNew, const C // Only create superblocks when one is actually triggered. const auto tip_mn_list = m_dmnman.GetListAtChainTip(); - if (m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { + if (m_superblocks.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Triggered superblock creation at height %d\n", __func__, nBlockHeight); - m_govman.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblockPaymentsRet); + m_superblocks.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblockPaymentsRet); } if (!GetMasternodeTxOuts(pindexPrev, blockSubsidy, feeReward, voutMasternodePaymentsRet)) { diff --git a/src/masternode/payments.h b/src/masternode/payments.h index 358d58d00d44..2b7b662e600d 100644 --- a/src/masternode/payments.h +++ b/src/masternode/payments.h @@ -13,7 +13,6 @@ class CBlock; class CBlockIndex; class CDeterministicMNManager; -class CGovernanceManager; class ChainstateManager; class CMasternodeSync; class CTransaction; @@ -21,6 +20,9 @@ class CTxOut; struct CMutableTransaction; +namespace governance { +class SuperblockManager; +} namespace Consensus { struct Params; } /** @@ -33,7 +35,7 @@ class CMNPaymentsProcessor { private: CDeterministicMNManager& m_dmnman; - CGovernanceManager& m_govman; + governance::SuperblockManager& m_superblocks; const ChainstateManager& m_chainman; const Consensus::Params& m_consensus_params; const CMasternodeSync& m_mn_sync; @@ -48,9 +50,16 @@ class CMNPaymentsProcessor [[nodiscard]] bool IsOldBudgetBlockValueValid(const CBlock& block, const int nBlockHeight, const CAmount blockReward, std::string& strErrorRet); public: - explicit CMNPaymentsProcessor(CDeterministicMNManager& dmnman, CGovernanceManager& govman, const ChainstateManager& chainman, - const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync) : - m_dmnman{dmnman}, m_govman{govman}, m_chainman{chainman}, m_consensus_params{consensus_params}, m_mn_sync{mn_sync} {} + explicit CMNPaymentsProcessor(CDeterministicMNManager& dmnman, governance::SuperblockManager& superblocks, + const ChainstateManager& chainman, const Consensus::Params& consensus_params, + const CMasternodeSync& mn_sync) : + m_dmnman{dmnman}, + m_superblocks{superblocks}, + m_chainman{chainman}, + m_consensus_params{consensus_params}, + m_mn_sync{mn_sync} + { + } bool IsBlockValueValid(const CBlock& block, const int nBlockHeight, const CAmount blockReward, std::string& strErrorRet, const bool check_superblock); bool IsBlockPayeeValid(const CTransaction& txNew, const CBlockIndex* pindexPrev, const CAmount blockSubsidy, const CAmount feeReward, const bool check_superblock); diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index a7bfb33fd133..27a9ccc13761 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -35,7 +35,6 @@ namespace node { std::optional LoadChainstate(bool fReset, ChainstateManager& chainman, - CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, @@ -83,7 +82,7 @@ std::optional LoadChainstate(bool fReset, pblocktree.reset(); pblocktree.reset(new CBlockTreeDB(nBlockTreeDBCache, block_tree_db_in_memory, fReset)); - DashChainstateSetup(chainman, govman, mn_metaman, mn_sync, sporkman, chainlocks, chain_helper, + DashChainstateSetup(chainman, mn_metaman, mn_sync, sporkman, chainlocks, chain_helper, dmnman, *evodb, llmq_ctx, mempool, data_dir, dash_dbs_in_memory, /*llmq_dbs_wipe=*/fReset || fReindexChainState, bls_threads, worker_count, max_recsigs_age, consensus_params); @@ -207,7 +206,6 @@ std::optional LoadChainstate(bool fReset, } void DashChainstateSetup(ChainstateManager& chainman, - CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, @@ -237,7 +235,7 @@ void DashChainstateSetup(ChainstateManager& chainman, mempool->ConnectManagers(dmnman.get(), llmq_ctx->isman.get()); } chain_helper.reset(); - chain_helper = std::make_unique(evodb, *dmnman, govman, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor), + chain_helper = std::make_unique(evodb, *dmnman, *(llmq_ctx->isman), *(llmq_ctx->quorum_block_processor), *(llmq_ctx->qsnapman), chainman, consensus_params, mn_sync, chainlocks, *(llmq_ctx->qman)); } diff --git a/src/node/chainstate.h b/src/node/chainstate.h index 09adc7cdf214..a97ea89c8e3e 100644 --- a/src/node/chainstate.h +++ b/src/node/chainstate.h @@ -14,7 +14,6 @@ class CChainstateHelper; class CDeterministicMNManager; class CEvoDB; -class CGovernanceManager; class ChainstateManager; class CMasternodeMetaMan; class CMasternodeSync; @@ -78,7 +77,6 @@ enum class ChainstateLoadingError { */ std::optional LoadChainstate(bool fReset, ChainstateManager& chainman, - CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, @@ -109,7 +107,6 @@ std::optional LoadChainstate(bool fReset, /** Initialize Dash-specific components during chainstate initialization */ void DashChainstateSetup(ChainstateManager& chainman, - CGovernanceManager& govman, CMasternodeMetaMan& mn_metaman, CMasternodeSync& mn_sync, CSporkManager& sporkman, diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index f5172c1da9c3..c512b62d9225 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -309,9 +310,9 @@ class GOVImpl : public GOV } std::optional getProposalFundedHeight(const uint256& proposal_hash) override { - if (context().govman != nullptr && context().chainman != nullptr) { + if (context().chain_helper != nullptr && context().chainman != nullptr) { const int32_t nTipHeight = context().chainman->ActiveHeight(); - for (const auto& trigger : context().govman->GetActiveTriggers()) { + for (const auto& trigger : context().chain_helper->superblocks->GetActiveTriggers()) { if (!trigger || trigger->GetBlockHeight() > nTipHeight) continue; for (const auto& hash : trigger->GetProposalHashes()) { if (hash == proposal_hash) { diff --git a/src/rpc/masternode.cpp b/src/rpc/masternode.cpp index 201d126e5252..14e940b61136 100644 --- a/src/rpc/masternode.cpp +++ b/src/rpc/masternode.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include @@ -222,7 +222,9 @@ static RPCHelpMan masternode_status() }; } -static std::string GetRequiredPaymentsString(CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, int nBlockHeight, const CDeterministicMNCPtr &payee) +static std::string GetRequiredPaymentsString(governance::SuperblockManager& superblocks, + const CDeterministicMNList& tip_mn_list, int nBlockHeight, + const CDeterministicMNCPtr& payee) { std::string strPayments = "Unknown"; if (payee) { @@ -238,9 +240,9 @@ static std::string GetRequiredPaymentsString(CGovernanceManager& govman, const C strPayments += ", " + EncodeDestination(dest); } } - if (govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { + if (superblocks.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { std::vector voutSuperblock; - if (!govman.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblock)) { + if (!superblocks.GetSuperblockPayments(tip_mn_list, nBlockHeight, voutSuperblock)) { return strPayments + ", error"; } std::string strSBPayees = "Unknown"; @@ -305,7 +307,8 @@ static RPCHelpMan masternode_winners() const CBlockIndex* pIndex = pindexTip->GetAncestor(h - 1); auto payee = node.dmnman->GetListForBlock(pIndex).GetMNPayee(pIndex); if (payee) { - std::string strPayments = GetRequiredPaymentsString(*CHECK_NONFATAL(node.govman), tip_mn_list, h, payee); + std::string strPayments = GetRequiredPaymentsString(*CHECK_NONFATAL(node.chain_helper)->superblocks, + tip_mn_list, h, payee); if (!strFilter.empty() && strPayments.find(strFilter) == std::string::npos) continue; obj.pushKV(strprintf("%d", h), strPayments); } @@ -314,7 +317,7 @@ static RPCHelpMan masternode_winners() auto projection = node.dmnman->GetListForBlock(pindexTip).GetProjectedMNPayees(pindexTip, /*nCount=*/20); for (size_t i = 0; i < projection.size(); i++) { int h = nChainTipHeight + 1 + i; - std::string strPayments = GetRequiredPaymentsString(*node.govman, tip_mn_list, h, projection[i]); + std::string strPayments = GetRequiredPaymentsString(*node.chain_helper->superblocks, tip_mn_list, h, projection[i]); if (!strFilter.empty() && strPayments.find(strFilter) == std::string::npos) continue; obj.pushKV(strprintf("%d", h), strPayments); } diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 8a96cb0c9ba4..f4b97a0f6a41 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -144,7 +144,7 @@ void DashChainstateSetup(ChainstateManager& chainman, bool llmq_dbs_wipe, const Consensus::Params& consensus_params) { - DashChainstateSetup(chainman, *Assert(node.govman.get()), *Assert(node.mn_metaman.get()), *Assert(node.mn_sync.get()), + DashChainstateSetup(chainman, *Assert(node.mn_metaman.get()), *Assert(node.mn_sync.get()), *Assert(node.sporkman.get()), *Assert(node.chainlocks), node.chain_helper, node.dmnman, *node.evodb, node.llmq_ctx, Assert(node.mempool.get()), node.args->GetDataDirNet(), llmq_dbs_in_memory, llmq_dbs_wipe, llmq::DEFAULT_BLSCHECK_THREADS, llmq::DEFAULT_WORKER_COUNT, llmq::DEFAULT_MAX_RECOVERED_SIGS_AGE, @@ -288,7 +288,6 @@ ChainTestingSetup::ChainTestingSetup(const std::string& chainName, const std::ve m_node.chainman->m_blockman.m_block_tree_db = std::make_unique(m_cache_sizes.block_tree_db, true); m_node.mn_sync = std::make_unique(std::make_unique(*m_node.connman, *m_node.netfulfilledman)); - m_node.govman = std::make_unique(*m_node.mn_metaman, *m_node.chainman, m_node.dmnman, *m_node.mn_sync); m_node.clhandler = std::make_unique(*m_node.chainlocks, *m_node.chainman, *m_node.mempool, *m_node.mn_sync); @@ -318,7 +317,6 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() auto& chainman{*Assert(m_node.chainman)}; auto maybe_load_error = LoadChainstate(fReindex.load(), chainman, - *Assert(m_node.govman.get()), *Assert(m_node.mn_metaman.get()), *Assert(m_node.mn_sync.get()), *Assert(m_node.sporkman.get()), @@ -346,6 +344,8 @@ void ChainTestingSetup::LoadVerifyActivateChainstate() llmq::DEFAULT_MAX_RECOVERED_SIGS_AGE); assert(!maybe_load_error.has_value()); + m_node.govman = std::make_unique(*m_node.mn_metaman, *m_node.chainman, *m_node.chain_helper->superblocks, m_node.dmnman, *m_node.mn_sync); + auto maybe_verify_error = VerifyLoadedChainstate( chainman, *Assert(m_node.evodb.get()), diff --git a/test/functional/feature_governance_cl.py b/test/functional/feature_governance_cl.py index 3c6ef7356397..9c9991e70dac 100755 --- a/test/functional/feature_governance_cl.py +++ b/test/functional/feature_governance_cl.py @@ -158,7 +158,7 @@ def governance_tip_updated(node): self.log.info("Bump mocktime to trigger governance cleanup") for delta, expected in ( - (5 * 60, ['CleanAndRemoveTriggers -- Removing trigger object']), # mark old triggers for deletion + (5 * 60, ['SuperblockManager::Clean -- Removing trigger object']), # mark old triggers for deletion (10 * 60, ['UpdateCachesAndClean -- Governance Objects: 0']), # deletion after delay ): self.mocktime += delta From 1c1376f26922a3665e3d8b222d9263594c83997b Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 18 May 2026 03:37:36 +0700 Subject: [PATCH 03/13] refactor: break circular dependency between governance/object <-> governance/governance --- src/governance/governance.cpp | 4 ++-- src/governance/object.cpp | 5 ++--- src/governance/object.h | 3 +-- test/lint/lint-circular-dependencies.py | 1 - 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 77b3e0cc006e..7d6c0edb2822 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -253,7 +253,7 @@ void CGovernanceManager::CheckOrphanVotes(CGovernanceObject& govobj) CGovernanceException e; if (time < nNow) { fRemove = true; - } else if (govobj.ProcessVote(m_mn_metaman, *this, tip_mn_list, vote, e)) { + } else if (govobj.ProcessVote(m_mn_metaman, fRateChecksEnabled, tip_mn_list, vote, e)) { RelayVote(vote); fRemove = true; } @@ -811,7 +811,7 @@ bool CGovernanceManager::ProcessVote(const CGovernanceVote& vote, CGovernanceExc return false; } - bool fOk = govobj.ProcessVote(m_mn_metaman, *this, Assert(m_dmnman)->GetListAtChainTip(), vote, exception); + bool fOk = govobj.ProcessVote(m_mn_metaman, fRateChecksEnabled, Assert(m_dmnman)->GetListAtChainTip(), vote, exception); if (fOk) { fOk = cmapVoteToObject.Insert(nHashVote, it->second); } else if (exception.GetType() == GOVERNANCE_EXCEPTION_PERMANENT_ERROR && exception.GetNodePenalty() == 20) { diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 86431439196f..bf0d269e80a0 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include #include @@ -56,7 +55,7 @@ CGovernanceObject::CGovernanceObject(const CGovernanceObject& other) : { } -bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, +bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, const CDeterministicMNList& tip_mn_list, const CGovernanceVote& vote, CGovernanceException& exception) { assert(mn_metaman.IsValid()); @@ -123,7 +122,7 @@ bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, CGovernanceM int64_t nNow = GetAdjustedTime(); int64_t nVoteTimeUpdate = voteInstanceRef.nTime; - if (govman.AreRateChecksEnabled()) { + if (fRateChecksEnabled) { int64_t nTimeDelta = nNow - voteInstanceRef.nTime; if (nTimeDelta < GOVERNANCE_UPDATE_MIN) { std::string msg{strprintf("CGovernanceObject::%s -- Masternode voting too often, MN outpoint = %s, " diff --git a/src/governance/object.h b/src/governance/object.h index 2f2443915835..67fa9eeb9e70 100644 --- a/src/governance/object.h +++ b/src/governance/object.h @@ -17,7 +17,6 @@ class CBLSPublicKey; class CDeterministicMNList; -class CGovernanceManager; class CGovernanceObject; class CGovernanceVote; class ChainstateManager; @@ -284,7 +283,7 @@ class CGovernanceObject void LoadData(); void GetData(UniValue& objResult) const; - bool ProcessVote(CMasternodeMetaMan& mn_metaman, CGovernanceManager& govman, const CDeterministicMNList& tip_mn_list, + bool ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, const CDeterministicMNList& tip_mn_list, const CGovernanceVote& vote, CGovernanceException& exception) EXCLUSIVE_LOCKS_REQUIRED(!cs); diff --git a/test/lint/lint-circular-dependencies.py b/test/lint/lint-circular-dependencies.py index fb9e2644d7d0..eb23208e5971 100755 --- a/test/lint/lint-circular-dependencies.py +++ b/test/lint/lint-circular-dependencies.py @@ -37,7 +37,6 @@ "evo/providertx -> validation -> txmempool -> evo/providertx", "evo/smldiff -> llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> evo/smldiff", "evo/specialtxman -> validation -> evo/specialtxman", - "governance/classes -> governance/object -> governance/governance -> governance/classes", "instantsend/instantsend -> node/blockstorage -> validation -> txmempool -> instantsend/instantsend", "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor", "llmq/commitment -> llmq/utils -> llmq/snapshot -> llmq/commitment", From 62c6dc9112bf2e011903c3dff4fd440cff90f8a3 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 19 May 2026 20:22:07 +0700 Subject: [PATCH 04/13] fmt: clang-apply --- src/governance/governance.cpp | 6 ++---- src/governance/governance.h | 12 ++++-------- src/governance/object.cpp | 5 +++-- src/governance/object.h | 3 +-- src/governance/superblock.cpp | 15 +++++++-------- src/governance/superblock.h | 25 +++++++++---------------- 6 files changed, 26 insertions(+), 40 deletions(-) diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 7d6c0edb2822..d004fa1a1619 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -66,8 +66,7 @@ GovernanceStore::GovernanceStore() : { } -CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, - const ChainstateManager& chainman, +CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman, governance::SuperblockManager& superblocks, const std::unique_ptr& dmnman, CMasternodeSync& mn_sync) : m_db{std::make_unique("governance.dat", "magicGovernanceCache")}, @@ -305,8 +304,7 @@ void CGovernanceManager::AddGovernanceObjectInternal(CGovernanceObject& insert_o LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- Before trigger block, GetDataAsPlainString = %s, nObjectType = %d\n", Assert(govobj)->GetDataAsPlainString(), std23::to_underlying(govobj->GetObjectType())); - if (govobj->GetObjectType() == GovernanceObject::TRIGGER && - !m_superblocks.AddTrigger(govobj, nCachedBlockHeight)) { + if (govobj->GetObjectType() == GovernanceObject::TRIGGER && !m_superblocks.AddTrigger(govobj, nCachedBlockHeight)) { LogPrint(BCLog::GOBJECT, "CGovernanceManager::AddGovernanceObject -- undo adding invalid trigger object: hash = %s\n", nHash.ToString()); govobj->PrepareDeletion(GetTime().count()); return; diff --git a/src/governance/governance.h b/src/governance/governance.h index 4ac8629f7d7b..7c63b327ef03 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -41,8 +41,7 @@ class CMasternodeMetaMan; class CMasternodeSync; class CSuperblock; -namespace governance -{ +namespace governance { class SuperblockManager; } // namespace governance @@ -269,11 +268,9 @@ class CGovernanceManager : public GovernanceStore CGovernanceManager() = delete; CGovernanceManager(const CGovernanceManager&) = delete; CGovernanceManager& operator=(const CGovernanceManager&) = delete; - explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, - const ChainstateManager& chainman, + explicit CGovernanceManager(CMasternodeMetaMan& mn_metaman, const ChainstateManager& chainman, governance::SuperblockManager& superblocks, - const std::unique_ptr& dmnman, - CMasternodeSync& mn_sync); + const std::unique_ptr& dmnman, CMasternodeSync& mn_sync); ~CGovernanceManager(); // Basic initialization and querying @@ -339,8 +336,7 @@ class CGovernanceManager : public GovernanceStore EXCLUSIVE_LOCKS_REQUIRED(!cs_store); bool SerializeVoteForHash(const uint256& nHash, CDataStream& ss) const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); - std::shared_ptr FindGovernanceObject(const uint256& nHash) - EXCLUSIVE_LOCKS_REQUIRED(!cs_store); + std::shared_ptr FindGovernanceObject(const uint256& nHash) EXCLUSIVE_LOCKS_REQUIRED(!cs_store); int GetVoteCount() const EXCLUSIVE_LOCKS_REQUIRED(!cs_store); void AddPostponedObject(const CGovernanceObject& govobj) diff --git a/src/governance/object.cpp b/src/governance/object.cpp index bf0d269e80a0..da001244308e 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -55,8 +55,9 @@ CGovernanceObject::CGovernanceObject(const CGovernanceObject& other) : { } -bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, const CDeterministicMNList& tip_mn_list, - const CGovernanceVote& vote, CGovernanceException& exception) +bool CGovernanceObject::ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, + const CDeterministicMNList& tip_mn_list, const CGovernanceVote& vote, + CGovernanceException& exception) { assert(mn_metaman.IsValid()); diff --git a/src/governance/object.h b/src/governance/object.h index 67fa9eeb9e70..8c694bc34b94 100644 --- a/src/governance/object.h +++ b/src/governance/object.h @@ -284,8 +284,7 @@ class CGovernanceObject void GetData(UniValue& objResult) const; bool ProcessVote(CMasternodeMetaMan& mn_metaman, bool fRateChecksEnabled, const CDeterministicMNList& tip_mn_list, - const CGovernanceVote& vote, CGovernanceException& exception) - EXCLUSIVE_LOCKS_REQUIRED(!cs); + const CGovernanceVote& vote, CGovernanceException& exception) EXCLUSIVE_LOCKS_REQUIRED(!cs); /// Called when MN's which have voted on this object have been removed void ClearMasternodeVotes(const CDeterministicMNList& tip_mn_list) diff --git a/src/governance/superblock.cpp b/src/governance/superblock.cpp index 36f169467027..87eb1c50e6e2 100644 --- a/src/governance/superblock.cpp +++ b/src/governance/superblock.cpp @@ -25,8 +25,8 @@ bool SuperblockManager::AddTrigger(std::shared_ptr obj, int c LOCK(cs_sb); if (m_triggers.count(nHash)) { - LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Already have hash, nHash = %s, size = %s\n", - __func__, nHash.GetHex(), m_triggers.size()); + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- Already have hash, nHash = %s, size = %s\n", __func__, + nHash.GetHex(), m_triggers.size()); return false; } @@ -92,8 +92,7 @@ void SuperblockManager::Clean(int cachedHeight) break; } } - LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- %smarked for removal\n", __func__, - remove ? "" : "NOT "); + LogPrint(BCLog::GOBJECT, "SuperblockManager::%s -- %smarked for removal\n", __func__, remove ? "" : "NOT "); if (remove) { std::string strDataAsPlainString = "nullptr"; @@ -129,15 +128,15 @@ std::vector SuperblockManager::GetActiveTriggers() const return vecResults; } -bool SuperblockManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, - CSuperblock_sptr& sbRet, int nBlockHeight) const +bool SuperblockManager::GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& sbRet, + int nBlockHeight) const { LOCK(cs_sb); return GetBestSuperblockInternal(tip_mn_list, sbRet, nBlockHeight); } -bool SuperblockManager::GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, - CSuperblock_sptr& sbRet, int nBlockHeight) const +bool SuperblockManager::GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& sbRet, + int nBlockHeight) const { AssertLockHeld(cs_sb); if (!CSuperblock::IsValidBlockHeight(nBlockHeight)) { diff --git a/src/governance/superblock.h b/src/governance/superblock.h index cbc42ea71ed4..f47978ca29a7 100644 --- a/src/governance/superblock.h +++ b/src/governance/superblock.h @@ -40,8 +40,7 @@ class SuperblockManager /** Register a TRIGGER governance object. Returns true if the resulting * trigger is live (not already height-expired). */ - bool AddTrigger(std::shared_ptr obj, int cachedHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + bool AddTrigger(std::shared_ptr obj, int cachedHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); /** Single-direction notification from CGovernanceManager when it erases * a TRIGGER object from its store. */ @@ -56,23 +55,18 @@ class SuperblockManager std::vector GetActiveTriggers() const EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); - bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, - CSuperblock_sptr& sbRet, int nBlockHeight) const + bool GetBestSuperblock(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& sbRet, int nBlockHeight) const EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); - bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + bool IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); - bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, - const CTransaction& txNew, int nBlockHeight, CAmount blockReward) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + bool IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, const CTransaction& txNew, + int nBlockHeight, CAmount blockReward) const EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); bool GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, - std::vector& voutSuperblockRet) const - EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + std::vector& voutSuperblockRet) const EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); - void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) - EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); + void ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) EXCLUSIVE_LOCKS_REQUIRED(!cs_sb); private: struct TriggerEntry { @@ -80,9 +74,8 @@ class SuperblockManager std::shared_ptr obj; }; - bool GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, - CSuperblock_sptr& sbRet, int nBlockHeight) const - EXCLUSIVE_LOCKS_REQUIRED(cs_sb); + bool GetBestSuperblockInternal(const CDeterministicMNList& tip_mn_list, CSuperblock_sptr& sbRet, + int nBlockHeight) const EXCLUSIVE_LOCKS_REQUIRED(cs_sb); mutable Mutex cs_sb; std::atomic m_loaded{false}; From 87c79487d6ee4dc594f3c5c1b23a41df5f1ec3b1 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 18 May 2026 03:45:25 +0700 Subject: [PATCH 05/13] refactor: cleanup governance/governance includes and forward declarations --- src/governance/core_write.cpp | 1 + src/governance/governance.cpp | 2 -- src/governance/governance.h | 21 +++++++-------------- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/src/governance/core_write.cpp b/src/governance/core_write.cpp index 9093ec2748fc..4d90dd269c44 100644 --- a/src/governance/core_write.cpp +++ b/src/governance/core_write.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index d004fa1a1619..efafb44e83e1 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -20,10 +20,8 @@ #include #include #include -#include #include #include -#include #include #include diff --git a/src/governance/governance.h b/src/governance/governance.h index 7c63b327ef03..6e8974899c59 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -17,37 +16,31 @@ #include #include #include -#include #include class CBloomFilter; class CBlockIndex; -class CChain; class CConnman; +class CDataStream; +class CDeterministicMNList; +class CDeterministicMNManager; class ChainstateManager; template class CFlatDB; -class CInv; -class CNode; -struct RPCResult; - -class CDeterministicMNList; -class CDeterministicMNManager; class CGovernanceException; -class CGovernanceManager; class CGovernanceObject; class CGovernanceVote; +class CInv; class CMasternodeMetaMan; class CMasternodeSync; -class CSuperblock; +class CService; +struct RPCResult; +class UniValue; namespace governance { class SuperblockManager; } // namespace governance -class UniValue; - -using CSuperblock_sptr = std::shared_ptr; using vote_time_pair_t = std::pair; static constexpr int RATE_BUFFER_SIZE = 5; From e76d4efa9671a167469143f4d842fe78baf8be88 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Mon, 18 May 2026 03:58:50 +0700 Subject: [PATCH 06/13] refactor: move code from governance/classes to governance/superblock where it belongs --- src/Makefile.am | 2 - src/governance/classes.cpp | 421 ---------------------------------- src/governance/classes.h | 117 ---------- src/governance/governance.cpp | 1 - src/governance/signing.cpp | 1 - src/governance/signing.h | 2 +- src/governance/superblock.cpp | 410 ++++++++++++++++++++++++++++++++- src/governance/superblock.h | 95 +++++++- src/masternode/payments.cpp | 1 - src/node/interfaces.cpp | 1 - src/qt/proposalmodel.cpp | 2 +- src/rpc/governance.cpp | 2 +- src/rpc/mining.cpp | 2 +- 13 files changed, 507 insertions(+), 550 deletions(-) delete mode 100644 src/governance/classes.cpp delete mode 100644 src/governance/classes.h diff --git a/src/Makefile.am b/src/Makefile.am index 31e1b158461b..194eb6bb4a04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,7 +230,6 @@ BITCOIN_CORE_H = \ evo/types.h \ external_signer.h \ dsnotificationinterface.h \ - governance/classes.h \ governance/common.h \ governance/exceptions.h \ governance/governance.h \ @@ -522,7 +521,6 @@ libbitcoin_node_a_SOURCES = \ evo/specialtx_filter.cpp \ evo/specialtxman.cpp \ flatfile.cpp \ - governance/classes.cpp \ governance/exceptions.cpp \ governance/governance.cpp \ governance/net_governance.cpp \ diff --git a/src/governance/classes.cpp b/src/governance/classes.cpp deleted file mode 100644 index e7ad845aaff6..000000000000 --- a/src/governance/classes.cpp +++ /dev/null @@ -1,421 +0,0 @@ -// Copyright (c) 2014-2025 The Dash Core developers -// Distributed under the MIT/X11 software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -#include - -#include - -#include -#include -#include -#include -#include