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 : 11 : #include <boost/test/unit_test.hpp> 12 : 13 : #include <limits> 14 : 15 : using namespace llmq; 16 : using namespace llmq::testutils; 17 : using namespace Consensus; 18 : 19 146 : BOOST_FIXTURE_TEST_SUITE(llmq_params_tests, BasicTestingSetup) 20 : 21 : // Get test params for use in tests 22 146 : static const Consensus::LLMQParams& TEST_PARAMS_BASE = GetLLMQParams(Consensus::LLMQType::LLMQ_TEST_V17); 23 : 24 149 : BOOST_AUTO_TEST_CASE(llmq_params_max_cycles_test) 25 : { 26 : // Test non-rotated quorum 27 1 : LLMQParams nonRotated = TEST_PARAMS_BASE; 28 1 : nonRotated.useRotation = false; 29 1 : nonRotated.signingActiveQuorumCount = 2; 30 : 31 : // For non-rotated: max_cycles = quorums_count 32 1 : BOOST_CHECK_EQUAL(nonRotated.max_cycles(10), 10); 33 1 : BOOST_CHECK_EQUAL(nonRotated.max_cycles(100), 100); 34 1 : BOOST_CHECK_EQUAL(nonRotated.max_cycles(1), 1); 35 1 : BOOST_CHECK_EQUAL(nonRotated.max_cycles(0), 0); 36 : 37 : // Test rotated quorum 38 1 : LLMQParams rotated = TEST_PARAMS_BASE; 39 1 : rotated.useRotation = true; 40 1 : rotated.signingActiveQuorumCount = 2; 41 : 42 : // For rotated: max_cycles = quorums_count / signingActiveQuorumCount 43 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(10), 5); 44 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(100), 50); 45 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(1), 0); // Integer division 46 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(0), 0); 47 : 48 : // Test with different signingActiveQuorumCount 49 1 : rotated.signingActiveQuorumCount = 4; 50 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(100), 25); 51 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(16), 4); 52 1 : BOOST_CHECK_EQUAL(rotated.max_cycles(15), 3); // Integer division 53 1 : } 54 : 55 149 : BOOST_AUTO_TEST_CASE(llmq_params_max_store_depth_test) 56 : { 57 1 : LLMQParams params = TEST_PARAMS_BASE; 58 1 : params.dkgInterval = 24; 59 1 : params.signingActiveQuorumCount = 2; 60 1 : params.keepOldKeys = 10; 61 : 62 : // max_store_depth = max_cycles(keepOldKeys) * dkgInterval 63 : 64 : // Test non-rotated 65 1 : params.useRotation = false; 66 : // max_cycles(10) = 10 for non-rotated 67 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 10 * 24); // 240 68 : 69 : // Test rotated 70 1 : params.useRotation = true; 71 : // max_cycles(10) = 10/2 = 5 for rotated 72 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 5 * 24); // 120 73 : 74 : // Test with different values 75 1 : params.keepOldKeys = 20; 76 1 : params.dkgInterval = 48; 77 1 : params.signingActiveQuorumCount = 4; 78 : // max_cycles(20) = 20/4 = 5 for rotated 79 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 5 * 48); // 240 80 : 81 : // Test edge cases 82 1 : params.keepOldKeys = 0; 83 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 0); 84 : 85 1 : params.keepOldKeys = 1; 86 1 : params.dkgInterval = 1; 87 1 : params.signingActiveQuorumCount = 1; 88 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 1); 89 1 : } 90 : 91 149 : BOOST_AUTO_TEST_CASE(llmq_params_validation_test) 92 : { 93 : // Test parameter constraints and relationships 94 1 : LLMQParams params = TEST_PARAMS_BASE; 95 : 96 : // minSize should be less than or equal to size 97 1 : BOOST_CHECK_LE(params.minSize, params.size); 98 : 99 : // threshold should be less than or equal to size 100 1 : BOOST_CHECK_LE(params.threshold, params.size); 101 : 102 : // threshold should typically be > 50% of size for security 103 1 : BOOST_CHECK_GT(params.threshold * 2, params.size); 104 : 105 : // dkgMiningWindowStart should be after DKG phases complete 106 : // Typically should be >= 5 * dkgPhaseBlocks 107 1 : BOOST_CHECK_GE(params.dkgMiningWindowStart, 5 * params.dkgPhaseBlocks); 108 : 109 : // dkgMiningWindowEnd should be after dkgMiningWindowStart 110 1 : BOOST_CHECK_GT(params.dkgMiningWindowEnd, params.dkgMiningWindowStart); 111 : 112 : // dkgMiningWindowEnd should be within dkgInterval 113 1 : BOOST_CHECK_LT(params.dkgMiningWindowEnd, params.dkgInterval); 114 1 : } 115 : 116 149 : BOOST_AUTO_TEST_CASE(llmq_params_types_test) 117 : { 118 : // Test that LLMQ types are properly defined 119 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_NONE), 0xff); 120 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_50_60), 1); 121 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_400_60), 2); 122 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_400_85), 3); 123 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_100_67), 4); 124 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_60_75), 5); 125 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_25_67), 6); 126 : 127 : // Test special types 128 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_TEST), 100); 129 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_DEVNET), 101); 130 1 : BOOST_CHECK_EQUAL(static_cast<uint8_t>(LLMQType::LLMQ_TEST_V17), 102); 131 1 : } 132 : 133 149 : BOOST_AUTO_TEST_CASE(llmq_params_edge_calculations_test) 134 : { 135 1 : LLMQParams params; 136 : 137 : // Test with maximum values 138 1 : params.useRotation = true; 139 1 : params.signingActiveQuorumCount = 1; 140 1 : params.keepOldKeys = std::numeric_limits<int>::max() / 2; // Avoid overflow 141 1 : params.dkgInterval = 2; 142 : 143 : // Should not overflow 144 1 : int depth = params.max_store_depth(); 145 1 : BOOST_CHECK_GT(depth, 0); 146 : 147 : // Test division by zero protection 148 1 : params.signingActiveQuorumCount = 0; 149 : // This would cause division by zero in max_cycles if not handled 150 : // The implementation should handle this gracefully or it's a bug 151 : 152 : // Test with all zeros 153 1 : params.useRotation = false; 154 1 : params.keepOldKeys = 0; 155 1 : params.dkgInterval = 0; 156 1 : BOOST_CHECK_EQUAL(params.max_store_depth(), 0); 157 1 : } 158 : 159 149 : BOOST_AUTO_TEST_CASE(llmq_params_rotation_consistency_test) 160 : { 161 : // Test that rotation parameters are consistent 162 1 : LLMQParams rotatedParams; 163 1 : rotatedParams.useRotation = true; 164 1 : rotatedParams.signingActiveQuorumCount = 4; 165 1 : rotatedParams.keepOldConnections = 8; // Should be 2x active for rotated 166 1 : rotatedParams.keepOldKeys = 8; 167 1 : rotatedParams.dkgInterval = 24; 168 : 169 : // For rotated quorums, keepOldConnections should typically be 2x signingActiveQuorumCount 170 1 : BOOST_CHECK_EQUAL(rotatedParams.keepOldConnections, 2 * rotatedParams.signingActiveQuorumCount); 171 : 172 1 : LLMQParams nonRotatedParams; 173 1 : nonRotatedParams.useRotation = false; 174 1 : nonRotatedParams.signingActiveQuorumCount = 4; 175 1 : nonRotatedParams.keepOldConnections = 5; // Should be at least active + 1 for non-rotated 176 1 : nonRotatedParams.keepOldKeys = 8; 177 1 : nonRotatedParams.dkgInterval = 24; 178 : 179 : // For non-rotated quorums, keepOldConnections should be > signingActiveQuorumCount 180 1 : BOOST_CHECK_GT(nonRotatedParams.keepOldConnections, nonRotatedParams.signingActiveQuorumCount); 181 1 : } 182 : 183 149 : BOOST_AUTO_TEST_CASE(llmq_params_calculations_overflow_test) 184 : { 185 1 : LLMQParams params; 186 1 : params.useRotation = false; 187 1 : params.signingActiveQuorumCount = 1; 188 : 189 : // Test max_cycles with large values 190 1 : int largeQuorumCount = std::numeric_limits<int>::max(); 191 1 : int cycles = params.max_cycles(largeQuorumCount); 192 1 : BOOST_CHECK_EQUAL(cycles, largeQuorumCount); // Non-rotated returns input 193 : 194 : // Test potential overflow in max_store_depth 195 1 : params.keepOldKeys = std::numeric_limits<int>::max() / 100; 196 1 : params.dkgInterval = 100; 197 : 198 : // This should not crash or overflow 199 1 : int depth = params.max_store_depth(); 200 1 : BOOST_CHECK_GE(depth, 0); // Result should be valid 201 : 202 : // Test with rotation and potential division issues 203 1 : params.useRotation = true; 204 1 : params.signingActiveQuorumCount = std::numeric_limits<int>::max(); 205 1 : cycles = params.max_cycles(1000); 206 1 : BOOST_CHECK_EQUAL(cycles, 0); // 1000 / max_int = 0 207 1 : } 208 : 209 146 : BOOST_AUTO_TEST_SUITE_END()