From 829d345c7d2cd3f96c11d416520fd5248f42d8e9 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Thu, 29 Aug 2024 13:00:10 +0200 Subject: [PATCH 1/9] Change of emission rules --- src/chainparams.cpp | 5 +++ src/consensus/params.h | 11 ++++++ src/validation.cpp | 76 +++++++++++++++++++++++------------------- 3 files changed, 57 insertions(+), 35 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index fd8a90dbbd..ac14ccfc67 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -528,6 +528,11 @@ class CTestNetParams : public CChainParams { consensus.stage3DevelopmentFundAddress = "TWDxLLKsFp6qcV1LL4U2uNmW4HwMcapmMU"; consensus.stage3CommunityFundAddress = "TCkC4uoErEyCB4MK3d6ouyJELoXnuyqe9L"; + consensus.stage4CommunityFundShare = 10; + consensus.stage4DevelopmentFundShare = 15; + consensus.stage4MasternodeShare = 70; + consensus.tailEmissionBlockSubsidy = 4 * COIN; // real value would be 1 FIRO (because of two halvings due to different block times) + consensus.nStartBlacklist = 0; consensus.nStartDuplicationCheck = 0; consensus.nMajorityEnforceBlockUpgrade = 51; diff --git a/src/consensus/params.h b/src/consensus/params.h index 1db0a6ac3c..4f05375cd5 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -163,6 +163,17 @@ struct Params { /** percentage of block subsidy going to masternode */ int stage3MasternodeShare; + /** parameters for coinbase payment distribution after stage three (aka stage 4) */ + /** percentage of block subsidy going to developer fund */ + int stage4DevelopmentFundShare; + /** percentage of block subsidy going to community fund */ + int stage4CommunityFundShare; + /** percentage of block subsidy going to masternode */ + int stage4MasternodeShare; + + /** tail emission (after stage 4) */ + int tailEmissionBlockSubsidy; + int nStartDuplicationCheck; int nStartBlacklist; diff --git a/src/validation.cpp b/src/validation.cpp index abcb55e0ff..2b82972c0b 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1931,13 +1931,15 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens else halvings = (nHeight - consensusParams.nSubsidyHalvingSecond) / consensusParams.nSubsidyHalvingInterval + 2; - // Force block reward to zero when right shift is undefined. - if (halvings >= 64) - return 0; - CAmount nSubsidy = 50 * COIN; - nSubsidy >>= halvings; - + if (halvings > 2) + nSubsidy = consensusParams.tailEmissionBlockSubsidy; // 1 coin tail emission + else if (halvings == 2) + // stage 4 + nSubsidy = 25*COIN; + else + nSubsidy >>= halvings; + if (nHeight > 0 && fMTP) nSubsidy /= consensusParams.nMTPRewardReduction; @@ -1956,7 +1958,9 @@ CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams, i CAmount GetMasternodePayment(int nHeight, int nTime, CAmount blockValue) { const Consensus::Params ¶ms = Params().GetConsensus(); - if (nTime >= params.stage3StartTime) + if (nHeight >= params.stage4MasternodeShare) + return blockValue*params.stage4MasternodeShare/100; + else if (nTime >= params.stage3StartTime) return blockValue*params.stage3MasternodeShare/100; else if (nHeight >= params.nSubsidyHalvingFirst) return blockValue*params.stage2ZnodeShare/100; @@ -4835,35 +4839,37 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co } if (nHeight >= consensusParams.nSubsidyHalvingFirst) { - if (nHeight < consensusParams.nSubsidyHalvingSecond) { - if (block.nTime >= consensusParams.stage3StartTime) { - CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3DevelopmentFundAddress).Get()); - CAmount devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * consensusParams.stage3DevelopmentFundShare) / 100; - CScript communityPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get()); - CAmount communityPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * consensusParams.stage3CommunityFundShare) / 100; - - bool devFound = false, communityFound = false; - for (const CTxOut &txout: block.vtx[0]->vout) { - if (txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) - devFound = true; - else if (txout.scriptPubKey == communityPayoutScript && txout.nValue == communityPayoutValue) - communityFound = true; - } - if (!devFound || !communityFound) - return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 3 developer/community reward check failed"); - } - else { - // "stage 2" interval between first and second halvings - CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage2DevelopmentFundAddress).Get()); - CAmount devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * consensusParams.stage2DevelopmentFundShare) / 100; - bool found = false; - for (const CTxOut &txout: block.vtx[0]->vout) { - if ((found = txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) == true) - break; - } - if (!found) - return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 2 developer reward check failed"); + if (block.nTime >= consensusParams.stage3StartTime) { + bool fStage4 = nHeight >= consensusParams.nSubsidyHalvingSecond; + int devPayoutShare = fStage4 ? consensusParams.stage4DevelopmentFundShare : consensusParams.stage3DevelopmentFundShare; + int communityPayoutShare = fStage4 ? consensusParams.stage4CommunityFundShare : consensusParams.stage3CommunityFundShare; + + CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3DevelopmentFundAddress).Get()); + CAmount devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * devPayoutShare) / 100; + CScript communityPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get()); + CAmount communityPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * communityPayoutShare) / 100; + + bool devFound = false, communityFound = false; + for (const CTxOut &txout: block.vtx[0]->vout) { + if (txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) + devFound = true; + else if (txout.scriptPubKey == communityPayoutScript && txout.nValue == communityPayoutValue) + communityFound = true; + } + if (!devFound || !communityFound) + return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 3 developer/community reward check failed"); + } + else { + // "stage 2" interval between first and second halvings + CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage2DevelopmentFundAddress).Get()); + CAmount devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * consensusParams.stage2DevelopmentFundShare) / 100; + bool found = false; + for (const CTxOut &txout: block.vtx[0]->vout) { + if ((found = txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) == true) + break; } + if (!found) + return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 2 developer reward check failed"); } } else if (!CheckZerocoinFoundersInputs(*block.vtx[0], state, consensusParams, nHeight, block.IsMTP())) { From 7527d32c00813184796ef3a629a1ec7953e0e8f5 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 1 Sep 2024 17:06:42 +0200 Subject: [PATCH 2/9] Fixes for testnet --- src/chainparams.cpp | 23 +++++++++++++++++++++-- src/consensus/params.h | 2 ++ src/miner.cpp | 30 +++++++++++++++++++++--------- src/validation.cpp | 28 +++++++++++++--------------- 4 files changed, 57 insertions(+), 26 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index ac14ccfc67..5412bc8b17 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -206,6 +206,12 @@ class CMainParams : public CChainParams { consensus.stage3DevelopmentFundAddress = "aLgRaYSFk6iVw2FqY1oei8Tdn2aTsGPVmP"; consensus.stage3CommunityFundAddress = "aFA2TbqG9cnhhzX5Yny2pBJRK5EaEqLCH7"; + consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond; + consensus.stage4CommunityFundShare = 10; + consensus.stage4DevelopmentFundShare = 15; + consensus.stage4MasternodeShare = 70; + consensus.tailEmissionBlockSubsidy = 4 * COIN; // real value would be 1 FIRO (because of two halvings due to different block times) + consensus.nStartBlacklist = 293990; consensus.nStartDuplicationCheck = 293526; @@ -528,6 +534,7 @@ class CTestNetParams : public CChainParams { consensus.stage3DevelopmentFundAddress = "TWDxLLKsFp6qcV1LL4U2uNmW4HwMcapmMU"; consensus.stage3CommunityFundAddress = "TCkC4uoErEyCB4MK3d6ouyJELoXnuyqe9L"; + consensus.stage4StartBlock = 168500; consensus.stage4CommunityFundShare = 10; consensus.stage4DevelopmentFundShare = 15; consensus.stage4MasternodeShare = 70; @@ -794,7 +801,7 @@ class CDevNetParams : public CChainParams { consensus.chainType = Consensus::chainDevnet; consensus.nSubsidyHalvingFirst = 1; - consensus.nSubsidyHalvingSecond = 100000; + consensus.nSubsidyHalvingSecond = 3500; consensus.nSubsidyHalvingInterval = 100000; consensus.nSubsidyHalvingStopBlock = 1000000; @@ -810,6 +817,12 @@ class CDevNetParams : public CChainParams { consensus.stage3DevelopmentFundAddress = "TfvbHyGTo8hexoKBBS8fz9Gq7g9VZQQpcg"; consensus.stage3CommunityFundAddress = "TgoL9nh8vDTz7UB5WkBbknBksBdUaD9qbT"; + consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond; + consensus.stage4CommunityFundShare = 10; + consensus.stage4DevelopmentFundShare = 15; + consensus.stage4MasternodeShare = 70; + consensus.tailEmissionBlockSubsidy = 4 * COIN; // real value would be 1 FIRO (because of two halvings due to different block times) + consensus.nStartBlacklist = 0; consensus.nStartDuplicationCheck = 0; consensus.nMajorityEnforceBlockUpgrade = 51; @@ -1044,13 +1057,19 @@ class CRegTestParams : public CChainParams { consensus.stage2ZnodeShare = 35; consensus.stage3StartTime = INT_MAX; - consensus.stage3StartBlock = 0; + consensus.stage3StartBlock = 2000; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; consensus.stage3DevelopmentFundAddress = "TGEGf26GwyUBE2P2o2beBAfE9Y438dCp5t"; // private key cMrz8Df36VR9TvZjtvSqLPhUQR7pcpkXRXaLNYUxfkKsRuCzHpAN consensus.stage3CommunityFundAddress = "TJmPzeJF4DECrBwUftc265U7rTPxKmpa4F"; // private key cTyPWqTMM1CgT5qy3K3LSgC1H6Q2RHvnXZHvjWtKB4vq9qXqKmMu + consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond; + consensus.stage4CommunityFundShare = 15; + consensus.stage4DevelopmentFundShare = 25; + consensus.stage4MasternodeShare = 50; + consensus.tailEmissionBlockSubsidy = 4 * COIN; // real value would be 1 FIRO (because of two halvings due to different block times) + consensus.nMajorityEnforceBlockUpgrade = 750; consensus.nMajorityRejectBlockOutdated = 950; consensus.nMajorityWindow = 1000; diff --git a/src/consensus/params.h b/src/consensus/params.h index 4f05375cd5..59cb05c490 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -164,6 +164,8 @@ struct Params { int stage3MasternodeShare; /** parameters for coinbase payment distribution after stage three (aka stage 4) */ + /** start time of stage 4 (usually the same as nSubsidyHalvingSecond)*/ + int stage4StartBlock; /** percentage of block subsidy going to developer fund */ int stage4DevelopmentFundShare; /** percentage of block subsidy going to community fund */ diff --git a/src/miner.cpp b/src/miner.cpp index 492cb3477b..f41d9b52a4 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -192,7 +192,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc pblock->nTime = GetAdjustedTime(); bool fMTP = (pblock->nTime >= params.nMTPSwitchTime); - bool fShorterBlockDistance = (pblock->nTime >= params.stage3StartTime); + bool fShorterBlockDistance = nHeight >= params.stage3StartBlock; const int64_t nMedianTimePast = pindexPrev->GetMedianTimePast(); pblock->nVersion = ComputeBlockVersion(pindexPrev, chainparams.GetConsensus()) | (fMTP ? 0x1000 : 0); @@ -835,19 +835,31 @@ void BlockAssembler::FillFoundersReward(CMutableTransaction &coinbaseTx, bool fM if (fShorterBlockDistance) coin /= 2; - if (nHeight >= params.nSubsidyHalvingFirst && nHeight < params.nSubsidyHalvingSecond) { + if ((nHeight >= params.nSubsidyHalvingFirst && nHeight < params.nSubsidyHalvingSecond) || nHeight >= params.stage4StartBlock) { if (fShorterBlockDistance) { - // Stage 3 + bool fStage3 = nHeight < params.nSubsidyHalvingSecond; + bool fStage4 = nHeight >= params.stage4StartBlock; + CAmount devPayoutValue = 0, communityPayoutValue = 0; CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(params.stage3DevelopmentFundAddress).Get()); - CAmount devPayoutValue = (GetBlockSubsidyWithMTPFlag(nHeight, params, fMTP, true) * params.stage3DevelopmentFundShare) / 100; CScript communityPayoutScript = GetScriptForDestination(CBitcoinAddress(params.stage3CommunityFundAddress).Get()); - CAmount communityPayoutValue = (GetBlockSubsidyWithMTPFlag(nHeight, params, fMTP, true) * params.stage3CommunityFundShare) / 100; - coinbaseTx.vout[0].nValue -= devPayoutValue; - coinbaseTx.vout.push_back(CTxOut(devPayoutValue, devPayoutScript)); + // There is no dev/community payout for testnet for some time + if (fStage3 || fStage4) { + int devShare = fStage3 ? params.stage3DevelopmentFundShare : params.stage4DevelopmentFundShare; + int communityShare = fStage3 ? params.stage3CommunityFundShare : params.stage4CommunityFundShare; + devPayoutValue = (GetBlockSubsidyWithMTPFlag(nHeight, params, fMTP, true) * devShare) / 100; + communityPayoutValue = (GetBlockSubsidyWithMTPFlag(nHeight, params, fMTP, true) * communityShare) / 100; + } - coinbaseTx.vout[0].nValue -= communityPayoutValue; - coinbaseTx.vout.push_back(CTxOut(communityPayoutValue, communityPayoutScript)); + if (devPayoutValue != 0) { + coinbaseTx.vout[0].nValue -= devPayoutValue; + coinbaseTx.vout.push_back(CTxOut(devPayoutValue, devPayoutScript)); + } + + if (communityPayoutValue != 0) { + coinbaseTx.vout[0].nValue -= communityPayoutValue; + coinbaseTx.vout.push_back(CTxOut(communityPayoutValue, communityPayoutScript)); + } } else { // Stage 2 diff --git a/src/validation.cpp b/src/validation.cpp index 2b82972c0b..f7dc045d72 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1923,22 +1923,18 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens if (nHeight >= consensusParams.nSubsidyHalvingStopBlock) return 0; - int halvings; + CAmount nSubsidy; + if (nHeight < consensusParams.nSubsidyHalvingFirst) - halvings = 0; + nSubsidy = 50 * COIN; else if (nHeight < consensusParams.nSubsidyHalvingSecond) - halvings = 1; + nSubsidy = 25 * COIN; + else if (nHeight < consensusParams.stage4StartBlock) + nSubsidy = 25 * COIN / 2; + else if (nHeight < consensusParams.stage4StartBlock + consensusParams.nSubsidyHalvingInterval) + nSubsidy = 25 * COIN; else - halvings = (nHeight - consensusParams.nSubsidyHalvingSecond) / consensusParams.nSubsidyHalvingInterval + 2; - - CAmount nSubsidy = 50 * COIN; - if (halvings > 2) nSubsidy = consensusParams.tailEmissionBlockSubsidy; // 1 coin tail emission - else if (halvings == 2) - // stage 4 - nSubsidy = 25*COIN; - else - nSubsidy >>= halvings; if (nHeight > 0 && fMTP) nSubsidy /= consensusParams.nMTPRewardReduction; @@ -1952,7 +1948,7 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams, int nTime) { return GetBlockSubsidyWithMTPFlag(nHeight, consensusParams, nTime >= (int)consensusParams.nMTPSwitchTime, - nTime >= (int)consensusParams.stage3StartTime); + nHeight >= (int)consensusParams.stage3StartBlock); } CAmount GetMasternodePayment(int nHeight, int nTime, CAmount blockValue) @@ -1960,7 +1956,9 @@ CAmount GetMasternodePayment(int nHeight, int nTime, CAmount blockValue) const Consensus::Params ¶ms = Params().GetConsensus(); if (nHeight >= params.stage4MasternodeShare) return blockValue*params.stage4MasternodeShare/100; - else if (nTime >= params.stage3StartTime) + else if (nHeight >= params.nSubsidyHalvingSecond) + return blockValue/2; + else if (nHeight >= params.stage3StartBlock) return blockValue*params.stage3MasternodeShare/100; else if (nHeight >= params.nSubsidyHalvingFirst) return blockValue*params.stage2ZnodeShare/100; @@ -4839,7 +4837,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co } if (nHeight >= consensusParams.nSubsidyHalvingFirst) { - if (block.nTime >= consensusParams.stage3StartTime) { + if (nHeight >= consensusParams.stage3StartBlock) { bool fStage4 = nHeight >= consensusParams.nSubsidyHalvingSecond; int devPayoutShare = fStage4 ? consensusParams.stage4DevelopmentFundShare : consensusParams.stage3DevelopmentFundShare; int communityPayoutShare = fStage4 ? consensusParams.stage4CommunityFundShare : consensusParams.stage3CommunityFundShare; From cf1edca5f37e06fa4120063da7ea111baa2ebd93 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 1 Sep 2024 18:06:53 +0200 Subject: [PATCH 3/9] Cleaning up code and tests --- src/chainparams.cpp | 4 --- src/consensus/params.h | 2 -- src/test/firsthalving_tests.cpp | 2 -- src/test/main_tests.cpp | 53 ++++----------------------------- src/validation.cpp | 5 ---- 5 files changed, 6 insertions(+), 60 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 5412bc8b17..031c9a746c 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -192,7 +192,6 @@ class CMainParams : public CChainParams { consensus.nSubsidyHalvingFirst = 302438; consensus.nSubsidyHalvingSecond = AdjustEndingBlockNumberAfterSubsidyHalving(302438, 420000, 486221); // =958655 consensus.nSubsidyHalvingInterval = 420000*2; - consensus.nSubsidyHalvingStopBlock = AdjustEndingBlockNumberAfterSubsidyHalving(0, 3646849, 486221); // =6807477 consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; @@ -520,7 +519,6 @@ class CTestNetParams : public CChainParams { consensus.nSubsidyHalvingFirst = 12000; consensus.nSubsidyHalvingSecond = 150000; consensus.nSubsidyHalvingInterval = 150000; - consensus.nSubsidyHalvingStopBlock = 1000000; consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; @@ -803,7 +801,6 @@ class CDevNetParams : public CChainParams { consensus.nSubsidyHalvingFirst = 1; consensus.nSubsidyHalvingSecond = 3500; consensus.nSubsidyHalvingInterval = 100000; - consensus.nSubsidyHalvingStopBlock = 1000000; consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; @@ -1049,7 +1046,6 @@ class CRegTestParams : public CChainParams { consensus.nSubsidyHalvingFirst = 1500; consensus.nSubsidyHalvingSecond = 2500; consensus.nSubsidyHalvingInterval = 1000; - consensus.nSubsidyHalvingStopBlock = 10000; consensus.nStartBlacklist = 0; consensus.nStartDuplicationCheck = 0; diff --git a/src/consensus/params.h b/src/consensus/params.h index 59cb05c490..a2c7e48d8c 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -136,8 +136,6 @@ struct Params { int nSubsidyHalvingSecond; /** Subsequent subsidy halving intervals */ int nSubsidyHalvingInterval; - /** Stop subsidy at this block number */ - int nSubsidyHalvingStopBlock; /** parameters for coinbase payment distribution between first halving and stage 3 (aka stage 2) */ /** P2PKH or P2SH address for developer funds */ diff --git a/src/test/firsthalving_tests.cpp b/src/test/firsthalving_tests.cpp index e3d8b4e56c..e7059a0319 100644 --- a/src/test/firsthalving_tests.cpp +++ b/src/test/firsthalving_tests.cpp @@ -156,7 +156,6 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) consensusParams.stage3StartTime = INT_MAX; consensusParams.nSubsidyHalvingSecond = 620; consensusParams.nSubsidyHalvingInterval = 10; - consensusParams.nSubsidyHalvingStopBlock = 1000; CScript devPayoutScript = GenerateRandomAddress(); CTxDestination devPayoutDest{CScriptID(devPayoutScript)}; @@ -305,7 +304,6 @@ BOOST_FIXTURE_TEST_CASE(devpayoutverification, TestChainDIP3BeforeActivationSetu consensusParams.nSubsidyHalvingFirst = 600; consensusParams.nSubsidyHalvingSecond = 610; consensusParams.nSubsidyHalvingInterval = 10; - consensusParams.nSubsidyHalvingStopBlock = 1000; // skip to block 600 for (int i=498; i<600; i++) diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index f4352ed396..6a3d6230a5 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -21,19 +21,13 @@ static void TestBlockSubsidyHalvings(const Consensus::Params& consensusParams) BOOST_CHECK_EQUAL(GetBlockSubsidy(1, consensusParams, consensusParams.nMTPSwitchTime-1000), nInitialSubsidy); nInitialSubsidy /= consensusParams.nMTPRewardReduction; BOOST_CHECK_EQUAL(GetBlockSubsidy(2, consensusParams, consensusParams.nMTPSwitchTime), nInitialSubsidy); + CAmount baseSubsidy = nInitialSubsidy; - CAmount nPreviousSubsidy = nInitialSubsidy; - for (int nHalvings = 1; nHalvings < maxHalvings; nHalvings++) { - int nHeight = consensusParams.nSubsidyHalvingFirst + (nHalvings-1) * consensusParams.nSubsidyHalvingInterval; - if (nHeight >= consensusParams.nSubsidyHalvingStopBlock) - break; - CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, consensusParams.nMTPSwitchTime); - BOOST_CHECK(nSubsidy <= nInitialSubsidy); - if(nHeight > 0) - BOOST_CHECK_EQUAL(nSubsidy, nPreviousSubsidy / 2); - nPreviousSubsidy = nPreviousSubsidy / 2; - } - BOOST_CHECK_EQUAL(GetBlockSubsidy(consensusParams.nSubsidyHalvingStopBlock, consensusParams), 0); + BOOST_CHECK_EQUAL(GetBlockSubsidy(consensusParams.nSubsidyHalvingFirst, consensusParams, consensusParams.nMTPSwitchTime), baseSubsidy/2); + BOOST_CHECK_EQUAL(GetBlockSubsidy(consensusParams.stage3StartBlock, consensusParams, consensusParams.stage3StartTime), baseSubsidy/4); + BOOST_CHECK_EQUAL(GetBlockSubsidy(consensusParams.nSubsidyHalvingSecond, consensusParams, consensusParams.stage3StartTime), baseSubsidy/4); + BOOST_CHECK_EQUAL(GetBlockSubsidy(consensusParams.nSubsidyHalvingSecond + consensusParams.nSubsidyHalvingInterval, + consensusParams, consensusParams.stage3StartTime), consensusParams.tailEmissionBlockSubsidy/consensusParams.nMTPRewardReduction/2); } BOOST_AUTO_TEST_CASE(block_subsidy_test) @@ -42,41 +36,6 @@ BOOST_AUTO_TEST_CASE(block_subsidy_test) //TestBlockSubsidyHalvings(1000); // Just another interval } -BOOST_AUTO_TEST_CASE(subsidy_limit_test) -{ - Consensus::Params consensusParams = Params(CBaseChainParams::MAIN).GetConsensus(); - CAmount nSum = 0; - int lastHalving = (consensusParams.nSubsidyHalvingStopBlock - consensusParams.nSubsidyHalvingSecond)/consensusParams.nSubsidyHalvingInterval; - int lastHalvingBlock = consensusParams.nSubsidyHalvingSecond + lastHalving*consensusParams.nSubsidyHalvingInterval; - - int step = 1; - - for(int nHeight = 0; nHeight < 14000000; nHeight += step) - { - if (nHeight == consensusParams.nSubsidyHalvingSecond) - step = 1000; - else if (nHeight == lastHalvingBlock) - step = 1; - else if (nHeight == consensusParams.nSubsidyHalvingStopBlock) - step = 10000; - - int nTime; - if (nHeight < consensusParams.nMTPStartBlock) - nTime = consensusParams.nMTPSwitchTime-1000; - else if (nHeight < consensusParams.stage3StartBlock) - nTime = consensusParams.stage3StartTime-1000; - else - nTime = consensusParams.stage3StartTime; - CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, nTime); - if (nHeight == 0) - nSubsidy = 50*COIN; - BOOST_CHECK(nSubsidy <= 50 * COIN); - nSum += nSubsidy * step; - BOOST_CHECK(MoneyRange(nSum)); - } - BOOST_CHECK_EQUAL(nSum, 2095751200767464ULL); -} - bool ReturnFalse() { return false; } bool ReturnTrue() { return true; } diff --git a/src/validation.cpp b/src/validation.cpp index f7dc045d72..49c5bd79a3 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1918,11 +1918,6 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens if (nHeight == 0) return 0; - // Subsidy is cut in half after nSubsidyHalvingFirst block, then after nSubsidyHalvingSecond, then every nSubsidyHalvingInterval blocks. - // After block nSubsidyHalvingStopBlock there will be no subsidy at all - if (nHeight >= consensusParams.nSubsidyHalvingStopBlock) - return 0; - CAmount nSubsidy; if (nHeight < consensusParams.nSubsidyHalvingFirst) From 5f4ea11386e2cd5f119f705a0a866ca526af4da2 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 1 Sep 2024 18:59:28 +0200 Subject: [PATCH 4/9] Workaround for current devnet bugs --- src/chainparams.cpp | 2 +- src/validation.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 031c9a746c..1fe414fa1f 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -807,7 +807,7 @@ class CDevNetParams : public CChainParams { consensus.stage2DevelopmentFundAddress = "Tq99tes2sRbQ1yNUJPJ7BforYnKcitgwWq"; consensus.stage3StartTime = 1653382800; - consensus.stage3StartBlock = 1514; + consensus.stage3StartBlock = 1514; // this is incorrect value but we have to leave it for now consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; diff --git a/src/validation.cpp b/src/validation.cpp index 49c5bd79a3..292ef44bd3 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1943,17 +1943,17 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams, int nTime) { return GetBlockSubsidyWithMTPFlag(nHeight, consensusParams, nTime >= (int)consensusParams.nMTPSwitchTime, - nHeight >= (int)consensusParams.stage3StartBlock); + nTime >= (int)consensusParams.stage3StartTime); } CAmount GetMasternodePayment(int nHeight, int nTime, CAmount blockValue) { const Consensus::Params ¶ms = Params().GetConsensus(); - if (nHeight >= params.stage4MasternodeShare) + if (nHeight >= params.stage4StartBlock) return blockValue*params.stage4MasternodeShare/100; else if (nHeight >= params.nSubsidyHalvingSecond) return blockValue/2; - else if (nHeight >= params.stage3StartBlock) + else if (nTime >= params.stage3StartTime) return blockValue*params.stage3MasternodeShare/100; else if (nHeight >= params.nSubsidyHalvingFirst) return blockValue*params.stage2ZnodeShare/100; @@ -4832,7 +4832,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co } if (nHeight >= consensusParams.nSubsidyHalvingFirst) { - if (nHeight >= consensusParams.stage3StartBlock) { + if (block.nTime >= consensusParams.stage3StartTime) { bool fStage4 = nHeight >= consensusParams.nSubsidyHalvingSecond; int devPayoutShare = fStage4 ? consensusParams.stage4DevelopmentFundShare : consensusParams.stage3DevelopmentFundShare; int communityPayoutShare = fStage4 ? consensusParams.stage4CommunityFundShare : consensusParams.stage3CommunityFundShare; From 327c3e84ebdc515cf838cd40d7f6793494f4137d Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 1 Sep 2024 19:52:47 +0200 Subject: [PATCH 5/9] Workaround for testnet --- src/validation.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index 292ef44bd3..5cba58e368 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -4833,24 +4833,29 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co if (nHeight >= consensusParams.nSubsidyHalvingFirst) { if (block.nTime >= consensusParams.stage3StartTime) { - bool fStage4 = nHeight >= consensusParams.nSubsidyHalvingSecond; - int devPayoutShare = fStage4 ? consensusParams.stage4DevelopmentFundShare : consensusParams.stage3DevelopmentFundShare; - int communityPayoutShare = fStage4 ? consensusParams.stage4CommunityFundShare : consensusParams.stage3CommunityFundShare; - + bool fStage3 = nHeight < consensusParams.nSubsidyHalvingSecond; + bool fStage4 = nHeight >= consensusParams.stage4StartBlock; + CAmount devPayoutValue = 0, communityPayoutValue = 0; CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3DevelopmentFundAddress).Get()); - CAmount devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * devPayoutShare) / 100; CScript communityPayoutScript = GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get()); - CAmount communityPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * communityPayoutShare) / 100; - bool devFound = false, communityFound = false; - for (const CTxOut &txout: block.vtx[0]->vout) { - if (txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) - devFound = true; - else if (txout.scriptPubKey == communityPayoutScript && txout.nValue == communityPayoutValue) - communityFound = true; + // There is no dev/community payout for testnet for some time + if (fStage3 || fStage4) { + int devShare = fStage3 ? consensusParams.stage3DevelopmentFundShare : consensusParams.stage4DevelopmentFundShare; + int communityShare = fStage3 ? consensusParams.stage3CommunityFundShare : consensusParams.stage4CommunityFundShare; + devPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * devShare) / 100; + communityPayoutValue = (GetBlockSubsidy(nHeight, consensusParams, block.nTime) * communityShare) / 100; + + bool devFound = false, communityFound = false; + for (const CTxOut &txout: block.vtx[0]->vout) { + if (txout.scriptPubKey == devPayoutScript && txout.nValue == devPayoutValue) + devFound = true; + else if (txout.scriptPubKey == communityPayoutScript && txout.nValue == communityPayoutValue) + communityFound = true; + } + if (!devFound || !communityFound) + return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 3 developer/community reward check failed"); } - if (!devFound || !communityFound) - return state.Invalid(false, state.GetRejectCode(), state.GetRejectReason(), "Stage 3 developer/community reward check failed"); } else { // "stage 2" interval between first and second halvings From dfede8fe136983b3209093fe5c4940e013b2338e Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 1 Sep 2024 20:07:12 +0200 Subject: [PATCH 6/9] Devnet parameter tweak --- src/chainparams.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 1fe414fa1f..8a5d9fc168 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -799,8 +799,8 @@ class CDevNetParams : public CChainParams { consensus.chainType = Consensus::chainDevnet; consensus.nSubsidyHalvingFirst = 1; - consensus.nSubsidyHalvingSecond = 3500; - consensus.nSubsidyHalvingInterval = 100000; + consensus.nSubsidyHalvingSecond = 3000; + consensus.nSubsidyHalvingInterval = 10000; consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; From 29666c7719e239d2bc4bc4e9bba96b84eb2abb84 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Mon, 2 Sep 2024 12:10:47 +0200 Subject: [PATCH 7/9] Changed HF block for testnet --- src/chainparams.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 8a5d9fc168..67558159cf 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -532,7 +532,7 @@ class CTestNetParams : public CChainParams { consensus.stage3DevelopmentFundAddress = "TWDxLLKsFp6qcV1LL4U2uNmW4HwMcapmMU"; consensus.stage3CommunityFundAddress = "TCkC4uoErEyCB4MK3d6ouyJELoXnuyqe9L"; - consensus.stage4StartBlock = 168500; + consensus.stage4StartBlock = 167500; consensus.stage4CommunityFundShare = 10; consensus.stage4DevelopmentFundShare = 15; consensus.stage4MasternodeShare = 70; From a1e98700f5f639732f45f33ad098813a3ac9cd56 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Mon, 2 Sep 2024 19:27:52 +0200 Subject: [PATCH 8/9] Fix for tests --- src/chainparams.cpp | 6 ++--- src/test/firsthalving_tests.cpp | 43 ++++++++++++++++++--------------- src/test/mtp_halving_tests.cpp | 15 +++++++++++- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 67558159cf..db67781038 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1052,15 +1052,15 @@ class CRegTestParams : public CChainParams { consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; - consensus.stage3StartTime = INT_MAX; - consensus.stage3StartBlock = 2000; + consensus.stage3StartTime = 0; + consensus.stage3StartBlock = 1500; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; consensus.stage3DevelopmentFundAddress = "TGEGf26GwyUBE2P2o2beBAfE9Y438dCp5t"; // private key cMrz8Df36VR9TvZjtvSqLPhUQR7pcpkXRXaLNYUxfkKsRuCzHpAN consensus.stage3CommunityFundAddress = "TJmPzeJF4DECrBwUftc265U7rTPxKmpa4F"; // private key cTyPWqTMM1CgT5qy3K3LSgC1H6Q2RHvnXZHvjWtKB4vq9qXqKmMu - consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond; + consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond + 500; consensus.stage4CommunityFundShare = 15; consensus.stage4DevelopmentFundShare = 25; consensus.stage4MasternodeShare = 50; diff --git a/src/test/firsthalving_tests.cpp b/src/test/firsthalving_tests.cpp index e7059a0319..966c55a1ce 100644 --- a/src/test/firsthalving_tests.cpp +++ b/src/test/firsthalving_tests.cpp @@ -154,7 +154,7 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) consensusParams.nSubsidyHalvingFirst = 600; consensusParams.stage3StartTime = INT_MAX; - consensusParams.nSubsidyHalvingSecond = 620; + consensusParams.nSubsidyHalvingSecond = consensusParams.stage4StartBlock = 620; consensusParams.nSubsidyHalvingInterval = 10; CScript devPayoutScript = GenerateRandomAddress(); @@ -225,6 +225,8 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) // initiate stage3 consensusParams.stage3StartTime = GetTime(); + consensusParams.stage3StartBlock = chainActive.Height(); + // for stage3 there is dev payout and community payout for (int i=610; i<620; i++) { CBlock block = CreateAndProcessBlock({}, coinbaseKey); @@ -259,39 +261,39 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) CAmount nValue; auto dmnPayout = FindPayoutDmn(block, nValue); - BOOST_ASSERT(dmnPayout != nullptr && nValue == 3125*COIN/1000); // 3.125 (6.25*0.5) + // stage 4: no real halving here + BOOST_ASSERT(dmnPayout != nullptr && nValue == 625*COIN/100); // 6.25 // there should be no more payment to devs fund for (const CTxOut &txout: block.vtx[0]->vout) { BOOST_ASSERT(txout.scriptPubKey != GetScriptForDestination(CBitcoinAddress(consensusParams.stage2DevelopmentFundAddress).Get())); } - // miner's reward should be 6.25-3.125 = 3.125 - BOOST_ASSERT(block.vtx[0]->vout[0].nValue == 3125*COIN/1000); - // should be only 2 vouts in coinbase - BOOST_ASSERT(block.vtx[0]->vout.size() == 2); + // miner's reward should be 1.25 (10%) + BOOST_ASSERT(block.vtx[0]->vout[0].nValue == 125*COIN/100); + + bool paymentToDevFound = false, paymentToCommunityFound = false; + for (const CTxOut &txout: block.vtx[0]->vout) { + if (txout.scriptPubKey == GetScriptForDestination(CBitcoinAddress(consensusParams.stage3DevelopmentFundAddress).Get())) { + BOOST_ASSERT(txout.nValue == 3125*COIN/1000); // 25/2*0.25 + paymentToDevFound = true; + } + if (txout.scriptPubKey == GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get())) { + BOOST_ASSERT(txout.nValue == 1875*COIN/1000); // 25/2*0.15 + paymentToCommunityFound = true; + } + } + BOOST_ASSERT(paymentToDevFound && paymentToCommunityFound); } - // the third halving should occur at block 630 + // tail emission should occur at block 630 CBlock block = CreateAndProcessBlock({}, coinbaseKey); deterministicMNManager->UpdatedBlockTip(chainActive.Tip()); CAmount nValue; auto dmnPayout = FindPayoutDmn(block, nValue); - BOOST_ASSERT(dmnPayout != nullptr && nValue == 3125*COIN/1000/2); // 3.125/2 (3.125*0.5) - - // there should be no more payment to devs/community funds fund - for (const CTxOut &txout: block.vtx[0]->vout) { - BOOST_ASSERT(txout.scriptPubKey != GetScriptForDestination(CBitcoinAddress(consensusParams.stage2DevelopmentFundAddress).Get()) && - txout.scriptPubKey != GetScriptForDestination(CBitcoinAddress(consensusParams.stage3DevelopmentFundAddress).Get()) && - txout.scriptPubKey != GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get())); - } - - // miner's reward should be 3.125/2 - BOOST_ASSERT(block.vtx[0]->vout[0].nValue == 3125*COIN/1000/2); - // should be only 2 vouts in coinbase - BOOST_ASSERT(block.vtx[0]->vout.size() == 2); + BOOST_ASSERT(dmnPayout != nullptr && nValue == COIN); consensusParams = consensusParamsBackup; } @@ -303,6 +305,7 @@ BOOST_FIXTURE_TEST_CASE(devpayoutverification, TestChainDIP3BeforeActivationSetu consensusParams.nSubsidyHalvingFirst = 600; consensusParams.nSubsidyHalvingSecond = 610; + consensusParams.stage3StartTime = INT_MAX; consensusParams.nSubsidyHalvingInterval = 10; // skip to block 600 diff --git a/src/test/mtp_halving_tests.cpp b/src/test/mtp_halving_tests.cpp index 5baaa4e9a9..39a466d4cc 100644 --- a/src/test/mtp_halving_tests.cpp +++ b/src/test/mtp_halving_tests.cpp @@ -42,8 +42,17 @@ CScript scriptPubKeyMtpHalving; struct MtpHalvingTestingSetup : public TestingSetup { - MtpHalvingTestingSetup() : TestingSetup(CBaseChainParams::REGTEST) + Consensus::Params &mutableParams; + Consensus::Params oldParams; + + MtpHalvingTestingSetup() : TestingSetup(CBaseChainParams::REGTEST), mutableParams(const_cast(Params().GetConsensus())) { + oldParams = mutableParams; + + // disable stage 3 stuff for now + mutableParams.stage3StartTime = INT_MAX; + mutableParams.stage3StartBlock = INT_MAX; + CPubKey newKey; BOOST_CHECK(pwalletMain->GetKeyFromPool(newKey)); @@ -66,6 +75,10 @@ struct MtpHalvingTestingSetup : public TestingSetup { } } + ~MtpHalvingTestingSetup() { + mutableParams = oldParams; + } + CBlock CreateBlock(const CScript& scriptPubKeyMtpHalving, bool mtp = false) { const CChainParams& chainparams = Params(); std::unique_ptr pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKeyMtpHalving); From a7abf1161ae7364f37cd58a7a0133b7a9875d75e Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Tue, 3 Sep 2024 13:42:13 +0200 Subject: [PATCH 9/9] Tweaked regtest parameter to fix tests --- src/chainparams.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index db67781038..4c4137be35 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -1052,15 +1052,15 @@ class CRegTestParams : public CChainParams { consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; - consensus.stage3StartTime = 0; - consensus.stage3StartBlock = 1500; + consensus.stage3StartTime = INT_MAX; // tests should set this value individually + consensus.stage3StartBlock = INT_MAX; // same as above consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; consensus.stage3DevelopmentFundAddress = "TGEGf26GwyUBE2P2o2beBAfE9Y438dCp5t"; // private key cMrz8Df36VR9TvZjtvSqLPhUQR7pcpkXRXaLNYUxfkKsRuCzHpAN consensus.stage3CommunityFundAddress = "TJmPzeJF4DECrBwUftc265U7rTPxKmpa4F"; // private key cTyPWqTMM1CgT5qy3K3LSgC1H6Q2RHvnXZHvjWtKB4vq9qXqKmMu - consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond + 500; + consensus.stage4StartBlock = consensus.nSubsidyHalvingSecond; consensus.stage4CommunityFundShare = 15; consensus.stage4DevelopmentFundShare = 25; consensus.stage4MasternodeShare = 50;