diff --git a/src/Makefile.am b/src/Makefile.am index 57d000012b00..49582bb2b658 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -222,7 +222,6 @@ BITCOIN_CORE_H = \ dsnotificationinterface.h \ evo/assetlocktx.h \ evo/cbtx.h \ - evo/chainhelper.h \ evo/creditpool.h \ evo/deterministicmns.h \ evo/dmn_types.h \ @@ -548,7 +547,6 @@ libbitcoin_node_a_SOURCES = \ dsnotificationinterface.cpp \ evo/assetlocktx.cpp \ evo/cbtx.cpp \ - evo/chainhelper.cpp \ evo/creditpool.cpp \ evo/deterministicmns.cpp \ evo/dmnstate.cpp \ @@ -1282,7 +1280,6 @@ libdashkernel_la_SOURCES = \ deploymentstatus.cpp \ evo/assetlocktx.cpp \ evo/cbtx.cpp \ - evo/chainhelper.cpp \ evo/creditpool.cpp \ evo/deterministicmns.cpp \ evo/dmnstate.cpp \ @@ -1297,19 +1294,10 @@ libdashkernel_la_SOURCES = \ evo/specialtx_filter.cpp \ evo/specialtxman.cpp \ flatfile.cpp \ - governance/common.cpp \ - governance/object.cpp \ - governance/superblock.cpp \ - governance/vote.cpp \ - governance/votedb.cpp \ gsl/assert.cpp \ hash.cpp \ - index/addressindex.cpp \ index/addressindex_util.cpp \ index/base.cpp \ - index/blockfilterindex.cpp \ - index/coinstatsindex.cpp \ - index/spentindex.cpp \ index/txindex.cpp \ init/common.cpp \ instantsend/db.cpp \ @@ -1326,9 +1314,6 @@ libdashkernel_la_SOURCES = \ llmq/blockprocessor.cpp \ llmq/commitment.cpp \ llmq/context.cpp \ - llmq/debug.cpp \ - llmq/dkgsession.cpp \ - llmq/dkgsessionhandler.cpp \ llmq/dkgsessionmgr.cpp \ llmq/options.cpp \ llmq/quorums.cpp \ @@ -1340,7 +1325,6 @@ libdashkernel_la_SOURCES = \ logging.cpp \ masternode/meta.cpp \ masternode/payments.cpp \ - masternode/sync.cpp \ merkleblock.cpp \ messagesigner.cpp \ netaddress.cpp \ diff --git a/src/active/context.cpp b/src/active/context.cpp index a28ac91f5f71..83926f5e030a 100644 --- a/src/active/context.cpp +++ b/src/active/context.cpp @@ -27,7 +27,7 @@ #include ActiveContext::ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman, CConnman& connman, - CDeterministicMNManager& dmnman, CGovernanceManager& govman, + CDeterministicMNManager& dmnman, CGovernanceManager& govman, CMNHFManager& mnhfman, governance::SuperblockManager& superblocks, CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, CTxMemPool& mempool, chainlock::ChainlockHandler& clhandler, llmq::CInstantSendManager& isman, @@ -43,7 +43,7 @@ ActiveContext::ActiveContext(CBLSWorker& bls_worker, ChainstateManager& chainman qdkgsman{std::make_unique(dmnman, qsnapman, chainman, sporkman, db_params)}, shareman{std::make_unique(connman, chainman, sigman, *nodeman, qman, sporkman)}, gov_signer{std::make_unique(dmnman, govman, superblocks, *nodeman, chainman, mn_sync)}, - ehf_sighandler{std::make_unique(chainman, sigman, *shareman, qman)}, + ehf_sighandler{std::make_unique(chainman, mnhfman, sigman, *shareman, qman)}, cl_signer{std::make_unique(chainman, chainlocks, clhandler, isman, qman, sigman, *shareman, mn_sync)}, is_signer{std::make_unique(chainman, chainlocks, isman, sigman, diff --git a/src/active/context.h b/src/active/context.h index d7d45d8e15e2..dcaa1781f144 100644 --- a/src/active/context.h +++ b/src/active/context.h @@ -59,7 +59,7 @@ 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, + CDeterministicMNManager& dmnman, CGovernanceManager& govman, CMNHFManager& mnhfman, governance::SuperblockManager& superblocks, CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, CTxMemPool& mempool, chainlock::ChainlockHandler& clhandler, llmq::CInstantSendManager& isman, diff --git a/src/bitcoin-chainstate.cpp b/src/bitcoin-chainstate.cpp index 204c4701f08d..531872340c74 100644 --- a/src/bitcoin-chainstate.cpp +++ b/src/bitcoin-chainstate.cpp @@ -19,14 +19,13 @@ #include #include #include -#include #include #include +#include #include -#include #include +#include #include -#include #include #include #include @@ -98,27 +97,27 @@ int main(int argc, char* argv[]) CMasternodeMetaMan metaman; 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; + auto llmq_ctx = WITH_LOCK(::cs_main, return std::make_unique(dmnman, evodb, chainman, + util::DbWrapperParams{.path = gArgs.GetDataDirNet(), .memory = false, .wipe = false}, + llmq::DEFAULT_BLSCHECK_THREADS, llmq::DEFAULT_WORKER_COUNT, llmq::DEFAULT_MAX_RECOVERED_SIGS_AGE)); + auto special_tx = std::make_unique(evodb, dmnman, + *llmq_ctx->quorum_block_processor, *llmq_ctx->qsnapman, + chainman, chainman.m_blockman, chainman.GetConsensus(), + chainlocks, *llmq_ctx->qman); node::CacheSizes cache_sizes; cache_sizes.block_tree_db = 2 << 20; cache_sizes.coins_db = 2 << 22; cache_sizes.coins = (450 << 20) - (2 << 20) - (2 << 22); node::ChainstateLoadOptions options; - options.isman = &isman; options.chainlocks = &chainlocks; - options.mn_sync = &mn_sync; options.data_dir = gArgs.GetDataDirNet(); options.check_interrupt = [] { return false; }; options.coins_error_cb = [] {}; - auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options, evodb, dmnman, llmq_ctx, chain_helper); + auto [status, error] = node::LoadChainstate(chainman, cache_sizes, options, evodb, dmnman, *special_tx); if (status != node::ChainstateLoadStatus::SUCCESS) { std::cerr << "Failed to load Chain state from your datadir." << std::endl; goto epilogue; @@ -280,6 +279,6 @@ int main(int argc, char* argv[]) } GetMainSignals().UnregisterBackgroundSignalScheduler(); // Tear down Dash kernel objects before kernel::~Context(). - chain_helper.reset(); + special_tx.reset(); llmq_ctx.reset(); } diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp deleted file mode 100644 index 8e92000851e1..000000000000 --- a/src/evo/chainhelper.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2024-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 -#include -#include -#include -#include -#include - -CChainstateHelper::CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, const CMasternodeSync& mn_sync, - llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, - llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const node::BlockManager& blockman, const Consensus::Params& consensus_params, - const chainlock::Chainlocks& chainlocks, const llmq::CQuorumManager& qman) : - isman{isman}, - mn_sync{mn_sync}, - m_dmnman{dmnman}, - credit_pool_manager{std::make_unique(evodb, chainman)}, - m_chainlocks{chainlocks}, - ehf_manager{std::make_unique(evodb, consensus_params)}, - superblocks{std::make_unique()}, - mn_payments{std::make_unique(dmnman, *superblocks, consensus_params)}, - special_tx{std::make_unique(*credit_pool_manager, dmnman, *ehf_manager, qblockman, qsnapman, - chainman, blockman, consensus_params, chainlocks, qman)} -{} - -CChainstateHelper::~CChainstateHelper() = default; - -bool CChainstateHelper::IsSuperblockValidationRequired(const CBlockIndex* const pindex) -{ - if (m_chainlocks.GetBestChainLockHeight() >= pindex->nHeight) { - LogPrint(BCLog::MNPAYMENTS, "%s -- validation of chainlocked block=%s is skipped\n", __func__, pindex->GetBlockHash().ToString()); - return false; - } - if (!mn_sync.IsSynced()) { - LogPrint(BCLog::MNPAYMENTS, "%s -- WARNING! Node is not fully synced, checked superblock for block=%s max bounds only\n", __func__, pindex->GetBlockHash().ToString()); - return false; - } - return true; -} - -/** Passthrough functions to chainlock::Chainlocks */ -bool CChainstateHelper::HasConflictingChainLock(int nHeight, const uint256& blockHash) const -{ - return m_chainlocks.HasConflictingChainLock(nHeight, blockHash); -} - -bool CChainstateHelper::HasChainLock(int nHeight, const uint256& blockHash) const -{ - return m_chainlocks.HasChainLock(nHeight, blockHash); -} - -int32_t CChainstateHelper::GetBestChainLockHeight() const { return m_chainlocks.GetBestChainLockHeight(); } - -uint256 CChainstateHelper::GetDeterministicMNListHash(const CBlockIndex* pindex) const -{ - return SerializeHash(m_dmnman.GetListForBlock(Assert(pindex))); -} - -/** Passthrough functions to CCreditPoolManager */ -CCreditPool CChainstateHelper::GetCreditPool(const CBlockIndex* const pindex) -{ - return credit_pool_manager->GetCreditPool(pindex); -} - -/** Passthrough functions to CInstantSendManager */ -std::optional> CChainstateHelper::ConflictingISLockIfAny( - const CTransaction& tx) const -{ - const auto islock = isman.GetConflictingLock(tx); - if (!islock) return std::nullopt; - 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) -{ - const auto islock = isman.GetConflictingLock(tx); - if (!islock) return false; - isman.RemoveConflictingLock(::SerializeHash(*islock), *islock); - return true; -} - -std::map CChainstateHelper::GetSignalsStage(const CBlockIndex* const pindexPrev) -{ - return ehf_manager->GetSignalsStage(pindexPrev); -} diff --git a/src/evo/chainhelper.h b/src/evo/chainhelper.h deleted file mode 100644 index a501dd82ceaf..000000000000 --- a/src/evo/chainhelper.h +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) 2024-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_EVO_CHAINHELPER_H -#define BITCOIN_EVO_CHAINHELPER_H - -#include -#include -#include -#include - -class CBlockIndex; -class CCreditPoolManager; -class CDeterministicMNManager; -class CEvoDB; -class ChainstateManager; -class CMasternodeSync; -class CMNHFManager; -class CMNPaymentsProcessor; -class CSpecialTxProcessor; -class CTransaction; -class uint256; -struct CCreditPool; -namespace chainlock { -class Chainlocks; -} // namespace chainlock -namespace governance { -class SuperblockManager; -} // namespace governance -namespace Consensus { -struct Params; -} // namespace Consensus -namespace llmq { -class CInstantSendManager; -class CQuorumBlockProcessor; -class CQuorumManager; -class CQuorumSnapshotManager; -} // namespace llmq -namespace node { -class BlockManager; -} // namespace node -class CChainstateHelper -{ -private: - llmq::CInstantSendManager& isman; - const CMasternodeSync& mn_sync; - CDeterministicMNManager& m_dmnman; - -public: - 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; - -public: - CChainstateHelper() = delete; - CChainstateHelper(const CChainstateHelper&) = delete; - CChainstateHelper& operator=(const CChainstateHelper&) = delete; - explicit CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmnman, const CMasternodeSync& mn_sync, - llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, - llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, - const node::BlockManager& blockman, const Consensus::Params& consensus_params, - const chainlock::Chainlocks& chainlocks, const llmq::CQuorumManager& qman); - ~CChainstateHelper(); - - bool IsSuperblockValidationRequired(const CBlockIndex* const pindex); - - /** Passthrough functions to chainlock::Chainlocks */ - bool HasConflictingChainLock(int nHeight, const uint256& blockHash) const; - bool HasChainLock(int nHeight, const uint256& blockHash) const; - int32_t GetBestChainLockHeight() const; - - /** Return a canonical hash of the deterministic MN list derived at a block. */ - uint256 GetDeterministicMNListHash(const CBlockIndex* pindex) const; - - /** Passthrough functions to CCreditPoolManager */ - CCreditPool GetCreditPool(const CBlockIndex* const pindex); - - /** 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); - - std::map GetSignalsStage(const CBlockIndex* const pindexPrev); -}; - -#endif // BITCOIN_EVO_CHAINHELPER_H diff --git a/src/evo/providertx_service.cpp b/src/evo/providertx_service.cpp index aa9426567183..5f776847cddb 100644 --- a/src/evo/providertx_service.cpp +++ b/src/evo/providertx_service.cpp @@ -7,7 +7,6 @@ #include #include #include -#include #include #include #include @@ -360,7 +359,7 @@ std::optional Preflight(node::NodeContext& node, const CTransac { AssertLockNotHeld(::cs_main); auto& chainman{*Assert(node.chainman)}; - auto& chain_helper{*Assert(node.chain_helper)}; + auto& special_tx{*Assert(node.special_tx)}; LOCK(::cs_main); const CBlockIndex* tip{chainman.ActiveChain().Tip()}; @@ -379,7 +378,7 @@ std::optional Preflight(node::NodeContext& node, const CTransac } TxValidationState state; - if (!chain_helper.special_tx->CheckSpecialTx(tx, tip, GetSpecialTxRules(tip, chainman), + if (!special_tx.CheckSpecialTx(tx, tip, GetSpecialTxRules(tip, chainman), chainman.ActiveChainstate().CoinsTip(), true, state)) { return Error(ProviderTxErrorCode::CONSENSUS_REJECTED, state.ToString(), state.GetRejectReason()); } diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 28f59ec6ced5..aef331c99d8d 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -30,6 +30,26 @@ #include #include +CSpecialTxProcessor::CSpecialTxProcessor(CEvoDB& evodb, CDeterministicMNManager& dmnman, + llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, + const ChainstateManager& chainman, const node::BlockManager& blockman, + const Consensus::Params& consensus_params, + const chainlock::Chainlocks& chainlocks, const llmq::CQuorumManager& qman) : + m_cpoolman{std::make_unique(evodb, chainman)}, + m_mnhfman{std::make_unique(evodb, consensus_params)}, + m_dmnman{dmnman}, + m_qblockman{qblockman}, + m_qsnapman{qsnapman}, + m_chainman(chainman), + m_blockman{blockman}, + m_consensus_params{consensus_params}, + m_chainlocks{chainlocks}, + m_qman{qman} +{ +} + +CSpecialTxProcessor::~CSpecialTxProcessor() = default; + static bool AddNetInfoEntries(const std::shared_ptr& net_info, NetInfoPurpose purpose, const NetInfoList& entries, BlockValidationState& state) { @@ -794,6 +814,11 @@ bool CSpecialTxProcessor::RebuildListFromBlock(const CBlock& block, gsl::not_nul return true; } +uint256 CSpecialTxProcessor::GetDeterministicMNListHash(gsl::not_null pindex) const +{ + return SerializeHash(m_dmnman.GetListForBlock(pindex)); +} + bool CSpecialTxProcessor::ProcessSpecialTxsInBlock(Chainstate& chainstate, const CChain& chain, const CBlock& block, const CBlockIndex* pindex, SpecialTxRules rules, const CCoinsViewCache& view, CAmount blockSubsidy, bool fJustCheck, @@ -845,7 +870,7 @@ bool CSpecialTxProcessor::ProcessSpecialTxsInBlock(Chainstate& chainstate, const CRangesSet indexes; if (DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_V20)) { - CCreditPool creditPool{m_cpoolman.GetCreditPool(pindex->pprev)}; + CCreditPool creditPool{m_cpoolman->GetCreditPool(pindex->pprev)}; LogPrint(BCLog::CREDITPOOL, "CSpecialTxProcessor::%s -- CCreditPool is %s\n", __func__, creditPool.ToString()); indexes = std::move(creditPool.indexes); } @@ -904,6 +929,9 @@ bool CSpecialTxProcessor::ProcessSpecialTxsInBlock(Chainstate& chainstate, const CDeterministicMNList mn_list; if (DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_DIP0003)) { + // ConnectBlock validates masternode payments against the list at the + // previous block, also under fJustCheck where ProcessBlock is skipped. + updatesRet.old_list = m_dmnman.GetListForBlock(pindex->pprev); if (!BuildNewListFromBlock(block, pindex->pprev, rules.v24, view, true, state, mn_list)) { // pass the state returned by the function above return false; @@ -970,14 +998,14 @@ bool CSpecialTxProcessor::ProcessSpecialTxsInBlock(Chainstate& chainstate, const int64_t nTime7 = GetTimeMicros(); - if (!m_mnhfman.ProcessBlock(block, pindex, fJustCheck, state)) { + if (!m_mnhfman->ProcessBlock(block, pindex, fJustCheck, state)) { // pass the state returned by the function above return false; } int64_t nTime8 = GetTimeMicros(); nTimeMnehf += nTime8 - nTime7; - LogPrint(BCLog::BENCHMARK, " - m_mnhfman.ProcessBlock: %.2fms [%.2fs]\n", 0.001 * (nTime8 - nTime7), + LogPrint(BCLog::BENCHMARK, " - m_mnhfman->ProcessBlock: %.2fms [%.2fs]\n", 0.001 * (nTime8 - nTime7), nTimeMnehf * 0.000001); if (DeploymentActiveAfter(pindex, m_consensus_params, Consensus::DEPLOYMENT_V19) && bls::bls_legacy_scheme.load()) { @@ -1012,7 +1040,7 @@ bool CSpecialTxProcessor::UndoSpecialTxsInBlock(const Chainstate& chainstate, co LogPrintf("CSpecialTxProcessor::%s -- bls_legacy_scheme=%d\n", __func__, bls::bls_legacy_scheme.load()); } - if (!m_mnhfman.UndoBlock(block, pindex)) { + if (!m_mnhfman->UndoBlock(block, pindex)) { return false; } @@ -1042,7 +1070,7 @@ bool CSpecialTxProcessor::CheckCreditPoolDiffForBlock(const CBlock& block, const if (!DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_V20)) return true; try { - const auto creditPoolDiff = GetCreditPoolDiffForBlock(m_cpoolman, block, + const auto creditPoolDiff = GetCreditPoolDiffForBlock(*m_cpoolman, block, pindex->pprev, m_consensus_params, blockSubsidy, state); if (!creditPoolDiff.has_value()) return false; diff --git a/src/evo/specialtxman.h b/src/evo/specialtxman.h index c90858d22062..1481ad01683a 100644 --- a/src/evo/specialtxman.h +++ b/src/evo/specialtxman.h @@ -11,6 +11,7 @@ #include #include +#include #include class BlockValidationState; @@ -22,6 +23,7 @@ class CCoinsViewCache; class CCreditPoolManager; class CDeterministicMNList; class CDeterministicMNManager; +class CEvoDB; class CProDisTx; class CRangesSet; class CTransaction; @@ -29,6 +31,7 @@ class ChainstateManager; class Chainstate; class CMNHFManager; class TxValidationState; +class uint256; struct MNListUpdates; namespace chainlock { @@ -54,10 +57,14 @@ struct SpecialTxRules { class CSpecialTxProcessor { +public: + //! Credit-pool and EHF-signal state is carried by special transactions, + //! so the processor owns their managers; other consumers reach them here. + const std::unique_ptr m_cpoolman; + const std::unique_ptr m_mnhfman; + private: - CCreditPoolManager& m_cpoolman; CDeterministicMNManager& m_dmnman; - CMNHFManager& m_mnhfman; llmq::CQuorumBlockProcessor& m_qblockman; llmq::CQuorumSnapshotManager& m_qsnapman; const ChainstateManager& m_chainman; @@ -67,23 +74,12 @@ class CSpecialTxProcessor const llmq::CQuorumManager& m_qman; public: - explicit CSpecialTxProcessor(CCreditPoolManager& cpoolman, CDeterministicMNManager& dmnman, CMNHFManager& mnhfman, + explicit CSpecialTxProcessor(CEvoDB& evodb, CDeterministicMNManager& dmnman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const node::BlockManager& blockman, const Consensus::Params& consensus_params, const chainlock::Chainlocks& chainlocks, - const llmq::CQuorumManager& qman) : - m_cpoolman(cpoolman), - m_dmnman{dmnman}, - m_mnhfman{mnhfman}, - m_qblockman{qblockman}, - m_qsnapman{qsnapman}, - m_chainman(chainman), - m_blockman{blockman}, - m_consensus_params{consensus_params}, - m_chainlocks{chainlocks}, - m_qman{qman} - { - } + const llmq::CQuorumManager& qman); + ~CSpecialTxProcessor(); bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, SpecialTxRules rules, const CCoinsViewCache& view, bool check_sigs, TxValidationState& state) @@ -108,6 +104,9 @@ class CSpecialTxProcessor const CDeterministicMNList& prevList, const CCoinsViewCache& view, bool debugLogs, BlockValidationState& state, CDeterministicMNList& mnListRet); + /** Return a canonical hash of the deterministic MN list derived at a block. */ + uint256 GetDeterministicMNListHash(gsl::not_null pindex) const; + private: bool CheckSpecialTxInner(const CChain* chain, const CTransaction& tx, const CBlockIndex* pindexPrev, SpecialTxRules rules, const CCoinsViewCache& view, const std::optional& indexes, diff --git a/src/governance/governance.cpp b/src/governance/governance.cpp index 6e34c5c56e95..78adb6e72af3 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -88,7 +88,7 @@ CGovernanceManager::CGovernanceManager(CMasternodeMetaMan& mn_metaman, const Cha CGovernanceManager::~CGovernanceManager() { // Reset the paired SuperblockManager so its loaded-flag and trigger map don't - // outlive us. chain_helper (its owner) must outlive govman -- see PrepareShutdown + // outlive us. node.sbman (its owner) must outlive govman -- see PrepareShutdown // in init.cpp and the test teardown ordering. m_superblocks.Clear(); if (!is_loaded) return; diff --git a/src/governance/signing.cpp b/src/governance/signing.cpp index 1eea9b60dac6..da2b5752085e 100644 --- a/src/governance/signing.cpp +++ b/src/governance/signing.cpp @@ -57,7 +57,7 @@ std::optional GovernanceSigner::CreateSuperblockCandidate(int CSuperblock::GetNearestSuperblocksHeights(nHeight, nLastSuperblock, nNextSuperblock); auto SBEpochTime = static_cast(GetTime().count() + (nNextSuperblock - nHeight) * 2.62 * 60); - auto governanceBudget = WITH_LOCK(::cs_main, return CSuperblock::GetPaymentsLimit(m_chainman.ActiveChain(), nNextSuperblock)); + auto governanceBudget = CSuperblock::GetPaymentsLimit(nNextSuperblock); CAmount budgetAllocated{}; for (const auto& proposal : approvedProposals) { diff --git a/src/governance/superblock.cpp b/src/governance/superblock.cpp index 54213f62579b..e4bfeb171e12 100644 --- a/src/governance/superblock.cpp +++ b/src/governance/superblock.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -118,9 +119,7 @@ CSuperblock::CSuperblock(int nBlockHeight, std::vector vecPa bool CSuperblock::IsValidBlockHeight(int nBlockHeight) { - // SUPERBLOCKS CAN HAPPEN ONLY after hardfork and only ONCE PER CYCLE - return nBlockHeight >= Params().GetConsensus().nSuperblockStartBlock && - ((nBlockHeight % Params().GetConsensus().nSuperblockCycle) == 0); + return IsSuperblockHeight(nBlockHeight, Params().GetConsensus()); } void CSuperblock::GetNearestSuperblocksHeights(int nBlockHeight, int& nLastSuperblockRet, int& nNextSuperblockRet) @@ -142,24 +141,9 @@ void CSuperblock::GetNearestSuperblocksHeights(int nBlockHeight, int& nLastSuper } } -CAmount CSuperblock::GetPaymentsLimit(const CChain& active_chain, int nBlockHeight) +CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight) { - const Consensus::Params& consensusParams = Params().GetConsensus(); - - if (!IsValidBlockHeight(nBlockHeight)) { - return 0; - } - - const bool fV20Active{nBlockHeight >= consensusParams.V20Height}; - - // min subsidy for high diff networks and vice versa - int nBits = consensusParams.fPowAllowMinDifficultyBlocks ? UintToArith256(consensusParams.powLimit).GetCompact() : 1; - // some part of all blocks issued during the cycle goes to superblock, see GetBlockSubsidy - CAmount nSuperblockPartOfSubsidy = GetSuperblockSubsidyInner(nBits, nBlockHeight - 1, consensusParams, fV20Active); - CAmount nPaymentsLimit = nSuperblockPartOfSubsidy * consensusParams.nSuperblockCycle; - LogPrint(BCLog::GOBJECT, "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit); - - return nPaymentsLimit; + return GetSuperblockPaymentsLimit(nBlockHeight, Params().GetConsensus()); } void CSuperblock::ParsePaymentSchedule(const std::string& strPaymentAddresses, const std::string& strPaymentAmounts, const std::string& strProposalHashes) @@ -234,108 +218,6 @@ bool CSuperblock::GetPayment(int nPaymentIndex, CGovernancePayment& paymentRet) return true; } -CAmount CSuperblock::GetPaymentsTotalAmount() -{ - return std23::ranges::fold_left(vecPayments, CAmount{0}, [](CAmount s, const auto& p) { return s + p.nAmount; }); -} - -/** -* Is Transaction Valid -* -* - Does this transaction match the superblock? -*/ - -bool CSuperblock::IsValid(const CChain& active_chain, const CTransaction& txNew, int block_height, CAmount blockReward, bool is_v24) -{ - // TODO : LOCK(cs); - // No reason for a lock here now since this method only accesses data - // internal to *this and since CSuperblock's are accessed only through - // shared pointers there's no way our object can get deleted while this - // code is running. - if (!IsValidBlockHeight(block_height)) { - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid, incorrect block height\n"); - return false; - } - - // CONFIGURE SUPERBLOCK OUTPUTS - - int nOutputs = txNew.vout.size(); - int nPayments = CountPayments(); - int nMinerAndMasternodePayments = nOutputs - nPayments; - - LogPrint(BCLog::GOBJECT, "CSuperblock::IsValid -- nOutputs = %d, nPayments = %d, hash = %s\n", nOutputs, nPayments, - nGovObjHash.ToString()); - - // We require an exact match (including order) between the expected - // superblock payments and the payments actually in the block. - - if (nMinerAndMasternodePayments < 0) { - // This means the block cannot have all the superblock payments - // so it is not valid. - // TODO: could that be that we just hit coinbase size limit? - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid, too few superblock payments\n"); - return false; - } - - // payments should not exceed limit - CAmount nPaymentsTotalAmount = GetPaymentsTotalAmount(); - CAmount nPaymentsLimit = GetPaymentsLimit(active_chain, block_height); - if (nPaymentsTotalAmount > nPaymentsLimit) { - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid, payments limit exceeded: payments %lld, limit %lld\n", nPaymentsTotalAmount, nPaymentsLimit); - return false; - } - - // miner and masternodes should not get more than they would usually get - CAmount nBlockValue = txNew.GetValueOut(); - if (nBlockValue > blockReward + nPaymentsTotalAmount) { - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid, block value limit exceeded: block %lld, limit %lld\n", nBlockValue, blockReward + nPaymentsTotalAmount); - return false; - } - - int nVoutIndex = -1; - for (int i = 0; i < nPayments; i++) { - CGovernancePayment payment; - if (!GetPayment(i, payment)) { - // This shouldn't happen so log a warning - LogPrintf("CSuperblock::IsValid -- WARNING: Failed to find payment: %d of %d total payments\n", i, nPayments); - continue; - } - - bool fPaymentMatch = false; - - // From V24 on, start past the previously matched output so each expected - // payment consumes a distinct vout (two adjacent payments with the same - // script and amount must match two separate outputs, not the same one - // twice). Before V24 the scan restarted at the previously matched index - // (inclusive), which is kept for backwards compatibility. - // TODO: After V24 is hardened/finalized so historical duplicate-output - // blocks cannot be encountered, simplify this path to the V24 scan only. - const int nVoutStart = is_v24 ? nVoutIndex + 1 : std::max(nVoutIndex, 0); - for (int j = nVoutStart; j < nOutputs; j++) { - // Find superblock payment - fPaymentMatch = ((payment.script == txNew.vout[j].scriptPubKey) && - (payment.nAmount == txNew.vout[j].nValue)); - - if (fPaymentMatch) { - nVoutIndex = j; - break; - } - } - - if (!fPaymentMatch) { - // Superblock payment not found! - - CTxDestination dest; - ExtractDestination(payment.script, dest); - LogPrintf("CSuperblock::IsValid -- ERROR: Block invalid: %d payment %d to %s not found\n", i, payment.nAmount, EncodeDestination(dest)); - - return false; - } - } - - return true; -} - bool CSuperblock::IsExpired(int heightToTest) const { int nExpirationBlocks; @@ -575,15 +457,14 @@ bool SuperblockManager::GetBestSuperblockInternal(const CDeterministicMNList& ti return nYesCount > 0; } -bool SuperblockManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn_list, int nBlockHeight) +bool SuperblockManager::IsSuperblockTriggeredInternal(const CDeterministicMNList& tip_mn_list, int nBlockHeight) { + AssertLockHeld(cs_sb); 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) { @@ -619,29 +500,24 @@ bool SuperblockManager::IsSuperblockTriggered(const CDeterministicMNList& tip_mn return false; } -bool SuperblockManager::IsValidSuperblock(const CChain& active_chain, const CDeterministicMNList& tip_mn_list, - const CTransaction& txNew, int nBlockHeight, CAmount blockReward, bool is_v24) const +SuperblockStatus SuperblockManager::GetStatus(const CDeterministicMNList& tip_mn_list, int nBlockHeight) { - LOCK(cs_sb); - CSuperblock_sptr pSuperblock; - if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { - return pSuperblock->IsValid(active_chain, txNew, nBlockHeight, blockReward, is_v24); + SuperblockStatus ret; + if (!IsValid()) { + return ret; } - return false; -} + ret.state = SuperblockStatus::State::NotTriggered; -bool SuperblockManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn_list, int nBlockHeight, - std::vector& voutSuperblockRet) const -{ LOCK(cs_sb); - + if (!IsSuperblockTriggeredInternal(tip_mn_list, nBlockHeight)) { + return ret; + } 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; + LogPrint(BCLog::GOBJECT, "%s -- Can't find superblock for height %d\n", __func__, nBlockHeight); + return ret; } - - voutSuperblockRet.clear(); + ret.state = SuperblockStatus::State::Triggered; // TODO: How many payments can we add before things blow up? // Consider at least following limits: @@ -650,19 +526,19 @@ bool SuperblockManager::GetSuperblockPayments(const CDeterministicMNList& tip_mn for (int i = 0; i < pSuperblock->CountPayments(); i++) { CGovernancePayment payment; if (pSuperblock->GetPayment(i, payment)) { - voutSuperblockRet.emplace_back(payment.nAmount, payment.script); + ret.payments.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", + LogPrint(BCLog::GOBJECT, "%s -- NEW Superblock: output %d (addr %s, amount %d.%08d)\n", __func__, i, EncodeDestination(dest), payment.nAmount / COIN, payment.nAmount % COIN); } else { - LogPrint(BCLog::GOBJECT, "GetSuperblockPayments -- Payment not found\n"); + LogPrint(BCLog::GOBJECT, "%s -- Payment not found\n", __func__); } } - return true; + return ret; } void SuperblockManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn_list, int nBlockHeight) @@ -670,7 +546,7 @@ void SuperblockManager::ExecuteBestSuperblock(const CDeterministicMNList& tip_mn LOCK(cs_sb); CSuperblock_sptr pSuperblock; if (GetBestSuperblockInternal(tip_mn_list, pSuperblock, nBlockHeight)) { - // All checks are done in CSuperblock::IsValid via IsBlockValueValid and IsBlockPayeeValid, + // All checks are done in Chainstate::IsBlockValueValid, // tip wouldn't be updated if anything was wrong. Mark this trigger as executed. pSuperblock->SetExecuted(); } diff --git a/src/governance/superblock.h b/src/governance/superblock.h index 9fb43dc7ce5a..779a2cf93422 100644 --- a/src/governance/superblock.h +++ b/src/governance/superblock.h @@ -7,6 +7,7 @@ #include #include +#include #include