Skip to content

Commit

Permalink
Merge pull request #5342 from knst/reward-reallocation
Browse files Browse the repository at this point in the history
  • Loading branch information
PastaPastaPasta committed Sep 5, 2023
2 parents 15ba788 + 759a69e commit bc6360f
Show file tree
Hide file tree
Showing 11 changed files with 157 additions and 44 deletions.
31 changes: 26 additions & 5 deletions src/evo/creditpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,8 @@
#include <evo/assetlocktx.h>
#include <evo/cbtx.h>

#include <llmq/utils.h>

#include <chain.h>
#include <llmq/utils.h>
#include <logging.h>
#include <validation.h>
#include <node/blockstorage.h>
Expand All @@ -19,6 +18,11 @@
#include <memory>
#include <stack>

// Forward declaration to prevent a new circular dependencies through masternode/payments.h
namespace MasternodePayments {
CAmount PlatformShare(const CAmount masternodeReward);
} // namespace MasternodePayments

static const std::string DB_CREDITPOOL_SNAPSHOT = "cpm_S";

std::unique_ptr<CCreditPoolManager> creditPoolManager;
Expand Down Expand Up @@ -213,21 +217,38 @@ CCreditPoolManager::CCreditPoolManager(CEvoDB& _evoDb)

CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams) :
pool(std::move(starter)),
pindex(pindex)
pindex(pindex),
params(consensusParams)
{
assert(pindex);
}

void CCreditPoolDiff::AddRewardRealloced(const CAmount reward) {
assert(MoneyRange(reward));
platformReward += reward;
}

bool CCreditPoolDiff::SetTarget(const CTransaction& tx, TxValidationState& state)
{
CCbTx cbTx;
if (!GetTxPayload(tx, cbTx)) {
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload");
}

if (cbTx.nVersion == 3) {
targetBalance = cbTx.creditPoolBalance;
if (cbTx.nVersion != 3) return true;

targetBalance = cbTx.creditPoolBalance;


if (!llmq::utils::IsMNRewardReallocationActive(pindex)) return true;

CAmount blockReward = 0;
for (const CTxOut& txout : tx.vout) {
blockReward += txout.nValue;
}
platformReward = MasternodePayments::PlatformShare(GetMasternodePayment(cbTx.nHeight, blockReward, params.BRRHeight));
LogPrintf("CreditPool: set target to %lld with MN reward %lld\n", *targetBalance, platformReward);

return true;
}

Expand Down
9 changes: 8 additions & 1 deletion src/evo/creditpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,13 @@ class CCreditPoolDiff {

CAmount sessionLocked{0};
CAmount sessionUnlocked{0};
CAmount platformReward{0};

// target value is used to validate CbTx. If values mismatched, block is invalid
std::optional<CAmount> targetBalance;

const CBlockIndex *pindex{nullptr};
const Consensus::Params& params;
public:
explicit CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams);

Expand All @@ -82,8 +84,13 @@ class CCreditPoolDiff {
*/
bool ProcessTransaction(const CTransaction& tx, TxValidationState& state);

/**
* This function should be called by miner for initialization of MasterNode reward
*/
void AddRewardRealloced(const CAmount reward);

CAmount GetTotalLocked() const {
return pool.locked + sessionLocked - sessionUnlocked;
return pool.locked + sessionLocked - sessionUnlocked + platformReward;
}

const std::optional<CAmount>& GetTargetBalance() const {
Expand Down
1 change: 1 addition & 0 deletions src/llmq/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ bool IsMNRewardReallocationActive(const CBlockIndex* pindex)
{
assert(pindex);
if (!IsV20Active(pindex)) return false;
if (Params().NetworkIDString() == CBaseChainParams::TESTNET) return IsV20Active(pindex); // TODO remove this before re-hardforking testnet to check EHF

LOCK(cs_llmq_vbc);
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache) == ThresholdState::ACTIVE;
Expand Down
55 changes: 39 additions & 16 deletions src/masternode/payments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <governance/governance.h>
#include <key_io.h>
#include <logging.h>
#include <llmq/utils.h>
#include <masternode/sync.h>
#include <primitives/block.h>
#include <script/standard.h>
Expand All @@ -20,26 +21,34 @@
#include <util/system.h>
#include <validation.h>

#include <cassert>
#include <string>

/**
* GetMasternodeTxOuts
*
* Get masternode payment tx outputs
*/

static bool GetBlockTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
[[nodiscard]] static bool GetBlockTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
{
voutMasternodePaymentsRet.clear();

CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);

const CBlockIndex* pindex = WITH_LOCK(cs_main, return ::ChainActive()[nBlockHeight - 1]);
bool fMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(pindex);

if (fMNRewardReallocated) {
const CAmount platformReward = MasternodePayments::PlatformShare(masternodeReward);
masternodeReward -= platformReward;

assert(MoneyRange(masternodeReward));

LogPrint(BCLog::MNPAYMENTS, "CMasternodePayments::%s -- MN reward %lld reallocated to credit pool\n", __func__, platformReward);
voutMasternodePaymentsRet.emplace_back(platformReward, CScript() << OP_RETURN);
}

auto dmnPayee = deterministicMNManager->GetListForBlock(pindex).GetMNPayee(pindex);
if (!dmnPayee) {
return false;
}

CAmount operatorReward = 0;
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);

if (dmnPayee->nOperatorReward != 0 && dmnPayee->pdmnState->scriptOperatorPayout != CScript()) {
// This calculation might eventually turn out to result in 0 even if an operator reward percentage is given.
Expand All @@ -59,27 +68,32 @@ static bool GetBlockTxOuts(const int nBlockHeight, const CAmount blockReward, st
}


static bool GetMasternodeTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
/**
* GetMasternodeTxOuts
*
* Get masternode payment tx outputs
*/
[[nodiscard]] static bool GetMasternodeTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
{
// make sure it's not filled yet
voutMasternodePaymentsRet.clear();

if(!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePaymentsRet)) {
LogPrintf("CMasternodePayments::%s -- no payee (deterministic masternode list empty)\n", __func__);
LogPrintf("MasternodePayments::%s -- no payee (deterministic masternode list empty)\n", __func__);
return false;
}

for (const auto& txout : voutMasternodePaymentsRet) {
CTxDestination dest;
ExtractDestination(txout.scriptPubKey, dest);

LogPrintf("CMasternodePayments::%s -- Masternode payment %lld to %s\n", __func__, txout.nValue, EncodeDestination(dest));
LogPrintf("MasternodePayments::%s -- Masternode payment %lld to %s\n", __func__, txout.nValue, EncodeDestination(dest));
}

return true;
}

static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight, const CAmount blockReward)
[[nodiscard]] static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight, const CAmount blockReward)
{
if (!deterministicMNManager->IsDIP3Enforced(nBlockHeight)) {
// can't verify historical blocks here
Expand All @@ -88,7 +102,7 @@ static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight

std::vector<CTxOut> voutMasternodePayments;
if (!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePayments)) {
LogPrintf("CMasternodePayments::%s -- ERROR failed to get payees for block at height %s\n", __func__, nBlockHeight);
LogPrintf("MasternodePayments::%s -- ERROR failed to get payees for block at height %s\n", __func__, nBlockHeight);
return true;
}

Expand All @@ -98,7 +112,7 @@ static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight
CTxDestination dest;
if (!ExtractDestination(txout.scriptPubKey, dest))
assert(false);
LogPrintf("CMasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, EncodeDestination(dest), nBlockHeight);
LogPrintf("MasternodePayments::%s -- ERROR failed to find expected payee %s in block at height %s\n", __func__, EncodeDestination(dest), nBlockHeight);
return false;
}
}
Expand Down Expand Up @@ -147,7 +161,7 @@ static bool IsOldBudgetBlockValueValid(const CMasternodeSync& mn_sync, const CBl
return isBlockRewardValueMet;
}

namespace CMasternodePayments {
namespace MasternodePayments {

/**
* IsBlockValueValid
Expand Down Expand Up @@ -329,4 +343,13 @@ void FillBlockPayments(const CSporkManager& sporkManager, CGovernanceManager& go
nBlockHeight, blockReward, voutMasternodeStr, txNew.ToString());
}

} // namespace CMasternodePayments
CAmount PlatformShare(const CAmount reward)
{
constexpr double platformShare = 0.375;
const CAmount platformReward = reward * platformShare;
assert(MoneyRange(platformReward));

return platformReward;
}

} // namespace MasternodePayments
19 changes: 13 additions & 6 deletions src/masternode/payments.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ class CSporkManager;
class CTxOut;
class CMasternodeSync;

//
// Masternode Payments Class
// Keeps track of who should get paid for which blocks
//
/**
* Masternode Payments Namespace
* Helpers to kees track of who should get paid for which blocks
*/

namespace CMasternodePayments
namespace MasternodePayments
{
bool IsBlockValueValid(const CSporkManager& sporkManager, CGovernanceManager& governanceManager, const CMasternodeSync& mn_sync,
const CBlock& block, const int nBlockHeight, const CAmount blockReward, std::string& strErrorRet);
Expand All @@ -32,6 +32,13 @@ bool IsBlockPayeeValid(const CSporkManager& sporkManager, CGovernanceManager& go
void FillBlockPayments(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
CMutableTransaction& txNew, const int nBlockHeight, const CAmount blockReward,
std::vector<CTxOut>& voutMasternodePaymentsRet, std::vector<CTxOut>& voutSuperblockPaymentsRet);
} // namespace CMasternodePayments

/**
* this helper returns amount that should be reallocated to platform
* it is calculated based on total amount of Masternode rewards (not block reward)
*/
CAmount PlatformShare(const CAmount masternodeReward);

} // namespace MasternodePayments

#endif // BITCOIN_MASTERNODE_PAYMENTS_H
10 changes: 9 additions & 1 deletion src/miner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,14 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
LogPrintf("CreateNewBlock() h[%d] CbTx failed to find best CL. Inserting null CL\n", nHeight);
}
assert(creditPoolDiff != std::nullopt);

bool fMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(pindexPrev);
if (fMNRewardReallocated) {
const CAmount masternodeReward = GetMasternodePayment(nHeight, blockReward, Params().GetConsensus().BRRHeight);
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);
}
cbTx.creditPoolBalance = creditPoolDiff->GetTotalLocked();
}
}
Expand All @@ -240,7 +248,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc

// Update coinbase transaction with additional info about masternode and governance payments,
// get some info back to pass to getblocktemplate
CMasternodePayments::FillBlockPayments(spork_manager, governance_manager, coinbaseTx, nHeight, blockReward, pblocktemplate->voutMasternodePayments, pblocktemplate->voutSuperblockPayments);
MasternodePayments::FillBlockPayments(spork_manager, governance_manager, coinbaseTx, nHeight, blockReward, pblocktemplate->voutMasternodePayments, pblocktemplate->voutSuperblockPayments);

pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
pblocktemplate->vTxFees[0] = -nFees;
Expand Down
2 changes: 1 addition & 1 deletion src/rpc/masternode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ static UniValue masternode_payments(const JSONRPCRequest& request, const Chainst
std::vector<CTxOut> voutMasternodePayments, voutDummy;
CMutableTransaction dummyTx;
CAmount blockReward = nBlockFees + GetBlockSubsidy(pindex, Params().GetConsensus());
CMasternodePayments::FillBlockPayments(*sporkManager, *governance, dummyTx, pindex->nHeight, blockReward, voutMasternodePayments, voutDummy);
MasternodePayments::FillBlockPayments(*sporkManager, *governance, dummyTx, pindex->nHeight, blockReward, voutMasternodePayments, voutDummy);

UniValue blockObj(UniValue::VOBJ);
CAmount payedPerBlock{0};
Expand Down
36 changes: 26 additions & 10 deletions src/test/block_reward_reallocation_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
#include <llmq/chainlocks.h>
#include <llmq/context.h>
#include <llmq/instantsend.h>
#include <llmq/utils.h>
#include <masternode/payments.h>
#include <util/enumerate.h>
#include <util/irange.h>

Expand Down Expand Up @@ -201,7 +203,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
LOCK(cs_main);
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash()));
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
}
Expand All @@ -212,7 +214,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS

{
LOCK(cs_main);
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 13748571607);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
Expand All @@ -227,7 +229,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
CreateAndProcessBlock({}, coinbaseKey);
}
LOCK(cs_main);
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
}
Expand All @@ -236,7 +238,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
{
// Reward split should reach ~60/40 after reallocation is done
LOCK(cs_main);
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 10221599170);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
Expand All @@ -250,19 +252,33 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
CreateAndProcessBlock({}, coinbaseKey);
}
LOCK(cs_main);
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);

CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
const auto pblocktemplate = BlockAssembler(*sporkManager, *governance, *m_node.llmq_ctx, *m_node.evodb, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);

bool isMNRewardReallocated = llmq::utils::IsMNRewardReallocationActive(::ChainActive().Tip());
if (isMNRewardReallocated) {
const CAmount platform_payment = MasternodePayments::PlatformShare(masternode_payment);
masternode_payment -= platform_payment;
}
size_t payment_index = isMNRewardReallocated ? 1 : 0;

BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[payment_index].nValue, masternode_payment);
}

{
{ // At this moment Masternode reward should be reallocated to platform
// Reward split should reach ~60/40 after reallocation is done
LOCK(cs_main);
auto masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
CAmount masternode_payment = GetMasternodePayment(::ChainActive().Height(), GetBlockSubsidyInner(::ChainActive().Tip()->nBits, ::ChainActive().Height(), consensus_params), 2500);
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, ::ChainstateActive(), *m_node.mempool, Params()).CreateNewBlock(coinbasePubKey);
BOOST_CHECK_EQUAL(pblocktemplate->block.vtx[0]->GetValueOut(), 9491484944);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, 5694890966); // 0.6

BOOST_CHECK(llmq::utils::IsMNRewardReallocationActive(::ChainActive().Tip()));

BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[1].nValue, masternode_payment);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[1].nValue, 3559306854); // 0.6
}
}

Expand Down
Loading

0 comments on commit bc6360f

Please sign in to comment.