Line data Source code
1 : // Copyright (c) 2025 The Dash 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/util/setup_common.h> 6 : 7 : #include <chain.h> 8 : #include <coinjoin/coinjoin.h> 9 : #include <coinjoin/common.h> 10 : #include <script/script.h> 11 : #include <uint256.h> 12 : 13 : #include <algorithm> 14 : #include <array> 15 : #include <vector> 16 : 17 : #include <boost/test/unit_test.hpp> 18 : 19 146 : BOOST_FIXTURE_TEST_SUITE(coinjoin_dstxmanager_tests, TestingSetup) 20 : 21 2 : static CCoinJoinBroadcastTx MakeDSTX(int vin_vout_count = 3) 22 : { 23 2 : CCoinJoinBroadcastTx dstx; 24 2 : CMutableTransaction mtx; 25 2 : const int count = std::max(vin_vout_count, 1); 26 8 : for (int i = 0; i < count; ++i) { 27 6 : mtx.vin.emplace_back(COutPoint(uint256S("0a"), i)); 28 : // Use denominated P2PKH outputs 29 6 : CScript spk; 30 6 : spk << OP_DUP << OP_HASH160 << std::vector<unsigned char>(20, i) << OP_EQUALVERIFY << OP_CHECKSIG; 31 6 : mtx.vout.emplace_back(CoinJoin::GetSmallestDenomination(), spk); 32 6 : } 33 2 : dstx.tx = MakeTransactionRef(mtx); 34 2 : dstx.m_protxHash = uint256::ONE; 35 2 : return dstx; 36 2 : } 37 : 38 149 : BOOST_AUTO_TEST_CASE(add_get_dstx) 39 : { 40 1 : CCoinJoinBroadcastTx dstx = MakeDSTX(); 41 1 : auto& man = *Assert(m_node.dstxman); 42 : // Not present initially 43 1 : BOOST_CHECK(!man.GetDSTX(dstx.tx->GetHash())); 44 : // Add 45 1 : man.AddDSTX(dstx); 46 : // Fetch back 47 1 : auto got = man.GetDSTX(dstx.tx->GetHash()); 48 1 : BOOST_CHECK(static_cast<bool>(got)); 49 1 : BOOST_CHECK_EQUAL(got.tx->GetHash().ToString(), dstx.tx->GetHash().ToString()); 50 1 : } 51 : 52 149 : BOOST_AUTO_TEST_CASE(broadcasttx_expiry_height_logic) 53 : { 54 : // Build a valid-looking CCoinJoinBroadcastTx with confirmed height 55 1 : CCoinJoinBroadcastTx dstx; 56 : { 57 1 : CMutableTransaction mtx; 58 1 : const int participants = std::max(3, CoinJoin::GetMinPoolParticipants()); 59 4 : for (int i = 0; i < participants; ++i) { 60 3 : mtx.vin.emplace_back(COutPoint(uint256::TWO, i)); 61 3 : CScript spk; 62 3 : spk << OP_DUP << OP_HASH160 << std::vector<unsigned char>(20, i) << OP_EQUALVERIFY << OP_CHECKSIG; 63 3 : mtx.vout.emplace_back(CoinJoin::GetSmallestDenomination(), spk); 64 3 : } 65 1 : dstx.tx = MakeTransactionRef(mtx); 66 1 : dstx.m_protxHash = uint256::ONE; 67 : // mark as confirmed at height 100 68 1 : dstx.SetConfirmedHeight(100); 69 1 : } 70 : 71 1 : int expiry_height = 124; // 125 - 100 == 25 > 24 → expired by height 72 : 73 : // Minimal CBlockIndex with required fields 74 : // Create a minimal block index to satisfy the interface 75 1 : CBlockIndex index; 76 1 : uint256 blk_hash = uint256S("03"); 77 1 : index.nHeight = expiry_height; 78 1 : index.phashBlock = &blk_hash; 79 : 80 1 : auto& man = *Assert(m_node.dstxman); 81 1 : auto& hash = dstx.tx->GetHash(); 82 1 : man.AddDSTX(dstx); 83 1 : BOOST_CHECK(static_cast<bool>(man.GetDSTX(hash))); 84 : 85 1 : man.UpdatedBlockTip(&index); 86 1 : BOOST_CHECK(static_cast<bool>(man.GetDSTX(hash))); 87 : 88 1 : index.nHeight = expiry_height + 1; 89 1 : man.UpdatedBlockTip(&index); 90 1 : BOOST_CHECK(!static_cast<bool>(man.GetDSTX(hash))); 91 1 : } 92 : 93 149 : BOOST_AUTO_TEST_CASE(update_heights_block_connect_disconnect) 94 : { 95 1 : CCoinJoinBroadcastTx dstx = MakeDSTX(); 96 1 : auto& man = *Assert(m_node.dstxman); 97 1 : man.AddDSTX(dstx); 98 : 99 : // Create a fake block containing the tx 100 1 : auto block = std::make_shared<CBlock>(); 101 1 : block->vtx.push_back(dstx.tx); 102 1 : CBlockIndex index; 103 1 : index.nHeight = 100; 104 1 : uint256 bh = uint256S("0b"); 105 1 : index.phashBlock = &bh; 106 : 107 : // Height should set to 100 on connect 108 1 : man.BlockConnected(block, &index); 109 : { 110 1 : auto got = man.GetDSTX(dstx.tx->GetHash()); 111 1 : BOOST_CHECK(static_cast<bool>(got)); 112 1 : BOOST_CHECK(got.GetConfirmedHeight().has_value()); 113 1 : BOOST_CHECK_EQUAL(*got.GetConfirmedHeight(), 100); 114 1 : } 115 : 116 : // Height should clear on disconnect 117 1 : man.BlockDisconnected(block, nullptr); 118 : { 119 1 : auto got = man.GetDSTX(dstx.tx->GetHash()); 120 1 : BOOST_CHECK(static_cast<bool>(got)); 121 1 : BOOST_CHECK(!got.GetConfirmedHeight().has_value()); 122 1 : } 123 1 : } 124 : 125 146 : BOOST_AUTO_TEST_SUITE_END()