From ca83b2681500f0f2b0003be2057850b821cad2f0 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Fri, 16 Aug 2024 15:16:36 +0700 Subject: [PATCH 1/6] fix: crash in CreditPool: it meant to check that DIP0003 is activated --- src/evo/specialtxman.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/evo/specialtxman.cpp b/src/evo/specialtxman.cpp index 9f3c61070e39e..2e1b29ce8ece0 100644 --- a/src/evo/specialtxman.cpp +++ b/src/evo/specialtxman.cpp @@ -278,6 +278,7 @@ bool CSpecialTxProcessor::CheckCreditPoolDiffForBlock(const CBlock& block, const AssertLockHeld(cs_main); try { + if (!DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_DIP0003)) return true; if (!DeploymentActiveAt(*pindex, m_consensus_params, Consensus::DEPLOYMENT_V20)) return true; auto creditPoolDiff = GetCreditPoolDiffForBlock(m_cpoolman, m_chainman.m_blockman, m_qman, block, pindex->pprev, m_consensus_params, blockSubsidy, state); From 7735631aadd3edd13b625099bee3ee37f601ab51 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 15 Aug 2024 15:38:39 +0700 Subject: [PATCH 2/6] fix: remove v20 from test feature_llmq_evo as far as mn_rr used --- test/functional/feature_llmq_evo.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/functional/feature_llmq_evo.py b/test/functional/feature_llmq_evo.py index 26da9eab9fdbc..e3a95cea676af 100755 --- a/test/functional/feature_llmq_evo.py +++ b/test/functional/feature_llmq_evo.py @@ -115,7 +115,6 @@ def run_test(self): self.test_evo_payments(window_analysis=48) self.test_masternode_winners() - self.activate_v20() self.activate_mn_rr() self.log.info("Activated MN RewardReallocation at height:" + str(self.nodes[0].getblockcount())) @@ -125,24 +124,24 @@ def run_test(self): self.sync_blocks() self.log.info("Test that EvoNodes are paid 1 block in a row after MN RewardReallocation activation") - self.test_evo_payments(window_analysis=48, v20active=True) + self.test_evo_payments(window_analysis=48, mnrr_active=True) self.test_masternode_winners(mn_rr_active=True) self.log.info(self.nodes[0].masternodelist()) return - def test_evo_payments(self, window_analysis, v20active=False): + def test_evo_payments(self, window_analysis, mnrr_active=False): current_evo = None consecutive_payments = 0 - n_payments = 0 if v20active else 4 + n_payments = 0 if mnrr_active else 4 for i in range(0, window_analysis): payee = self.get_mn_payee_for_block(self.nodes[0].getbestblockhash()) if payee is not None and payee.evo: if current_evo is not None and payee.proTxHash == current_evo.proTxHash: # same EvoNode assert consecutive_payments > 0 - if not v20active: + if not mnrr_active: consecutive_payments += 1 consecutive_payments_rpc = self.nodes[0].protx('info', current_evo.proTxHash)['state']['consecutivePayments'] assert_equal(consecutive_payments, consecutive_payments_rpc) @@ -157,7 +156,7 @@ def test_evo_payments(self, window_analysis, v20active=False): consecutive_payments_rpc = self.nodes[0].protx('info', payee.proTxHash)['state']['consecutivePayments'] # if EvoNode is the one we start "for" loop with, # we have no idea how many times it was paid before - rely on rpc results here - new_payment_value = 0 if v20active else 1 + new_payment_value = 0 if mnrr_active else 1 consecutive_payments = consecutive_payments_rpc if i == 0 and current_evo is None else new_payment_value current_evo = payee assert_equal(consecutive_payments, consecutive_payments_rpc) From 762a808b8c1257a6e1e67c1f21305a22ac7d467f Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 15 Aug 2024 14:54:33 +0700 Subject: [PATCH 3/6] chore: drop irrelevant bip9 code from feature_llmq_rotation.py --- test/functional/feature_llmq_rotation.py | 57 ++---------------------- 1 file changed, 4 insertions(+), 53 deletions(-) diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index cd8c9b64ff4e7..8bfcbbd6a60b5 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -18,7 +18,6 @@ from test_framework.util import ( assert_equal, assert_greater_than_or_equal, - assert_greater_than, get_bip9_details, ) @@ -114,17 +113,14 @@ def run_test(self): expectedNew = [h_100_0, h_106_0, h_104_0, h_100_1, h_106_1, h_104_1] quorumList = self.test_getmnlistdiff_quorums(b_h_0, b_h_1, {}, expectedDeleted, expectedNew, testQuorumsCLSigs=False) - self.log.info(f"Wait for v20 locked_in phase") - # Expected locked_in phase starts at 1200 - 400 (window size in regtest) - projected_activation_height = self.advance_to_locked_in_for_v20(expected_locked_in_height=800) + projected_activation_height = 1200 self.activate_v20(expected_activation_height=1200) self.log.info("Activated v20 at height:" + str(self.nodes[0].getblockcount())) - softfork_info = get_bip9_details(self.nodes[0], 'v20') - assert_equal(softfork_info['status'], 'active') - assert 'since' in softfork_info - assert_equal(projected_activation_height, softfork_info['since']) + softfork_info = self.nodes[0].getblockchaininfo()['softforks']['v20'] + assert_equal(softfork_info['active'], True) + assert_equal(projected_activation_height, softfork_info['height']) # v20 is active for the next block, not for the tip self.nodes[0].generate(1) @@ -393,51 +389,6 @@ def test_quorum_listextended(self, quorum_info, llmq_type_name): return True return False - def advance_to_locked_in_for_v20(self, expected_locked_in_height): - # disable spork17 while mining blocks to activate "name" to prevent accidental quorum formation - spork17_value = self.nodes[0].spork('show')['SPORK_17_QUORUM_DKG_ENABLED'] - self.bump_mocktime(1) - self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", 4070908800) - self.wait_for_sporks_same() - - # mine blocks in batches - batch_size = 10 - height = self.nodes[0].getblockcount() - assert_greater_than(expected_locked_in_height, height) - # NOTE: getblockchaininfo shows softforks locked_in at block (window * 2 - 1) - # since it's returning whether a softwork is locked_in for the _next_ block. - # Hence the last block prior to the locked_in state is (expected_locked_in_height - 2). - while expected_locked_in_height - height - 2 >= batch_size: - self.bump_mocktime(batch_size) - self.nodes[0].generate(batch_size) - height += batch_size - self.sync_blocks() - blocks_left = expected_locked_in_height - height - 2 - assert_greater_than(batch_size, blocks_left) - self.bump_mocktime(blocks_left) - self.nodes[0].generate(blocks_left) - self.sync_blocks() - - softfork_info = get_bip9_details(self.nodes[0], 'v20') - assert_equal(softfork_info['status'], 'started') - assert 'activation_height' not in softfork_info - - self.bump_mocktime(1) - self.nodes[0].generate(1) - self.sync_blocks() - - softfork_info = get_bip9_details(self.nodes[0], 'v20') - assert_equal(softfork_info['status'], 'locked_in') - assert_equal(softfork_info['since'], expected_locked_in_height) - assert 'activation_height' in softfork_info - projected_activation_height = softfork_info['activation_height'] - - # revert spork17 changes - self.bump_mocktime(1) - self.nodes[0].sporkupdate("SPORK_17_QUORUM_DKG_ENABLED", spork17_value) - self.wait_for_sporks_same() - - return projected_activation_height if __name__ == '__main__': LLMQQuorumRotationTest().main() From 64cedb30bd126e48ef80ef9e92c90ce4c274d712 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Wed, 21 Aug 2024 00:14:44 +0700 Subject: [PATCH 4/6] feat: actually test something EHF unit tests --- src/evo/mnhftx.cpp | 8 +++--- src/test/evo_mnhf_tests.cpp | 43 +++++++++++++++++--------------- test/functional/feature_mnehf.py | 2 -- 3 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 02f1839f087fb..c5c4cc9dd96ac 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -116,6 +116,10 @@ bool CheckMNHFTx(const ChainstateManager& chainman, const llmq::CQuorumManager& return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version"); } + if (!Params().IsValidMNActivation(mnhfTx.signal.versionBit, pindexPrev->GetMedianTimePast())) { + return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-non-ehf"); + } + const CBlockIndex* pindexQuorum = WITH_LOCK(::cs_main, return chainman.m_blockman.LookupBlockIndex(mnhfTx.signal.quorumHash)); if (!pindexQuorum) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-quorum-hash"); @@ -139,10 +143,6 @@ bool CheckMNHFTx(const ChainstateManager& chainman, const llmq::CQuorumManager& return false; } - if (!Params().IsValidMNActivation(mnhfTx.signal.versionBit, pindexPrev->GetMedianTimePast())) { - return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-non-ehf"); - } - return true; } diff --git a/src/test/evo_mnhf_tests.cpp b/src/test/evo_mnhf_tests.cpp index 2be08a4804709..7c1d29973356e 100644 --- a/src/test/evo_mnhf_tests.cpp +++ b/src/test/evo_mnhf_tests.cpp @@ -6,10 +6,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -18,24 +20,12 @@ #include -bool VerifyMNHFTx(const CTransaction& tx, TxValidationState& state) -{ - if (const auto opt_mnhfTx_payload = GetTxPayload(tx); !opt_mnhfTx_payload) { - return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-payload"); - } else if (opt_mnhfTx_payload->nVersion == 0 || - opt_mnhfTx_payload->nVersion > MNHFTxPayload::CURRENT_VERSION) { - return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-version"); - } - - return true; -} - -static CMutableTransaction CreateMNHFTx(const uint256& mnhfTxHash, const CBLSSignature& cblSig, const uint16_t& versionBit) +static CMutableTransaction CreateMNHFTx(const uint256& quorumHash, const CBLSSignature& cblSig, const uint16_t& versionBit) { MNHFTxPayload extraPayload; extraPayload.nVersion = 1; extraPayload.signal.versionBit = versionBit; - extraPayload.signal.quorumHash = mnhfTxHash; + extraPayload.signal.quorumHash = quorumHash; extraPayload.signal.sig = cblSig; CMutableTransaction tx; @@ -46,19 +36,18 @@ static CMutableTransaction CreateMNHFTx(const uint256& mnhfTxHash, const CBLSSig return tx; } -BOOST_FIXTURE_TEST_SUITE(evo_mnhf_tests, BasicTestingSetup) +BOOST_FIXTURE_TEST_SUITE(evo_mnhf_tests, TestChain100Setup) BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests) { int count = 10; - uint16_t ver = 2; + uint16_t bit = 1; std::vector vec_sigs; std::vector vec_pks; std::vector vec_sks; CBLSSecretKey sk; - uint256 hash = GetRandHash(); for (int i = 0; i < count; i++) { sk.MakeNewKey(); vec_pks.push_back(sk.GetPublicKey()); @@ -71,13 +60,27 @@ BOOST_AUTO_TEST_CASE(verify_mnhf_specialtx_tests) BOOST_CHECK(ag_sk.IsValid()); BOOST_CHECK(ag_pk.IsValid()); - uint256 verHash = uint256S(ToString(ver)); + uint256 verHash = uint256S(ToString(bit)); auto sig = ag_sk.Sign(verHash); BOOST_CHECK(sig.VerifyInsecure(ag_pk, verHash)); - const CMutableTransaction tx = CreateMNHFTx(hash, sig, ver); + auto& chainman = Assert(m_node.chainman); + auto& qman = *Assert(m_node.llmq_ctx)->qman; + const CBlockIndex* pindex = chainman->ActiveChain().Tip(); + uint256 hash = GetRandHash(); TxValidationState state; - BOOST_CHECK(VerifyMNHFTx(CTransaction(tx), state)); + + { // wrong quorum (we don't have any indeed) + const CTransaction tx{CTransaction(CreateMNHFTx(hash, sig, bit))}; + CheckMNHFTx(*chainman, qman, CTransaction(tx), pindex, state); + BOOST_CHECK_EQUAL(state.ToString(), "bad-mnhf-quorum-hash"); + } + + { // non EHF fork + const CTransaction tx{CTransaction(CreateMNHFTx(hash, sig, 28))}; + CheckMNHFTx(*chainman, qman, CTransaction(tx), pindex, state); + BOOST_CHECK_EQUAL(state.ToString(), "bad-mnhf-non-ehf"); + } } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/functional/feature_mnehf.py b/test/functional/feature_mnehf.py index a7406e7197e5c..96c71a67e543b 100755 --- a/test/functional/feature_mnehf.py +++ b/test/functional/feature_mnehf.py @@ -145,7 +145,6 @@ def run_test(self): pubkey = key.get_pubkey().get_bytes() ehf_tx = self.create_mnehf(28, pubkey) ehf_unknown_tx = self.create_mnehf(27, pubkey) - ehf_invalid_tx = self.create_mnehf(9, pubkey) # deployment that is known as non-EHF self.log.info("Checking deserialization of CMnEhf by python's code") mnehf_payload = CMnEhf() @@ -166,7 +165,6 @@ def run_test(self): self.log.info(f"ehf tx: {ehf_tx_sent}") ehf_unknown_tx_sent = self.send_tx(ehf_unknown_tx) self.log.info(f"unknown ehf tx: {ehf_unknown_tx_sent}") - self.send_tx(ehf_invalid_tx, expected_error='bad-mnhf-non-ehf') self.sync_all() ehf_blockhash = self.nodes[1].generate(1)[0] self.sync_blocks() From 1087489fd48a5676f7c269d1e6b3106e73e2b339 Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Tue, 13 Aug 2024 17:10:24 +0700 Subject: [PATCH 5/6] feat: bury v20 deployment --- src/chainparams.cpp | 44 ++++++--------------------- src/chainparamsbase.cpp | 2 +- src/consensus/params.h | 8 +++-- src/deploymentinfo.cpp | 6 ++-- src/evo/mnhftx.cpp | 8 ++--- src/evo/mnhftx.h | 2 -- src/governance/classes.cpp | 16 +--------- src/rpc/blockchain.cpp | 2 +- src/test/util/setup_common.cpp | 10 +++--- test/functional/feature_cltv.py | 2 +- test/functional/feature_dersig.py | 3 +- test/functional/feature_governance.py | 33 ++++++++------------ test/functional/feature_mnehf.py | 8 ++--- test/functional/rpc_blockchain.py | 11 +------ 14 files changed, 46 insertions(+), 109 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 2798deed85a83..fdd96c01e07d7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -192,7 +192,8 @@ class CMainParams : public CChainParams { consensus.DIP0024Height = 1737792; // 0000000000000001342be9c0b75ad40c276beaad91616423c4d9cb101b3db438 consensus.DIP0024QuorumsHeight = 1738698; // 000000000000001aa25181e4c466e593992c98f9eb21c69ee757b8bb0af50244 consensus.V19Height = 1899072; // 0000000000000015e32e73052d663626327004c81c5c22cb8b42c361015c0eae - consensus.MinBIP9WarningHeight = 1899072 + 2016; // V19 activation height + miner confirmation window + consensus.V20Height = 1987776; // 000000000000001bf41cff06b76780050682ca29e61a91c391893d4745579777 + consensus.MinBIP9WarningHeight = 1987776 + 2016; // V20 activation height + miner confirmation window consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes @@ -207,14 +208,6 @@ class CMainParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 1700006400; // November 15, 2023 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = 1731628800; // November 15, 2024 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 4032; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 3226; // 80% of 4032 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 2420; // 60% of 4032 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10; consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 1704067200; // January 1, 2024 consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = 1767225600; // January 1, 2026 @@ -394,7 +387,8 @@ class CTestNetParams : public CChainParams { consensus.DIP0024Height = 769700; // 0000008d84e4efd890ae95c70a7a6126a70a80e5c19e4cb264a5b3469aeef172 consensus.DIP0024QuorumsHeight = 770730; // 0000003c43b3ae7fffe61278ca5537a0e256ebf4d709d45f0ab040271074d51e consensus.V19Height = 850100; // 000004728b8ff2a16b9d4eebb0fd61eeffadc9c7fe4b0ec0b5a739869401ab5b - consensus.MinBIP9WarningHeight = 850100 + 2016; // v19 activation height + miner confirmation window + consensus.V20Height = 905100; // 0000020c5e0f86f385cbf8e90210de9a9fd63633f01433bf47a6b3227a2851fd + consensus.MinBIP9WarningHeight = 905100 + 2016; // v19 activation height + miner confirmation window consensus.powLimit = uint256S("00000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 20 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes @@ -409,14 +403,6 @@ class CTestNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 1693526400; // Friday, September 1, 2023 0:00:00 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 100; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 80; // 80% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 60; // 60% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10; consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 1693526400; // Friday, September 1, 2023 0:00:00 consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; @@ -570,7 +556,8 @@ class CDevNetParams : public CChainParams { consensus.DIP0024Height = 300; consensus.DIP0024QuorumsHeight = 300; consensus.V19Height = 300; - consensus.MinBIP9WarningHeight = 300 + 2016; // v19 activation height + miner confirmation window + consensus.V20Height = 300; + consensus.MinBIP9WarningHeight = 300 + 2016; // v20 activation height + miner confirmation window consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day consensus.nPowTargetSpacing = 2.5 * 60; // Dash: 2.5 minutes @@ -585,14 +572,6 @@ class CDevNetParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 1661990400; // Sep 1st, 2022 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 120; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 80; // 80% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 60; // 60% of 100 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10; consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 1661990400; // Sep 1st, 2022 consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; @@ -810,6 +789,7 @@ class CRegTestParams : public CChainParams { consensus.DIP0024Height = 900; consensus.DIP0024QuorumsHeight = 900; consensus.V19Height = 900; + consensus.V20Height = 1200; consensus.MinBIP9WarningHeight = 0; consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~uint256(0) >> 1 consensus.nPowTargetTimespan = 24 * 60 * 60; // Dash: 1 day @@ -826,14 +806,6 @@ class CRegTestParams : public CChainParams { consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay - consensus.vDeployments[Consensus::DEPLOYMENT_V20].bit = 9; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nStartTime = 0; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize = 400; - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdStart = 384; // 80% of 480 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nThresholdMin = 288; // 60% of 480 - consensus.vDeployments[Consensus::DEPLOYMENT_V20].nFalloffCoeff = 5; // this corresponds to 10 periods - consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].bit = 10; consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nStartTime = 0; consensus.vDeployments[Consensus::DEPLOYMENT_MN_RR].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT; @@ -1062,6 +1034,8 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse consensus.DIP0008Height = int{height}; } else if (name == "dip0020") { consensus.DIP0020Height = int{height}; + } else if (name == "v20") { + consensus.V20Height = int{height}; } else { throw std::runtime_error(strprintf("Invalid name (%s) for -testactivationheight=name@height.", arg)); } diff --git a/src/chainparamsbase.cpp b/src/chainparamsbase.cpp index c9700e3626a7f..4e2f7f8a4ed41 100644 --- a/src/chainparamsbase.cpp +++ b/src/chainparamsbase.cpp @@ -22,7 +22,7 @@ void SetupChainParamsBaseOptions(ArgsManager& argsman) argsman.AddArg("-dip3params=:", "Override DIP3 activation and enforcement heights (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-dip8params=", "Override DIP8 activation height (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-bip147height=", "Override BIP147 activation height (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CHAINPARAMS); - argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0020). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-testactivationheight=name@height.", "Set the activation height of 'name' (bip147, bip34, dersig, cltv, csv, brr, dip0001, dip0008, dip0020, v20). (regtest-only)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-highsubsidyblocks=", "The number of blocks with a higher than normal subsidy to mine at the start of a chain. Block after that height will have fixed subsidy base. (default: 0, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-highsubsidyfactor=", "The factor to multiply the normal block subsidy by while in the highsubsidyblocks window of a chain (default: 1, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); argsman.AddArg("-llmqchainlocks=", "Override the default LLMQ type used for ChainLocks. Allows using ChainLocks with smaller LLMQs. (default: llmq_devnet, devnet-only)", ArgsManager::ALLOW_ANY, OptionsCategory::CHAINPARAMS); diff --git a/src/consensus/params.h b/src/consensus/params.h index e5e5d6ff9574f..2fbd5f44420b2 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -32,12 +32,12 @@ enum BuriedDeployment : int16_t { DEPLOYMENT_DIP0024, DEPLOYMENT_BRR, DEPLOYMENT_V19, + DEPLOYMENT_V20, }; -constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_V19; } +constexpr bool ValidDeployment(BuriedDeployment dep) { return dep <= DEPLOYMENT_V20; } enum DeploymentPos : uint16_t { DEPLOYMENT_TESTDUMMY, - DEPLOYMENT_V20, // Deployment of EHF, LLMQ Randomness Beacon DEPLOYMENT_MN_RR, // Deployment of Masternode Reward Location Reallocation // NOTE: Also add new deployments to VersionBitsDeploymentInfo in deploymentinfo.cpp MAX_VERSION_BITS_DEPLOYMENTS @@ -142,6 +142,8 @@ struct Params { int DIP0024QuorumsHeight; /** Block height at which V19 (Basic BLS and EvoNodes) becomes active */ int V19Height; + /** Block height at which V20 (Deployment of EHF, LLMQ Randomness Beacon) becomes active */ + int V20Height; /** Don't warn about unknown BIP 9 activations below this height. * This prevents us from warning about the CSV and DIP activations. */ int MinBIP9WarningHeight; @@ -205,6 +207,8 @@ struct Params { return BRRHeight; case DEPLOYMENT_V19: return V19Height; + case DEPLOYMENT_V20: + return V20Height; } // no default case, so the compiler can warn about missing cases return std::numeric_limits::max(); } diff --git a/src/deploymentinfo.cpp b/src/deploymentinfo.cpp index 17da5d3d36fa5..5a0f86ef913ca 100644 --- a/src/deploymentinfo.cpp +++ b/src/deploymentinfo.cpp @@ -11,10 +11,6 @@ const struct VBDeploymentInfo VersionBitsDeploymentInfo[Consensus::MAX_VERSION_B /*.name =*/ "testdummy", /*.gbt_force =*/ true, }, - { - /*.name =*/"v20", - /*.gbt_force =*/true, - }, { /*.name =*/"mn_rr", /*.gbt_force =*/true, @@ -49,6 +45,8 @@ std::string DeploymentName(Consensus::BuriedDeployment dep) return "realloc"; case Consensus::DEPLOYMENT_V19: return "v19"; + case Consensus::DEPLOYMENT_V20: + return "v20"; } // no default case, so the compiler can warn about missing cases return ""; } diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index c5c4cc9dd96ac..aef76cd96c52e 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -319,7 +319,7 @@ std::optional CMNHFManager::GetFromCache(const CBlockInde } { LOCK(cs_cache); - if (ThresholdState::ACTIVE != v20_activation.State(pindex->pprev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) { + if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) { mnhfCache.insert(blockHash, signals); return signals; } @@ -340,10 +340,8 @@ void CMNHFManager::AddToCache(const Signals& signals, const CBlockIndex* const p LOCK(cs_cache); mnhfCache.insert(blockHash, signals); } - { - LOCK(cs_cache); - if (ThresholdState::ACTIVE != v20_activation.State(pindex->pprev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; - } + if (!DeploymentActiveAt(*pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return; + m_evoDb.Write(std::make_pair(DB_SIGNALS, blockHash), signals); } diff --git a/src/evo/mnhftx.h b/src/evo/mnhftx.h index a6386203dc1e0..732b8049762b5 100644 --- a/src/evo/mnhftx.h +++ b/src/evo/mnhftx.h @@ -109,8 +109,6 @@ class CMNHFManager : public AbstractEHFManager // versionBit <-> height unordered_lru_cache mnhfCache GUARDED_BY(cs_cache) {MNHFCacheSize}; - // This cache is used only for v20 activation to avoid double lock through VersionBitsConditionChecker::SignalHeight - VersionBitsCache v20_activation GUARDED_BY(cs_cache); public: explicit CMNHFManager(CEvoDB& evoDb); ~CMNHFManager(); diff --git a/src/governance/classes.cpp b/src/governance/classes.cpp index 163abde1b6b5d..7d410a790f5de 100644 --- a/src/governance/classes.cpp +++ b/src/governance/classes.cpp @@ -490,21 +490,7 @@ CAmount CSuperblock::GetPaymentsLimit(const CChain& active_chain, int nBlockHeig return 0; } - const CBlockIndex* pindex = active_chain.Tip(); - if (pindex->nHeight > nBlockHeight) pindex = pindex->GetAncestor(nBlockHeight); - - const auto v20_state = g_versionbitscache.State(pindex, consensusParams, Consensus::DEPLOYMENT_V20); - bool fV20Active{v20_state == ThresholdState::ACTIVE}; - if (!fV20Active && nBlockHeight > pindex->nHeight) { - // If fV20Active isn't active yet and nBlockHeight refers to a future SuperBlock - // then we need to check if the fork is locked_in and see if it will be active by the time of the future SuperBlock - if (v20_state == ThresholdState::LOCKED_IN) { - int activation_height = g_versionbitscache.StateSinceHeight(pindex, consensusParams, Consensus::DEPLOYMENT_V20) + static_cast(Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize); - if (nBlockHeight >= activation_height) { - fV20Active = true; - } - } - } + const bool fV20Active{nBlockHeight >= consensusParams.V20Height}; // min subsidy for high diff networks and vice versa int nBits = consensusParams.fPowAllowMinDifficultyBlocks ? UintToArith256(consensusParams.powLimit).GetCompact() : 1; diff --git a/src/rpc/blockchain.cpp b/src/rpc/blockchain.cpp index cd0fd147eec6e..020bb3ae4aef6 100644 --- a/src/rpc/blockchain.cpp +++ b/src/rpc/blockchain.cpp @@ -1806,7 +1806,7 @@ RPCHelpMan getblockchaininfo() SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_DIP0024); SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_BRR); SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_V19); - SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, Consensus::DEPLOYMENT_V20); + SoftForkDescPushBack(tip, softforks, consensusParams, Consensus::DEPLOYMENT_V20); SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, Consensus::DEPLOYMENT_MN_RR); SoftForkDescPushBack(tip, ehfSignals, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 3e8fa5521c82a..fb92ab64e4706 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -337,15 +337,15 @@ TestChainSetup::TestChainSetup(int num_blocks, const std::vector& e /* TestChain100Setup */ { 100, uint256S("0x6ffb83129c19ebdf1ae3771be6a67fe34b35f4c956326b9ba152fac1649f65ae") }, /* TestChainDIP3BeforeActivationSetup */ - { 430, uint256S("0x592b23a8882162ea48606e40c9ee00b2166ddae092c691d7f1b1758ec13647d9") }, + { 430, uint256S("0x0bcefaa33fec56cd84d05d0e76cd6a78badcc20f627d91903646de6a07930a14") }, /* TestChainDIP3Setup */ - { 431, uint256S("0x49db248651517f3fc3725fbbc7087db90552d487d11e0962b0148fc4788aeb77") }, + { 431, uint256S("0x5fd3aa5ef29464839499d7f847edd9362e3e73392b79d3bd88b1591f5fb17d4e") }, /* TestChainBRRBeforeActivationSetup */ - { 497, uint256S("0x626036f6adff51fbbdd0c609e827ef6a3730ce2498a3eb33edeb27092d006170") }, + { 497, uint256S("0x23c31820ec5160b7181bfdf328e2b76cd12c9fa4544d892b7f01e74dd6220849") }, /* TestChainV19BeforeActivationSetup */ - { 894, uint256S("0x03cbf1871d7d915cda10aded00ced45f71a4e2acf6a3c7a77a1ff488267dd1cd") }, + { 894, uint256S("0x2885cf0fe8fdf29803b6c65002ba2570ff011531d8ea92be312a85d655e00c51") }, /* TestChainV19Setup */ - { 899, uint256S("0x405a630e16d0ca0efe3abb0e24c9a157a69ec2e07b04333cc5d004efa634ac89") }, + { 899, uint256S("0x7df3c857ce647b3ecd0d4b389b6b0f16e2bdc60b20a8d01c4ad946fe5f15dbc2") }, } }; diff --git a/test/functional/feature_cltv.py b/test/functional/feature_cltv.py index 00b0800e975e0..fda6037bc96e6 100755 --- a/test/functional/feature_cltv.py +++ b/test/functional/feature_cltv.py @@ -88,9 +88,9 @@ def set_test_params(self): f'-testactivationheight=cltv@{CLTV_HEIGHT}', '-whitelist=noban@127.0.0.1', '-dip3params=9000:9000', + '-testactivationheight=v20@9000', # disabled for this test '-par=1', # Use only one script thread to get the exact reject reason for testing '-acceptnonstdtxn=1', # cltv_invalidate is nonstandard - '-vbparams=v20:0:999999999999:0:480:384:288:5:0' # Delay v20 for this test as we don't need it ]] self.setup_clean_chain = True self.rpc_timeout = 480 diff --git a/test/functional/feature_dersig.py b/test/functional/feature_dersig.py index 834e07e6fe01c..351edefdea404 100755 --- a/test/functional/feature_dersig.py +++ b/test/functional/feature_dersig.py @@ -50,10 +50,11 @@ def set_test_params(self): self.num_nodes = 1 self.extra_args = [[ f'-testactivationheight=dersig@{DERSIG_HEIGHT}', + '-testactivationheight=v20@9000', # due to changes in CbTx '-whitelist=noban@127.0.0.1', '-dip3params=9000:9000', '-par=1', # Use only one script thread to get the exact log msg for testing - '-vbparams=v20:0:999999999999:0:480:384:288:5:0']] + ]] self.setup_clean_chain = True self.rpc_timeout = 240 diff --git a/test/functional/feature_governance.py b/test/functional/feature_governance.py index e98cf6ba1b0d1..e36c078e249de 100755 --- a/test/functional/feature_governance.py +++ b/test/functional/feature_governance.py @@ -9,27 +9,22 @@ from test_framework.messages import uint256_to_string from test_framework.test_framework import DashTestFramework from test_framework.governance import have_trigger_for_height, prepare_object -from test_framework.util import assert_equal, satoshi_round, set_node_times, wait_until_helper +from test_framework.util import assert_equal, satoshi_round, wait_until_helper class DashGovernanceTest (DashTestFramework): def set_test_params(self): - self.v20_start_time = 1417713500 + 80 - # using adjusted v20 deployment params to test an edge case where superblock maturity window is equal to deployment window size - self.set_dash_test_params(6, 5, [["-budgetparams=10:10:10", f"-vbparams=v20:{self.v20_start_time}:999999999999:0:10:8:6:5:0"]] * 6, fast_dip3_enforcement=True) + self.set_dash_test_params(6, 5, [[ + "-budgetparams=10:10:10", + '-testactivationheight=v20@240', + ]] * 6, fast_dip3_enforcement=True) def check_superblockbudget(self, v20_active): v20_state = self.nodes[0].getblockchaininfo()["softforks"]["v20"] assert_equal(v20_state["active"], v20_active) assert_equal(self.nodes[0].getsuperblockbudget(200), self.expected_old_budget) assert_equal(self.nodes[0].getsuperblockbudget(220), self.expected_old_budget) - if v20_state["bip9"]["status"] == "locked_in" or v20_state["bip9"]["status"] == "active": - assert_equal(self.nodes[0].getsuperblockbudget(240), self.expected_v20_budget) - assert_equal(self.nodes[0].getsuperblockbudget(260), self.expected_v20_budget) - assert_equal(self.nodes[0].getsuperblockbudget(280), self.expected_v20_budget) - else: - assert_equal(self.nodes[0].getsuperblockbudget(240), self.expected_old_budget) - assert_equal(self.nodes[0].getsuperblockbudget(260), self.expected_old_budget) - assert_equal(self.nodes[0].getsuperblockbudget(280), self.expected_old_budget) + assert_equal(self.nodes[0].getsuperblockbudget(240), self.expected_v20_budget) + assert_equal(self.nodes[0].getsuperblockbudget(260), self.expected_v20_budget) def check_superblock(self): # Make sure Superblock has only payments that fit into the budget @@ -98,18 +93,14 @@ def run_test(self): self.bump_mocktime(3) self.sync_blocks() assert_equal(self.nodes[0].getblockcount(), 210) - assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["bip9"]["status"], "defined") + assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], False) self.check_superblockbudget(False) - assert self.mocktime < self.v20_start_time - self.mocktime = self.v20_start_time - set_node_times(self.nodes, self.mocktime) - self.nodes[0].generate(10) self.bump_mocktime(10) self.sync_blocks() assert_equal(self.nodes[0].getblockcount(), 220) - assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["bip9"]["status"], "started") + assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], False) self.check_superblockbudget(False) proposal_time = self.mocktime @@ -213,7 +204,7 @@ def run_test(self): self.nodes[0].generate(1) self.bump_mocktime(1) assert_equal(self.nodes[0].getblockcount(), 230) - assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["bip9"]["status"], "locked_in") + assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], False) self.check_superblockbudget(False) # The "winner" should submit new trigger and vote for it, but it's isolated so no triggers should be found @@ -322,7 +313,7 @@ def sync_gov(node): self.bump_mocktime(1) self.sync_blocks() assert_equal(self.nodes[0].getblockcount(), 260) - assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["bip9"]["status"], "active") + assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], True) # Mine and check a couple more superblocks for i in range(2): @@ -338,7 +329,7 @@ def sync_gov(node): self.bump_mocktime(1) self.sync_blocks() assert_equal(self.nodes[0].getblockcount(), sb_block_height) - assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["bip9"]["status"], "active") + assert_equal(self.nodes[0].getblockchaininfo()["softforks"]["v20"]["active"], True) self.check_superblockbudget(True) self.check_superblock() diff --git a/test/functional/feature_mnehf.py b/test/functional/feature_mnehf.py index 96c71a67e543b..c509f121ce0e8 100755 --- a/test/functional/feature_mnehf.py +++ b/test/functional/feature_mnehf.py @@ -131,8 +131,8 @@ def run_test(self): node = self.nodes[0] self.set_sporks() - self.activate_v19() - self.log.info(f"After v19 activation should be plenty of blocks: {node.getblockcount()}") + self.activate_v20() + self.log.info(f"After v20 activation should be plenty of blocks: {node.getblockcount()}") assert_greater_than(node.getblockcount(), 900) assert_equal(get_bip9_details(node, 'testdummy')['status'], 'defined') @@ -154,10 +154,6 @@ def run_test(self): self.log.info("Checking correctness of requestId and quorumHash") assert_equal(mnehf_payload.quorumHash, int(self.mninfo[0].node.quorum("selectquorum", 100, 'a0eee872d7d3170dd20d5c5e8380c92b3aa887da5f63d8033289fafa35a90691')["quorumHash"], 16)) - self.send_tx(ehf_tx, expected_error='mnhf-before-v20') - - assert_equal(get_bip9_details(node, 'testdummy')['status'], 'defined') - self.activate_v20() assert_equal(get_bip9_details(node, 'testdummy')['status'], 'defined') assert_equal(get_bip9_details(node, 'mn_rr')['status'], 'defined') diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py index b2db3e7b89eb5..fedeb1f3d838b 100755 --- a/test/functional/rpc_blockchain.py +++ b/test/functional/rpc_blockchain.py @@ -154,16 +154,7 @@ def _test_getblockchaininfo(self): 'dip0024': { 'type': 'buried', 'active': False, 'height': 900}, 'realloc': { 'type': 'buried', 'active': True, 'height': 1}, 'v19': { 'type': 'buried', 'active': False, 'height': 900}, - 'v20': { - 'type': 'bip9', - 'bip9': { - 'status': 'defined', - 'start_time': 0, - 'timeout': 9223372036854775807, - 'since': 0, - 'min_activation_height': 0, - 'ehf': False, - }, 'active': False}, + 'v20': { 'type': 'buried', 'active': False, 'height': 1200}, 'mn_rr': { 'type': 'bip9', 'bip9': { From 23812555b181746503d8bde2f1ec0b0fe3a9926f Mon Sep 17 00:00:00 2001 From: Konstantin Akimov Date: Thu, 22 Aug 2024 01:39:06 +0700 Subject: [PATCH 6/6] fix: possible deadlock during calculation of signals for historical blocks during re-index Relevant crash dump: Assertion failed: detected inconsistent lock order for 'cs_main' in node/blockstorage.cpp:778 (in thread 'main'), details in debug log. Posix Signal: Aborted 0#: (0x62349D233974) stl_vector.h:115 - std::_Vector_base >::_Vector_impl_data::_M_copy_data(std::_Vector_base >::_Vector_impl_data const&) 1#: (0x62349D233974) stl_vector.h:127 - std::_Vector_base >::_Vector_impl_data::_M_swap_data(std::_Vector_base >::_Vector_impl_data&) 2#: (0x62349D233974) stl_vector.h:1959 - std::vector >::_M_move_assign(std::vector >&&, std::integral_constant) 3#: (0x62349D233974) stl_vector.h:768 - std::vector >::operator=(std::vector >&&) 4#: (0x62349D233974) stacktraces.cpp:777 - HandlePosixSignal 5#: (0x71E435442990) libc_sigaction.c - ??? 6#: (0x71E435499A1B) pthread_kill.c:44 - __pthread_kill_implementation 7#: (0x71E435499A1B) pthread_kill.c:78 - __pthread_kill_internal 8#: (0x71E435499A1B) pthread_kill.c:89 - __GI___pthread_kill 9#: (0x71E4354428E6) raise.c:27 - __GI_raise 10#: (0x71E4354268B7) abort.c:81 - __GI_abort 11#: (0x62349D239956) basic_string.h:390 - std::__cxx11::basic_string, std::allocator >::_M_check_length(unsigned long, unsigned long, char const*) const 12#: (0x62349D239956) basic_string.h:1461 - std::__cxx11::basic_string, std::allocator >::append(char const*) 13#: (0x62349D239956) basic_string.h:1365 - std::__cxx11::basic_string, std::allocator >::operator+=(char const*) 14#: (0x62349D239956) sync.cpp:114 - potential_deadlock_detected 15#: (0x62349D2403DE) sync.cpp:188 - push_lock 16#: (0x62349D2403DE) sync.cpp:212 - void EnterCritical(char const*, char const*, int, std::recursive_mutex*, bool) 17#: (0x62349CAA8B72) unique_lock.h:150 - std::unique_lock::try_lock() 18#: (0x62349CAA8B72) sync.h:162 - UniqueLock, std::unique_lock >::Enter(char const*, char const*, int) 19#: (0x62349CAA8B72) sync.h:183 - UniqueLock, std::unique_lock >::UniqueLock(AnnotatedMixin&, char const*, char const*, int, bool) 20#: (0x62349CE349CD) chain.h:225 - CBlockIndex::GetBlockPos() const 21#: (0x62349CE349CD) blockstorage.cpp:778 - operator() 22#: (0x62349CE349CD) blockstorage.cpp:778 - ReadBlockFromDisk(CBlock&, CBlockIndex const*, Consensus::Params const&) 23#: (0x62349D102F82) mnhftx.cpp:284 - CMNHFManager::GetForBlock(CBlockIndex const*) 24#: (0x62349D103E9B) mnhftx.cpp:58 - CMNHFManager::GetSignalsStage(CBlockIndex const*) 25#: (0x62349D07F0E9) versionbits.cpp:222 - SignalHeight 26#: (0x62349D07F90D) versionbits.cpp:37 - AbstractThresholdConditionChecker::GetStateFor(CBlockIndex const*, Consensus::Params const&, std::map, std::allocator > >&) const 27#: (0x62349D080D93) sync.h:199 - UniqueLock, std::unique_lock >::~UniqueLock() 28#: (0x62349D080D93) versionbits.cpp:260 - VersionBitsCache::State(CBlockIndex const*, Consensus::Params const&, Consensus::DeploymentPos) 29#: (0x62349CC06C73) deterministicmns.cpp:227 - CDeterministicMNList::GetProjectedMNPayees(gsl::not_null, int) const Aborted (core dumped) --- src/evo/mnhftx.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index aef76cd96c52e..788d25f4fd0e6 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -54,6 +54,8 @@ CMNHFManager::~CMNHFManager() CMNHFManager::Signals CMNHFManager::GetSignalsStage(const CBlockIndex* const pindexPrev) { + if (!DeploymentActiveAfter(pindexPrev, Params().GetConsensus(), Consensus::DEPLOYMENT_V20)) return {}; + Signals signals = GetForBlock(pindexPrev); if (pindexPrev == nullptr) return {}; const int height = pindexPrev->nHeight + 1;