LCOV - code coverage report
Current view: top level - src/test - coinjoin_queue_tests.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 107 107 100.0 %
Date: 2026-06-25 07:23:51 Functions: 61 61 100.0 %

          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 <active/masternode.h>
       8             : #include <bls/bls.h>
       9             : #include <coinjoin/coinjoin.h>
      10             : #include <coinjoin/common.h>
      11             : #include <consensus/amount.h>
      12             : 
      13             : #include <uint256.h>
      14             : 
      15             : #include <climits>
      16             : #include <cstdint>
      17             : 
      18             : #include <boost/test/unit_test.hpp>
      19             : 
      20         146 : BOOST_FIXTURE_TEST_SUITE(coinjoin_queue_tests, TestingSetup)
      21             : 
      22           1 : static CBLSSecretKey MakeSecretKey()
      23             : {
      24             :     // Generate a dummy operator key pair for signing
      25           1 :     CBLSSecretKey sk;
      26           1 :     sk.MakeNewKey();
      27           1 :     return sk;
      28           1 : }
      29             : 
      30         149 : BOOST_AUTO_TEST_CASE(queue_sign_and_verify)
      31             : {
      32             :     // Build active MN manager with operator key using node context wiring
      33           1 :     CActiveMasternodeManager mn_activeman(*Assert(m_node.connman), *Assert(m_node.dmnman), MakeSecretKey());
      34             : 
      35           1 :     CCoinJoinQueue q;
      36           1 :     q.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
      37           1 :     q.masternodeOutpoint = COutPoint(uint256S("aa"), 1);
      38           1 :     q.m_protxHash = uint256::ONE;
      39           1 :     q.nTime = GetAdjustedTime();
      40           1 :     q.fReady = false;
      41             : 
      42             :     // Sign and verify with corresponding pubkey
      43           1 :     q.vchSig = mn_activeman.SignBasic(q.GetSignatureHash());
      44           1 :     const CBLSPublicKey pub = mn_activeman.GetPubKey();
      45           1 :     BOOST_CHECK(q.CheckSignature(pub));
      46           1 : }
      47             : 
      48         149 : BOOST_AUTO_TEST_CASE(queue_hashes_and_equality)
      49             : {
      50           1 :     CCoinJoinQueue a, b;
      51           1 :     a.nDenom = b.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
      52           1 :     a.masternodeOutpoint = b.masternodeOutpoint = COutPoint(uint256S("bb"), 2);
      53           1 :     a.m_protxHash = b.m_protxHash = uint256::ONE;
      54           1 :     a.nTime = b.nTime = GetAdjustedTime();
      55           1 :     a.fReady = b.fReady = true;
      56             : 
      57           1 :     BOOST_CHECK(a == b);
      58           1 :     BOOST_CHECK(a.GetHash() == b.GetHash());
      59           1 :     BOOST_CHECK(a.GetSignatureHash() == b.GetSignatureHash());
      60           1 : }
      61             : 
      62         149 : BOOST_AUTO_TEST_CASE(queue_denomination_validation)
      63             : {
      64             :     // Test that valid denominations pass
      65           1 :     int validDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
      66           1 :     BOOST_CHECK(CoinJoin::IsValidDenomination(validDenom));
      67             : 
      68             :     // Test that invalid denominations fail
      69           1 :     BOOST_CHECK(!CoinJoin::IsValidDenomination(0));     // Zero
      70           1 :     BOOST_CHECK(!CoinJoin::IsValidDenomination(-1));    // Negative
      71           1 :     BOOST_CHECK(!CoinJoin::IsValidDenomination(999));   // Invalid value
      72           1 : }
      73             : 
      74         149 : BOOST_AUTO_TEST_CASE(queue_timestamp_validation)
      75             : {
      76           1 :     CCoinJoinQueue q;
      77           1 :     q.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
      78           1 :     q.masternodeOutpoint = COutPoint(uint256S("cc"), 3);
      79           1 :     q.m_protxHash = uint256::ONE;
      80             : 
      81           1 :     int64_t current_time = GetAdjustedTime();
      82             : 
      83             :     // Test valid timestamp (current time)
      84           1 :     q.nTime = current_time;
      85           1 :     BOOST_CHECK(!q.IsTimeOutOfBounds(current_time));
      86             : 
      87             :     // Test timestamp slightly in future (within COINJOIN_QUEUE_TIMEOUT = 30)
      88           1 :     q.nTime = current_time + 15; // 15 seconds in future
      89           1 :     BOOST_CHECK(!q.IsTimeOutOfBounds(current_time));
      90             : 
      91             :     // Test timestamp slightly in past (within COINJOIN_QUEUE_TIMEOUT = 30)
      92           1 :     q.nTime = current_time - 15; // 15 seconds ago
      93           1 :     BOOST_CHECK(!q.IsTimeOutOfBounds(current_time));
      94             : 
      95             :     // Test timestamp too far in future (outside COINJOIN_QUEUE_TIMEOUT = 30)
      96           1 :     q.nTime = current_time + 60; // 60 seconds in future
      97           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(current_time));
      98             : 
      99             :     // Test timestamp too far in past (outside COINJOIN_QUEUE_TIMEOUT = 30)
     100           1 :     q.nTime = current_time - 60; // 60 seconds ago
     101           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(current_time));
     102           1 : }
     103             : 
     104         149 : BOOST_AUTO_TEST_CASE(queue_timestamp_extreme_values)
     105             : {
     106           1 :     CCoinJoinQueue q;
     107           1 :     q.nDenom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
     108           1 :     q.m_protxHash = uint256::ONE;
     109             : 
     110             :     // Negative timestamps are rejected by the guard
     111           1 :     q.nTime = INT64_MIN;
     112           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MAX));
     113             : 
     114           1 :     q.nTime = INT64_MAX;
     115           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));
     116             : 
     117           1 :     q.nTime = INT64_MIN;
     118           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));
     119             : 
     120             :     // Large positive timestamp with same value: zero diff, in bounds
     121           1 :     q.nTime = INT64_MAX;
     122           1 :     BOOST_CHECK(!q.IsTimeOutOfBounds(INT64_MAX));
     123             : 
     124             :     // Zero vs extreme positive: huge gap, out of bounds
     125           1 :     q.nTime = 0;
     126           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MAX));
     127             : 
     128             :     // Zero vs negative: rejected by guard
     129           1 :     q.nTime = 0;
     130           1 :     BOOST_CHECK(q.IsTimeOutOfBounds(INT64_MIN));
     131           1 : }
     132             : 
     133             : static_assert(CoinJoin::CalculateAmountPriority(MAX_MONEY) == -(MAX_MONEY / COIN));
     134             : static_assert(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(INT64_MAX)) == 0);
     135             : static_assert(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(-1)) == 0);
     136             : 
     137         149 : BOOST_AUTO_TEST_CASE(calculate_amount_priority_guard)
     138             : {
     139             :     // Realistic amount: MAX_MONEY (21 million DASH)
     140           1 :     BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(MAX_MONEY), -(MAX_MONEY / COIN));
     141             : 
     142             :     // Out-of-range amounts return 0
     143           1 :     BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(INT64_MAX)), 0);
     144           1 :     BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(static_cast<CAmount>(-1)), 0);
     145           1 :     BOOST_CHECK_EQUAL(CoinJoin::CalculateAmountPriority(MAX_MONEY + 1), 0);
     146           1 : }
     147             : 
     148           3 : static CCoinJoinQueue MakeQueue(int denom, int64_t nTime, bool fReady, const COutPoint& outpoint)
     149             : {
     150           3 :     CCoinJoinQueue q;
     151           3 :     q.nDenom = denom;
     152           3 :     q.masternodeOutpoint = outpoint;
     153           3 :     q.m_protxHash = uint256::ONE;
     154           3 :     q.nTime = nTime;
     155           3 :     q.fReady = fReady;
     156           3 :     return q;
     157           3 : }
     158             : 
     159         149 : BOOST_AUTO_TEST_CASE(queuemanager_checkqueue_removes_timeouts)
     160             : {
     161           1 :     CoinJoinQueueManager man;
     162           1 :     const int denom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
     163           1 :     const int64_t now = GetAdjustedTime();
     164             :     // Non-expired
     165           1 :     man.AddQueue(MakeQueue(denom, now, false, COutPoint(uint256S("11"), 0)));
     166             :     // Expired (too old)
     167           1 :     man.AddQueue(MakeQueue(denom, now - COINJOIN_QUEUE_TIMEOUT - 1, false, COutPoint(uint256S("12"), 0)));
     168             : 
     169           1 :     BOOST_CHECK_EQUAL(man.GetQueueSize(), 2);
     170           1 :     man.CheckQueue();
     171             :     // One should be removed
     172           1 :     BOOST_CHECK_EQUAL(man.GetQueueSize(), 1);
     173           1 : }
     174             : 
     175         149 : BOOST_AUTO_TEST_CASE(queuemanager_getqueueitem_marks_tried_once)
     176             : {
     177           1 :     CoinJoinQueueManager man;
     178           1 :     const int denom = CoinJoin::AmountToDenomination(CoinJoin::GetSmallestDenomination());
     179           1 :     const int64_t now = GetAdjustedTime();
     180           1 :     CCoinJoinQueue dsq = MakeQueue(denom, now, false, COutPoint(uint256S("21"), 0));
     181           1 :     man.AddQueue(dsq);
     182             : 
     183           1 :     CCoinJoinQueue picked;
     184             :     // First retrieval should succeed
     185           1 :     BOOST_CHECK(man.GetQueueItemAndTry(picked));
     186             :     // No other items left to try (picked is marked tried inside)
     187           1 :     CCoinJoinQueue picked2;
     188           1 :     BOOST_CHECK(!man.GetQueueItemAndTry(picked2));
     189           1 : }
     190             : 
     191         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16