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()
|