Skip to content

Commit

Permalink
Adjustment for block numbers in consensus following faster blocks har…
Browse files Browse the repository at this point in the history
…dfork (#1185)

* Adjustment for consensus parameters following faster blocks hardfork

* Test for having a second and third halvings at correct block numbers

* Change minimum version of peer to 0.14.10.0

* Fixed subsidy_limit_test

* Fixed peer version parsing
  • Loading branch information
psolstice authored Jul 20, 2022
1 parent 1bd003c commit 21d5c65
Show file tree
Hide file tree
Showing 9 changed files with 98 additions and 32 deletions.
27 changes: 23 additions & 4 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<unsigned char> extraNonce) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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); // =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
Expand Down Expand Up @@ -490,6 +503,7 @@ class CTestNetParams : public CChainParams {
consensus.chainType = Consensus::chainTestnet;

consensus.nSubsidyHalvingFirst = 12000;
consensus.nSubsidyHalvingSecond = 150000;
consensus.nSubsidyHalvingInterval = 150000;
consensus.nSubsidyHalvingStopBlock = 1000000;

Expand All @@ -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;
Expand Down Expand Up @@ -753,6 +768,7 @@ class CDevNetParams : public CChainParams {
consensus.chainType = Consensus::chainDevnet;

consensus.nSubsidyHalvingFirst = 120;
consensus.nSubsidyHalvingSecond = 100000;
consensus.nSubsidyHalvingInterval = 100000;
consensus.nSubsidyHalvingStopBlock = 1000000;

Expand All @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -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 */
Expand Down
2 changes: 1 addition & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
4 changes: 2 additions & 2 deletions src/net_processing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
Expand Down
28 changes: 17 additions & 11 deletions src/pow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 27 additions & 4 deletions src/test/firsthalving_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 = 10;
consensusParams.nSubsidyHalvingStopBlock = 1000;

CScript devPayoutScript = GenerateRandomAddress();
Expand Down Expand Up @@ -252,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) {
Expand All @@ -267,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);

Expand All @@ -281,6 +303,7 @@ BOOST_FIXTURE_TEST_CASE(devpayoutverification, TestChainDIP3BeforeActivationSetu
Consensus::Params consensusParamsBackup = consensusParams;

consensusParams.nSubsidyHalvingFirst = 600;
consensusParams.nSubsidyHalvingSecond = 610;
consensusParams.nSubsidyHalvingInterval = 10;
consensusParams.nSubsidyHalvingStopBlock = 1000;

Expand Down
18 changes: 12 additions & 6 deletions src/test/main_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<nMTPFirstBlock ? consensusParams.nMTPSwitchTime-1000 : consensusParams.nMTPSwitchTime);
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, 2095751201171875ULL);
BOOST_CHECK_EQUAL(nSum, 2095751200767464ULL);
}

bool ReturnFalse() { return false; }
Expand Down
14 changes: 11 additions & 3 deletions src/validation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 21d5c65

Please sign in to comment.