From a8c85b4304d229c5f341202f5f2b45c491d0cd78 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 26 Jun 2022 14:00:13 +0400 Subject: [PATCH 1/5] Adjustment for consensus parameters following faster blocks hardfork --- src/chainparams.cpp | 27 +++++++++++++++++++++++---- src/consensus/params.h | 4 ++++ src/miner.cpp | 2 +- src/pow.cpp | 28 +++++++++++++++++----------- src/test/firsthalving_tests.cpp | 4 +++- src/validation.cpp | 14 +++++++++++--- 6 files changed, 59 insertions(+), 20 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 9f90262641..7967199ae2 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -23,6 +23,17 @@ using namespace secp_primitives; +// If some feature is enabled at block intervalStart and its duration is intervalLength halving distance between blocks +// causes the end to happen sooner in real time. This function adjusts the end block number so the approximate ending time +// is left intact +static constexpr int AdjustEndingBlockNumberAfterSubsidyHalving(int intervalStart, int intervalLength, int halvingPoint) { + if (halvingPoint < intervalStart || halvingPoint >= intervalStart + intervalLength) + // halving occurs outside of interval + return intervalStart + intervalLength; + else + return halvingPoint + (intervalStart + intervalLength - halvingPoint)*2; +} + static CBlock CreateGenesisBlock(const char *pszTimestamp, const CScript &genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount &genesisReward, std::vector extraNonce) { @@ -179,14 +190,16 @@ class CMainParams : public CChainParams { consensus.chainType = Consensus::chainMain; consensus.nSubsidyHalvingFirst = 302438; - consensus.nSubsidyHalvingInterval = 420000; - consensus.nSubsidyHalvingStopBlock = 3646849; + consensus.nSubsidyHalvingSecond = AdjustEndingBlockNumberAfterSubsidyHalving(302438, 420000, 486221); // =958665 + consensus.nSubsidyHalvingInterval = 420000*2; + consensus.nSubsidyHalvingStopBlock = AdjustEndingBlockNumberAfterSubsidyHalving(0, 3646849, 486221); // =6807477 consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; consensus.stage2DevelopmentFundAddress = "aFrAVZFr8pva5mG8XKaUH8EXcFVVNxLiuB"; consensus.stage3StartTime = 1655380800; // Thursday, 16 June 2022 12:00:00 UTC + consensus.stage3StartBlock = 486221; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; @@ -425,7 +438,7 @@ class CMainParams : public CChainParams { consensus.evoSporkKeyID = "a78fERshquPsTv2TuKMSsxTeKom56uBwLP"; consensus.nEvoSporkStartBlock = ZC_LELANTUS_STARTING_BLOCK; - consensus.nEvoSporkStopBlock = ZC_LELANTUS_STARTING_BLOCK + 2*24*12*365; // two years after lelantus + consensus.nEvoSporkStopBlock = AdjustEndingBlockNumberAfterSubsidyHalving(ZC_LELANTUS_STARTING_BLOCK, 2*24*12*365, 486221); // two years after lelantus consensus.nEvoSporkStopBlockExtensionVersion = 140903; consensus.nEvoSporkStopBlockPrevious = ZC_LELANTUS_STARTING_BLOCK + 1*24*12*365; // one year after lelantus consensus.nEvoSporkStopBlockExtensionGracefulPeriod = 24*12*14; // two weeks @@ -490,6 +503,7 @@ class CTestNetParams : public CChainParams { consensus.chainType = Consensus::chainTestnet; consensus.nSubsidyHalvingFirst = 12000; + consensus.nSubsidyHalvingSecond = 150000; consensus.nSubsidyHalvingInterval = 150000; consensus.nSubsidyHalvingStopBlock = 1000000; @@ -498,6 +512,7 @@ class CTestNetParams : public CChainParams { consensus.stage2DevelopmentFundAddress = "TUuKypsbbnHHmZ2auC2BBWfaP1oTEnxjK2"; consensus.stage3StartTime = 1653409800; // May 24th 2022 04:30 UTC + consensus.stage3StartBlock = 84459; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; @@ -753,6 +768,7 @@ class CDevNetParams : public CChainParams { consensus.chainType = Consensus::chainDevnet; consensus.nSubsidyHalvingFirst = 120; + consensus.nSubsidyHalvingSecond = 100000; consensus.nSubsidyHalvingInterval = 100000; consensus.nSubsidyHalvingStopBlock = 1000000; @@ -761,6 +777,7 @@ class CDevNetParams : public CChainParams { consensus.stage2DevelopmentFundAddress = "TixHByoJ21dmx5xfMAXTVC4V7k53U7RncU"; consensus.stage3StartTime = 1653382800; + consensus.stage3StartBlock = 1514; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; @@ -979,6 +996,7 @@ class CRegTestParams : public CChainParams { // To be changed for specific tests consensus.nSubsidyHalvingFirst = 1500; + consensus.nSubsidyHalvingSecond = 2500; consensus.nSubsidyHalvingInterval = 1000; consensus.nSubsidyHalvingStopBlock = 10000; @@ -987,7 +1005,8 @@ class CRegTestParams : public CChainParams { consensus.stage2DevelopmentFundShare = 15; consensus.stage2ZnodeShare = 35; - consensus.stage3StartTime = INT_MAX; // Thursday, 16 June 2022 12:00:00 UTC + consensus.stage3StartTime = INT_MAX; + consensus.stage3StartBlock = 0; consensus.stage3DevelopmentFundShare = 15; consensus.stage3CommunityFundShare = 10; consensus.stage3MasternodeShare = 50; diff --git a/src/consensus/params.h b/src/consensus/params.h index 58f3a0fd36..73d86013e7 100644 --- a/src/consensus/params.h +++ b/src/consensus/params.h @@ -132,6 +132,8 @@ struct Params { uint256 hashGenesisBlock; /** First subsidy halving */ int nSubsidyHalvingFirst; + /** Second subsidy halving */ + int nSubsidyHalvingSecond; /** Subsequent subsidy halving intervals */ int nSubsidyHalvingInterval; /** Stop subsidy at this block number */ @@ -148,6 +150,8 @@ struct Params { /** parameters for coinbase payment distribution after stage two and before second halving (aka stage 3) */ /** start time of stage 3 */ int stage3StartTime; + /** starting block number of stage 3 (zero if unknown) */ + int stage3StartBlock; /** P2PKH or P2SH address for developer funds */ std::string stage3DevelopmentFundAddress; /** P2PKH or P2SH address for community funds */ diff --git a/src/miner.cpp b/src/miner.cpp index c514d649cc..25d88d54ea 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -807,7 +807,7 @@ void BlockAssembler::FillFoundersReward(CMutableTransaction &coinbaseTx, bool fM if (fShorterBlockDistance) coin /= 2; - if (nHeight >= params.nSubsidyHalvingFirst && nHeight < params.nSubsidyHalvingFirst + params.nSubsidyHalvingInterval) { + if (nHeight >= params.nSubsidyHalvingFirst && nHeight < params.nSubsidyHalvingSecond) { if (fShorterBlockDistance) { // Stage 3 CScript devPayoutScript = GetScriptForDestination(CBitcoinAddress(params.stage3DevelopmentFundAddress).Get()); diff --git a/src/pow.cpp b/src/pow.cpp index 32fd9a8b2e..ecd405499d 100644 --- a/src/pow.cpp +++ b/src/pow.cpp @@ -109,25 +109,31 @@ unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHead return (exponent << 24) | base; } - if (pblock->nTime < params.stage3StartTime + BlocksTargetSpacing*PastBlocksMax*3) { + uint32_t numberOfStage3Blocks = pindexLast->nHeight; + + if (params.stage3StartBlock != 0) { + // we know the first stage3 block + numberOfStage3Blocks = pindexLast->nHeight - params.stage3StartBlock + 1; + } + else if (pblock->nTime < params.stage3StartTime + BlocksTargetSpacing*PastBlocksMax*3) { // transition to stage3 happened recently, look for the last block before the transition const CBlockIndex *pindex = pindexLast; while (pindex && pindex->nTime >= params.stage3StartTime) pindex = pindex->pprev; - if (pindex) { - uint32_t numberOfStage3Blocks = pindexLast->nHeight - pindex->nHeight; - if (numberOfStage3Blocks < params.DifficultyAdjustmentInterval(true)/2) - // do not retarget if too few stage3 blocks - return pindexLast->nBits; - - PastBlocksMin = std::min(PastBlocksMin, numberOfStage3Blocks); - PastBlocksMax = std::min(PastBlocksMax, numberOfStage3Blocks); - } + if (pindex) + numberOfStage3Blocks = pindexLast->nHeight - pindex->nHeight; } + + if (numberOfStage3Blocks < params.DifficultyAdjustmentInterval(true)/2) + // do not retarget if too few stage3 blocks + return pindexLast->nBits; + + PastBlocksMin = std::min(PastBlocksMin, numberOfStage3Blocks); + PastBlocksMax = std::min(PastBlocksMax, numberOfStage3Blocks); } else if (pblock->IsProgPow()) { - uint32_t numberOfPPBlocks = 0; + uint32_t numberOfPPBlocks = pindexLast->nHeight; if (params.nPPBlockNumber != 0) { // we know the first ProgPow block diff --git a/src/test/firsthalving_tests.cpp b/src/test/firsthalving_tests.cpp index 1c2a16647d..6994d71c74 100644 --- a/src/test/firsthalving_tests.cpp +++ b/src/test/firsthalving_tests.cpp @@ -154,7 +154,8 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) consensusParams.nSubsidyHalvingFirst = 600; consensusParams.stage3StartTime = INT_MAX; - consensusParams.nSubsidyHalvingInterval = 20; + consensusParams.nSubsidyHalvingSecond = 620; + consensusParams.nSubsidyHalvingInterval = 30; consensusParams.nSubsidyHalvingStopBlock = 1000; CScript devPayoutScript = GenerateRandomAddress(); @@ -281,6 +282,7 @@ BOOST_FIXTURE_TEST_CASE(devpayoutverification, TestChainDIP3BeforeActivationSetu Consensus::Params consensusParamsBackup = consensusParams; consensusParams.nSubsidyHalvingFirst = 600; + consensusParams.nSubsidyHalvingSecond = 610; consensusParams.nSubsidyHalvingInterval = 10; consensusParams.nSubsidyHalvingStopBlock = 1000; diff --git a/src/validation.cpp b/src/validation.cpp index d72de51e3c..cad5d46a78 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1717,11 +1717,19 @@ CAmount GetBlockSubsidyWithMTPFlag(int nHeight, const Consensus::Params &consens if (nHeight == 0) return 0; - // Subsidy is cut in half after nSubsidyHalvingFirst block, then every nSubsidyHalvingInterval blocks. + // 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; - int halvings = nHeight < consensusParams.nSubsidyHalvingFirst ? 0 : (nHeight - consensusParams.nSubsidyHalvingFirst) / consensusParams.nSubsidyHalvingInterval + 1; + + int halvings; + if (nHeight < consensusParams.nSubsidyHalvingFirst) + halvings = 0; + else if (nHeight < consensusParams.nSubsidyHalvingSecond) + halvings = 1; + else + halvings = (nHeight - consensusParams.nSubsidyHalvingSecond) / consensusParams.nSubsidyHalvingInterval + 2; + // Force block reward to zero when right shift is undefined. if (halvings >= 64) return 0; @@ -4576,7 +4584,7 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, const Co } if (nHeight >= consensusParams.nSubsidyHalvingFirst) { - if (nHeight < consensusParams.nSubsidyHalvingFirst + consensusParams.nSubsidyHalvingInterval) { + 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; From 7afd0820b9308614b393be6a568339b3d85a987c Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 26 Jun 2022 16:00:08 +0400 Subject: [PATCH 2/5] Test for having a second and third halvings at correct block numbers --- src/test/firsthalving_tests.cpp | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/test/firsthalving_tests.cpp b/src/test/firsthalving_tests.cpp index 6994d71c74..e3d8b4e56c 100644 --- a/src/test/firsthalving_tests.cpp +++ b/src/test/firsthalving_tests.cpp @@ -155,7 +155,7 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) consensusParams.nSubsidyHalvingFirst = 600; consensusParams.stage3StartTime = INT_MAX; consensusParams.nSubsidyHalvingSecond = 620; - consensusParams.nSubsidyHalvingInterval = 30; + consensusParams.nSubsidyHalvingInterval = 10; consensusParams.nSubsidyHalvingStopBlock = 1000; CScript devPayoutScript = GenerateRandomAddress(); @@ -253,13 +253,34 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) BOOST_ASSERT(block.vtx[0]->GetValueOut() == 25*COIN/2); } + for (int i=620; i<630; i++) { + CBlock block = CreateAndProcessBlock({}, coinbaseKey); + deterministicMNManager->UpdatedBlockTip(chainActive.Tip()); + + CAmount nValue; + auto dmnPayout = FindPayoutDmn(block, nValue); + + BOOST_ASSERT(dmnPayout != nullptr && nValue == 3125*COIN/1000); // 3.125 (6.25*0.5) + + // 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); + } + + // the third halving 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); // (25/4*0.5) + 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) { @@ -268,8 +289,8 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup) txout.scriptPubKey != GetScriptForDestination(CBitcoinAddress(consensusParams.stage3CommunityFundAddress).Get())); } - // miner's reward should be 3.125 - BOOST_ASSERT(block.vtx[0]->vout[0].nValue == 3125*COIN/1000); + // 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); From d8699b49e6ee73e3dbd469799f9f6281d30542a8 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 26 Jun 2022 16:06:47 +0400 Subject: [PATCH 3/5] Change minimum version of peer to 0.14.10.0 --- src/version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/version.h b/src/version.h index 90df94a5c3..1088ac93a8 100644 --- a/src/version.h +++ b/src/version.h @@ -52,7 +52,7 @@ static const int SHORT_IDS_BLOCKS_VERSION = 90013; static const int INVALID_CB_NO_BAN_VERSION = 90013; //! minimum version of official client to connect to -static const int MIN_FIRO_CLIENT_VERSION = 140900; // 0.14.9.0 +static const int MIN_FIRO_CLIENT_VERSION = 141000; // 0.14.10.0 //! introduction of DIP3/deterministic masternodes static const int DMN_PROTO_VERSION = 90030; From b5c96ddf7936a4ac1cc990c629482fbeda5eda73 Mon Sep 17 00:00:00 2001 From: Peter Shugalev Date: Sun, 26 Jun 2022 20:57:46 +0400 Subject: [PATCH 4/5] Fixed subsidy_limit_test --- src/chainparams.cpp | 2 +- src/test/main_tests.cpp | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/chainparams.cpp b/src/chainparams.cpp index 7967199ae2..1f9224afd5 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -438,7 +438,7 @@ class CMainParams : public CChainParams { consensus.evoSporkKeyID = "a78fERshquPsTv2TuKMSsxTeKom56uBwLP"; consensus.nEvoSporkStartBlock = ZC_LELANTUS_STARTING_BLOCK; - consensus.nEvoSporkStopBlock = AdjustEndingBlockNumberAfterSubsidyHalving(ZC_LELANTUS_STARTING_BLOCK, 2*24*12*365, 486221); // two years after lelantus + consensus.nEvoSporkStopBlock = AdjustEndingBlockNumberAfterSubsidyHalving(ZC_LELANTUS_STARTING_BLOCK, 2*24*12*365, 486221); // =608035, two years after lelantus consensus.nEvoSporkStopBlockExtensionVersion = 140903; consensus.nEvoSporkStopBlockPrevious = ZC_LELANTUS_STARTING_BLOCK + 1*24*12*365; // one year after lelantus consensus.nEvoSporkStopBlockExtensionGracefulPeriod = 24*12*14; // two weeks diff --git a/src/test/main_tests.cpp b/src/test/main_tests.cpp index 299e206e7d..f4352ed396 100644 --- a/src/test/main_tests.cpp +++ b/src/test/main_tests.cpp @@ -46,29 +46,35 @@ BOOST_AUTO_TEST_CASE(subsidy_limit_test) { Consensus::Params consensusParams = Params(CBaseChainParams::MAIN).GetConsensus(); CAmount nSum = 0; - const int nMTPFirstBlock = 117564; - int lastHalving = (consensusParams.nSubsidyHalvingStopBlock - consensusParams.nSubsidyHalvingFirst)/consensusParams.nSubsidyHalvingInterval; - int lastHalvingBlock = consensusParams.nSubsidyHalvingFirst + lastHalving*consensusParams.nSubsidyHalvingInterval; + 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.nSubsidyHalvingFirst) + if (nHeight == consensusParams.nSubsidyHalvingSecond) step = 1000; else if (nHeight == lastHalvingBlock) step = 1; else if (nHeight == consensusParams.nSubsidyHalvingStopBlock) step = 10000; - CAmount nSubsidy = GetBlockSubsidy(nHeight, consensusParams, nHeight Date: Mon, 27 Jun 2022 11:22:22 +0400 Subject: [PATCH 5/5] Fixed peer version parsing --- src/net_processing.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net_processing.cpp b/src/net_processing.cpp index a8a14a359f..585bfc902d 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1443,9 +1443,9 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr if (!vRecv.empty()) { vRecv >> LIMITED_STRING(strSubVer, MAX_SUBVERSION_LENGTH); cleanSubVer = SanitizeString(strSubVer); - int parsedVersion[4]; + int parsedVersion[4] = {0, 0, 0, 0}; if (sscanf(cleanSubVer.c_str(), "/Satoshi:%2d.%2d.%2d.%2d/", - &parsedVersion[0], &parsedVersion[1], &parsedVersion[2], &parsedVersion[3]) == 4) { + &parsedVersion[0], &parsedVersion[1], &parsedVersion[2], &parsedVersion[3]) >= 2) { int peerClientVersion = parsedVersion[0]*1000000 + parsedVersion[1]*10000 + parsedVersion[2]*100 + parsedVersion[3]; if (peerClientVersion < MIN_FIRO_CLIENT_VERSION) { connman.PushMessage(pfrom, CNetMsgMaker(INIT_PROTO_VERSION).Make(NetMsgType::REJECT, strCommand, REJECT_OBSOLETE, "This version is banned from the network"));