Line data Source code
1 : // Copyright (c) 2020-2021 The PIVX Core developers 2 : // Distributed under the MIT software license, see the accompanying 3 : // file COPYING or https://www.opensource.org/licenses/mit-license.php. 4 : 5 : #include "test/test_pivx.h" 6 : #include "blockassembler.h" 7 : #include "primitives/transaction.h" 8 : #include "sapling/sapling_validation.h" 9 : #include "test/librust/utiltest.h" 10 : #include "util/blockstatecatcher.h" 11 : #include "wallet/test/wallet_test_fixture.h" 12 : 13 : #include <boost/test/unit_test.hpp> 14 : 15 : BOOST_AUTO_TEST_SUITE(validation_tests) 16 : 17 2 : BOOST_FIXTURE_TEST_CASE(test_simple_shielded_invalid, TestingSetup) 18 : { 19 2 : CMutableTransaction tx; 20 1 : tx.nVersion = CTransaction::TxVersion::SAPLING; 21 1 : CAmount nDummyValueOut; 22 1 : { 23 2 : CMutableTransaction newTx(tx); 24 2 : CValidationState state; 25 : 26 2 : BOOST_CHECK(!CheckTransaction(newTx, state, false)); 27 4 : BOOST_CHECK(state.GetRejectReason() == "bad-txns-vin-empty"); 28 : } 29 1 : { 30 2 : CMutableTransaction newTx(tx); 31 2 : CValidationState state; 32 : 33 1 : newTx.sapData->vShieldedSpend.emplace_back(); 34 1 : newTx.sapData->vShieldedSpend[0].nullifier = GetRandHash(); 35 : 36 2 : BOOST_CHECK(!CheckTransaction(newTx, state, false)); 37 4 : BOOST_CHECK(state.GetRejectReason() == "bad-txns-vout-empty"); 38 : } 39 1 : { 40 : // Ensure that nullifiers are never duplicated within a transaction. 41 2 : CMutableTransaction newTx(tx); 42 2 : CValidationState state; 43 : 44 1 : newTx.sapData->vShieldedSpend.emplace_back(); 45 1 : newTx.sapData->vShieldedSpend[0].nullifier = GetRandHash(); 46 : 47 1 : newTx.sapData->vShieldedOutput.emplace_back(); 48 : 49 1 : newTx.sapData->vShieldedSpend.emplace_back(); 50 1 : newTx.sapData->vShieldedSpend[1].nullifier = newTx.sapData->vShieldedSpend[0].nullifier; 51 : 52 2 : BOOST_CHECK(!SaplingValidation::CheckTransactionWithoutProofVerification(newTx, state, nDummyValueOut)); 53 4 : BOOST_CHECK(state.GetRejectReason() == "bad-spend-description-nullifiers-duplicate"); 54 : 55 1 : newTx.sapData->vShieldedSpend[1].nullifier = GetRandHash(); 56 : 57 2 : BOOST_CHECK(SaplingValidation::CheckTransactionWithoutProofVerification(newTx, state, nDummyValueOut)); 58 : } 59 1 : { 60 2 : CMutableTransaction newTx(tx); 61 1 : CValidationState state; 62 : 63 : // Create a coinbase transaction 64 2 : CTxIn vin; 65 1 : vin.prevout = COutPoint(); 66 1 : newTx.vin.emplace_back(vin); 67 2 : CTxOut vout; 68 1 : vout.nValue = 2; 69 1 : newTx.vout.emplace_back(vout); 70 : 71 1 : newTx.sapData->vShieldedSpend.emplace_back(); 72 : 73 2 : BOOST_CHECK(!CheckTransaction(newTx, state, false)); 74 4 : BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-sapling"); 75 : } 76 1 : { 77 2 : CMutableTransaction newTx(tx); 78 1 : CValidationState state; 79 : 80 : // Create a coinstake transaction 81 2 : CTxIn vin; 82 1 : vin.prevout = COutPoint(UINT256_ZERO, 0); 83 1 : newTx.vin.emplace_back(vin); 84 2 : CTxOut vout; 85 1 : vout.nValue = 0; 86 1 : newTx.vout.emplace_back(vout); 87 1 : vout.nValue = 2; 88 1 : newTx.vout.emplace_back(vout); 89 : 90 1 : newTx.sapData->vShieldedSpend.emplace_back(); 91 : 92 2 : BOOST_CHECK(!CheckTransaction(newTx, state, false)); 93 4 : BOOST_CHECK(state.GetRejectReason() == "bad-txns-invalid-sapling"); 94 : } 95 1 : } 96 : 97 3 : void CheckBlockZcRejection(std::shared_ptr<CBlock>& pblock, int nHeight, CMutableTransaction& mtx, const std::string& expected_msg) 98 : { 99 3 : pblock->vtx.emplace_back(MakeTransactionRef(mtx)); 100 6 : BOOST_CHECK(SolveBlock(pblock, nHeight)); 101 6 : BlockStateCatcherWrapper stateCatcher(pblock->GetHash()); 102 3 : stateCatcher.registerEvent(); 103 9 : BOOST_CHECK(!ProcessNewBlock(pblock, nullptr)); 104 6 : BOOST_CHECK(stateCatcher.get().found && !stateCatcher.get().state.IsValid()); 105 9 : BOOST_CHECK_EQUAL(stateCatcher.get().state.GetRejectReason(), expected_msg); 106 12 : BOOST_CHECK(WITH_LOCK(cs_main, return chainActive.Tip()->GetBlockHash(); ) != pblock->GetHash()); 107 3 : } 108 : 109 3 : void CheckMempoolZcRejection(CMutableTransaction& mtx, const std::string& expected_msg) 110 : { 111 3 : LOCK(cs_main); 112 6 : CValidationState state; 113 9 : BOOST_CHECK(!AcceptToMemoryPool( 114 : mempool, state, MakeTransactionRef(mtx), true, nullptr, false, true)); 115 6 : BOOST_CHECK(!state.IsValid()); 116 9 : BOOST_CHECK_EQUAL(state.GetRejectReason(), expected_msg); 117 3 : } 118 : 119 : /* 120 : * Running on regtest to have v5 upgrade enforced at block 1 and test in-block zc rejection 121 : */ 122 2 : BOOST_FIXTURE_TEST_CASE(zerocoin_rejection_tests, WalletRegTestingSetup) 123 : { 124 1 : UpdateNetworkUpgradeParameters(Consensus::UPGRADE_V5_0, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); 125 1 : UpdateNetworkUpgradeParameters(Consensus::UPGRADE_ZC_PUBLIC, Consensus::NetworkUpgrade::ALWAYS_ACTIVE); 126 1 : const CChainParams& chainparams = Params(); 127 : 128 2 : std::unique_ptr<CBlockTemplate> pblocktemplate; 129 3 : CScript scriptPubKey = CScript() << OP_DUP << OP_HASH160 << ParseHex("8d5b4f83212214d6ef693e02e6d71969fddad976") << OP_EQUALVERIFY << OP_CHECKSIG; 130 4 : BOOST_CHECK(pblocktemplate = BlockAssembler(Params(), false).CreateNewBlock(scriptPubKey, &m_wallet, false)); 131 1 : pblocktemplate->block.hashPrevBlock = chainparams.GetConsensus().hashGenesisBlock; 132 : 133 : // Base tx 134 2 : CMutableTransaction mtx; 135 2 : CTxIn vin; 136 1 : vin.prevout = COutPoint(UINT256_ZERO, 0); 137 1 : mtx.vin.emplace_back(vin); 138 : 139 : // Zerocoin mints rejection test 140 1 : mtx.vout.emplace_back(); 141 2 : mtx.vout[0].scriptPubKey = CScript() << OP_ZEROCOINMINT << 142 2 : CBigNum::randBignum(chainparams.GetConsensus().Zerocoin_Params(false)->coinCommitmentGroup.groupOrder).getvch(); 143 1 : mtx.vout[0].nValue = 1 * COIN; 144 2 : std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(pblocktemplate->block); 145 1 : CheckBlockZcRejection(pblock, 1, mtx, "bad-txns-zc-mint"); 146 1 : CheckMempoolZcRejection(mtx, "bad-txns-zc-mint"); 147 : 148 : // Zerocoin spends rejection test 149 1 : mtx.vout[0].scriptPubKey = scriptPubKey; 150 1 : mtx.vin[0].scriptSig = CScript() << OP_ZEROCOINSPEND; 151 2 : pblock = std::make_shared<CBlock>(pblocktemplate->block); 152 1 : CheckBlockZcRejection(pblock, 1, mtx, "bad-txns-zc-private-spend"); 153 1 : CheckMempoolZcRejection(mtx, "bad-txns-zc-private-spend"); 154 : 155 : // Zerocoin public spends rejection test 156 1 : mtx.vin[0].scriptSig = CScript() << OP_ZEROCOINPUBLICSPEND; 157 2 : pblock = std::make_shared<CBlock>(pblocktemplate->block); 158 1 : CheckBlockZcRejection(pblock, 1, mtx, "bad-txns-zc-public-spend"); 159 2 : CheckMempoolZcRejection(mtx, "bad-txns-zc-public-spend"); 160 1 : } 161 : 162 : BOOST_AUTO_TEST_SUITE_END()