Skip to content

Commit b5d1405

Browse files
committed
feat: masternode payment reallocation from coin base to platform
Move funds from the coinbase, into the Asset Lock Pool. This is to incentivize MNs to upgrade to platform, because only MNs running platform will get these migrated rewards
1 parent 77c0c34 commit b5d1405

File tree

9 files changed

+76
-10
lines changed

9 files changed

+76
-10
lines changed

src/evo/creditpool.cpp

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
#include <evo/assetlocktx.h>
88
#include <evo/cbtx.h>
99

10-
#include <llmq/utils.h>
11-
1210
#include <chain.h>
11+
#include <llmq/utils.h>
1312
#include <logging.h>
13+
#include <spork.h>
1414
#include <util/validation.h>
1515
#include <validation.h>
1616

@@ -251,16 +251,31 @@ CCreditPoolDiff::CCreditPoolDiff(CCreditPool starter, const CBlockIndex *pindex,
251251
assert(pindex);
252252
}
253253

254+
void CCreditPoolDiff::addRewardRealloced(const CAmount reward) {
255+
masternodeReward += reward;
256+
}
257+
254258
bool CCreditPoolDiff::setTarget(const CTransaction& tx, TxValidationState& state)
255259
{
256260
CCbTx cbTx;
257261
if (!GetTxPayload(tx, cbTx)) {
258262
return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-cbtx-payload");
259263
}
260264

261-
if (cbTx.nVersion == 3) {
262-
targetLocked = cbTx.assetLockedAmount;
265+
if (cbTx.nVersion != 3) return true;
266+
267+
targetLocked = cbTx.assetLockedAmount;
268+
269+
270+
if (isIgnoringMNRewardReallocation(*sporkManager)) return true;
271+
272+
CAmount blockReward = 0;
273+
for (const CTxOut& txout : tx.vout) {
274+
blockReward += txout.nValue;
263275
}
276+
masternodeReward = GetMasternodePayment(cbTx.nHeight, blockReward, Params().GetConsensus().BRRHeight);
277+
LogPrintf("CreditPool: set target to %lld with MN reward %lld\n", *targetLocked, masternodeReward);
278+
264279
return true;
265280
}
266281

@@ -333,3 +348,11 @@ bool CCreditPoolDiff::processTransaction(const CTransaction& tx, TxValidationSta
333348
return state.Invalid(TxValidationResult::TX_CONSENSUS, "failed-procassetlocksinblock");
334349
}
335350
}
351+
352+
bool isIgnoringMNRewardReallocation(const CSporkManager& spork_manager) {
353+
if (Params().NetworkIDString() != CBaseChainParams::REGTEST) return false;
354+
355+
bool ret = spork_manager.IsSporkActive(SPORK_24_IGNORE_MN_REWARD_REALLOCED);
356+
LogPrintf("%s: spork IGNORE_MN_REWARD_REALLOCED value: %d\n", __func__, ret);
357+
return ret;
358+
}

src/evo/creditpool.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
class CBlockIndex;
2323
class TxValidationState;
24+
class CSporkManager;
2425

2526
namespace Consensus
2627
{
@@ -103,6 +104,7 @@ class CCreditPoolDiff {
103104

104105
CAmount sessionLocked{0};
105106
CAmount sessionUnlocked{0};
107+
CAmount masternodeReward{0};
106108

107109
// target value is used to validate CbTx. If values mismatched, block is invalid
108110
std::optional<CAmount> targetLocked;
@@ -118,8 +120,14 @@ class CCreditPoolDiff {
118120
*/
119121
bool processTransaction(const CTransaction& tx, TxValidationState& state);
120122

123+
/**
124+
* This function should be called by miner for initalization of MasterNode reward
125+
*
126+
*/
127+
void addRewardRealloced(const CAmount reward);
128+
121129
CAmount getTotalLocked() const {
122-
return pool.locked + sessionLocked - sessionUnlocked;
130+
return pool.locked + sessionLocked - sessionUnlocked + masternodeReward;
123131
}
124132

125133
const std::optional<CAmount>& getTargetLocked() const {
@@ -170,6 +178,8 @@ class CCreditPoolManager
170178
CCreditPool constructCreditPool(const CBlockIndex* block_index, CCreditPool prev, const Consensus::Params& consensusParams);
171179
};
172180

181+
bool isIgnoringMNRewardReallocation(const CSporkManager& spork_manager);
182+
173183
extern std::unique_ptr<CCreditPoolManager> creditPoolManager;
174184

175185
#endif

src/evo/specialtxman.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@
1717
#include <llmq/commitment.h>
1818
#include <llmq/utils.h>
1919
#include <primitives/block.h>
20+
#include <spork.h>
2021
#include <validation.h>
2122

23+
#include <masternode/payments.h>
2224
bool CheckSpecialTx(const CTransaction& tx, const CBlockIndex* pindexPrev, const CCoinsViewCache& view, const CCreditPool& creditPool, bool check_sigs, TxValidationState& state)
2325
{
2426
AssertLockHeld(cs_main);

src/masternode/payments.cpp

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,16 @@
1212
#include <governance/governance.h>
1313
#include <key_io.h>
1414
#include <logging.h>
15+
#include <llmq/utils.h>
1516
#include <masternode/sync.h>
1617
#include <primitives/block.h>
1718
#include <script/standard.h>
19+
#include <spork.h>
1820
#include <tinyformat.h>
1921
#include <util/ranges.h>
2022
#include <util/system.h>
2123
#include <validation.h>
22-
24+
#include <evo/creditpool.h>
2325
#include <string>
2426

2527
CMasternodePayments mnpayments;
@@ -276,22 +278,28 @@ bool CMasternodePayments::GetBlockTxOuts(int nBlockHeight, CAmount blockReward,
276278
{
277279
voutMasternodePaymentsRet.clear();
278280

281+
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);
282+
283+
bool fV20Active_context = llmq::utils::IsV20Active(::ChainActive().Tip());
284+
if (fV20Active_context && !isIgnoringMNRewardReallocation(*sporkManager)) {
285+
LogPrintf("CMasternodePayments::%s -- MN reward %lld reallocated to credit pool\n", __func__, masternodeReward);
286+
voutMasternodePaymentsRet.emplace_back(masternodeReward, CScript() << OP_RETURN);
287+
return true;
288+
}
289+
279290
const CBlockIndex* pindex = WITH_LOCK(cs_main, return ::ChainActive()[nBlockHeight - 1]);
280291
auto dmnPayee = deterministicMNManager->GetListForBlock(pindex).GetMNPayee(pindex);
281292
if (!dmnPayee) {
282293
return false;
283294
}
284295

285296
CAmount operatorReward = 0;
286-
CAmount masternodeReward = GetMasternodePayment(nBlockHeight, blockReward, Params().GetConsensus().BRRHeight);
287-
288297
if (dmnPayee->nOperatorReward != 0 && dmnPayee->pdmnState->scriptOperatorPayout != CScript()) {
289298
// This calculation might eventually turn out to result in 0 even if an operator reward percentage is given.
290299
// This will however only happen in a few years when the block rewards drops very low.
291300
operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000;
292301
masternodeReward -= operatorReward;
293302
}
294-
295303
if (masternodeReward > 0) {
296304
voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout);
297305
}

src/miner.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,17 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(CChainState& chai
232232
LogPrintf("CreateNewBlock() height[%d] CBTx bestCLHeightDiff[%d] CLSig[%s]\n", nHeight, cbTx.bestCLHeightDiff, cbTx.bestCLSignature.ToString());
233233
}
234234
assert(creditPoolDiff);
235+
236+
if (!isIgnoringMNRewardReallocation(spork_manager)) {
237+
if (!CMasternodePayments::GetMasternodeTxOuts(nHeight, blockReward, pblocktemplate->voutMasternodePayments)) {
238+
LogPrint(BCLog::MNPAYMENTS, "%s -- no masternode to pay (MN list probably empty)\n", __func__);
239+
}
240+
for (const auto& txout : pblocktemplate->voutMasternodePayments) {
241+
// subtract MN payment from miner reward
242+
LogPrintf("CreateNewBlock() add MN reward %lld to credit pool\n", txout.nValue);
243+
creditPoolDiff->addRewardRealloced(txout.nValue);
244+
}
245+
}
235246
cbTx.assetLockedAmount = creditPoolDiff->getTotalLocked();
236247
}
237248
}

src/spork.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ enum SporkId : int32_t {
3838
SPORK_19_CHAINLOCKS_ENABLED = 10018,
3939
SPORK_21_QUORUM_ALL_CONNECTED = 10020,
4040
SPORK_23_QUORUM_POSE = 10022,
41+
SPORK_24_IGNORE_MN_REWARD_REALLOCED = 10023,
4142

4243
SPORK_INVALID = -1,
4344
};
@@ -63,14 +64,15 @@ struct CSporkDef
6364
};
6465

6566
#define MAKE_SPORK_DEF(name, defaultValue) CSporkDef{name, defaultValue, #name}
66-
[[maybe_unused]] static constexpr std::array<CSporkDef, 7> sporkDefs = {
67+
[[maybe_unused]] static constexpr std::array<CSporkDef, 8> sporkDefs = {
6768
MAKE_SPORK_DEF(SPORK_2_INSTANTSEND_ENABLED, 4070908800ULL), // OFF
6869
MAKE_SPORK_DEF(SPORK_3_INSTANTSEND_BLOCK_FILTERING, 4070908800ULL), // OFF
6970
MAKE_SPORK_DEF(SPORK_9_SUPERBLOCKS_ENABLED, 4070908800ULL), // OFF
7071
MAKE_SPORK_DEF(SPORK_17_QUORUM_DKG_ENABLED, 4070908800ULL), // OFF
7172
MAKE_SPORK_DEF(SPORK_19_CHAINLOCKS_ENABLED, 4070908800ULL), // OFF
7273
MAKE_SPORK_DEF(SPORK_21_QUORUM_ALL_CONNECTED, 4070908800ULL), // OFF
7374
MAKE_SPORK_DEF(SPORK_23_QUORUM_POSE, 4070908800ULL), // OFF
75+
MAKE_SPORK_DEF(SPORK_24_IGNORE_MN_REWARD_REALLOCED, 4070908800ULL), // OFF
7476
};
7577
#undef MAKE_SPORK_DEF
7678
extern std::unique_ptr<CSporkManager> sporkManager;

src/test/evo_deterministicmns_tests.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,11 @@ void FuncDIP3Protx(TestChainSetup& setup)
271271
sporkManager->SetSporkAddress(EncodeDestination(PKHash(sporkKey.GetPubKey())));
272272
sporkManager->SetPrivKey(EncodeSecret(sporkKey));
273273

274+
// broadcast new spork
275+
if (sporkManager->UpdateSpork(SporkId::SPORK_24_IGNORE_MN_REWARD_REALLOCED, 0, *setup.m_node.connman)) {
276+
LogPrintf("spork SPORK_24_IGNORE_MN_REWARD_REALLOCED updated\n");
277+
}
278+
274279
auto utxos = BuildSimpleUtxoMap(setup.m_coinbase_txns);
275280

276281
int nHeight = ::ChainActive().Height();

test/functional/feature_asset_locks.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,8 @@ def set_sporks(self):
169169
self.nodes[0].sporkupdate("SPORK_19_CHAINLOCKS_ENABLED", spork_disabled)
170170
self.nodes[0].sporkupdate("SPORK_3_INSTANTSEND_BLOCK_FILTERING", spork_disabled)
171171
self.nodes[0].sporkupdate("SPORK_2_INSTANTSEND_ENABLED", spork_disabled)
172+
self.nodes[0].sporkupdate("SPORK_24_IGNORE_MN_REWARD_REALLOCED", spork_enabled)
173+
172174
self.wait_for_sporks_same()
173175

174176
def ensure_tx_is_not_mined(self, tx_id):

test/functional/feature_llmq_is_cl_conflicts.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
from test_framework.test_framework import DashTestFramework
2121
from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes, get_bip9_status, wait_until
2222

23+
from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE
2324

2425
class TestP2PConn(P2PInterface):
2526
def __init__(self):
@@ -317,6 +318,8 @@ def create_block(self, node, vtx=None):
317318

318319
outputs = {miner_address: str(Decimal(miner_amount) / COIN)}
319320
if mn_amount > 0:
321+
if mn_payee is None or mn_payee == '':
322+
mn_payee = ADDRESS_BCRT1_UNSPENDABLE
320323
outputs[mn_payee] = str(Decimal(mn_amount) / COIN)
321324

322325
coinbase = FromHex(CTransaction(), node.createrawtransaction([], outputs))

0 commit comments

Comments
 (0)