From 4c731a907fb0290a1a11203c31e64a55a6360802 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Fri, 5 Mar 2021 15:58:25 +0100 Subject: [PATCH 1/6] [Consensus] New DMN payment logic --- src/masternode-payments.cpp | 40 ++++++++++++++++++++++++++++++++----- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/masternode-payments.cpp b/src/masternode-payments.cpp index 9ae558cfa265..1f2715ea2fb0 100644 --- a/src/masternode-payments.cpp +++ b/src/masternode-payments.cpp @@ -308,8 +308,23 @@ std::string GetRequiredPaymentsString(int nBlockHeight) bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std::vector& voutMasternodePaymentsRet) const { if (deterministicMNManager->LegacyMNObsolete(pindexPrev->nHeight + 1)) { - // New payment logic (!TODO) - return false; + CAmount masternodeReward = GetMasternodePayment(); + auto dmnPayee = deterministicMNManager->GetListForBlock(pindexPrev).GetMNPayee(); + if (!dmnPayee) { + return error("%s: Failed to get payees for block at height %d", __func__, pindexPrev->nHeight + 1); + } + CAmount operatorReward = 0; + if (dmnPayee->nOperatorReward != 0 && !dmnPayee->pdmnState->scriptOperatorPayout.empty()) { + operatorReward = (masternodeReward * dmnPayee->nOperatorReward) / 10000; + masternodeReward -= operatorReward; + } + if (masternodeReward > 0) { + voutMasternodePaymentsRet.emplace_back(masternodeReward, dmnPayee->pdmnState->scriptPayout); + } + if (operatorReward > 0) { + voutMasternodePaymentsRet.emplace_back(operatorReward, dmnPayee->pdmnState->scriptOperatorPayout); + } + return true; } // Legacy payment logic. !TODO: remove when transition to DMN is complete @@ -318,7 +333,6 @@ bool CMasternodePayments::GetMasternodeTxOuts(const CBlockIndex* pindexPrev, std bool CMasternodePayments::GetLegacyMasternodeTxOut(int nHeight, std::vector& voutMasternodePaymentsRet) const { - if (nHeight == 0) return false; voutMasternodePaymentsRet.clear(); CScript payee; @@ -622,8 +636,24 @@ bool CMasternodePayments::IsTransactionValid(const CTransaction& txNew, const CB { const int nBlockHeight = pindexPrev->nHeight + 1; if (deterministicMNManager->LegacyMNObsolete(nBlockHeight)) { - // !TODO - return false; + std::vector vecMnOuts; + if (!GetMasternodeTxOuts(pindexPrev, vecMnOuts)) { + // No masternode scheduled to be paid. + return true; + } + + for (const CTxOut& o : vecMnOuts) { + if (std::find(txNew.vout.begin(), txNew.vout.end(), o) == txNew.vout.end()) { + CTxDestination mnDest; + const std::string& payee = ExtractDestination(o.scriptPubKey, mnDest) ? EncodeDestination(mnDest) + : HexStr(o.scriptPubKey); + LogPrint(BCLog::MASTERNODE, "%s: Failed to find expected payee %s in block at height %d (tx %s)", + __func__, payee, pindexPrev->nHeight + 1, txNew.GetHash().ToString()); + return false; + } + } + // all the expected payees have been found in txNew outputs + return true; } // Legacy payment logic. !TODO: remove when transition to DMN is complete From f6aefd8bacb86f518a7ce4bfde9211e85fe8f2f7 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Thu, 11 Mar 2021 22:06:39 +0100 Subject: [PATCH 2/6] [Tests] Check masternode payments in evo_deterministicmns_tests --- src/spork.cpp | 4 +- src/test/evo_deterministicmns_tests.cpp | 111 +++++++++++++++++++----- 2 files changed, 93 insertions(+), 22 deletions(-) diff --git a/src/spork.cpp b/src/spork.cpp index ba286c28fc73..73609b96bdc5 100644 --- a/src/spork.cpp +++ b/src/spork.cpp @@ -202,9 +202,9 @@ void CSporkManager::ProcessGetSporks(CNode* pfrom, std::string& strCommand, CDat bool CSporkManager::UpdateSpork(SporkId nSporkID, int64_t nValue) { - CSporkMessage spork = CSporkMessage(nSporkID, nValue, GetTime()); + CSporkMessage spork(nSporkID, nValue, GetTime()); - if(spork.Sign(strMasterPrivKey)){ + if (spork.Sign(strMasterPrivKey)) { spork.Relay(); AddOrUpdateSporkMessage(spork); return true; diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index c6d18f91130e..985411d8b226 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -13,6 +13,7 @@ #include "policy/policy.h" #include "primitives/transaction.h" #include "script/sign.h" +#include "spork.h" #include "validation.h" #include @@ -161,6 +162,24 @@ static bool CheckTransactionSignature(const CMutableTransaction& tx) return true; } +static bool IsMNPayeeInBlock(const CBlock& block, const CScript& expected) +{ + for (const auto& txout : block.vtx[0]->vout) { + if (txout.scriptPubKey == expected) return true; + } + return false; +} + +static void CheckPayments(std::map mp, size_t mapSize, int minCount) +{ + BOOST_CHECK_EQUAL(mp.size(), mapSize); + for (const auto& it : mp) { + BOOST_CHECK_MESSAGE(it.second >= minCount, + strprintf("MN %s didn't receive expected num of payments (%d<%d)",it.first.ToString(), it.second, minCount) + ); + } +} + BOOST_AUTO_TEST_SUITE(deterministicmns_tests) BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) @@ -172,7 +191,6 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V6_0, nHeight); int port = 1; - // these maps are only populated, but not used for now. They will be needed later on, in the next commits. std::vector dmnHashes; std::map ownerKeys; std::map operatorKeys; @@ -215,48 +233,57 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) nHeight++; } - // Mine 30 more blocks - for (size_t i = 0; i < 30; i++) { - CreateAndProcessBlock({}, coinbaseKey); + + // enable SPORK_21 + const CSporkMessage& spork = CSporkMessage(SPORK_21_LEGACY_MNS_MAX_HEIGHT, nHeight, GetTime()); + sporkManager.AddOrUpdateSporkMessage(spork); + BOOST_CHECK(deterministicMNManager->LegacyMNObsolete(nHeight + 1)); + + // Mine 20 blocks, checking MN reward payments + std::map mapPayments; + for (size_t i = 0; i < 20; i++) { + auto dmnExpectedPayee = deterministicMNManager->GetListAtChainTip().GetMNPayee(); + CBlock block = CreateAndProcessBlock({}, coinbaseKey); chainTip = chainActive.Tip(); - BOOST_CHECK_EQUAL(chainTip->nHeight, ++nHeight); deterministicMNManager->UpdatedBlockTip(chainTip); + BOOST_ASSERT(!block.vtx.empty()); + BOOST_CHECK(IsMNPayeeInBlock(block, dmnExpectedPayee->pdmnState->scriptPayout)); + mapPayments[dmnExpectedPayee->proTxHash]++; + BOOST_CHECK_EQUAL(chainTip->nHeight, ++nHeight); } + // 20 blocks, 6 masternodes. Must have been paid at least 3 times each. + CheckPayments(mapPayments, 6, 3); // Try to register used owner key { - SimpleUTXOMap utxos_copy(utxos); const CKey& ownerKey = ownerKeys.at(dmnHashes[InsecureRandRange(dmnHashes.size())]); - auto tx = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, ownerKey, GetRandomKey()); + auto tx = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, ownerKey, GetRandomKey()); CValidationState state; BOOST_CHECK(!CheckSpecialTx(tx, chainTip, state)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-dup-owner-key"); } // Try to register used operator key { - SimpleUTXOMap utxos_copy(utxos); const CKey& operatorKey = operatorKeys.at(dmnHashes[InsecureRandRange(dmnHashes.size())]); - auto tx = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), operatorKey); + auto tx = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), operatorKey); CValidationState state; BOOST_CHECK(!CheckSpecialTx(tx, chainTip, state)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-dup-operator-key"); } // Try to register used IP address { - SimpleUTXOMap utxos_copy(utxos); - auto tx = CreateProRegTx(nullopt, utxos_copy, 1 + InsecureRandRange(port-1), GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); + auto tx = CreateProRegTx(nullopt, utxos, 1 + InsecureRandRange(port-1), GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); CValidationState state; BOOST_CHECK(!CheckSpecialTx(tx, chainTip, state)); BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-protx-dup-IP-address"); } // Block with two ProReg txes using same owner key { - SimpleUTXOMap utxos_copy(utxos); const CKey& ownerKey = GetRandomKey(); const CKey& operatorKey1 = GetRandomKey(); const CKey& operatorKey2 = GetRandomKey(); - auto tx1 = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey1); - auto tx2 = CreateProRegTx(nullopt, utxos_copy, (port+1), GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey2); + auto tx1 = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey1); + auto tx2 = CreateProRegTx(nullopt, utxos, (port+1), GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey2); CBlock block = CreateBlock({tx1, tx2}, coinbaseKey); CBlockIndex indexFake(block); indexFake.nHeight = nHeight; @@ -269,12 +296,11 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) } // Block with two ProReg txes using same operator key { - SimpleUTXOMap utxos_copy(utxos); const CKey& ownerKey1 = GetRandomKey(); const CKey& ownerKey2 = GetRandomKey(); const CKey& operatorKey = GetRandomKey(); - auto tx1 = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, ownerKey1, operatorKey); - auto tx2 = CreateProRegTx(nullopt, utxos_copy, (port+1), GenerateRandomAddress(), coinbaseKey, ownerKey2, operatorKey); + auto tx1 = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, ownerKey1, operatorKey); + auto tx2 = CreateProRegTx(nullopt, utxos, (port+1), GenerateRandomAddress(), coinbaseKey, ownerKey2, operatorKey); CBlock block = CreateBlock({tx1, tx2}, coinbaseKey); CBlockIndex indexFake(block); indexFake.nHeight = nHeight; @@ -287,9 +313,8 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) } // Block with two ProReg txes using ip address { - SimpleUTXOMap utxos_copy(utxos); - auto tx1 = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); - auto tx2 = CreateProRegTx(nullopt, utxos_copy, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); + auto tx1 = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); + auto tx2 = CreateProRegTx(nullopt, utxos, port, GenerateRandomAddress(), coinbaseKey, GetRandomKey(), GetRandomKey()); CBlock block = CreateBlock({tx1, tx2}, coinbaseKey); CBlockIndex indexFake(block); indexFake.nHeight = nHeight; @@ -301,6 +326,52 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) BOOST_CHECK_EQUAL(chainActive.Height(), nHeight); // bad block not connected } + // register multiple MNs per block + for (size_t i = 0; i < 3; i++) { + std::vector txns; + for (size_t j = 0; j < 3; j++) { + const CKey& ownerKey = GetRandomKey(); + const CKey& operatorKey = GetRandomKey(); + auto tx = CreateProRegTx(nullopt, utxos, port++, GenerateRandomAddress(), coinbaseKey, ownerKey, operatorKey); + const uint256& txid = tx.GetHash(); + dmnHashes.emplace_back(txid); + ownerKeys.emplace(txid, ownerKey); + operatorKeys.emplace(txid, operatorKey); + + CValidationState dummyState; + BOOST_CHECK(CheckSpecialTx(tx, chainActive.Tip(), dummyState)); + BOOST_CHECK(CheckTransactionSignature(tx)); + txns.emplace_back(tx); + } + CreateAndProcessBlock(txns, coinbaseKey); + chainTip = chainActive.Tip(); + BOOST_CHECK_EQUAL(chainTip->nHeight, nHeight + 1); + + deterministicMNManager->UpdatedBlockTip(chainTip); + auto mnList = deterministicMNManager->GetListAtChainTip(); + for (size_t j = 0; j < 3; j++) { + BOOST_CHECK(mnList.HasMN(txns[j].GetHash())); + } + + nHeight++; + } + + // Mine 30 blocks, checking MN reward payments + mapPayments.clear(); + for (size_t i = 0; i < 30; i++) { + auto dmnExpectedPayee = deterministicMNManager->GetListAtChainTip().GetMNPayee(); + CBlock block = CreateAndProcessBlock({}, coinbaseKey); + chainTip = chainActive.Tip(); + deterministicMNManager->UpdatedBlockTip(chainTip); + BOOST_ASSERT(!block.vtx.empty()); + BOOST_CHECK(IsMNPayeeInBlock(block, dmnExpectedPayee->pdmnState->scriptPayout)); + mapPayments[dmnExpectedPayee->proTxHash]++; + + nHeight++; + } + // 30 blocks, 15 masternodes. Must have been paid exactly 2 times each. + CheckPayments(mapPayments, 15, 2); + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V6_0, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } From a81abb48455716dd0b491cbca1745748d45f701d Mon Sep 17 00:00:00 2001 From: random-zebra Date: Sun, 11 Apr 2021 22:13:26 +0200 Subject: [PATCH 3/6] [Trivial] Fix typo utoxs --> utxos --- src/test/evo_deterministicmns_tests.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index 985411d8b226..fd9d7d09d5a2 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -37,7 +37,7 @@ static SimpleUTXOMap BuildSimpleUtxoMap(const std::vector& txs) return utxos; } -static std::vector SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, CAmount& changeRet) +static std::vector SelectUTXOs(SimpleUTXOMap& utxos, CAmount amount, CAmount& changeRet) { changeRet = 0; amount += fee; @@ -45,9 +45,9 @@ static std::vector SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, std::vector selectedUtxos; CAmount selectedAmount = 0; int chainHeight = chainActive.Height(); - while (!utoxs.empty()) { + while (!utxos.empty()) { bool found = false; - for (auto it = utoxs.begin(); it != utoxs.end(); ++it) { + for (auto it = utxos.begin(); it != utxos.end(); ++it) { if (chainHeight - it->second.first < 100) { continue; } @@ -55,7 +55,7 @@ static std::vector SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, found = true; selectedAmount += it->second.second; selectedUtxos.emplace_back(it->first); - utoxs.erase(it); + utxos.erase(it); break; } BOOST_ASSERT(found); @@ -68,10 +68,10 @@ static std::vector SelectUTXOs(SimpleUTXOMap& utoxs, CAmount amount, return selectedUtxos; } -static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utoxs, const CScript& scriptPayout, const CScript& scriptChange, CAmount amount) +static void FundTransaction(CMutableTransaction& tx, SimpleUTXOMap& utxos, const CScript& scriptPayout, const CScript& scriptChange, CAmount amount) { CAmount change; - auto inputs = SelectUTXOs(utoxs, amount, change); + auto inputs = SelectUTXOs(utxos, amount, change); for (size_t i = 0; i < inputs.size(); i++) { tx.vin.emplace_back(inputs[i]); } From 753986ac7842b27c5bf430b346dd7731d0ef1f21 Mon Sep 17 00:00:00 2001 From: furszy Date: Fri, 21 May 2021 17:59:03 -0300 Subject: [PATCH 4/6] [test] Add unit test coverage for invalid block payee --- src/blockassembler.cpp | 9 +++++++-- src/blockassembler.h | 1 + src/test/evo_deterministicmns_tests.cpp | 27 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/blockassembler.cpp b/src/blockassembler.cpp index f3edbc65e4f6..bf19985ef776 100644 --- a/src/blockassembler.cpp +++ b/src/blockassembler.cpp @@ -111,7 +111,7 @@ bool SolveProofOfStake(CBlock* pblock, CBlockIndex* pindexPrev, CWallet* pwallet return true; } -bool CreateCoinbaseTx(CBlock* pblock, const CScript& scriptPubKeyIn, CBlockIndex* pindexPrev) +CMutableTransaction CreateCoinbaseTx(const CScript& scriptPubKeyIn, CBlockIndex* pindexPrev) { assert(pindexPrev); const int nHeight = pindexPrev->nHeight + 1; @@ -128,7 +128,12 @@ bool CreateCoinbaseTx(CBlock* pblock, const CScript& scriptPubKeyIn, CBlockIndex txCoinbase.vout[0].nValue = GetBlockValue(nHeight); } - pblock->vtx.emplace_back(MakeTransactionRef(txCoinbase)); + return txCoinbase; +} + +bool CreateCoinbaseTx(CBlock* pblock, const CScript& scriptPubKeyIn, CBlockIndex* pindexPrev) +{ + pblock->vtx.emplace_back(MakeTransactionRef(CreateCoinbaseTx(scriptPubKeyIn, pindexPrev))); return true; } diff --git a/src/blockassembler.h b/src/blockassembler.h index 9014167326e1..f4b88b142c45 100644 --- a/src/blockassembler.h +++ b/src/blockassembler.h @@ -100,6 +100,7 @@ int32_t ComputeBlockVersion(const Consensus::Params& consensusParams, int nHeigh // Visible for testing purposes only bool CreateCoinbaseTx(CBlock* pblock, const CScript& scriptPubKeyIn, CBlockIndex* pindexPrev); +CMutableTransaction CreateCoinbaseTx(const CScript& scriptPubKeyIn, CBlockIndex* pindexPrev); // Visible for testing purposes only uint256 CalculateSaplingTreeRoot(CBlock* pblock, int nHeight, const CChainParams& chainparams); diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index fd9d7d09d5a2..abb82e73ed0f 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -5,9 +5,12 @@ #include "test/test_pivx.h" +#include "blockassembler.h" +#include "consensus/merkle.h" #include "evo/specialtx.h" #include "evo/providertx.h" #include "evo/deterministicmns.h" +#include "masternode-payments.h" #include "messagesigner.h" #include "netbase.h" #include "policy/policy.h" @@ -372,6 +375,30 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) // 30 blocks, 15 masternodes. Must have been paid exactly 2 times each. CheckPayments(mapPayments, 15, 2); + // Check that the prev DMN winner is different that the tip one + std::vector vecMnOutsPrev; + BOOST_CHECK(masternodePayments.GetMasternodeTxOuts(chainTip->pprev, vecMnOutsPrev)); + std::vector vecMnOutsNow; + BOOST_CHECK(masternodePayments.GetMasternodeTxOuts(chainTip, vecMnOutsNow)); + BOOST_CHECK(vecMnOutsPrev != vecMnOutsNow); + + // Craft an invalid block paying to the previous block DMN again + CBlock invalidBlock = CreateBlock({}, coinbaseKey); + std::shared_ptr pblock = std::make_shared(invalidBlock); + CMutableTransaction invalidCoinbaseTx = CreateCoinbaseTx(CScript(), chainTip); + invalidCoinbaseTx.vout.clear(); + for (const CTxOut& mnOut: vecMnOutsPrev) { + invalidCoinbaseTx.vout.emplace_back(mnOut); + } + invalidCoinbaseTx.vout.emplace_back( + CTxOut(GetBlockValue(nHeight + 1) - GetMasternodePayment(), + GetScriptForDestination(coinbaseKey.GetPubKey().GetID()))); + pblock->vtx[0] = MakeTransactionRef(invalidCoinbaseTx); + pblock->hashMerkleRoot = BlockMerkleRoot(*pblock); + CValidationState state; + BOOST_CHECK_MESSAGE(!ProcessNewBlock(state, nullptr, pblock, nullptr), "Error, invalid block paying to an already paid DMN passed"); + BOOST_CHECK(WITH_LOCK(cs_main, return chainActive.Height()) == nHeight); // no block connected + UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V6_0, Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT); } From f593706cee74a4d57aa9942a9490aa8bb435fd26 Mon Sep 17 00:00:00 2001 From: furszy Date: Fri, 21 May 2021 18:24:06 -0300 Subject: [PATCH 5/6] [test] add mnsync and spork8 activation in deterministicmns_tests --- src/test/evo_deterministicmns_tests.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/test/evo_deterministicmns_tests.cpp b/src/test/evo_deterministicmns_tests.cpp index abb82e73ed0f..87e13136667e 100644 --- a/src/test/evo_deterministicmns_tests.cpp +++ b/src/test/evo_deterministicmns_tests.cpp @@ -11,6 +11,7 @@ #include "evo/providertx.h" #include "evo/deterministicmns.h" #include "masternode-payments.h" +#include "masternode-sync.h" #include "messagesigner.h" #include "netbase.h" #include "policy/policy.h" @@ -192,6 +193,12 @@ BOOST_FIXTURE_TEST_CASE(dip3_protx, TestChain400Setup) CBlockIndex* chainTip = chainActive.Tip(); int nHeight = chainTip->nHeight; UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V6_0, nHeight); + masternodeSync.RequestedMasternodeAssets = MASTERNODE_SYNC_FINISHED; + // enable SPORK_8 + int64_t nTime = GetTime() - 10; + const CSporkMessage& sporkMnPayment = CSporkMessage(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT, nTime + 1, nTime); + sporkManager.AddOrUpdateSporkMessage(sporkMnPayment); + BOOST_CHECK(sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT)); int port = 1; std::vector dmnHashes; From 6b7b9df415f65529e2d5dc9fe699cc3f27c80382 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Sat, 22 May 2021 12:41:35 +0200 Subject: [PATCH 6/6] [BUG][Test] Return directly block template without mempool txes Bug introduced in https://github.com/PIVX-Project/PIVX/commit/0b670c872d99e848be58914a9215fbe974722d3a When the coinbase includes a masternode payment, if the entire block value is given to the miner (first coinbase output), the block over-mints. --- src/blockassembler.cpp | 5 +++-- src/blockassembler.h | 3 ++- src/test/test_pivx.cpp | 16 ++++------------ 3 files changed, 9 insertions(+), 15 deletions(-) diff --git a/src/blockassembler.cpp b/src/blockassembler.cpp index bf19985ef776..bf6c3d371a1e 100644 --- a/src/blockassembler.cpp +++ b/src/blockassembler.cpp @@ -170,7 +170,8 @@ void BlockAssembler::resetBlock() std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, bool fProofOfStake, - std::vector* availableCoins) + std::vector* availableCoins, + bool fNoMempoolTx) { resetBlock(); @@ -199,7 +200,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc return nullptr; } - { + if (!fNoMempoolTx) { // Add transactions from mempool LOCK2(cs_main,mempool.cs); addPriorityTxs(); diff --git a/src/blockassembler.h b/src/blockassembler.h index f4b88b142c45..d927feca2b76 100644 --- a/src/blockassembler.h +++ b/src/blockassembler.h @@ -68,7 +68,8 @@ class BlockAssembler std::unique_ptr CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet = nullptr, bool fProofOfStake = false, - std::vector* availableCoins = nullptr); + std::vector* availableCoins = nullptr, + bool fNoMempoolTx = false); private: // utility functions diff --git a/src/test/test_pivx.cpp b/src/test/test_pivx.cpp index 5f3e4dc79cc4..46f811cdffcb 100644 --- a/src/test/test_pivx.cpp +++ b/src/test/test_pivx.cpp @@ -160,24 +160,16 @@ CBlock TestChainSetup::CreateAndProcessBlock(const std::vector& txns, const CScript& scriptPubKey, bool fNoMempoolTx) { std::unique_ptr pblocktemplate = BlockAssembler( - Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(scriptPubKey, nullptr, false); + Params(), DEFAULT_PRINTPRIORITY).CreateNewBlock(scriptPubKey, nullptr, false, nullptr, fNoMempoolTx); std::shared_ptr pblock = std::make_shared(pblocktemplate->block); - const int nHeight = WITH_LOCK(cs_main, return chainActive.Height()) + 1; - - // Replace mempool-selected txns with just coinbase plus passed-in txns: - if (fNoMempoolTx) { - pblock->vtx.resize(1); - - // Replace coinbase output amount (could have included fee in CreateNewBlock) - CMutableTransaction txCoinbase(*pblock->vtx[0]); - txCoinbase.vout[0].nValue = GetBlockValue(nHeight); - pblock->vtx[0] = MakeTransactionRef(txCoinbase); - } + // Add passed-in txns: for (const CMutableTransaction& tx : txns) { pblock->vtx.push_back(MakeTransactionRef(tx)); } + const int nHeight = WITH_LOCK(cs_main, return chainActive.Height()) + 1; + // Re-compute sapling root pblock->hashFinalSaplingRoot = CalculateSaplingTreeRoot(pblock.get(), nHeight, Params());