Line data Source code
1 : // Copyright (c) 2011-2015 The Bitcoin Core developers 2 : // Copyright (c) 2020-2021 The PIVX Core developers 3 : // Distributed under the MIT software license, see the accompanying 4 : // file COPYING or https://www.opensource.org/licenses/mit-license.php. 5 : 6 : #include "test/test_pivx.h" 7 : 8 : #include "consensus/validation.h" 9 : #include "pubkey.h" 10 : #include "random.h" 11 : #include "script/standard.h" 12 : #include "utiltime.h" 13 : #include "validation.h" 14 : 15 : #include <boost/test/unit_test.hpp> 16 : 17 : BOOST_AUTO_TEST_SUITE(tx_validationcache_tests) 18 : 19 3 : static bool ToMemPool(CMutableTransaction& tx) 20 : { 21 3 : LOCK(cs_main); 22 6 : CValidationState state; 23 9 : return AcceptToMemoryPool(mempool, state, MakeTransactionRef(tx), false, nullptr, true, false, false); 24 : } 25 : 26 2 : BOOST_FIXTURE_TEST_CASE(tx_mempool_block_doublespend, TestChain100Setup) 27 : { 28 : // Make sure skipping validation of transactions that were 29 : // validated going into the memory pool does not allow 30 : // double-spends in blocks to pass validation when they should not. 31 : 32 2 : CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; 33 : 34 : // Create a double-spend of mature coinbase txn: 35 2 : std::vector<CMutableTransaction> spends; 36 1 : spends.resize(2); 37 3 : for (int i = 0; i < 2; i++) 38 : { 39 2 : spends[i].nVersion = 1; 40 2 : spends[i].vin.resize(1); 41 2 : spends[i].vin[0].prevout.hash = coinbaseTxns[0].GetHash(); 42 2 : spends[i].vin[0].prevout.n = 0; 43 2 : spends[i].vout.resize(1); 44 2 : spends[i].vout[0].nValue = 11*CENT; 45 2 : spends[i].vout[0].scriptPubKey = scriptPubKey; 46 : 47 : // Sign: 48 4 : std::vector<unsigned char> vchSig; 49 2 : uint256 hash = SignatureHash(scriptPubKey, spends[i], 0, SIGHASH_ALL, 0, SIGVERSION_BASE); 50 4 : BOOST_CHECK(coinbaseKey.Sign(hash, vchSig)); 51 2 : vchSig.push_back((unsigned char)SIGHASH_ALL); 52 2 : spends[i].vin[0].scriptSig << vchSig; 53 : } 54 : 55 2 : const uint256& tipHash = chainActive.Tip()->GetBlockHash(); 56 2 : CBlock block; 57 : 58 : // Test 1: block with both of those transactions should be rejected. 59 1 : block = CreateAndProcessBlock(spends, scriptPubKey); 60 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); 61 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() == tipHash); 62 : 63 : // Test 2: ... and should be rejected if spend1 is in the memory pool 64 2 : BOOST_CHECK(ToMemPool(spends[0])); 65 1 : block = CreateAndProcessBlock(spends, scriptPubKey); 66 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); 67 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() == tipHash); 68 1 : mempool.clear(); 69 : 70 : // Test 3: ... and should be rejected if spend2 is in the memory pool 71 2 : BOOST_CHECK(ToMemPool(spends[1])); 72 1 : SetMockTime(GetTime() + 60); // to generate a different block hash 73 1 : block = CreateAndProcessBlock(spends, scriptPubKey); 74 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() != block.GetHash()); 75 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() == tipHash); 76 1 : mempool.clear(); 77 : 78 : // Final sanity test: first spend in mempool, second in block, that's OK: 79 2 : std::vector<CMutableTransaction> oneSpend; 80 1 : oneSpend.push_back(spends[0]); 81 2 : BOOST_CHECK(ToMemPool(spends[1])); 82 1 : block = CreateAndProcessBlock(oneSpend, scriptPubKey); 83 3 : BOOST_CHECK(chainActive.Tip()->GetBlockHash() == block.GetHash()); 84 : // spends[1] should have been removed from the mempool when the 85 : // block with spends[0] is accepted: 86 1 : BOOST_CHECK_EQUAL(mempool.size(), 0); 87 1 : } 88 : 89 : BOOST_AUTO_TEST_SUITE_END()