diff --git a/doc/release-notes-7278.md b/doc/release-notes-7278.md new file mode 100644 index 000000000000..9adbdcd16591 --- /dev/null +++ b/doc/release-notes-7278.md @@ -0,0 +1,19 @@ +Removed Sporks +-------------- + +* `SPORK_3_INSTANTSEND_BLOCK_FILTERING` and `SPORK_9_SUPERBLOCKS_ENABLED` have + been removed. These sporks were already effectively always enabled on mainnet + but continued to gate behavior on test networks (testnet, regtest, and devnet). + The associated functionality (InstantSend conflicting-block rejection and + superblock payments) is now permanently enabled across all networks, and the + sporks will no longer appear in the `spork` RPC output. + +Updated RPCs +------------ + +* `getblocktemplate` now always reports `superblocks_enabled` as `true`. The + field is retained for backwards compatibility. + +* `getblocktemplate` now requires a fully synced node at superblock heights. + This check is skipped on test networks. Previously it was gated by + `SPORK_9_SUPERBLOCKS_ENABLED` which was already always active on mainnet. diff --git a/src/evo/chainhelper.cpp b/src/evo/chainhelper.cpp index 5c1f19a508d0..63c6fdafd2a7 100644 --- a/src/evo/chainhelper.cpp +++ b/src/evo/chainhelper.cpp @@ -18,13 +18,12 @@ CChainstateHelper::CChainstateHelper(CEvoDB& evodb, CDeterministicMNManager& dmn llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync, - const CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, - const llmq::CQuorumManager& qman) : + 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, sporkman)}, + mn_payments{std::make_unique(dmnman, govman, 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 69a229d93cad..13561012a98b 100644 --- a/src/evo/chainhelper.h +++ b/src/evo/chainhelper.h @@ -19,7 +19,6 @@ class CMasternodeSync; class CMNHFManager; class CMNPaymentsProcessor; class CSpecialTxProcessor; -class CSporkManager; class CTransaction; class uint256; struct CCreditPool; @@ -61,8 +60,7 @@ class CChainstateHelper llmq::CInstantSendManager& isman, llmq::CQuorumBlockProcessor& qblockman, llmq::CQuorumSnapshotManager& qsnapman, const ChainstateManager& chainman, const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync, - const CSporkManager& sporkman, const chainlock::Chainlocks& chainlocks, - const llmq::CQuorumManager& qman); + 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 f72c8d837846..0123bba56b2b 100644 --- a/src/governance/governance.cpp +++ b/src/governance/governance.cpp @@ -11,16 +11,17 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -1490,8 +1491,3 @@ std::vector> CGovernanceManager::GetApp return ret; } - -bool AreSuperblocksEnabled(const CSporkManager& sporkman) -{ - return sporkman.IsSporkActive(SPORK_9_SUPERBLOCKS_ENABLED); -} diff --git a/src/governance/governance.h b/src/governance/governance.h index fa048b40d9d2..cb43b3bbd452 100644 --- a/src/governance/governance.h +++ b/src/governance/governance.h @@ -40,7 +40,6 @@ class CGovernanceObject; class CGovernanceVote; class CMasternodeMetaMan; class CMasternodeSync; -class CSporkManager; class CSuperblock; class UniValue; @@ -444,6 +443,4 @@ class CGovernanceManager : public GovernanceStore, public GovernanceSignerParent EXCLUSIVE_LOCKS_REQUIRED(cs_store); }; -bool AreSuperblocksEnabled(const CSporkManager& sporkman); - #endif // BITCOIN_GOVERNANCE_GOVERNANCE_H diff --git a/src/instantsend/instantsend.cpp b/src/instantsend/instantsend.cpp index 26d0e3f90559..29afd31f9dda 100644 --- a/src/instantsend/instantsend.cpp +++ b/src/instantsend/instantsend.cpp @@ -474,10 +474,6 @@ bool CInstantSendManager::RejectConflictingBlocks() const if (!m_mn_sync.IsBlockchainSynced()) { return false; } - if (!spork_manager.IsSporkActive(SPORK_3_INSTANTSEND_BLOCK_FILTERING)) { - LogPrint(BCLog::INSTANTSEND, "%s: spork3 is off, skipping transaction locking checks\n", __func__); - return false; - } return true; } diff --git a/src/masternode/payments.cpp b/src/masternode/payments.cpp index 72fb0cff9b84..01a379b1d1b8 100644 --- a/src/masternode/payments.cpp +++ b/src/masternode/payments.cpp @@ -241,17 +241,6 @@ bool CMNPaymentsProcessor::IsBlockValueValid(const CBlock& block, const int nBlo // we are synced and possibly on a superblock now - if (!AreSuperblocksEnabled(m_sporkman)) { - // should NOT allow superblocks at all, when superblocks are disabled - // revert to block reward limits in this case - LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Superblocks are disabled, no superblocks allowed\n", __func__); - if(!isBlockRewardValueMet) { - strErrorRet = strprintf("coinbase pays too much at height %d (actual=%d vs limit=%d), exceeded block reward, superblocks are disabled", - nBlockHeight, block.vtx[0]->GetValueOut(), blockReward); - } - return isBlockRewardValueMet; - } - if (!check_superblock) return true; const auto tip_mn_list = m_dmnman.GetListAtChainTip(); @@ -308,26 +297,23 @@ bool CMNPaymentsProcessor::IsBlockPayeeValid(const CTransaction& txNew, const CB } // superblocks started + if (!check_superblock) return true; - if (AreSuperblocksEnabled(m_sporkman)) { - 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)) { - LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Valid superblock at height %d: %s", __func__, nBlockHeight, txNew.ToString()); /* Continued */ - // continue validation, should also pay MN - } else { - LogPrintf("CMNPaymentsProcessor::%s -- ERROR! Invalid superblock detected at height %d: %s", __func__, nBlockHeight, txNew.ToString()); /* Continued */ - // should NOT allow such superblocks, when superblocks are enabled - return false; - } + 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)) { + LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Valid superblock at height %d: %s", /* Continued */ + __func__, nBlockHeight, txNew.ToString()); + // continue validation, should also pay MN } else { - LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- No triggered superblock detected at height %d\n", __func__, nBlockHeight); + LogPrintf("CMNPaymentsProcessor::%s -- ERROR! Invalid superblock detected at height %d: %s", /* Continued */ + __func__, nBlockHeight, txNew.ToString()); + return false; } } else { - // should NOT allow superblocks at all, when superblocks are disabled - LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- Superblocks are disabled, no superblocks allowed\n", __func__); + LogPrint(BCLog::GOBJECT, "CMNPaymentsProcessor::%s -- No triggered superblock detected at height %d\n", + __func__, nBlockHeight); } return true; @@ -338,10 +324,9 @@ void CMNPaymentsProcessor::FillBlockPayments(CMutableTransaction& txNew, const C { int nBlockHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1; - // only create superblocks if spork is enabled AND if superblock is actually triggered - // (height should be validated inside) + // Only create superblocks when one is actually triggered. const auto tip_mn_list = m_dmnman.GetListAtChainTip(); - if (AreSuperblocksEnabled(m_sporkman) && m_govman.IsSuperblockTriggered(tip_mn_list, nBlockHeight)) { + if (m_govman.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); } diff --git a/src/masternode/payments.h b/src/masternode/payments.h index a4df891c8c1a..358d58d00d44 100644 --- a/src/masternode/payments.h +++ b/src/masternode/payments.h @@ -17,7 +17,6 @@ class CGovernanceManager; class ChainstateManager; class CMasternodeSync; class CTransaction; -class CSporkManager; class CTxOut; struct CMutableTransaction; @@ -38,7 +37,6 @@ class CMNPaymentsProcessor const ChainstateManager& m_chainman; const Consensus::Params& m_consensus_params; const CMasternodeSync& m_mn_sync; - const CSporkManager& m_sporkman; private: [[nodiscard]] bool GetBlockTxOuts(const CBlockIndex* pindexPrev, const CAmount blockSubsidy, const CAmount feeReward, @@ -51,9 +49,8 @@ class CMNPaymentsProcessor public: explicit CMNPaymentsProcessor(CDeterministicMNManager& dmnman, CGovernanceManager& govman, const ChainstateManager& chainman, - const Consensus::Params& consensus_params, const CMasternodeSync& mn_sync, const CSporkManager& sporkman) : - m_dmnman{dmnman}, m_govman{govman}, m_chainman{chainman}, m_consensus_params{consensus_params}, m_mn_sync{mn_sync}, - m_sporkman{sporkman} {} + 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} {} 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 98d4dc21d199..289720d0949f 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -236,7 +236,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), - *(llmq_ctx->qsnapman), chainman, consensus_params, mn_sync, sporkman, chainlocks, + *(llmq_ctx->qsnapman), chainman, consensus_params, mn_sync, chainlocks, *(llmq_ctx->qman)); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index ea13095ed37f..385240ee1e93 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -14,10 +14,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -42,10 +44,6 @@ #include #include -#include -#include -#include - #include #include @@ -729,14 +727,12 @@ static RPCHelpMan getblocktemplate() if (active_chainstate.IsInitialBlockDownload()) { throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is in initial sync and waiting for blocks..."); } - } - // next bock is a superblock and we need governance info to correctly construct it - CHECK_NONFATAL(node.sporkman); - if (AreSuperblocksEnabled(*node.sporkman) - && !node.mn_sync->IsSynced() - && CSuperblock::IsValidBlockHeight(active_chain.Height() + 1)) + if (!node.mn_sync->IsSynced() && CSuperblock::IsValidBlockHeight(active_chain.Height() + 1)) { + // Next block is a superblock but we need governance info to correctly construct it. throw JSONRPCError(RPC_CLIENT_IN_INITIAL_DOWNLOAD, PACKAGE_NAME " is syncing with network..."); + } + } static unsigned int nTransactionsUpdatedLast; const CTxMemPool& mempool = EnsureMemPool(node); @@ -962,7 +958,7 @@ static RPCHelpMan getblocktemplate() } result.pushKV("superblock", superblockObjArray); result.pushKV("superblocks_started", pindexPrev->nHeight + 1 > consensusParams.nSuperblockStartBlock); - result.pushKV("superblocks_enabled", AreSuperblocksEnabled(*node.sporkman)); + result.pushKV("superblocks_enabled", true); result.pushKV("coinbase_payload", HexStr(pblock->vtx[0]->vExtraPayload)); diff --git a/src/spork.h b/src/spork.h index b6e24619b9a1..1f9da2b74804 100644 --- a/src/spork.h +++ b/src/spork.h @@ -37,8 +37,6 @@ class CSporkManager; */ enum SporkId : int32_t { SPORK_2_INSTANTSEND_ENABLED = 10001, - SPORK_3_INSTANTSEND_BLOCK_FILTERING = 10002, - SPORK_9_SUPERBLOCKS_ENABLED = 10008, SPORK_17_QUORUM_DKG_ENABLED = 10016, SPORK_19_CHAINLOCKS_ENABLED = 10018, SPORK_21_QUORUM_ALL_CONNECTED = 10020, @@ -69,10 +67,8 @@ struct CSporkDef }; #define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name} -[[maybe_unused]] static constexpr std::array sporkDefs = { +[[maybe_unused]] static constexpr std::array sporkDefs = { MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 4070908800ULL), // OFF - MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 4070908800ULL), // OFF - MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL), // OFF MAKE_SPORK_DEF(SPORK_21_QUORUM_ALL_CONNECTED, 4070908800ULL), // OFF diff --git a/test/functional/feature_dip3_deterministicmns.py b/test/functional/feature_dip3_deterministicmns.py index 0d60ec282f63..74096321588b 100755 --- a/test/functional/feature_dip3_deterministicmns.py +++ b/test/functional/feature_dip3_deterministicmns.py @@ -173,6 +173,7 @@ def run_test(self): multisig = self.nodes[0].createmultisig(1, [addr1Obj['pubkey'], addr2Obj['pubkey']])['address'] self.update_mn_payee(mns[0], multisig) + self.wait_until(lambda: self.nodes[0].mnsync("status")['IsSynced']) found_multisig_payee = False for _ in range(len(mns)): bt = self.nodes[0].getblocktemplate() diff --git a/test/functional/feature_governance.py b/test/functional/feature_governance.py index 925ac0b1ccc6..f76ede05088b 100755 --- a/test/functional/feature_governance.py +++ b/test/functional/feature_governance.py @@ -89,7 +89,6 @@ def run_test(self): self.expected_v20_budget = satoshi_round("18.57142860") self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 4070908800) - self.nodes[0].sporkupdate("SPORK_9_SUPERBLOCKS_ENABLED", 0) self.wait_for_sporks_same() assert_equal(len(self.nodes[0].gobject("list-prepared")), 0) diff --git a/test/functional/feature_governance_cl.py b/test/functional/feature_governance_cl.py index 9b6ec2bca904..169266178f20 100755 --- a/test/functional/feature_governance_cl.py +++ b/test/functional/feature_governance_cl.py @@ -55,9 +55,6 @@ def run_test(self): self.sync_blocks() self.wait_for_chainlocked_block_all_nodes(self.nodes[0].getbestblockhash()) - self.nodes[0].sporkupdate("SPORK_9_SUPERBLOCKS_ENABLED", 0) - self.wait_for_sporks_same() - # Move to the superblock cycle start block n = sb_cycle - self.nodes[0].getblockcount() % sb_cycle if n > 0: diff --git a/test/functional/feature_mnehf.py b/test/functional/feature_mnehf.py index 952ee95ca40e..40b9631f07de 100755 --- a/test/functional/feature_mnehf.py +++ b/test/functional/feature_mnehf.py @@ -88,7 +88,6 @@ def set_sporks(self): self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", spork_enabled) self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", spork_disabled) - self.nodes[0].sporkupdate("SPORK_3_INSTANTSEND_BLOCK_FILTERING", spork_disabled) self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", spork_disabled) self.wait_for_sporks_same() diff --git a/test/functional/feature_multikeysporks.py b/test/functional/feature_multikeysporks.py index 999622b1e6d4..e65b99303408 100755 --- a/test/functional/feature_multikeysporks.py +++ b/test/functional/feature_multikeysporks.py @@ -124,10 +124,10 @@ def test_spork(self, spork_name, final_value): def run_test(self): self.test_spork('SPORK_2_INSTANTSEND_ENABLED', 2) - self.test_spork('SPORK_3_INSTANTSEND_BLOCK_FILTERING', 3) + self.test_spork('SPORK_19_CHAINLOCKS_ENABLED', 3) for node in self.nodes: assert self.get_test_spork_value(node, 'SPORK_2_INSTANTSEND_ENABLED') == 2 - assert self.get_test_spork_value(node, 'SPORK_3_INSTANTSEND_BLOCK_FILTERING') == 3 + assert self.get_test_spork_value(node, 'SPORK_19_CHAINLOCKS_ENABLED') == 3 if __name__ == '__main__': diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index de0e4ca70501..f63d486717e4 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -1844,9 +1844,8 @@ def setup_network(self): for i in range(1, num_simple_nodes): force_finish_mnsync(self.nodes[i]) - # Enable InstantSend (including block filtering) and ChainLocks by default + # Enable InstantSend and ChainLocks by default self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", 0) - self.nodes[0].sporkupdate("SPORK_3_INSTANTSEND_BLOCK_FILTERING", 0) self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", 0) self.wait_for_sporks_same() self.bump_mocktime(1)