Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tokenomics update #1478

Merged
merged 9 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 29 additions & 9 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -206,6 +205,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;

Expand Down Expand Up @@ -514,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;
Expand All @@ -528,6 +532,12 @@ class CTestNetParams : public CChainParams {
consensus.stage3DevelopmentFundAddress = "TWDxLLKsFp6qcV1LL4U2uNmW4HwMcapmMU";
consensus.stage3CommunityFundAddress = "TCkC4uoErEyCB4MK3d6ouyJELoXnuyqe9L";

consensus.stage4StartBlock = 167500;
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;
Expand Down Expand Up @@ -789,22 +799,27 @@ class CDevNetParams : public CChainParams {
consensus.chainType = Consensus::chainDevnet;

consensus.nSubsidyHalvingFirst = 1;
consensus.nSubsidyHalvingSecond = 100000;
consensus.nSubsidyHalvingInterval = 100000;
consensus.nSubsidyHalvingStopBlock = 1000000;
consensus.nSubsidyHalvingSecond = 3000;
consensus.nSubsidyHalvingInterval = 10000;

consensus.stage2DevelopmentFundShare = 15;
consensus.stage2ZnodeShare = 35;
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;
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;
Expand Down Expand Up @@ -1031,21 +1046,26 @@ class CRegTestParams : public CChainParams {
consensus.nSubsidyHalvingFirst = 1500;
consensus.nSubsidyHalvingSecond = 2500;
consensus.nSubsidyHalvingInterval = 1000;
consensus.nSubsidyHalvingStopBlock = 10000;

consensus.nStartBlacklist = 0;
consensus.nStartDuplicationCheck = 0;
consensus.stage2DevelopmentFundShare = 15;
consensus.stage2ZnodeShare = 35;

consensus.stage3StartTime = INT_MAX;
consensus.stage3StartBlock = 0;
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;
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;
Expand Down
15 changes: 13 additions & 2 deletions src/consensus/params.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -163,6 +161,19 @@ struct Params {
/** percentage of block subsidy going to masternode */
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 */
int stage4CommunityFundShare;
/** percentage of block subsidy going to masternode */
int stage4MasternodeShare;

/** tail emission (after stage 4) */
int tailEmissionBlockSubsidy;

int nStartDuplicationCheck;
int nStartBlacklist;

Expand Down
30 changes: 21 additions & 9 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ std::unique_ptr<CBlockTemplate> 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);
Expand Down Expand Up @@ -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
Expand Down
45 changes: 23 additions & 22 deletions src/test/firsthalving_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,8 @@ BOOST_FIXTURE_TEST_CASE(devpayout, TestChainDIP3BeforeActivationSetup)

consensusParams.nSubsidyHalvingFirst = 600;
consensusParams.stage3StartTime = INT_MAX;
consensusParams.nSubsidyHalvingSecond = 620;
consensusParams.nSubsidyHalvingSecond = consensusParams.stage4StartBlock = 620;
consensusParams.nSubsidyHalvingInterval = 10;
consensusParams.nSubsidyHalvingStopBlock = 1000;

CScript devPayoutScript = GenerateRandomAddress();
CTxDestination devPayoutDest{CScriptID(devPayoutScript)};
Expand Down Expand Up @@ -226,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);
Expand Down Expand Up @@ -260,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;
}
Expand All @@ -304,8 +305,8 @@ BOOST_FIXTURE_TEST_CASE(devpayoutverification, TestChainDIP3BeforeActivationSetu

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

// skip to block 600
for (int i=498; i<600; i++)
Expand Down
53 changes: 6 additions & 47 deletions src/test/main_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
psolstice marked this conversation as resolved.
Show resolved Hide resolved
}

BOOST_AUTO_TEST_CASE(block_subsidy_test)
Expand All @@ -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; }

Expand Down
15 changes: 14 additions & 1 deletion src/test/mtp_halving_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Consensus::Params&>(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));

Expand All @@ -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<CBlockTemplate> pblocktemplate = BlockAssembler(chainparams).CreateNewBlock(scriptPubKeyMtpHalving);
Expand Down
Loading
Loading