Merge pull request #5342 from knst/reward-reallocation

This commit is contained in:
pasta 2023-09-05 11:39:48 -05:00
commit bc6360f6aa
No known key found for this signature in database
GPG Key ID: 52527BEDABE87984
11 changed files with 157 additions and 44 deletions

View File

@ -7,9 +7,8 @@
#include <evo/assetlocktx.h> #include <evo/assetlocktx.h>
#include <evo/cbtx.h> #include <evo/cbtx.h>
#include <llmq/utils.h>
#include <chain.h> #include <chain.h>
#include <llmq/utils.h>
#include <logging.h> #include <logging.h>
#include <validation.h> #include <validation.h>
#include <node/blockstorage.h> #include <node/blockstorage.h>
@ -19,6 +18,11 @@
#include <memory> #include <memory>
#include <stack> #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"; static const std::string DB_CREDITPOOL_SNAPSHOT = "cpm_S";
std::unique_ptr<CCreditPoolManager> creditPoolManager; std::unique_ptr<CCreditPoolManager> creditPoolManager;
@ -213,11 +217,17 @@ CCreditPoolManager::CCreditPoolManager(CEvoDB& _evoDb)
CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams) : CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams) :
pool(std::move(starter)), pool(std::move(starter)),
pindex(pindex) pindex(pindex),
params(consensusParams)
{ {
assert(pindex); assert(pindex);
} }
void CCreditPoolDiff::AddRewardRealloced(const CAmount reward) {
assert(MoneyRange(reward));
platformReward += reward;
}
bool CCreditPoolDiff::SetTarget(const CTransaction& tx, TxValidationState& state) bool CCreditPoolDiff::SetTarget(const CTransaction& tx, TxValidationState& state)
{ {
CCbTx cbTx; CCbTx cbTx;
@ -225,9 +235,20 @@ bool CCreditPoolDiff::SetTarget(const CTransaction& tx, TxValidationState& state
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload"); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload");
} }
if (cbTx.nVersion == 3) { if (cbTx.nVersion != 3) return true;
targetBalance = cbTx.creditPoolBalance;
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; return true;
} }

View File

@ -67,11 +67,13 @@ private:
CAmount sessionLocked{0}; CAmount sessionLocked{0};
CAmount sessionUnlocked{0}; CAmount sessionUnlocked{0};
CAmount platformReward{0};
// target value is used to validate CbTx. If values mismatched, block is invalid // target value is used to validate CbTx. If values mismatched, block is invalid
std::optional<CAmount> targetBalance; std::optional<CAmount> targetBalance;
const CBlockIndex *pindex{nullptr}; const CBlockIndex *pindex{nullptr};
const Consensus::Params& params;
public: public:
explicit CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams); explicit CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex, const Consensus::Params& consensusParams);
@ -82,8 +84,13 @@ public:
*/ */
bool ProcessTransaction(const CTransaction& tx, TxValidationState& state); 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 { CAmount GetTotalLocked() const {
return pool.locked + sessionLocked - sessionUnlocked; return pool.locked + sessionLocked - sessionUnlocked + platformReward;
} }
const std::optional<CAmount>& GetTargetBalance() const { const std::optional<CAmount>& GetTargetBalance() const {

View File

@ -728,6 +728,7 @@ bool IsMNRewardReallocationActive(const CBlockIndex* pindex)
{ {
assert(pindex); assert(pindex);
if (!IsV20Active(pindex)) return false; 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); LOCK(cs_llmq_vbc);
return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache) == ThresholdState::ACTIVE; return VersionBitsState(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_MN_RR, llmq_versionbitscache) == ThresholdState::ACTIVE;

View File

@ -12,6 +12,7 @@
#include <governance/governance.h> #include <governance/governance.h>
#include <key_io.h> #include <key_io.h>
#include <logging.h> #include <logging.h>
#include <llmq/utils.h>
#include <masternode/sync.h> #include <masternode/sync.h>
#include <primitives/block.h> #include <primitives/block.h>
#include <script/standard.h> #include <script/standard.h>
@ -20,26 +21,34 @@
#include <util/system.h> #include <util/system.h>
#include <validation.h> #include <validation.h>
#include <cassert>
#include <string> #include <string>
/** [[nodiscard]] static bool GetBlockTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
* GetMasternodeTxOuts
*
* Get masternode payment tx outputs
*/
static bool GetBlockTxOuts(const int nBlockHeight, const CAmount blockReward, std::vector<CTxOut>& voutMasternodePaymentsRet)
{ {
voutMasternodePaymentsRet.clear(); voutMasternodePaymentsRet.clear();
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);
const CBlockIndex* pindex = WITH_LOCK(cs_main, return ::ChainActive()[nBlockHeight - 1]); 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); auto dmnPayee = deterministicMNManager->GetListForBlock(pindex).GetMNPayee(pindex);
if (!dmnPayee) { if (!dmnPayee) {
return false; return false;
} }
CAmount operatorReward = 0; CAmount operatorReward = 0;
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);
if (dmnPayee->nOperatorReward != 0 && dmnPayee->pdmnState->scriptOperatorPayout != CScript()) { 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. // This calculation might eventually turn out to result in 0 even if an operator reward percentage is given.
@ -59,13 +68,18 @@ 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 // make sure it's not filled yet
voutMasternodePaymentsRet.clear(); voutMasternodePaymentsRet.clear();
if(!GetBlockTxOuts(nBlockHeight, blockReward, voutMasternodePaymentsRet)) { 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; return false;
} }
@ -73,13 +87,13 @@ static bool GetMasternodeTxOuts(const int nBlockHeight, const CAmount blockRewar
CTxDestination dest; CTxDestination dest;
ExtractDestination(txout.scriptPubKey, 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; 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)) { if (!deterministicMNManager->IsDIP3Enforced(nBlockHeight)) {
// can't verify historical blocks here // can't verify historical blocks here
@ -88,7 +102,7 @@ static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight
std::vector<CTxOut> voutMasternodePayments; std::vector<CTxOut> voutMasternodePayments;
if (!GetBlockTxOuts(nBlockHeight, blockReward, 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; return true;
} }
@ -98,7 +112,7 @@ static bool IsTransactionValid(const CTransaction& txNew, const int nBlockHeight
CTxDestination dest; CTxDestination dest;
if (!ExtractDestination(txout.scriptPubKey, dest)) if (!ExtractDestination(txout.scriptPubKey, dest))
assert(false); 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; return false;
} }
} }
@ -147,7 +161,7 @@ static bool IsOldBudgetBlockValueValid(const CMasternodeSync& mn_sync, const CBl
return isBlockRewardValueMet; return isBlockRewardValueMet;
} }
namespace CMasternodePayments { namespace MasternodePayments {
/** /**
* IsBlockValueValid * IsBlockValueValid
@ -329,4 +343,13 @@ void FillBlockPayments(const CSporkManager& sporkManager, CGovernanceManager& go
nBlockHeight, blockReward, voutMasternodeStr, txNew.ToString()); 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

View File

@ -18,12 +18,12 @@ class CSporkManager;
class CTxOut; class CTxOut;
class CMasternodeSync; class CMasternodeSync;
// /**
// Masternode Payments Class * Masternode Payments Namespace
// Keeps track of who should get paid for which blocks * 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, bool IsBlockValueValid(const CSporkManager& sporkManager, CGovernanceManager& governanceManager, const CMasternodeSync& mn_sync,
const CBlock& block, const int nBlockHeight, const CAmount blockReward, std::string& strErrorRet); const CBlock& block, const int nBlockHeight, const CAmount blockReward, std::string& strErrorRet);
@ -32,6 +32,13 @@ bool IsBlockPayeeValid(const CSporkManager& sporkManager, CGovernanceManager& go
void FillBlockPayments(const CSporkManager& sporkManager, CGovernanceManager& governanceManager, void FillBlockPayments(const CSporkManager& sporkManager, CGovernanceManager& governanceManager,
CMutableTransaction& txNew, const int nBlockHeight, const CAmount blockReward, CMutableTransaction& txNew, const int nBlockHeight, const CAmount blockReward,
std::vector<CTxOut>& voutMasternodePaymentsRet, std::vector<CTxOut>& voutSuperblockPaymentsRet); 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 #endif // BITCOIN_MASTERNODE_PAYMENTS_H

View File

@ -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); LogPrintf("CreateNewBlock() h[%d] CbTx failed to find best CL. Inserting null CL\n", nHeight);
} }
assert(creditPoolDiff != std::nullopt); 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(); cbTx.creditPoolBalance = creditPoolDiff->GetTotalLocked();
} }
} }
@ -240,7 +248,7 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
// Update coinbase transaction with additional info about masternode and governance payments, // Update coinbase transaction with additional info about masternode and governance payments,
// get some info back to pass to getblocktemplate // 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)); pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
pblocktemplate->vTxFees[0] = -nFees; pblocktemplate->vTxFees[0] = -nFees;

View File

@ -460,7 +460,7 @@ static UniValue masternode_payments(const JSONRPCRequest& request, const Chainst
std::vector<CTxOut> voutMasternodePayments, voutDummy; std::vector<CTxOut> voutMasternodePayments, voutDummy;
CMutableTransaction dummyTx; CMutableTransaction dummyTx;
CAmount blockReward = nBlockFees + GetBlockSubsidy(pindex, Params().GetConsensus()); 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); UniValue blockObj(UniValue::VOBJ);
CAmount payedPerBlock{0}; CAmount payedPerBlock{0};

View File

@ -25,6 +25,8 @@
#include <llmq/chainlocks.h> #include <llmq/chainlocks.h>
#include <llmq/context.h> #include <llmq/context.h>
#include <llmq/instantsend.h> #include <llmq/instantsend.h>
#include <llmq/utils.h>
#include <masternode/payments.h>
#include <util/enumerate.h> #include <util/enumerate.h>
#include <util/irange.h> #include <util/irange.h>
@ -201,7 +203,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
LOCK(cs_main); LOCK(cs_main);
deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip()); deterministicMNManager->UpdatedBlockTip(::ChainActive().Tip());
BOOST_ASSERT(deterministicMNManager->GetListAtChainTip().HasMN(tx.GetHash())); 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); 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); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
} }
@ -212,7 +214,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
{ {
LOCK(cs_main); 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); 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->block.vtx[0]->GetValueOut(), 13748571607);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
@ -227,7 +229,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
CreateAndProcessBlock({}, coinbaseKey); CreateAndProcessBlock({}, coinbaseKey);
} }
LOCK(cs_main); 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); 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); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
} }
@ -236,7 +238,7 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
{ {
// Reward split should reach ~60/40 after reallocation is done // Reward split should reach ~60/40 after reallocation is done
LOCK(cs_main); 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); 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->block.vtx[0]->GetValueOut(), 10221599170);
BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment); BOOST_CHECK_EQUAL(pblocktemplate->voutMasternodePayments[0].nValue, masternode_payment);
@ -250,19 +252,33 @@ BOOST_FIXTURE_TEST_CASE(block_reward_reallocation, TestChainBRRBeforeActivationS
CreateAndProcessBlock({}, coinbaseKey); CreateAndProcessBlock({}, coinbaseKey);
} }
LOCK(cs_main); 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); 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 // Reward split should reach ~60/40 after reallocation is done
LOCK(cs_main); 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); 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->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
} }
} }

View File

@ -2413,7 +2413,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
int64_t nTime5_2 = GetTimeMicros(); nTimeSubsidy += nTime5_2 - nTime5_1; int64_t nTime5_2 = GetTimeMicros(); nTimeSubsidy += nTime5_2 - nTime5_1;
LogPrint(BCLog::BENCHMARK, " - GetBlockSubsidy: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5_2 - nTime5_1), nTimeSubsidy * MICRO, nTimeSubsidy * MILLI / nBlocksTotal); LogPrint(BCLog::BENCHMARK, " - GetBlockSubsidy: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5_2 - nTime5_1), nTimeSubsidy * MICRO, nTimeSubsidy * MILLI / nBlocksTotal);
if (!CMasternodePayments::IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) { if (!MasternodePayments::IsBlockValueValid(*sporkManager, *governance, *::masternodeSync, block, pindex->nHeight, blockReward, strError)) {
// NOTE: Do not punish, the node might be missing governance data // NOTE: Do not punish, the node might be missing governance data
LogPrintf("ERROR: ConnectBlock(DASH): %s\n", strError); LogPrintf("ERROR: ConnectBlock(DASH): %s\n", strError);
return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-amount"); return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-amount");
@ -2422,7 +2422,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2; int64_t nTime5_3 = GetTimeMicros(); nTimeValueValid += nTime5_3 - nTime5_2;
LogPrint(BCLog::BENCHMARK, " - IsBlockValueValid: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5_3 - nTime5_2), nTimeValueValid * MICRO, nTimeValueValid * MILLI / nBlocksTotal); LogPrint(BCLog::BENCHMARK, " - IsBlockValueValid: %.2fms [%.2fs (%.2fms/blk)]\n", MILLI * (nTime5_3 - nTime5_2), nTimeValueValid * MICRO, nTimeValueValid * MILLI / nBlocksTotal);
if (!CMasternodePayments::IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) { if (!MasternodePayments::IsBlockPayeeValid(*sporkManager, *governance, *block.vtx[0], pindex->nHeight, blockReward)) {
// NOTE: Do not punish, the node might be missing governance data // NOTE: Do not punish, the node might be missing governance data
LogPrintf("ERROR: ConnectBlock(DASH): couldn't find masternode or superblock payments\n"); LogPrintf("ERROR: ConnectBlock(DASH): couldn't find masternode or superblock payments\n");
return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-payee"); return state.Invalid(BlockValidationResult::BLOCK_RESULT_UNSET, "bad-cb-payee");

View File

@ -288,6 +288,7 @@ class AssetLocksTest(DashTestFramework):
self.mine_quorum() self.mine_quorum()
self.validate_credit_pool_balance(locked_1) self.validate_credit_pool_balance(locked_1)
self.log.info("Testing asset unlock...") self.log.info("Testing asset unlock...")
self.log.info("Generating several txes by same quorum....") self.log.info("Generating several txes by same quorum....")
@ -300,7 +301,7 @@ class AssetLocksTest(DashTestFramework):
asset_unlock_tx_duplicate_index = copy.deepcopy(asset_unlock_tx) asset_unlock_tx_duplicate_index = copy.deepcopy(asset_unlock_tx)
# modify this tx with duplicated index to make a hash of tx different, otherwise tx would be refused too early # modify this tx with duplicated index to make a hash of tx different, otherwise tx would be refused too early
asset_unlock_tx_duplicate_index.vout[0].nValue += COIN asset_unlock_tx_duplicate_index.vout[0].nValue += COIN
too_late_height = node.getblock(node.getbestblockhash())["height"] + 48 too_late_height = node.getblockcount() + 48
self.check_mempool_result(tx=asset_unlock_tx, result_expected={'allowed': True}) self.check_mempool_result(tx=asset_unlock_tx, result_expected={'allowed': True})
self.check_mempool_result(tx=asset_unlock_tx_too_big_fee, self.check_mempool_result(tx=asset_unlock_tx_too_big_fee,
@ -345,7 +346,7 @@ class AssetLocksTest(DashTestFramework):
self.validate_credit_pool_balance(locked_1 - 2 * COIN) self.validate_credit_pool_balance(locked_1 - 2 * COIN)
self.log.info("Generating many blocks to make quorum far behind (even still active)...") self.log.info("Generating many blocks to make quorum far behind (even still active)...")
self.slowly_generate_batch(too_late_height - node.getblock(node.getbestblockhash())["height"] - 1) self.slowly_generate_batch(too_late_height - node.getblockcount() - 1)
self.check_mempool_result(tx=asset_unlock_tx_too_late, result_expected={'allowed': True}) self.check_mempool_result(tx=asset_unlock_tx_too_late, result_expected={'allowed': True})
node.generate(1) node.generate(1)
self.sync_all() self.sync_all()
@ -495,5 +496,33 @@ class AssetLocksTest(DashTestFramework):
assert_equal(new_total, self.get_credit_pool_balance()) assert_equal(new_total, self.get_credit_pool_balance())
self.check_mempool_size() self.check_mempool_size()
self.activate_mn_rr(expected_activation_height=3090)
self.log.info(f'height: {node.getblockcount()} credit: {self.get_credit_pool_balance()}')
bt = node.getblocktemplate()
platform_reward = bt['masternode'][0]['amount']
assert_equal(bt['masternode'][0]['script'], '6a') # empty OP_RETURN
owner_reward = bt['masternode'][1]['amount']
operator_reward = bt['masternode'][2]['amount'] if len(bt['masternode']) == 3 else 0
all_mn_rewards = platform_reward + owner_reward + operator_reward
assert_equal(all_mn_rewards, bt['coinbasevalue'] * 0.6) # 60/40 mn/miner reward split
assert_equal(platform_reward, int(all_mn_rewards * 0.375)) # 0.375 platform share
assert_equal(platform_reward, 2299859813)
assert_equal(new_total, self.get_credit_pool_balance())
node.generate(1)
self.sync_all()
new_total += platform_reward
assert_equal(new_total, self.get_credit_pool_balance())
coin = coins.pop()
self.send_tx(self.create_assetlock(coin, COIN, pubkey))
new_total += platform_reward + COIN
node.generate(1)
self.sync_all()
# part of fee is going to master node reward
# these 2 conditions need to check a range
assert_greater_than(self.get_credit_pool_balance(), new_total)
assert_greater_than(new_total + tiny_amount, self.get_credit_pool_balance())
if __name__ == '__main__': if __name__ == '__main__':
AssetLocksTest().main() AssetLocksTest().main()

View File

@ -1092,6 +1092,7 @@ class DashTestFramework(BitcoinTestFramework):
def activate_v20(self, expected_activation_height=None): def activate_v20(self, expected_activation_height=None):
self.activate_by_name('v20', expected_activation_height) self.activate_by_name('v20', expected_activation_height)
def activate_mn_rr(self, expected_activation_height=None): def activate_mn_rr(self, expected_activation_height=None):
self.activate_by_name('mn_rr', expected_activation_height) self.activate_by_name('mn_rr', expected_activation_height)