LCOV - code coverage report
Current view: top level - src/test - budget_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 356 356 100.0 %
Date: 2025-02-23 09:33:43 Functions: 27 27 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2018-2022 The PIVX Core developers
       2             : // Distributed under the MIT/X11 software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include "test_pivx.h"
       6             : 
       7             : #include "bls/bls_wrapper.h"
       8             : #include "budget/budgetmanager.h"
       9             : #include "masternode-payments.h"
      10             : #include "spork.h"
      11             : #include "test/util/blocksutil.h"
      12             : #include "tiertwo/tiertwo_sync_state.h"
      13             : #include "tinyformat.h"
      14             : #include "utilmoneystr.h"
      15             : #include "validation.h"
      16             : 
      17             : #include <boost/test/unit_test.hpp>
      18             : 
      19             : BOOST_AUTO_TEST_SUITE(budget_tests)
      20             : 
      21           7 : void CheckBudgetValue(int nHeight, std::string strNetwork, CAmount nExpectedValue)
      22             : {
      23           7 :     CBudgetManager budget;
      24           7 :     CAmount nBudget = g_budgetman.GetTotalBudget(nHeight);
      25          21 :     std::string strError = strprintf("Budget is not as expected for %s. Result: %s, Expected: %s", strNetwork, FormatMoney(nBudget), FormatMoney(nExpectedValue));
      26          14 :     BOOST_CHECK_MESSAGE(nBudget == nExpectedValue, strError);
      27           7 : }
      28             : 
      29           3 : void enableMnSyncAndSuperblocksPayment()
      30             : {
      31             :     // force mnsync complete
      32           3 :     g_tiertwo_sync_state.SetCurrentSyncPhase(MASTERNODE_SYNC_FINISHED);
      33             : 
      34             :     // enable SPORK_13
      35           3 :     int64_t nTime = GetTime() - 10;
      36           3 :     CSporkMessage spork(SPORK_13_ENABLE_SUPERBLOCKS, nTime + 1, nTime);
      37           3 :     sporkManager.AddOrUpdateSporkMessage(spork);
      38           6 :     BOOST_CHECK(sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS));
      39             : 
      40           3 :     spork = CSporkMessage(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT, nTime + 1, nTime);
      41           3 :     sporkManager.AddOrUpdateSporkMessage(spork);
      42           6 :     BOOST_CHECK(sporkManager.IsSporkActive(SPORK_9_MASTERNODE_BUDGET_ENFORCEMENT));
      43           3 : }
      44             : 
      45           2 : BOOST_AUTO_TEST_CASE(masternode_value)
      46             : {
      47           1 :     SelectParams(CBaseChainParams::REGTEST);
      48           1 :     int nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight + 1;
      49           1 :     BOOST_CHECK_EQUAL(GetMasternodePayment(nHeightTest - 1), 3 * COIN);
      50           1 :     BOOST_CHECK_EQUAL(GetMasternodePayment(nHeightTest), 6 * COIN);
      51           1 : }
      52             : 
      53           2 : BOOST_AUTO_TEST_CASE(budget_value)
      54             : {
      55           1 :     SelectParams(CBaseChainParams::TESTNET);
      56           1 :     int nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_ZC_V2].nActivationHeight + 1;
      57           1 :     CheckBudgetValue(nHeightTest-1, "testnet", 7200*COIN);
      58           1 :     CheckBudgetValue(nHeightTest, "testnet", 144*COIN);
      59             : 
      60           1 :     SelectParams(CBaseChainParams::MAIN);
      61           1 :     nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_ZC_V2].nActivationHeight + 1;
      62           1 :     CheckBudgetValue(nHeightTest, "mainnet", 43200*COIN);
      63             : 
      64           1 :     SelectParams(CBaseChainParams::TESTNET);
      65           1 :     nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight + 1;
      66           1 :     CheckBudgetValue(nHeightTest-1, "testnet", 144*COIN);
      67           1 :     CheckBudgetValue(nHeightTest, "testnet", 1440*COIN);
      68             : 
      69           1 :     SelectParams(CBaseChainParams::MAIN);
      70           1 :     nHeightTest = Params().GetConsensus().vUpgrades[Consensus::UPGRADE_V5_5].nActivationHeight + 1;
      71           1 :     CheckBudgetValue(nHeightTest-1, "mainnet", 43200*COIN);
      72           1 :     CheckBudgetValue(nHeightTest, "mainnet", 432000*COIN);
      73             : 
      74           1 : }
      75             : 
      76           2 : BOOST_FIXTURE_TEST_CASE(block_value, TestnetSetup)
      77             : {
      78           1 :     enableMnSyncAndSuperblocksPayment();
      79           1 :     int nHeight = 100; std::string strError;
      80           1 :     const CAmount nBlockReward = GetBlockValue(nHeight);
      81           1 :     CAmount nExpectedRet = nBlockReward;
      82           1 :     CAmount nBudgetAmtRet = 0;
      83             : 
      84             :     // regular block
      85           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, 0, nBudgetAmtRet));
      86           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward-1, nBudgetAmtRet));
      87           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
      88           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
      89           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward, nBudgetAmtRet));
      90           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
      91           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
      92           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+1, nBudgetAmtRet));
      93           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
      94           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
      95             : 
      96             :     // superblock - create the finalized budget with a proposal, and vote on it
      97           1 :     nHeight = 144;
      98           2 :     const CTxIn mnVin(GetRandHash(), 0);
      99           4 :     const CScript payee = GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))));
     100           1 :     const CAmount propAmt = 100 * COIN;
     101           1 :     const uint256& propHash = GetRandHash(), finTxId = GetRandHash();
     102           2 :     const CTxBudgetPayment txBudgetPayment(propHash, payee, propAmt);
     103           4 :     CFinalizedBudget fin("main (test)", 144, {txBudgetPayment}, finTxId);
     104           1 :     const CFinalizedBudgetVote fvote(mnVin, fin.GetHash());
     105           2 :     BOOST_CHECK(fin.AddOrUpdateVote(fvote, strError));
     106           1 :     g_budgetman.ForceAddFinalizedBudget(fin.GetHash(), fin.GetFeeTXHash(), fin);
     107             : 
     108             :     // check superblock's block-value
     109           1 :     nExpectedRet = nBlockReward;
     110           1 :     nBudgetAmtRet = 0;
     111           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward, nBudgetAmtRet));
     112           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward + propAmt);
     113           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, propAmt);
     114           1 :     nExpectedRet = nBlockReward;
     115           1 :     nBudgetAmtRet = 0;
     116           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt-1, nBudgetAmtRet));
     117           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward + propAmt);
     118           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, propAmt);
     119           1 :     nExpectedRet = nBlockReward;
     120           1 :     nBudgetAmtRet = 0;
     121           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt, nBudgetAmtRet));
     122           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward + propAmt);
     123           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, propAmt);
     124           1 :     nExpectedRet = nBlockReward;
     125           1 :     nBudgetAmtRet = 0;
     126           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt+1, nBudgetAmtRet));
     127           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward + propAmt);
     128           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, propAmt);
     129             : 
     130             :     // disable SPORK_13
     131           2 :     const CSporkMessage& spork2 = CSporkMessage(SPORK_13_ENABLE_SUPERBLOCKS, 4070908800ULL, GetTime());
     132           1 :     sporkManager.AddOrUpdateSporkMessage(spork2);
     133           2 :     BOOST_CHECK(!sporkManager.IsSporkActive(SPORK_13_ENABLE_SUPERBLOCKS));
     134             : 
     135             :     // check with spork disabled
     136           1 :     nExpectedRet = nBlockReward;
     137           1 :     nBudgetAmtRet = 0;
     138           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, nBlockReward, nBudgetAmtRet));
     139           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
     140           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
     141           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt-1, nBudgetAmtRet));
     142           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
     143           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
     144           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt, nBudgetAmtRet));
     145           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
     146           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
     147           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, nBlockReward+propAmt+1, nBudgetAmtRet));
     148           1 :     BOOST_CHECK_EQUAL(nExpectedRet, nBlockReward);
     149           1 :     BOOST_CHECK_EQUAL(nBudgetAmtRet, 0);
     150           1 : }
     151             : 
     152           2 : BOOST_FIXTURE_TEST_CASE(block_value_undermint, RegTestingSetup)
     153             : {
     154           1 :     int nHeight = 100;
     155           1 :     CAmount nExpectedRet = GetBlockValue(nHeight);
     156           1 :     CAmount nBudgetAmtRet = 0;
     157             :     // under-minting blocks are invalid after v5.3
     158           2 :     BOOST_CHECK(IsBlockValueValid(nHeight, nExpectedRet, -1, nBudgetAmtRet));
     159           1 :     UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V5_3, Consensus::NetworkUpgrade::ALWAYS_ACTIVE);
     160           2 :     BOOST_CHECK(!IsBlockValueValid(nHeight, nExpectedRet, -1, nBudgetAmtRet));
     161           1 : }
     162             : 
     163             : /**
     164             :  * 1) Create two proposals and two budget finalizations with a different proposal payment order:
     165             :          BudA pays propA and propB, BudB pays propB and propA.
     166             :    2) Vote both finalization budgets, adding more votes to budA (so it becomes the most voted one).
     167             :  */
     168           2 : void forceAddFakeProposals(const CTxOut& payee1, const CTxOut& payee2)
     169             : {
     170           2 :     const CTxIn mnVin(GetRandHash(), 0);
     171           2 :     const uint256& propHash = GetRandHash(), finTxId = GetRandHash();
     172           4 :     const CTxBudgetPayment txBudgetPayment(propHash, payee1.scriptPubKey, payee1.nValue);
     173             : 
     174           4 :     const CTxIn mnVin2(GetRandHash(), 0);
     175           2 :     const uint256& propHash2 = GetRandHash(), finTxId2 = GetRandHash();
     176           4 :     const CTxBudgetPayment txBudgetPayment2(propHash2, payee2.scriptPubKey, payee2.nValue);
     177             : 
     178             :     // Create first finalization
     179          10 :     CFinalizedBudget fin("main (test)", 144, {txBudgetPayment, txBudgetPayment2}, finTxId);
     180           4 :     const CFinalizedBudgetVote fvote(mnVin, fin.GetHash());
     181           6 :     const CFinalizedBudgetVote fvote1_a({GetRandHash(), 0}, fin.GetHash());
     182           4 :     const CFinalizedBudgetVote fvote1_b({GetRandHash(), 0}, fin.GetHash());
     183           4 :     std::string strError;
     184           4 :     BOOST_CHECK(fin.AddOrUpdateVote(fvote, strError));
     185           4 :     BOOST_CHECK(fin.AddOrUpdateVote(fvote1_a, strError));
     186           4 :     BOOST_CHECK(fin.AddOrUpdateVote(fvote1_b, strError));
     187           2 :     g_budgetman.ForceAddFinalizedBudget(fin.GetHash(), fin.GetFeeTXHash(), fin);
     188             : 
     189             :     // Create second finalization
     190          10 :     CFinalizedBudget fin2("main2 (test)", 144, {txBudgetPayment2, txBudgetPayment}, finTxId2);
     191           4 :     const CFinalizedBudgetVote fvote2(mnVin2, fin2.GetHash());
     192           4 :     const CFinalizedBudgetVote fvote2_a({GetRandHash(), 0}, fin2.GetHash());
     193           4 :     BOOST_CHECK(fin2.AddOrUpdateVote(fvote2, strError));
     194           4 :     BOOST_CHECK(fin2.AddOrUpdateVote(fvote2_a, strError));
     195           2 :     g_budgetman.ForceAddFinalizedBudget(fin2.GetHash(), fin2.GetFeeTXHash(), fin2);
     196           2 : }
     197             : 
     198           2 : BOOST_FIXTURE_TEST_CASE(budget_blocks_payee_test, TestChain100Setup)
     199             : {
     200             :     // Regtest superblock is every 144 blocks.
     201          44 :     for (int i=0; i<43; i++) CreateAndProcessBlock({}, coinbaseKey);
     202           1 :     enableMnSyncAndSuperblocksPayment();
     203           1 :     g_budgetman.Clear();
     204           2 :     BOOST_CHECK_EQUAL(WITH_LOCK(cs_main, return chainActive.Height();), 143);
     205           1 :     BOOST_ASSERT(g_budgetman.GetFinalizedBudgets().size() == 0);
     206             : 
     207             :     // Now we are at the superblock height, let's add a proposal to pay.
     208           3 :     const CScript payee1 = GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))));
     209           1 :     const CAmount propAmt1 = 100 * COIN;
     210           4 :     const CScript payee2 = GetScriptForDestination(CKeyID(uint160(ParseHex("8d5b4f83212214d6ef693e02e6d71969fddad976"))));
     211           1 :     const CAmount propAmt2 = propAmt1;
     212           3 :     forceAddFakeProposals({propAmt1, payee1}, {propAmt2, payee2});
     213             : 
     214           2 :     CBlock block = CreateBlock({}, coinbaseKey);
     215             :     // Check payee validity:
     216           2 :     CTxOut payeeOut = block.vtx[0]->vout[1];
     217           1 :     BOOST_CHECK_EQUAL(payeeOut.nValue, propAmt1);
     218           2 :     BOOST_CHECK(payeeOut.scriptPubKey == payee1);
     219             : 
     220             :     // Good tx
     221           2 :     CMutableTransaction goodMtx(*block.vtx[0]);
     222             : 
     223             :     // Modify payee
     224           1 :     CMutableTransaction mtx(*block.vtx[0]);
     225           2 :     mtx.vout[1].scriptPubKey = GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))));
     226           2 :     block.vtx[0] = MakeTransactionRef(mtx);
     227           2 :     std::shared_ptr<CBlock> pblock = FinalizeBlock(std::make_shared<CBlock>(block));
     228           2 :     BOOST_CHECK(block.vtx[0]->vout[1].scriptPubKey != payee1);
     229             : 
     230             :     // Verify block rejection reason.
     231           1 :     ProcessBlockAndCheckRejectionReason(pblock, "bad-cb-payee", 143);
     232             : 
     233             :     // Try to overmint, valid payee --> bad amount.
     234           1 :     mtx = goodMtx; // reset
     235           1 :     mtx.vout[1].nValue *= 2; // invalid amount
     236           2 :     block.vtx[0] = MakeTransactionRef(mtx);
     237           2 :     pblock = FinalizeBlock(std::make_shared<CBlock>(block));
     238           2 :     BOOST_CHECK(block.vtx[0]->vout[1].scriptPubKey == payee1);
     239           2 :     BOOST_CHECK(block.vtx[0]->vout[1].nValue == payeeOut.nValue * 2);
     240           1 :     ProcessBlockAndCheckRejectionReason(pblock, "bad-blk-amount", 143);
     241             : 
     242             :     // Try to send less to a valid payee --> bad amount.
     243           1 :     mtx = goodMtx; // reset
     244           1 :     mtx.vout[1].nValue /= 2;
     245           2 :     block.vtx[0] = MakeTransactionRef(mtx);
     246           2 :     pblock = FinalizeBlock(std::make_shared<CBlock>(block));
     247           2 :     BOOST_CHECK(block.vtx[0]->vout[1].scriptPubKey == payee1);
     248           2 :     BOOST_CHECK(block.vtx[0]->vout[1].nValue == payeeOut.nValue / 2);
     249           1 :     ProcessBlockAndCheckRejectionReason(pblock, "bad-cb-payee", 143);
     250             : 
     251             :     // Context, this has:
     252             :     // 1) Two proposals and two budget finalizations with a different proposal payment order (read `forceAddFakeProposals()` description):
     253             :     //      BudA pays propA and propB, BudB pays propB and propA.
     254             :     // 2) Voted both budgets, adding more votes to budA (so it becomes the most voted one).
     255             :     // 3) Now: in the superblock, pay to budB order (the less voted finalization) --> which will fail.
     256             : 
     257             :     // Try to pay proposals in different order
     258           1 :     mtx = goodMtx; // reset
     259           2 :     std::vector<CFinalizedBudget*> vecFin = g_budgetman.GetFinalizedBudgets();
     260           1 :     CFinalizedBudget* secondFin{nullptr};
     261           3 :     for (auto fin : vecFin) {
     262           2 :         if (!secondFin || fin->GetVoteCount() < secondFin->GetVoteCount()) {
     263             :             secondFin = fin;
     264             :         }
     265             :     }
     266           1 :     secondFin->GetPayeeAndAmount(144, mtx.vout[1].scriptPubKey, mtx.vout[1].nValue);
     267           2 :     BOOST_CHECK(mtx.vout[1].scriptPubKey != goodMtx.vout[1].scriptPubKey);
     268           2 :     BOOST_CHECK(mtx.vout[1].nValue == goodMtx.vout[1].nValue);
     269           2 :     block.vtx[0] = MakeTransactionRef(mtx);
     270           2 :     pblock = FinalizeBlock(std::make_shared<CBlock>(block));
     271           1 :     ProcessBlockAndCheckRejectionReason(pblock, "bad-cb-payee", 143);
     272             : 
     273             :     // Now create the good block
     274           2 :     block.vtx[0] = MakeTransactionRef(goodMtx);
     275           2 :     pblock = FinalizeBlock(std::make_shared<CBlock>(block));
     276           1 :     ProcessNewBlock(pblock, nullptr);
     277           3 :     BOOST_CHECK_EQUAL(WITH_LOCK(cs_main, return chainActive.Tip()->GetBlockHash();), pblock->GetHash());
     278           1 : }
     279             : 
     280           2 : BOOST_FIXTURE_TEST_CASE(budget_blocks_reorg_test, TestChain100Setup)
     281             : {
     282             :     // Regtest superblock is every 144 blocks.
     283          44 :     for (int i=0; i<43; i++) CreateAndProcessBlock({}, coinbaseKey);
     284           1 :     enableMnSyncAndSuperblocksPayment();
     285           2 :     BOOST_CHECK_EQUAL(WITH_LOCK(cs_main, return chainActive.Height();), 143);
     286             : 
     287             :     // Now we are at the superblock height, let's add a proposal to pay.
     288           3 :     const CScript payee = GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))));
     289           1 :     const CAmount propAmt = 100 * COIN;
     290           4 :     const CScript payee2 = GetScriptForDestination(CKeyID(uint160(ParseHex("816115944e077fe7c803cfa57f29b36bf87c1d35"))));
     291           1 :     const CAmount propAmt2 = propAmt * 2;
     292           3 :     forceAddFakeProposals({propAmt, payee}, {propAmt2, payee2});
     293             : 
     294             :     // This will:
     295             :     // 1) Create a proposal to be paid at block 144 (first superblock).
     296             :     // 1) create blocksA and blockB at block 144 (paying for the proposal).
     297             :     // 2) Process and connect blockA.
     298             :     // 3) Create blockC on top of BlockA and blockD on top of blockB. At height 145.
     299             :     // 4) Process and connect blockC.
     300             :     // 5) Now force the reorg:
     301             :     //    a) Process blockB and blockD.
     302             :     //    b) Create and process blockE on top of blockD.
     303             :     // 6) Verify that tip is at blockE.
     304             : 
     305           4 :     CScript forkCoinbaseScript = GetScriptForDestination(CKeyID(uint160(ParseHex("8c988f1a4a4de2161e0f50aac7f17e7f9555caa4"))));
     306           2 :     CBlock blockA = CreateBlock({}, coinbaseKey, false);
     307           1 :     CBlock blockB = CreateBlock({}, forkCoinbaseScript, false);
     308           2 :     BOOST_CHECK(blockA.GetHash() != blockB.GetHash());
     309             :     // Check blocks payee validity:
     310           2 :     CTxOut payeeOut = blockA.vtx[0]->vout[1];
     311           1 :     BOOST_CHECK_EQUAL(payeeOut.nValue, propAmt);
     312           2 :     BOOST_CHECK(payeeOut.scriptPubKey == payee);
     313           1 :     payeeOut = blockB.vtx[0]->vout[1];
     314           1 :     BOOST_CHECK_EQUAL(payeeOut.nValue, propAmt);
     315           2 :     BOOST_CHECK(payeeOut.scriptPubKey == payee);
     316             : 
     317             :     // Now let's process BlockA:
     318           2 :     auto pblockA = std::make_shared<const CBlock>(blockA);
     319           1 :     ProcessNewBlock(pblockA, nullptr);
     320           4 :     BOOST_CHECK(WITH_LOCK(cs_main, return chainActive.Tip()->GetBlockHash()) == blockA.GetHash());
     321             : 
     322             :     // Now let's create blockC on top of BlockA, blockD on top of blockB
     323             :     // and process blockC to expand the chain.
     324           2 :     CBlock blockC = CreateBlock({}, coinbaseKey, false);
     325           2 :     BOOST_CHECK(blockC.hashPrevBlock == blockA.GetHash());
     326           1 :     CBlock blockD = CreateBlock({}, forkCoinbaseScript, false);
     327             : 
     328             :     // Process and connect blockC
     329           1 :     ProcessNewBlock(std::make_shared<const CBlock>(blockC), nullptr);
     330           4 :     BOOST_CHECK(WITH_LOCK(cs_main, return chainActive.Tip()->GetBlockHash()) == blockC.GetHash());
     331             : 
     332             :     // Now let's process the secondary chain
     333           1 :     blockD.hashPrevBlock = blockB.GetHash();
     334           2 :     std::shared_ptr<CBlock> pblockD = FinalizeBlock(std::make_shared<CBlock>(blockD));
     335             : 
     336           1 :     ProcessNewBlock(std::make_shared<const CBlock>(blockB), nullptr);
     337           1 :     ProcessNewBlock(pblockD, nullptr);
     338           2 :     CBlock blockE = CreateBlock({}, forkCoinbaseScript, false);
     339           1 :     blockE.hashPrevBlock = pblockD->GetHash();
     340           2 :     std::shared_ptr<CBlock> pblockE = FinalizeBlock(std::make_shared<CBlock>(blockE));
     341           1 :     ProcessNewBlock(pblockE, nullptr);
     342           4 :     BOOST_CHECK(WITH_LOCK(cs_main, return chainActive.Tip()->GetBlockHash()) == pblockE->GetHash());
     343           1 : }
     344             : 
     345           1 : static CScript GetRandomP2PKH()
     346             : {
     347           1 :     CKey key;
     348           1 :     key.MakeNewKey(false);
     349           3 :     return GetScriptForDestination(key.GetPubKey().GetID());
     350             : }
     351             : 
     352           1 : static CMutableTransaction NewCoinBase(int nHeight, CAmount cbaseAmt, const CScript& cbaseScript)
     353             : {
     354           1 :     CMutableTransaction tx;
     355           1 :     tx.vout.emplace_back(cbaseAmt, cbaseScript);
     356           1 :     tx.vin.emplace_back();
     357           1 :     tx.vin[0].scriptSig = CScript() << nHeight << OP_0;
     358           1 :     return tx;
     359             : }
     360             : 
     361           2 : BOOST_FIXTURE_TEST_CASE(IsCoinbaseValueValid_test, TestingSetup)
     362             : {
     363           1 :     int nHeight = 100;
     364           1 :     const CAmount mnAmt = GetMasternodePayment(nHeight);
     365           1 :     const CScript& cbaseScript = GetRandomP2PKH();
     366           2 :     CValidationState state;
     367             : 
     368             :     // force mnsync complete
     369           1 :     g_tiertwo_sync_state.SetCurrentSyncPhase(MASTERNODE_SYNC_FINISHED);
     370             : 
     371             :     // -- Regular blocks
     372             : 
     373             :     // Exact
     374           1 :     CMutableTransaction cbase = NewCoinBase(1, mnAmt, cbaseScript);
     375           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     376           1 :     cbase.vout[0].nValue /= 2;
     377           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     378           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     379             : 
     380             :     // Underpaying with SPORK_8 disabled (good)
     381           1 :     cbase.vout.clear();
     382           1 :     cbase.vout.emplace_back(mnAmt - 1, cbaseScript);
     383           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     384           1 :     cbase.vout[0].nValue = mnAmt/2;
     385           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     386           1 :     cbase.vout[1].nValue = mnAmt/2 - 1;
     387           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     388             : 
     389             :     // Overpaying with SPORK_8 disabled
     390           1 :     cbase.vout.clear();
     391           1 :     cbase.vout.emplace_back(mnAmt + 1, cbaseScript);
     392           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     393           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt-spork8-disabled");
     394           1 :     state = CValidationState();
     395           1 :     cbase.vout[0].nValue = mnAmt/2;
     396           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     397           1 :     cbase.vout[1].nValue = mnAmt/2 + 1;
     398           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     399           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt-spork8-disabled");
     400           1 :     state = CValidationState();
     401             : 
     402             :     // enable SPORK_8
     403           1 :     int64_t nTime = GetTime() - 10;
     404           2 :     const CSporkMessage& spork = CSporkMessage(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT, nTime + 1, nTime);
     405           1 :     sporkManager.AddOrUpdateSporkMessage(spork);
     406           2 :     BOOST_CHECK(sporkManager.IsSporkActive(SPORK_8_MASTERNODE_PAYMENT_ENFORCEMENT));
     407             : 
     408             :     // Underpaying with SPORK_8 enabled
     409           1 :     cbase.vout.clear();
     410           1 :     cbase.vout.emplace_back(mnAmt - 1, cbaseScript);
     411           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     412           2 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt");
     413           1 :     state = CValidationState();
     414           1 :     cbase.vout[0].nValue = mnAmt/2;
     415           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     416           1 :     cbase.vout[1].nValue = mnAmt/2 - 1;
     417           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     418           2 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt");
     419           1 :     state = CValidationState();
     420             : 
     421             :     // Overpaying with SPORK_8 enabled
     422           1 :     cbase.vout.clear();
     423           1 :     cbase.vout.emplace_back(mnAmt + 1, cbaseScript);
     424           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     425           2 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt");
     426           1 :     state = CValidationState();
     427           1 :     cbase.vout[0].nValue = mnAmt/2;
     428           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     429           1 :     cbase.vout[1].nValue = mnAmt/2 + 1;
     430           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), 0, state));
     431           2 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-cb-amt");
     432           1 :     state = CValidationState();
     433             : 
     434           1 :     const CAmount budgAmt = 200 * COIN;
     435             : 
     436             :     // -- Superblocks
     437             : 
     438             :     // Exact
     439           1 :     cbase.vout.clear();
     440           1 :     cbase.vout.emplace_back(budgAmt, cbaseScript);
     441           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     442           1 :     cbase.vout[0].nValue /= 2;
     443           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     444           3 :     BOOST_CHECK(IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     445             : 
     446             :     // Underpaying
     447           1 :     cbase.vout.clear();
     448           1 :     cbase.vout.emplace_back(budgAmt - 1, cbaseScript);
     449           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     450           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-superblock-cb-amt");
     451           1 :     state = CValidationState();
     452           1 :     cbase.vout[0].nValue = budgAmt/2;
     453           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     454           1 :     cbase.vout[1].nValue = budgAmt/2 - 1;
     455           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     456           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-superblock-cb-amt");
     457           1 :     state = CValidationState();
     458             : 
     459             :     // Overpaying
     460           1 :     cbase.vout.clear();
     461           1 :     cbase.vout.emplace_back(budgAmt + 1, cbaseScript);
     462           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     463           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-superblock-cb-amt");
     464           1 :     state = CValidationState();
     465           1 :     cbase.vout[0].nValue = budgAmt/2;
     466           1 :     cbase.vout.emplace_back(cbase.vout[0]);
     467           1 :     cbase.vout[1].nValue = budgAmt/2 + 1;
     468           3 :     BOOST_CHECK(!IsCoinbaseValueValid(MakeTransactionRef(cbase), budgAmt, state));
     469           3 :     BOOST_CHECK_EQUAL(state.GetRejectReason(), "bad-superblock-cb-amt");
     470           1 : }
     471             : 
     472           2 : BOOST_AUTO_TEST_CASE(fbv_signverify_bls)
     473             : {
     474           3 :     CBLSSecretKey sk1, sk2;
     475           1 :     sk1.MakeNewKey();
     476           1 :     sk2.MakeNewKey();
     477           1 :     BOOST_ASSERT(sk1 != sk2);
     478             : 
     479           3 :     CTxIn vin(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000002"), 0));
     480           3 :     CTxIn vin2(COutPoint(uint256S("000000000000000000000000000000000000000000000000000000000000003"), 0));
     481           3 :     CTxIn vin3(COutPoint(uint256S("0000000000000000000000000000000000000000000000000000000000000002"), 1));
     482             : 
     483           1 :     uint256 budgetHash1 = uint256S("0000000000000000000000000000000000000000000000000000000000000001");
     484           1 :     uint256 budgetHash2 = uint256S("0000000000000000000000000000000000010000000000000000000000000001");
     485             : 
     486             :     // Create serialized finalbudgetvote for budgetHash1, signed with sk1
     487           2 :     CFinalizedBudgetVote vote(vin, budgetHash1);
     488           2 :     BOOST_CHECK(vote.Sign(sk1));
     489           2 :     CDataStream ss(SER_NETWORK, PROTOCOL_VERSION);
     490           1 :     ss << vote;
     491             : 
     492             :     // Verify received message on pk1
     493           2 :     CFinalizedBudgetVote _vote;
     494           1 :     ss >> _vote;
     495           2 :     BOOST_CHECK(_vote.CheckSignature(sk1.GetPublicKey()));
     496             : 
     497             :     // Failing verification on pk2
     498           2 :     BOOST_CHECK(!_vote.CheckSignature(sk2.GetPublicKey()));
     499             : 
     500           2 :     std::vector<unsigned char> sig = _vote.GetVchSig();
     501             : 
     502             :     // Failing with different time
     503           2 :     CFinalizedBudgetVote vote1(_vote);
     504           1 :     vote1.SetTime(vote1.GetTime()+1);
     505           2 :     BOOST_CHECK(!vote1.CheckSignature(sk1.GetPublicKey()));
     506             : 
     507             :     // Failing with different budget hash
     508           2 :     CFinalizedBudgetVote vote2(vin, budgetHash2);
     509           1 :     vote2.SetTime(_vote.GetTime());
     510           1 :     vote2.SetVchSig(sig);
     511           2 :     BOOST_CHECK(!vote2.CheckSignature(sk1.GetPublicKey()));
     512             : 
     513             :     // Failing with different vins: different txid (vin2) or voutn (vin3)
     514           2 :     CFinalizedBudgetVote vote3_1(vin, budgetHash1);
     515           2 :     CFinalizedBudgetVote vote3_2(vin2, budgetHash1);
     516           2 :     CFinalizedBudgetVote vote3_3(vin3, budgetHash1);
     517           1 :     vote3_1.SetTime(_vote.GetTime());
     518           1 :     vote3_2.SetTime(_vote.GetTime());
     519           1 :     vote3_3.SetTime(_vote.GetTime());
     520           1 :     vote3_1.SetVchSig(sig);
     521           1 :     vote3_2.SetVchSig(sig);
     522           1 :     vote3_3.SetVchSig(sig);
     523           2 :     BOOST_CHECK(vote3_1.CheckSignature(sk1.GetPublicKey()));    // vote3_1 == _vote
     524           2 :     BOOST_CHECK(!vote3_2.CheckSignature(sk1.GetPublicKey()));
     525           2 :     BOOST_CHECK(!vote3_3.CheckSignature(sk1.GetPublicKey()));
     526           1 : }
     527             : 
     528             : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.14