Skip to content

Commit

Permalink
stable subsidy base
Browse files Browse the repository at this point in the history
  • Loading branch information
ogabrielides authored and UdjinM6 committed Oct 17, 2023
1 parent 833ce4c commit d6a733c
Show file tree
Hide file tree
Showing 8 changed files with 100 additions and 39 deletions.
2 changes: 1 addition & 1 deletion src/bench/duplicate_inputs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ static void DuplicateInputs(benchmark::Bench& bench)
coinbaseTx.vin[0].prevout.SetNull();
coinbaseTx.vout.resize(1);
coinbaseTx.vout[0].scriptPubKey = SCRIPT_PUB;
coinbaseTx.vout[0].nValue = GetBlockSubsidyInner(block.nBits, nHeight, chainparams.GetConsensus(), false);
coinbaseTx.vout[0].nValue = GetBlockSubsidyInner(block.nBits, nHeight, chainparams.GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;

naughtyTx.vout.resize(1);
Expand Down
8 changes: 6 additions & 2 deletions src/governance/classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,19 +496,23 @@ CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight)

const CBlockIndex* tipIndex = ::ChainActive().Tip();
bool fMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(tipIndex);
bool fV20Active = llmq::utils::IsV20Active(tipIndex);
if (!fMNRewardReallocated && nBlockHeight > tipIndex->nHeight) {
// If fMNRewardReallocated isn't active yet and nBlockHeight refers to a future SuperBlock
// then we need to check if the fork is locked_in and see if it will be active by the time of the future SuperBlock
if (llmq::utils::GetMNRewardReallocationState(tipIndex) == ThresholdState::LOCKED_IN) {
int activation_height = llmq::utils::GetMNRewardReallocationSince(tipIndex) + static_cast<int>(Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_MN_RR].nWindowSize);
if (nBlockHeight >= activation_height) fMNRewardReallocated = true;
if (nBlockHeight >= activation_height) {
fMNRewardReallocated = true;
fV20Active = true;
}
}
}

// min subsidy for high diff networks and vice versa
int nBits = consensusParams.fPowAllowMinDifficultyBlocks ? UintToArith256(consensusParams.powLimit).GetCompact() : 1;
// some part of all blocks issued during the cycle goes to superblock, see GetBlockSubsidy
CAmount nSuperblockPartOfSubsidy = GetSuperblockSubsidyInner(nBits, nBlockHeight - 1, consensusParams, fMNRewardReallocated);
CAmount nSuperblockPartOfSubsidy = GetSuperblockSubsidyInner(nBits, nBlockHeight - 1, consensusParams, fV20Active, fMNRewardReallocated);
CAmount nPaymentsLimit = nSuperblockPartOfSubsidy * consensusParams.nSuperblockCycle;
LogPrint(BCLog::GOBJECT, "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit);

Expand Down
3 changes: 2 additions & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,8 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc

// NOTE: unlike in bitcoin, we need to pass PREVIOUS block height here
bool fMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(pindexPrev);
CAmount blockReward = nFees + GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fMNRewardReallocated);
bool fV20Active = llmq::utils::IsV20Active(pindexPrev);
CAmount blockReward = nFees + GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fV20Active, fMNRewardReallocated);

// Compute regular coinbase transaction.
coinbaseTx.vout[0].nValue = blockReward;
Expand Down
41 changes: 27 additions & 14 deletions src/test/block_reward_reallocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,6 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
auto tx = CreateProRegTx(*m_node.mempool, utxos, 1, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey);

CreateAndProcessBlock({tx}, coinbaseKey);

{
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
Expand Down Expand Up @@ -205,10 +204,12 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
// next block should be signaling by default
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
deterministicMNManager->UpdatedBlockTip(tip);
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
}
Expand All @@ -220,12 +221,14 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
{
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 13748571607);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 137485721);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6874285801); // 0.4999999998
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 68742860); // 0.4999999998
}

// Reallocation should kick-in with the superblock mined at height = 2010,
Expand All @@ -237,8 +240,10 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
}
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
}
Expand All @@ -248,12 +253,14 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
// Reward split should reach ~60/40 after reallocation is done
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 10221599170);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 102215997);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 6132959502); // 0.6
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 61329598); // 0.6
}
BOOST_CHECK(!llmq::utils::IsMNRewardReallocationActive(m_node.chainman->ActiveChain().Tip()));

Expand All @@ -265,8 +272,10 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
}
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);

if (isMNRewardReallocated) {
Expand All @@ -283,16 +292,20 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
// Allocation of block subsidy is 60% MN, 20% miners and 20% treasury
LOCK(cs_main);
const CBlockIndex* const tip{m_node.chainman->ActiveChain().Tip()};
const bool isV20Active{llmq::utils::IsV20Active(tip)};
const bool isMNRewardReallocated{llmq::utils::IsMNRewardReallocationActive(tip)};
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, GetBlockSubsidy(tip, consensus_params), isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount block_subsidy_sb = GetSuperblockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount platform_payment = MasternodePayments::PlatformShare(masternode_payment);
masternode_payment -= platform_payment;
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);

// At this height (3178) the block subsidy is 10546094382.
CAmount block_subsidy = CAmount(10546094382);
// At this height (3178) the block subsidy is 105460950.
CAmount block_subsidy_potential = block_subsidy + block_subsidy_sb;
BOOST_CHECK_EQUAL(block_subsidy_potential, 105460950);
// Treasury is 20% since MNRewardReallocation
CAmount expected_block_reward = block_subsidy - block_subsidy / 5;
CAmount expected_block_reward = block_subsidy_potential - block_subsidy_potential / 5;
// Since MNRewardReallocation, MN reward share is 75% of the block reward
CAmount expected_masternode_reward = expected_block_reward * 3 / 4;
CAmount expected_mn_platform_payment = MasternodePayments::PlatformShare(expected_masternode_reward);
Expand Down
50 changes: 42 additions & 8 deletions src/test/subsidy_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,52 +22,86 @@ BOOST_AUTO_TEST_CASE(block_subsidy_test)
// details for block 4249 (subsidy returned will be for block 4250)
nPrevBits = 0x1c4a47c4;
nPrevHeight = 4249;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 50000000000ULL);

// details for block 4249 (subsidy returned will be for block 4250)
// v20 should make difference for blocks with low diff, regardless of their height
nPrevBits = 0x1c4a47c4;
nPrevHeight = 4249;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ true, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 500000000ULL);

// details for block 4501 (subsidy returned will be for block 4502)
nPrevBits = 0x1c4a47c4;
nPrevHeight = 4501;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 5600000000ULL);

// details for block 5464 (subsidy returned will be for block 5465)
nPrevBits = 0x1c29ec00;
nPrevHeight = 5464;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 2100000000ULL);

// details for block 5465 (subsidy returned will be for block 5466)
nPrevBits = 0x1c29ec00;
nPrevHeight = 5465;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 12200000000ULL);

// details for block 17588 (subsidy returned will be for block 17589)
nPrevBits = 0x1c08ba34;
nPrevHeight = 17588;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 6100000000ULL);

// details for block 99999 (subsidy returned will be for block 100000)
nPrevBits = 0x1b10cf42;
nPrevHeight = 99999;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 500000000ULL);

// details for block 210239 (subsidy returned will be for block 210240)
nPrevBits = 0x1b11548e;
nPrevHeight = 210239;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 500000000ULL);

// 1st subsidy reduction happens here

// details for block 210240 (subsidy returned will be for block 210241)
nPrevBits = 0x1b10d50b;
nPrevHeight = 210240;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), false);
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 464285715ULL);

// details for block 210240 (subsidy returned will be for block 210241)
// no budgets yet, same results
nPrevBits = 0x1b10d50b;
nPrevHeight = 210240;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ true);
BOOST_CHECK_EQUAL(nSubsidy, 464285715ULL);

// details for block 210240 (subsidy returned will be for block 210241)
// v20 makes no differ for blocks with high enough diff
nPrevBits = 0x1b10d50b;
nPrevHeight = 210240;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ true, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 464285715ULL);

// details for block 420480 (subsidy returned will be for block 210241)
nPrevBits = 0x1b10d50b;
nPrevHeight = 420480;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
BOOST_CHECK_EQUAL(nSubsidy, 388010205ULL);

// details for block 420480 (subsidy returned will be for block 210241)
// budgets are active, reallocation matters now
nPrevBits = 0x1b10d50b;
nPrevHeight = 420480;
nSubsidy = GetBlockSubsidyInner(nPrevBits, nPrevHeight, chainParams->GetConsensus(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ true);
BOOST_CHECK_EQUAL(nSubsidy, 344897960ULL);
}

BOOST_AUTO_TEST_SUITE_END()
Loading

0 comments on commit d6a733c

Please sign in to comment.