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

          Line data    Source code
       1             : // Copyright (c) 2025 The Dash Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <test/util/llmq_tests.h>
       6             : #include <test/util/setup_common.h>
       7             : 
       8             : #include <consensus/params.h>
       9             : #include <llmq/params.h>
      10             : #include <llmq/utils.h>
      11             : #include <netaddress.h>
      12             : #include <random.h>
      13             : 
      14             : #include <boost/test/unit_test.hpp>
      15             : 
      16             : #include <map>
      17             : #include <set>
      18             : 
      19             : using namespace llmq;
      20             : using namespace llmq::testutils;
      21             : 
      22         146 : BOOST_FIXTURE_TEST_SUITE(llmq_utils_tests, BasicTestingSetup)
      23             : 
      24         149 : BOOST_AUTO_TEST_CASE(trivially_passes) { BOOST_CHECK(true); }
      25             : 
      26         149 : BOOST_AUTO_TEST_CASE(deterministic_outbound_connection_test)
      27             : {
      28             :     // Test deterministic behavior
      29             :     // DeterministicOutboundConnection returns one of the two input hashes based on a deterministic calculation
      30           1 :     uint256 proTxHash1 = GetTestQuorumHash(1);
      31           1 :     uint256 proTxHash2 = GetTestQuorumHash(2);
      32             : 
      33             :     // Same inputs should produce same output
      34           1 :     uint256 conn1a = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash2);
      35           1 :     uint256 conn1b = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash2);
      36           1 :     BOOST_CHECK(conn1a == conn1b);
      37             :     // Result should be one of the input hashes
      38           1 :     BOOST_CHECK(conn1a == proTxHash1 || conn1a == proTxHash2);
      39             : 
      40             :     // Swapped inputs should produce the same result (commutative)
      41             :     // The function deterministically selects which node initiates the connection
      42           1 :     uint256 conn2 = llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash1);
      43           1 :     BOOST_CHECK(conn1a == conn2);
      44             : 
      45             :     // The result should consistently be the same node regardless of order
      46           1 :     BOOST_CHECK(llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash2) ==
      47             :                 llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash1));
      48           1 : }
      49             : 
      50         149 : BOOST_AUTO_TEST_CASE(deterministic_outbound_connection_edge_cases_test)
      51             : {
      52             :     // Test with null hashes
      53           1 :     uint256 nullHash;
      54           1 :     uint256 validHash = GetTestQuorumHash(1);
      55             : 
      56             :     // DeterministicOutboundConnection returns one of the input hashes
      57           1 :     uint256 conn1 = llmq::utils::DeterministicOutboundConnection(nullHash, validHash);
      58           1 :     uint256 conn2 = llmq::utils::DeterministicOutboundConnection(validHash, nullHash);
      59           1 :     uint256 conn3 = llmq::utils::DeterministicOutboundConnection(nullHash, nullHash);
      60             : 
      61             :     // With null and valid hash, should return one of them
      62           1 :     BOOST_CHECK(conn1 == nullHash || conn1 == validHash);
      63           1 :     BOOST_CHECK(conn2 == nullHash || conn2 == validHash);
      64             :     // Since the function is order-independent, conn1 and conn2 should be the same
      65           1 :     BOOST_CHECK(conn1 == conn2);
      66             : 
      67             :     // With two null hashes, should return null
      68           1 :     BOOST_CHECK(conn3 == nullHash);
      69             : 
      70             :     // Test with same source and destination
      71           1 :     uint256 sameHash = GetTestQuorumHash(42);
      72           1 :     uint256 connSame = llmq::utils::DeterministicOutboundConnection(sameHash, sameHash);
      73             :     // Should return the same hash
      74           1 :     BOOST_CHECK(connSame == sameHash);
      75           1 :     BOOST_CHECK(!connSame.IsNull());
      76           1 : }
      77             : 
      78             : // Note: CalcDeterministicWatchConnections requires CBlockIndex which is complex to mock
      79             : // Testing is deferred to functional tests
      80             : 
      81             : // Note: InitQuorumsCache requires specific cache types with LLMQ consensus parameters
      82             : // Testing is deferred to integration tests
      83             : 
      84         149 : BOOST_AUTO_TEST_CASE(deterministic_connection_symmetry_test)
      85             : {
      86             :     // Test interesting properties of DeterministicOutboundConnection
      87           1 :     uint256 proTxHash1 = GetTestQuorumHash(1);
      88           1 :     uint256 proTxHash2 = GetTestQuorumHash(2);
      89           1 :     uint256 proTxHash3 = GetTestQuorumHash(3);
      90             : 
      91             :     // Create a "network" of connections
      92             :     // DeterministicOutboundConnection is symmetric - order doesn't matter
      93           1 :     uint256 conn12 = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash2);
      94           1 :     uint256 conn21 = llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash1);
      95           1 :     uint256 conn13 = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash3);
      96           1 :     uint256 conn31 = llmq::utils::DeterministicOutboundConnection(proTxHash3, proTxHash1);
      97           1 :     uint256 conn23 = llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash3);
      98           1 :     uint256 conn32 = llmq::utils::DeterministicOutboundConnection(proTxHash3, proTxHash2);
      99             : 
     100             :     // Verify symmetry - swapped inputs produce same output
     101           1 :     BOOST_CHECK(conn12 == conn21);
     102           1 :     BOOST_CHECK(conn13 == conn31);
     103           1 :     BOOST_CHECK(conn23 == conn32);
     104             : 
     105             :     // Each connection returns one of the two nodes
     106           1 :     BOOST_CHECK(conn12 == proTxHash1 || conn12 == proTxHash2);
     107           1 :     BOOST_CHECK(conn13 == proTxHash1 || conn13 == proTxHash3);
     108           1 :     BOOST_CHECK(conn23 == proTxHash2 || conn23 == proTxHash3);
     109             : 
     110             :     // The function deterministically picks which node initiates the connection
     111             :     // Verify we get consistent results for each pair
     112           1 :     std::set<uint256> uniqueResults;
     113           1 :     uniqueResults.insert(conn12);
     114           1 :     uniqueResults.insert(conn13);
     115           1 :     uniqueResults.insert(conn23);
     116             :     // Each pair should produce one of its members, but pairs may have overlapping results
     117           1 :     BOOST_CHECK(uniqueResults.size() >= 2 && uniqueResults.size() <= 3);
     118           1 : }
     119             : 
     120         146 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.16