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

feat!: Block reward reallocation activation at v20 #5639

Merged
Merged
Show file tree
Hide file tree
Changes from 3 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
10 changes: 10 additions & 0 deletions doc/release-notes-5639.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Block Reward Reallocation
-------------------------

Once v20 activates:

- Treasury is bumped to 20% of block subsidy.
- Block reward shares are immediately set to 60% for MN and 20% miners.

Note: Previous reallocation periods are dropped.
Note: Same changes from PR 5588 but activation is done on v20 instead of Masternode Reward Location Reallocation.
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(), /*fV20Active=*/ false, /*fMNRewardReallocated=*/ false);
coinbaseTx.vout[0].nValue = GetBlockSubsidyInner(block.nBits, nHeight, chainparams.GetConsensus(), /*fV20Active=*/ false);
coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;

naughtyTx.vout.resize(1);
Expand Down
3 changes: 2 additions & 1 deletion src/evo/creditpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,9 @@ bool CCreditPoolDiff::SetTarget(const CTransaction& tx, const CAmount blockSubsi
targetBalance = cbTx.creditPoolBalance;

if (!llmq::utils::IsMNRewardReallocationActive(pindex)) return true;
// We consider V20 active if mn_rr is active

platformReward = MasternodePayments::PlatformShare(GetMasternodePayment(cbTx.nHeight, blockSubsidy, /* reward_reallocation= */ true));
platformReward = MasternodePayments::PlatformShare(GetMasternodePayment(cbTx.nHeight, blockSubsidy, /* v20_active= */ true));
LogPrintf("CreditPool: set target to %lld with MN reward %lld\n", *targetBalance, platformReward);

return true;
Expand Down
15 changes: 7 additions & 8 deletions src/governance/classes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -495,15 +495,14 @@ 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
const auto v20_state = llmq::utils::GetV20State(tipIndex);
bool fV20Active{v20_state == ThresholdState::ACTIVE};
if (!fV20Active && nBlockHeight > tipIndex->nHeight) {
// If fV20Active 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 (v20_state == ThresholdState::LOCKED_IN) {
int activation_height = llmq::utils::GetV20Since(tipIndex) + static_cast<int>(Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_V20].nWindowSize);
if (nBlockHeight >= activation_height) {
fMNRewardReallocated = true;
fV20Active = true;
}
}
Expand All @@ -512,7 +511,7 @@ CAmount CSuperblock::GetPaymentsLimit(int nBlockHeight)
// 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, fV20Active, fMNRewardReallocated);
CAmount nSuperblockPartOfSubsidy = GetSuperblockSubsidyInner(nBits, nBlockHeight - 1, consensusParams, fV20Active);
CAmount nPaymentsLimit = nSuperblockPartOfSubsidy * consensusParams.nSuperblockCycle;
LogPrint(BCLog::GOBJECT, "CSuperblock::GetPaymentsLimit -- Valid superblock height %d, payments max %lld\n", nBlockHeight, nPaymentsLimit);

Expand Down
8 changes: 4 additions & 4 deletions src/llmq/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -729,18 +729,18 @@ bool IsMNRewardReallocationActive(const CBlockIndex* pindex)
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache) == ThresholdState::ACTIVE;
}

ThresholdState GetMNRewardReallocationState(const CBlockIndex* pindex)
ThresholdState GetV20State(const CBlockIndex* pindex)
{
assert(pindex);
LOCK(cs_llmq_vbc);
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache);
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20, llmq_versionbitscache);
}

int GetMNRewardReallocationSince(const CBlockIndex* pindex)
int GetV20Since(const CBlockIndex* pindex)
{
assert(pindex);
LOCK(cs_llmq_vbc);
return VersionBitsStateSinceHeight(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache);
return VersionBitsStateSinceHeight(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V20, llmq_versionbitscache);
}

bool IsInstantSendLLMQTypeShared()
Expand Down
4 changes: 2 additions & 2 deletions src/llmq/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ bool IsDIP0024Active(const CBlockIndex* pindex);
bool IsV19Active(const CBlockIndex* pindex);
bool IsV20Active(const CBlockIndex* pindex);
bool IsMNRewardReallocationActive(const CBlockIndex* pindex);
ThresholdState GetMNRewardReallocationState(const CBlockIndex* pindex);
int GetMNRewardReallocationSince(const CBlockIndex* pindex);
ThresholdState GetV20State(const CBlockIndex* pindex);
int GetV20Since(const CBlockIndex* pindex);

/// Returns the state of `-llmq-data-recovery`
bool QuorumDataRecoveryEnabled();
Expand Down
5 changes: 3 additions & 2 deletions src/masternode/payments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@
const int nBlockHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;

bool fMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(pindexPrev);
bool fV20Active = llmq::utils::IsV20Active(pindexPrev);

CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockSubsidy + feeReward, fMNRewardReallocated);
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockSubsidy + feeReward, fV20Active);
if (fMNRewardReallocated) {
CAmount masternodeSubsidyReward = GetMasternodePayment(nBlockHeight, blockSubsidy, fMNRewardReallocated);
CAmount masternodeSubsidyReward = GetMasternodePayment(nBlockHeight, blockSubsidy, fV20Active);
// TODO remove this when we re-organize testnet
if (Params().NetworkIDString() == CBaseChainParams::TESTNET) {
masternodeSubsidyReward = masternodeReward;
Expand Down
5 changes: 2 additions & 3 deletions src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,8 +193,7 @@ 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);
bool fV20Active = llmq::utils::IsV20Active(pindexPrev);
CAmount blockSubsidy = GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fV20Active, fMNRewardReallocated);
CAmount blockSubsidy = GetBlockSubsidyInner(pindexPrev->nBits, pindexPrev->nHeight, Params().GetConsensus(), fV20Active_context);
CAmount blockReward = blockSubsidy + nFees;

// Compute regular coinbase transaction.
Expand Down Expand Up @@ -238,7 +237,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
assert(creditPoolDiff != std::nullopt);

if (fMNRewardReallocated) {
const CAmount masternodeReward = GetMasternodePayment(nHeight, blockSubsidy, fMNRewardReallocated);
const CAmount masternodeReward = GetMasternodePayment(nHeight, blockSubsidy, fV20Active_context);
const CAmount reallocedReward = MasternodePayments::PlatformShare(masternodeReward);
LogPrint(BCLog::MNPAYMENTS, "%s: add MN reward %lld (%lld) to credit pool\n", __func__, masternodeReward, reallocedReward);
creditPoolDiff->AddRewardRealloced(reallocedReward);
Expand Down
52 changes: 27 additions & 25 deletions src/test/block_reward_reallocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,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)};
deterministicMNManager->UpdatedBlockTip(tip);
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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 @@ -223,13 +222,12 @@ 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 block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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(), 137485721);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 122209530);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 68742860); // 0.4999999998
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 61104762);
}

// Reallocation should kick-in with the superblock mined at height = 2010,
Expand All @@ -242,33 +240,38 @@ 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 block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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);
}
}

BOOST_CHECK(llmq::utils::IsV20Active(m_node.chainman->ActiveChain().Tip()));
// Allocation of block subsidy is 60% MN, 20% miners and 20% treasury
{
// Reward split should reach ~60/40 after reallocation is done
// Reward split should reach ~75/25 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 block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
const CAmount block_subsidy_sb = GetSuperblockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
CAmount block_subsidy_potential = block_subsidy + block_subsidy_sb;
BOOST_CHECK_EQUAL(block_subsidy_potential, 113573330);
CAmount expected_block_reward = block_subsidy_potential - block_subsidy_potential / 5;

const CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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(), 102215997);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), expected_block_reward);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 90858664);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 61329598); // 0.6
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 68143998); // 0.75
}
BOOST_CHECK(!llmq::utils::IsMNRewardReallocationActive(m_node.chainman->ActiveChain().Tip()));

// Activate EHF "MN_RR"
Params().UpdateMNActivationParam(Params().GetConsensus().vDeployments[Consensus::DEPLOYMENT_MN_RR].bit, ::ChainActive().Height(), ::ChainActive().Tip()->GetMedianTimePast(), /*fJustCheck=*/ false);

// Reward split should stay ~60/40 after reallocation is done,
// Reward split should stay ~75/25 after reallocation is done,
// check 10 next superblocks
for ([[maybe_unused]] auto i : irange::range(10)) {
for ([[maybe_unused]] auto k : irange::range(10)) {
Expand All @@ -278,8 +281,8 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
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 block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active, isMNRewardReallocated);
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isMNRewardReallocated);
const CAmount block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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 @@ -297,10 +300,9 @@ 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 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 block_subsidy = GetBlockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
const CAmount block_subsidy_sb = GetSuperblockSubsidyInner(tip->nBits, tip->nHeight, consensus_params, isV20Active);
CAmount masternode_payment = GetMasternodePayment(tip->nHeight, block_subsidy, isV20Active);
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);
Expand Down
Loading
Loading