Skip to content

test: add comprehensive unit tests for LLMQ subsystem #6691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

PastaPastaPasta
Copy link
Member

What was done?

Adds unit test coverage for core LLMQ components that were previously only covered by functional tests.

New test files:

  • llmq_commitment_tests.cpp: CFinalCommitment serialization, validation
  • llmq_chainlock_tests.cpp: CChainLockSig construction and serialization
  • llmq_hash_tests.cpp: BuildCommitmentHash deterministic behavior
  • llmq_params_tests.cpp: LLMQParams calculations for rotated/non-rotated quorums
  • llmq_snapshot_tests.cpp: CQuorumSnapshot and CQuorumRotationInfo structures
  • llmq_utils_tests.cpp: DeterministicOutboundConnection behavior
  • llmq_test_utils.h: Common test utilities and helpers

How Has This Been Tested?

Running unit tests

Breaking Changes

None

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have made corresponding changes to the documentation
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@PastaPastaPasta PastaPastaPasta added this to the 23 milestone May 27, 2025
Copy link

coderabbitai bot commented May 27, 2025

Walkthrough

This change introduces a comprehensive suite of unit tests and supporting utilities for the Long Living Masternode Quorums (LLMQ) subsystem. Six new test source files are added to the build configuration, each targeting a different aspect of LLMQ: chain locks, final commitments, hash construction, parameter validation, snapshot serialization, and utility functions. Each test suite uses the Boost unit test framework and leverages a new shared header providing LLMQ-specific test helpers, random data generators, and serialization utilities. Additionally, the list of non-backported test files is updated to include these new LLMQ test files, and the new test utility header is included in the test utility build. No changes are made to exported or public entities outside of the new test utilities.

Estimated code review effort

4 (~90 minutes)

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🔭 Outside diff range comments (1)
src/test/llmq_hash_tests.cpp (1)

255-288: ⚠️ Potential issue

Fix the test logic inconsistency.

The test has a logical issue: hash1 and hash2 are expected to be different because they use different random public keys (lines 264-265), but the test comment on line 268 incorrectly states "Different quorum hash should produce different hash" when referring to hash3.

Apply this diff to fix the test logic:

-    // Same inputs should produce same hash
-    uint256 hash2 = llmq::BuildCommitmentHash(TEST_PARAMS.type, GetTestQuorumHash(1),
-                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), CreateRandomBLSPublicKey(),
-                                              GetTestQuorumHash(2));
+    // Same inputs should produce same hash (use fixed public key)
+    CBLSPublicKey fixedPubKey = CreateRandomBLSPublicKey();
+    uint256 hash2 = llmq::BuildCommitmentHash(TEST_PARAMS.type, GetTestQuorumHash(1),
+                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), fixedPubKey,
+                                              GetTestQuorumHash(2));

And update the assertion comment:

-    BOOST_CHECK(hash1 != hash2); // Different pubkeys
+    BOOST_CHECK(hash1 == hash2); // Same inputs should produce same hash
🧹 Nitpick comments (2)
src/test/llmq_utils_tests.cpp (1)

24-24: Remove the trivial placeholder test.

This test doesn't provide any meaningful validation and appears to be a placeholder. Consider removing it to keep the test suite focused on actual functionality.

-BOOST_AUTO_TEST_CASE(trivially_passes) { BOOST_CHECK(true); }
src/test/llmq_test_utils.h (1)

74-83: Enhance the bit vector creation function.

Consider adding bounds checking and validation to make the function more robust.

 inline std::vector<bool> CreateBitVector(size_t size, const std::vector<size_t>& trueBits)
 {
     std::vector<bool> result(size, false);
     for (size_t idx : trueBits) {
         if (idx < size) {
             result[idx] = true;
+        } else {
+            // Optional: log warning about out-of-bounds indices
         }
     }
     return result;
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd3f3d4 and 89d235c.

📒 Files selected for processing (9)
  • src/Makefile.test.include (1 hunks)
  • src/test/llmq_chainlock_tests.cpp (1 hunks)
  • src/test/llmq_commitment_tests.cpp (1 hunks)
  • src/test/llmq_hash_tests.cpp (1 hunks)
  • src/test/llmq_params_tests.cpp (1 hunks)
  • src/test/llmq_snapshot_tests.cpp (1 hunks)
  • src/test/llmq_test_utils.h (1 hunks)
  • src/test/llmq_utils_tests.cpp (1 hunks)
  • test/util/data/non-backported.txt (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/test/llmq_utils_tests.cpp (1)
src/test/llmq_test_utils.h (2)
  • GetTestQuorumHash (103-106)
  • GetTestQuorumHash (103-103)
src/test/llmq_chainlock_tests.cpp (1)
src/test/llmq_test_utils.h (6)
  • GetTestBlockHash (108-111)
  • GetTestBlockHash (108-108)
  • CreateRandomBLSSignature (45-51)
  • CreateRandomBLSSignature (45-45)
  • CreateChainLock (67-71)
  • CreateChainLock (67-67)
src/test/llmq_hash_tests.cpp (1)
src/test/llmq_test_utils.h (8)
  • GetLLMQParams (27-35)
  • GetLLMQParams (27-27)
  • GetTestQuorumHash (103-106)
  • GetTestQuorumHash (103-103)
  • CreateBitVector (74-83)
  • CreateBitVector (74-74)
  • CreateRandomBLSPublicKey (38-43)
  • CreateRandomBLSPublicKey (38-38)
src/test/llmq_commitment_tests.cpp (1)
src/test/llmq_test_utils.h (12)
  • GetLLMQParams (27-35)
  • GetLLMQParams (27-27)
  • CreateValidCommitment (53-65)
  • CreateValidCommitment (53-53)
  • GetTestQuorumHash (103-106)
  • GetTestQuorumHash (103-103)
  • CreateRandomBLSPublicKey (38-43)
  • CreateRandomBLSPublicKey (38-38)
  • CreateRandomBLSSignature (45-51)
  • CreateRandomBLSSignature (45-45)
  • CreateBitVector (74-83)
  • CreateBitVector (74-74)
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: arm-linux-gnueabihf / Build depends
  • GitHub Check: build-image
🔇 Additional comments (33)
test/util/data/non-backported.txt (1)

40-40: LGTM! Proper tracking of new LLMQ test files.

The addition of the src/test/llmq*.cpp pattern correctly tracks the new LLMQ test files as non-backported, which aligns with the test files being added in src/Makefile.test.include.

src/test/llmq_utils_tests.cpp (4)

26-48: Excellent test coverage for deterministic behavior.

The test properly validates that DeterministicOutboundConnection produces consistent, deterministic results and maintains commutativity (order independence). The assertions verify both consistency and that the result is always one of the input hashes.


50-76: Comprehensive edge case testing.

Good coverage of edge cases including null hashes, same source/destination, and proper handling of boundary conditions. The tests verify the function behaves predictably even with unusual inputs.


78-82: Good documentation of testing scope.

The comments clearly explain why certain functions are deferred to integration/functional tests due to complexity of mocking required dependencies. This helps maintainers understand the testing strategy.


84-118: Thorough symmetry and network behavior testing.

Excellent test that validates the symmetric properties of the connection function across multiple nodes. The verification that results are consistent for each pair while allowing for overlapping results demonstrates good understanding of the expected behavior.

src/test/llmq_chainlock_tests.cpp (7)

18-37: Excellent constructor testing.

Comprehensive testing of both default and parameterized constructors, properly validating the null state, height, block hash, and signature fields. The assertions correctly verify expected behavior for each constructor variant.


39-53: Thorough null state validation.

Good testing of the IsNull() logic across different initialization scenarios. The tests properly distinguish between default construction (null) and explicit construction with parameters (not null).


55-71: Robust serialization testing.

Proper round-trip serialization testing that verifies all fields are preserved during serialization and deserialization. This is crucial for network communication and persistence.


73-91: Comprehensive string representation testing.

Good validation of the ToString() method for both null and valid chainlocks. The substring checks ensure that important information (height and block hash) is included in the output.


93-115: Excellent edge case testing.

Thorough testing with boundary values including height 0 and maximum int32 value. The serialization testing of these edge cases ensures robust handling of extreme values.


117-138: Proper comparison and getter testing.

Good validation of getter methods and comparison behavior with identical and different chainlock instances. This ensures the class maintains data integrity and proper field access.


140-165: Robust malformed data handling.

Excellent testing of deserialization with truncated data streams. The try-catch structure and validation of different truncation points demonstrates good defensive programming practices and ensures the class handles corrupted data gracefully.

src/test/llmq_snapshot_tests.cpp (3)

21-46: LGTM! Comprehensive constructor testing.

The test correctly validates default constructor, parameterized constructor, and move semantics for CQuorumSnapshot. Good coverage of different initialization patterns.


191-212: LGTM! Good JSON serialization validation.

The test properly verifies that the JSON output contains all expected fields and validates the structure. The bit vector conversion to hex strings is appropriately tested.


214-237: Good robustness testing for malformed data.

The test appropriately handles truncated serialized data and expects exceptions for invalid inputs. This helps ensure the deserialization code is robust against corrupted data.

src/test/llmq_hash_tests.cpp (2)

25-43: LGTM! Excellent deterministic behavior testing.

The test correctly verifies that BuildCommitmentHash produces identical results when called multiple times with the same inputs, ensuring the function is deterministic.


167-198: LGTM! Comprehensive bit pattern testing.

The test thoroughly validates that different bit patterns produce unique hashes, covering edge cases like empty vectors, single bits, and alternating patterns. The uniqueness verification is particularly valuable.

src/test/llmq_commitment_tests.cpp (4)

22-36: LGTM! Good null state validation.

The test properly verifies that a default-constructed CFinalCommitment is in the expected null state with all fields properly initialized to their default values.


149-190: Excellent bit vector JSON serialization testing.

The test comprehensively validates bit vector serialization to JSON hex strings, including:

  • Empty vectors
  • Full byte patterns (8 bits)
  • Specific bit patterns with correct LSB-first encoding
  • Non-byte-aligned sizes with proper padding

This thorough testing ensures the serialization format is correctly implemented.


112-123: LGTM! Clear version calculation testing.

The test clearly validates the version calculation logic for different combinations of rotation and scheme flags, ensuring all expected version constants are returned correctly.


255-288: ⚠️ Potential issue

Address the test logic flaw.

The test attempts to verify deterministic behavior but has a critical flaw: it creates different random public keys in hash1 and hash2 (lines 259 and 264), then expects them to be different, which contradicts the purpose of testing deterministic behavior.

Apply this diff to fix the deterministic testing:

-    // Test deterministic hash generation
+    // Test deterministic hash generation with fixed inputs
+    CBLSPublicKey fixedPubKey = CreateRandomBLSPublicKey();
     uint256 hash1 = llmq::BuildCommitmentHash(TEST_PARAMS.type, GetTestQuorumHash(1),
-                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), CreateRandomBLSPublicKey(),
+                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), fixedPubKey,
                                               GetTestQuorumHash(2));

     // Same inputs should produce same hash
     uint256 hash2 = llmq::BuildCommitmentHash(TEST_PARAMS.type, GetTestQuorumHash(1),
-                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), CreateRandomBLSPublicKey(),
+                                              CreateBitVector(TEST_PARAMS.size, {0, 1, 2}), fixedPubKey,
                                               GetTestQuorumHash(2));

And update the assertion:

-    BOOST_CHECK(hash1 != hash2); // Different pubkeys
+    BOOST_CHECK(hash1 == hash2); // Same inputs produce same hash

Likely an incorrect or invalid review comment.

src/test/llmq_test_utils.h (4)

27-35: LGTM! Good parameter lookup utility.

The function provides a clean way to retrieve LLMQ parameters by type with appropriate error handling. The linear search is acceptable given the small number of available LLMQ types.


86-100: Excellent serialization roundtrip testing approach.

The template function uses a robust approach by re-serializing the deserialized object and comparing the byte streams. This ensures complete serialization fidelity rather than just field-by-field comparison.


53-65: Well-designed commitment creation utility.

The function creates a properly initialized CFinalCommitment with all required fields set to valid values, making it easy to create test data that passes validation checks.


103-111: Good deterministic test data generators.

The functions provide deterministic hash generation using different offsets, ensuring reproducible test results while avoiding collisions between quorum and block hashes.

src/test/llmq_params_tests.cpp (8)

1-18: LGTM! Good test file structure and includes.

The copyright header, includes, and namespace declarations are appropriate for a comprehensive LLMQ parameter test suite.


19-22: Good test fixture setup.

Using BasicTestingSetup fixture and defining a constant for test parameters follows good testing practices.


24-53: Comprehensive max_cycles testing with good edge case coverage.

The test correctly validates both rotated and non-rotated quorum scenarios, including integer division behavior and edge cases.


55-89: Well-structured max_store_depth calculation tests.

The tests properly verify the formula max_cycles(keepOldKeys) * dkgInterval for both rotation scenarios and include good edge case testing.


91-114: Excellent parameter validation tests.

These tests verify important business logic constraints including security thresholds (>50% for threshold), size relationships, and DKG timing constraints.


116-131: Good enum value verification.

Testing hardcoded enum values ensures API stability and catches potential breaking changes in LLMQ type definitions.


159-181: Good rotation consistency validation.

The tests properly verify the relationship between keepOldConnections and signingActiveQuorumCount for both rotated and non-rotated scenarios, which is important for network stability.


183-207: Comprehensive overflow protection testing.

The tests appropriately verify behavior with large integer values and protect against potential overflow scenarios in calculations.

Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't look bad overall.

See comments though

BOOST_CHECK(!commitment.IsNull());

// Reset and test signatures
commitment = CFinalCommitment();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: commitment = CFinalCommitment{};

is better IMO

BOOST_CHECK(!str.empty());

// ToString should contain height and hash info
BOOST_CHECK(str.find(std::to_string(height)) != std::string::npos);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

std::to_string() should not be used here; we have linter for it:

diff --git a/src/test/llmq_test_utils.h b/src/test/llmq_test_utils.h
@@ -0,0 +1,116 @@
+    
+    
+    
The locale dependent function std::to_string(...) appears to be used:
src/test/llmq_chainlock_tests.cpp:    BOOST_CHECK(str.find(std::to_string(height)) != std::string::npos);

Copy link

This pull request has conflicts, please rebase.

Copy link

github-actions bot commented Jul 18, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM overall, though 2 things require attention:

  • test/util/data/non-backported.txt
  • GetTestBlockHash

Other comments are optional and can be done in follow-up PRs / later

Performance of unit tests is not affected, as I tested:

$ time src/test/test_dash -t 'llmq*'
Running 45 test cases...

*** No errors detected

real    0m0,308s
user    0m0,232s
sys     0m0,076s


// Test parameterized constructor
int32_t height = 12345;
uint256 blockHash = GetTestBlockHash(1);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: names should be named in snake_case for new code; for example: block_hash instead blockHash.
nullClsig -> null_clsig (or clsig_null)
nonRotatedParams -> params_non_rotated (or non_rotated_params)
truncateAt -> truncate_at
hashDiffQuorum -> hash_diff_quorum
hashDiffPubKey -> hash_diff_pubkey
hashDiffVvec -> hash_diff_vvec
hashEmpty -> hash_empty
hashNoneValid -> hash_none_valid
hashAllValid -> hash_all_valid
proTxHash1 -> protx_hash1

also, hashNullQuorum, hashInvalidKey, hashNullVvec, largeValidMembers, hashLarge, hashLargeDiff, nonRotated, getInfo, activeMembers, skipMode, skipList, nullHash, validHash

See doc/developer-notes.md:

- **Symbol naming conventions**. These are preferred in new code, but are not
required when doing so would need changes to significant pieces of existing
code.
  - Variable (including function arguments) and namespace names are all lowercase and may use `_` to
    separate words (snake_case).
    - Class member variables have a `m_` prefix.
    - Global variables have a `g_` prefix.
  - Constant names are all uppercase, and use `_` to separate words.
  - Enumerator constants may be `snake_case`, `PascalCase` or `ALL_CAPS`.
    This is a more tolerant policy than the [C++ Core
    Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Renum-caps),
    which recommend using `snake_case`.  Please use what seems appropriate.
  - Class names, function names, and method names are UpperCamelCase
    (PascalCase). Do not prefix class names with `C`. See [Internal interface
    naming style](#internal-interface-naming-style) for an exception to this
    convention.

inline CChainLockSig CreateChainLock(int32_t height, const uint256& blockHash)
{
CBLSSignature sig = CreateRandomBLSSignature();
return CChainLockSig(height, blockHash, sig);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: use {}

    return CChainLockSig{height, blockHash, sig};

Comment on lines +84 to +118
BOOST_AUTO_TEST_CASE(deterministic_connection_symmetry_test)
{
// Test interesting properties of DeterministicOutboundConnection
uint256 proTxHash1 = GetTestQuorumHash(1);
uint256 proTxHash2 = GetTestQuorumHash(2);
uint256 proTxHash3 = GetTestQuorumHash(3);

// Create a "network" of connections
// DeterministicOutboundConnection is symmetric - order doesn't matter
uint256 conn12 = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash2);
uint256 conn21 = llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash1);
uint256 conn13 = llmq::utils::DeterministicOutboundConnection(proTxHash1, proTxHash3);
uint256 conn31 = llmq::utils::DeterministicOutboundConnection(proTxHash3, proTxHash1);
uint256 conn23 = llmq::utils::DeterministicOutboundConnection(proTxHash2, proTxHash3);
uint256 conn32 = llmq::utils::DeterministicOutboundConnection(proTxHash3, proTxHash2);

// Verify symmetry - swapped inputs produce same output
BOOST_CHECK(conn12 == conn21);
BOOST_CHECK(conn13 == conn31);
BOOST_CHECK(conn23 == conn32);

// Each connection returns one of the two nodes
BOOST_CHECK(conn12 == proTxHash1 || conn12 == proTxHash2);
BOOST_CHECK(conn13 == proTxHash1 || conn13 == proTxHash3);
BOOST_CHECK(conn23 == proTxHash2 || conn23 == proTxHash3);

// The function deterministically picks which node initiates the connection
// Verify we get consistent results for each pair
std::set<uint256> uniqueResults;
uniqueResults.insert(conn12);
uniqueResults.insert(conn13);
uniqueResults.insert(conn23);
// Each pair should produce one of its members, but pairs may have overlapping results
BOOST_CHECK(uniqueResults.size() >= 2 && uniqueResults.size() <= 3);
}
Copy link
Collaborator

@knst knst Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

conn12, conn13, conn23, ... looks a bit messy, easy to typo, difficult to review and edit. Consider something similar to:

BOOST_AUTO_TEST_CASE(deterministic_connection_symmetry_test)
{
    // Test interesting properties of DeterministicOutboundConnection
    std::vector<uint256> protx_hashes;
    for (int i = 0; i < 3; ++i) {
        protx_hashes.push_back(GetTestQuorumHash(i + 1));
    }
    // Create a "network" of connections
    std::vector<uint256> connections_1;
    std::vector<uint256> connections_2;
    for (int i = 0; i < 3; ++i) {
        connections_1.push_back(llmq::utils::DeterministicOutboundConnection(protx_hashes[i], protx_hashes[(i + 1) % 3]));
        connections_2.push_back(llmq::utils::DeterministicOutboundConnection(protx_hashes[(i + 1) % 3], protx_hashes[i]));
    }
    for (int i = 0; i < 3; ++i) {
        // DeterministicOutboundConnection is symmetric - order doesn't matter
        // Verify symmetry - swapped inputs produce same output
        BOOST_CHECK(connections_1[i] == connections_2[i]);
        // Each connection returns one of the two nodes
        BOOST_CHECK(connections_1[i] == protx_hashes[i] || connections_1[i] == protx_hashes[(i + 1) % 3]);
    }

    // Each pair should produce one of its members, but pairs may have overlapping results
    std::sort(connections_1.begin(), connections_1.end());
    BOOST_CHECK(connections_1[0] != connections_1[1] || connections_1[1] != connections_1[2]);
}

@@ -0,0 +1,260 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright 2025

@@ -0,0 +1,290 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright 2025

@@ -0,0 +1,209 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright 2025

@@ -0,0 +1,120 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright 2025

@@ -0,0 +1,116 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: copyright 2025

@@ -0,0 +1,200 @@
// Copyright (c) 2024 The Dash Core developers
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit:; copyright 2025

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/test/util/llmq_tests.h (2)

1-1: Update copyright year to 2025.

The copyright should reflect the current year when the code is being introduced.

-// Copyright (c) 2024 The Dash Core developers
+// Copyright (c) 2025 The Dash Core developers

67-71: Use uniform initialization for better consistency.

Consider using uniform initialization syntax for better code consistency.

-    return CChainLockSig(height, blockHash, sig);
+    return CChainLockSig{height, blockHash, sig};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d22bba2 and 41acd27.

📒 Files selected for processing (2)
  • src/test/util/llmq_tests.h (1 hunks)
  • test/util/data/non-backported.txt (1 hunks)
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/util/llmq_tests.h
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/util/llmq_tests.h
🧠 Learnings (2)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/util/llmq_tests.h (3)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

🪛 GitHub Actions: Clang Diff Format Check
src/test/util/llmq_tests.h

[error] 1-40: Clang format differences found. The file does not conform to the expected code style and requires reformatting.

🚧 Files skipped from review as they are similar to previous changes (1)
  • test/util/data/non-backported.txt
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/util/llmq_tests.h
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/util/llmq_tests.h
🧠 Learnings (2)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/util/llmq_tests.h (3)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

🪛 GitHub Actions: Clang Diff Format Check
src/test/util/llmq_tests.h

[error] 1-40: Clang format differences found. The file does not conform to the expected code style and requires reformatting.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: x86_64-pc-linux-gnu_multiprocess / Build depends
  • GitHub Check: x86_64-apple-darwin / Build depends
  • GitHub Check: Lint / Run linters
  • GitHub Check: x86_64-pc-linux-gnu / Build depends
  • GitHub Check: arm-linux-gnueabihf / Build depends
🔇 Additional comments (9)
src/test/util/llmq_tests.h (9)

27-35: LGTM! Helper function provides clean LLMQ parameter access.

The function correctly iterates through available LLMQ parameters and throws an appropriate exception when the type is not found. The implementation is straightforward and serves its purpose well.


38-43: LGTM! BLS public key generation is correct.

The function properly creates a new secret key and derives the public key from it. This is the standard approach for generating test BLS public keys.


45-51: LGTM! BLS signature generation follows correct pattern.

The function creates a new secret key, generates a random hash, and signs it. The false parameter for the signing method is appropriate for test scenarios.


53-65: LGTM! Comprehensive commitment creation with valid structure.

The function creates a well-formed CFinalCommitment with all necessary fields populated. The bit vectors are properly sized according to the LLMQ parameters, and all cryptographic fields use the appropriate random generation functions.


74-83: LGTM! Robust bit vector creation with bounds checking.

The function properly initializes a bit vector of the specified size and safely sets bits at the provided indices with appropriate bounds checking to prevent out-of-range access.


86-100: LGTM! Comprehensive serialization round-trip testing.

The template function properly tests serialization by comparing the original serialized data with the data after deserializing and re-serializing. This is a robust approach to verify serialization correctness.


103-106: LGTM! Simple and effective deterministic hash generation.

The function provides a straightforward way to generate deterministic test quorum hashes using arithmetic conversion.


108-111: LGTM! Effective differentiation between hash types.

The function creates deterministic block hashes that are clearly distinguishable from quorum hashes by using a left shift, ensuring no collision between test data types.


113-116: LGTM! Proper namespace and header guard closure.

The namespace and header guard are properly closed, maintaining good code organization and preventing multiple inclusions.

knst
knst previously approved these changes Jul 22, 2025
Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 0c0dadb

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
src/test/llmq_commitment_tests.cpp (1)

22-36: Test logic is correct. Consider using brace initialization.

The null state testing is comprehensive and correct. However, consider using brace initialization as suggested in previous reviews:

-    CFinalCommitment commitment;
+    CFinalCommitment commitment{};
src/test/util/llmq_tests.h (2)

67-83: LGTM! Useful utility functions.

Both functions provide good test data creation capabilities. Consider applying the previous review suggestion for cleaner initialization:

-    return CChainLockSig(height, blockHash, sig);
+    return CChainLockSig{height, blockHash, sig};

102-111: Fix potential integer overflow in GetTestQuorumHash.

The current implementation could cause integer overflow for large values of n. Apply the fix suggested in previous reviews:

-    return ArithToUint256(arith_uint256(n));
+    return ArithToUint256(arith_uint256(n) + 1000000);

This ensures distinct hash values while preventing overflow.

src/test/llmq_params_tests.cpp (1)

133-157: Remove unrealistic division by zero test case.

Based on the retrieved learning, signingActiveQuorumCount is never 0 in actual LLMQ parameters defined in params.h, making lines 148-150 test an impossible scenario.

Consider removing this test case entirely:

-    // Test division by zero protection
-    params.signingActiveQuorumCount = 0;
-    // This would cause division by zero in max_cycles if not handled
-    // The implementation should handle this gracefully or it's a bug

Since the actual implementation guarantees non-zero values, this test provides no value and tests unrealistic conditions.

🧹 Nitpick comments (1)
src/test/llmq_commitment_tests.cpp (1)

192-290: LGTM! Comprehensive edge case and hash testing.

Excellent coverage of:

  • Null state edge cases with individual field setting
  • Transaction payload construction
  • Deterministic hash generation and uniqueness validation

Consider using brace initialization for consistency (lines 229, 234, 238):

-    commitment = CFinalCommitment{};
+    commitment = {};
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 41acd27 and 0c0dadb.

📒 Files selected for processing (6)
  • src/test/llmq_commitment_tests.cpp (1 hunks)
  • src/test/llmq_hash_tests.cpp (1 hunks)
  • src/test/llmq_params_tests.cpp (1 hunks)
  • src/test/llmq_snapshot_tests.cpp (1 hunks)
  • src/test/llmq_utils_tests.cpp (1 hunks)
  • src/test/util/llmq_tests.h (1 hunks)
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/util/llmq_tests.h
  • src/test/llmq_params_tests.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/util/llmq_tests.h
  • src/test/llmq_params_tests.cpp
🧠 Learnings (4)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/llmq_commitment_tests.cpp (2)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

src/test/util/llmq_tests.h (5)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6529
File: src/rpc/governance.cpp:1074-1089
Timestamp: 2025-02-14T15:15:58.165Z
Learning: Code blocks marked with // clang-format off and // clang-format on directives should be excluded from clang-format suggestions as they are intentionally formatted manually for better readability.

Learnt from: kwvg
PR: #6729
File: src/rpc/evo.cpp:1273-1273
Timestamp: 2025-07-09T15:05:36.250Z
Learning: When clang-format suggestions significantly harm readability (like splitting logical parameter groups across multiple lines), it's acceptable to use // clang-format off and // clang-format on directives to exclude the problematic section from automatic formatting, prioritizing code readability over strict line length compliance.

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

src/test/llmq_params_tests.cpp (4)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6752
File: src/wallet/load.cpp:164-164
Timestamp: 2025-07-17T15:48:29.418Z
Learning: In Dash Core, kwvg prefers using assert() statements to document expected behavior in code paths, especially when the called function also has internal asserts. This is used as a defensive programming pattern rather than requiring conditional error handling.

🚧 Files skipped from review as they are similar to previous changes (3)
  • src/test/llmq_utils_tests.cpp
  • src/test/llmq_snapshot_tests.cpp
  • src/test/llmq_hash_tests.cpp
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/util/llmq_tests.h
  • src/test/llmq_params_tests.cpp
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/util/llmq_tests.h
  • src/test/llmq_params_tests.cpp
🧠 Learnings (4)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/llmq_commitment_tests.cpp (2)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

src/test/util/llmq_tests.h (5)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6529
File: src/rpc/governance.cpp:1074-1089
Timestamp: 2025-02-14T15:15:58.165Z
Learning: Code blocks marked with // clang-format off and // clang-format on directives should be excluded from clang-format suggestions as they are intentionally formatted manually for better readability.

Learnt from: kwvg
PR: #6729
File: src/rpc/evo.cpp:1273-1273
Timestamp: 2025-07-09T15:05:36.250Z
Learning: When clang-format suggestions significantly harm readability (like splitting logical parameter groups across multiple lines), it's acceptable to use // clang-format off and // clang-format on directives to exclude the problematic section from automatic formatting, prioritizing code readability over strict line length compliance.

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

src/test/llmq_params_tests.cpp (4)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6752
File: src/wallet/load.cpp:164-164
Timestamp: 2025-07-17T15:48:29.418Z
Learning: In Dash Core, kwvg prefers using assert() statements to document expected behavior in code paths, especially when the called function also has internal asserts. This is used as a defensive programming pattern rather than requiring conditional error handling.

🔇 Additional comments (17)
src/test/llmq_commitment_tests.cpp (6)

1-16: LGTM! Clean header structure with appropriate includes.

The copyright year is correctly set to 2025 and all necessary headers are included for the LLMQ commitment testing functionality.


17-21: LGTM! Proper test suite setup.

Using BasicTestingSetup fixture and getting consistent test parameters from LLMQ_TEST_V17 is the correct approach for LLMQ unit tests.


38-66: LGTM! Comprehensive counting method tests.

Excellent coverage of different bit vector patterns including empty, mixed, all true, and all false scenarios. The test cases thoroughly validate the counting functionality.


68-87: LGTM! Thorough size verification testing.

Well-designed test that validates both correct sizes and various incorrect size scenarios, ensuring the VerifySizes method properly validates vector dimensions.


89-110: LGTM! Comprehensive serialization round-trip test.

Excellent validation of serialization integrity - all commitment fields are properly verified after the serialization/deserialization cycle.


112-190: LGTM! Comprehensive version and JSON serialization tests.

Excellent test coverage including:

  • Version calculation with all rotation/scheme combinations
  • JSON field validation
  • Bit vector hex encoding with edge cases (empty, non-byte-aligned, specific patterns)

The bit order comment in line 177 is particularly helpful for understanding the LSB-first serialization format.

src/test/util/llmq_tests.h (5)

1-25: LGTM! Well-structured header with comprehensive includes.

Proper include guard structure and all necessary headers for LLMQ testing utilities are included.


26-35: LGTM! Clean LLMQ parameter lookup function.

Simple and effective implementation using modern C++ range-based loop with appropriate error handling.


37-51: LGTM! Appropriate BLS test data generators.

Correctly implemented random BLS key and signature generation for testing. Using InsecureRand256() is appropriate for test data.


53-65: LGTM! Well-designed commitment creation helper.

Creates structurally valid commitments with appropriate test data. The function properly initializes all fields with realistic values for testing.


85-100: LGTM! Excellent generic serialization test utility.

Well-designed template function that provides comprehensive serialization round-trip testing by comparing the byte-level output. This is a valuable utility for ensuring serialization correctness.

src/test/llmq_params_tests.cpp (6)

1-23: LGTM! Clean header and test setup.

Proper copyright header for 2025 and appropriate test suite configuration using LLMQ_TEST_V17 parameters.


24-53: LGTM! Comprehensive max_cycles testing.

Excellent coverage of both rotated and non-rotated quorum scenarios with appropriate edge cases and integer division testing.


55-89: LGTM! Thorough max_store_depth calculation testing.

Well-structured test that validates the max_store_depth calculation across different rotation modes and parameter combinations, including important edge cases.


91-131: LGTM! Important parameter validation and type testing.

Excellent validation of critical parameter relationships including security constraints (threshold > 50% of size) and proper LLMQ type enum verification.


159-181: LGTM! Important rotation parameter consistency validation.

Well-designed test that ensures proper parameter relationships between keepOldConnections and signingActiveQuorumCount for both rotated and non-rotated quorum configurations.


183-207: LGTM! Essential overflow protection testing.

Excellent defensive testing with large values to ensure calculations remain stable and don't overflow. This is particularly important for production robustness.

@UdjinM6
Copy link

UdjinM6 commented Jul 22, 2025

should drop baf8ddc and mabe make clang-format happy too

PastaPastaPasta and others added 8 commits July 22, 2025 12:56
Adds unit test coverage for core LLMQ
components that were previously only covered by functional tests.

New test files:
- llmq_commitment_tests.cpp: CFinalCommitment serialization, validation
- llmq_chainlock_tests.cpp: CChainLockSig construction and serialization
- llmq_hash_tests.cpp: BuildCommitmentHash deterministic behavior
- llmq_params_tests.cpp: LLMQParams calculations for rotated/non-rotated quorums
- llmq_snapshot_tests.cpp: CQuorumSnapshot and CQuorumRotationInfo structures
- llmq_utils_tests.cpp: DeterministicOutboundConnection behavior
- llmq_test_utils.h: Common test utilities and helpers
The BITCOIN_TESTS list should only contain .cpp files. Header files
are included through #include directives, not by adding them to the
test executable sources.

Co-Authored-By: Claude <[email protected]>
Document why serialization roundtrip tests are commented out:
- CQuorumSnapshot uses custom bit vector serialization that doesn't
  produce byte-identical output after roundtrip
- CGetQuorumRotationInfo may have issues with empty vectors
- Tests should be re-enabled once proper equality operators are
  implemented or serialization issues are resolved

Co-Authored-By: Claude <[email protected]>
- Move llmq_test_utils.h to test/util/llmq_tests.h following test utility pattern
- Update all include statements to use new header location
- Fix copyright year to 2025 in llmq_chainlock_tests.cpp
- Replace std::to_string with strprintf to comply with linter
- Update CFinalCommitment assignment to use {} syntax
- Add TODO comments explaining disabled serialization tests

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
The header file test/util/llmq_tests.h was missing from the TEST_UTIL_H
list in Makefile.test_util.include, causing compilation errors when
building tests that include this header.
Remove trailing whitespace from blank lines in the TestSerializationRoundtrip function.

Co-Authored-By: Claude <[email protected]>
- Add src/test/util/llmq_tests.h to non-backported.txt
- Fix GetTestBlockHash to use bit shift pattern instead of arbitrary constant
  to avoid potential collisions with GetTestQuorumHash and maintain consistency

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
Address knst's review feedback to correct copyright dates from 2024 to 2025
in all new LLMQ unit test files created this year.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@PastaPastaPasta PastaPastaPasta force-pushed the test/add-llmq-unit-tests branch from 0c0dadb to e5431a4 Compare July 22, 2025 17:56
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (4)
src/test/llmq_snapshot_tests.cpp (2)

114-136: TODO comments properly document serialization limitations.

The edge case tests are comprehensive, and the TODO comments clearly explain why the serialization roundtrip tests are disabled due to custom bit vector serialization.


138-170: Thorough bit vector edge case testing!

Excellent coverage of bit vector edge cases including single bit, byte boundaries, and alternating patterns. TODO comments consistently document the serialization limitations.

src/test/llmq_commitment_tests.cpp (1)

192-241: Excellent null state edge case coverage!

Very thorough testing of how each field affects the IsNull() state. The {} initialization style is properly used as suggested.

src/test/llmq_params_tests.cpp (1)

147-151: Remove or document unrealistic division by zero test.

As discussed in previous reviews, signingActiveQuorumCount is never 0 in actual LLMQ parameters. This test case should either be removed entirely or clearly documented as testing a theoretical edge case that cannot occur in practice.

Either remove these lines:

-    // Test division by zero protection
-    params.signingActiveQuorumCount = 0;
-    // This would cause division by zero in max_cycles if not handled
-    // The implementation should handle this gracefully or it's a bug

Or document the theoretical nature:

-    // Test division by zero protection
+    // Test theoretical edge case: division by zero protection
+    // Note: signingActiveQuorumCount is never 0 in actual LLMQ parameters
     params.signingActiveQuorumCount = 0;
-    // This would cause division by zero in max_cycles if not handled
-    // The implementation should handle this gracefully or it's a bug
+    // This scenario cannot occur in practice but tests defensive programming
🧹 Nitpick comments (1)
src/test/llmq_snapshot_tests.cpp (1)

188-210: Investigate empty vector serialization for CGetQuorumRotationInfo.

The TODO comments indicate potential serialization issues with empty base block hashes. This should be investigated to determine if it's a bug or expected behavior.

Would you like me to help investigate why CGetQuorumRotationInfo serialization might fail with empty vectors and propose a fix?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c0dadb and e08d628.

📒 Files selected for processing (10)
  • src/Makefile.test.include (1 hunks)
  • src/Makefile.test_util.include (1 hunks)
  • src/test/llmq_chainlock_tests.cpp (1 hunks)
  • src/test/llmq_commitment_tests.cpp (1 hunks)
  • src/test/llmq_hash_tests.cpp (1 hunks)
  • src/test/llmq_params_tests.cpp (1 hunks)
  • src/test/llmq_snapshot_tests.cpp (1 hunks)
  • src/test/llmq_utils_tests.cpp (1 hunks)
  • src/test/util/llmq_tests.h (1 hunks)
  • test/util/data/non-backported.txt (1 hunks)
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/llmq_params_tests.cpp
  • src/test/llmq_snapshot_tests.cpp
  • src/test/util/llmq_tests.h
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/llmq_params_tests.cpp
  • src/test/llmq_snapshot_tests.cpp
  • src/test/util/llmq_tests.h
🧠 Learnings (5)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/llmq_commitment_tests.cpp (2)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

src/test/llmq_params_tests.cpp (5)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/is_basic_scheme_active=/true, /is_extended_addr=/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Learnt from: kwvg
PR: #6752
File: src/wallet/load.cpp:164-164
Timestamp: 2025-07-17T15:48:29.418Z
Learning: In Dash Core, kwvg prefers using assert() statements to document expected behavior in code paths, especially when the called function also has internal asserts. This is used as a defensive programming pattern rather than requiring conditional error handling.

src/test/llmq_snapshot_tests.cpp (3)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/is_basic_scheme_active=/true, /is_extended_addr=/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

src/test/util/llmq_tests.h (4)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6529
File: src/rpc/governance.cpp:1074-1089
Timestamp: 2025-02-14T15:15:58.165Z
Learning: Code blocks marked with // clang-format off and // clang-format on directives should be excluded from clang-format suggestions as they are intentionally formatted manually for better readability.

Learnt from: kwvg
PR: #6729
File: src/rpc/evo.cpp:1273-1273
Timestamp: 2025-07-09T15:05:36.250Z
Learning: When clang-format suggestions significantly harm readability (like splitting logical parameter groups across multiple lines), it's acceptable to use // clang-format off and // clang-format on directives to exclude the problematic section from automatic formatting, prioritizing code readability over strict line length compliance.

🚧 Files skipped from review as they are similar to previous changes (6)
  • src/Makefile.test_util.include
  • test/util/data/non-backported.txt
  • src/Makefile.test.include
  • src/test/llmq_utils_tests.cpp
  • src/test/llmq_chainlock_tests.cpp
  • src/test/llmq_hash_tests.cpp
🧰 Additional context used
📓 Path-based instructions (2)
src/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

src/**/*.{cpp,h,cc,cxx,hpp}: Dash Core C++ codebase must be written in C++20 and require at least Clang 16 or GCC 11.1
Dash uses unordered_lru_cache for efficient caching with LRU eviction

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/llmq_params_tests.cpp
  • src/test/llmq_snapshot_tests.cpp
  • src/test/util/llmq_tests.h
src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp}

📄 CodeRabbit Inference Engine (CLAUDE.md)

Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Files:

  • src/test/llmq_commitment_tests.cpp
  • src/test/llmq_params_tests.cpp
  • src/test/llmq_snapshot_tests.cpp
  • src/test/util/llmq_tests.h
🧠 Learnings (5)
📓 Common learnings
Learnt from: kwvg
PR: dashpay/dash#6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.
Learnt from: kwvg
PR: dashpay/dash#6543
File: src/wallet/receive.cpp:240-251
Timestamp: 2025-02-06T14:34:30.466Z
Learning: Pull request #6543 is focused on move-only changes and refactoring, specifically backporting from Bitcoin. Behavior changes should be proposed in separate PRs.
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests
Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{masternode,evo}/**/*.{cpp,h,cc,cxx,hpp} : Masternode lists must use immutable data structures (Immer library) for thread safety
src/test/llmq_commitment_tests.cpp (2)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

src/test/llmq_params_tests.cpp (5)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: knst
PR: #6691
File: src/test/llmq_params_tests.cpp:148-151
Timestamp: 2025-07-15T14:53:04.819Z
Learning: In the Dash Core LLMQ implementation, signingActiveQuorumCount is never 0 in the actual parameters defined in params.h, making division by zero scenarios unrealistic in the max_cycles() function.

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/is_basic_scheme_active=/true, /is_extended_addr=/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

Learnt from: kwvg
PR: #6752
File: src/wallet/load.cpp:164-164
Timestamp: 2025-07-17T15:48:29.418Z
Learning: In Dash Core, kwvg prefers using assert() statements to document expected behavior in code paths, especially when the called function also has internal asserts. This is used as a defensive programming pattern rather than requiring conditional error handling.

src/test/llmq_snapshot_tests.cpp (3)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6665
File: src/evo/providertx.h:82-82
Timestamp: 2025-06-06T11:53:09.094Z
Learning: In ProTx serialization code (SERIALIZE_METHODS), version checks should use hardcoded maximum flags (/is_basic_scheme_active=/true, /is_extended_addr=/true) rather than deployment-based flags. This is because serialization code should be able to deserialize any structurally valid ProTx up to the maximum version the code knows how to handle, regardless of current consensus validity. Validation code, not serialization code, is responsible for checking whether a ProTx version is consensus-valid based on deployment status.

src/test/util/llmq_tests.h (4)

Learnt from: CR
PR: dashpay/dash#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-20T18:42:49.794Z
Learning: Applies to src/{test,wallet/test,qt/test}/**/*.{cpp,h,cc,cxx,hpp} : Unit tests for C++ code should be placed in src/test/, src/wallet/test/, or src/qt/test/ and use Boost::Test or Qt 5 for GUI tests

Learnt from: kwvg
PR: #6718
File: test/functional/test_framework/test_framework.py:2102-2102
Timestamp: 2025-06-09T16:43:20.996Z
Learning: In the test framework consolidation PR (#6718), user kwvg prefers to limit functional changes to those directly related to MasternodeInfo, avoiding scope creep even for minor improvements like error handling consistency.

Learnt from: kwvg
PR: #6529
File: src/rpc/governance.cpp:1074-1089
Timestamp: 2025-02-14T15:15:58.165Z
Learning: Code blocks marked with // clang-format off and // clang-format on directives should be excluded from clang-format suggestions as they are intentionally formatted manually for better readability.

Learnt from: kwvg
PR: #6729
File: src/rpc/evo.cpp:1273-1273
Timestamp: 2025-07-09T15:05:36.250Z
Learning: When clang-format suggestions significantly harm readability (like splitting logical parameter groups across multiple lines), it's acceptable to use // clang-format off and // clang-format on directives to exclude the problematic section from automatic formatting, prioritizing code readability over strict line length compliance.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: linux64_multiprocess-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: arm-linux-build / Build source
🔇 Additional comments (28)
src/test/llmq_snapshot_tests.cpp (7)

21-46: Well-structured construction tests!

The test thoroughly covers default construction, parameterized construction, and move semantics for CQuorumSnapshot.


48-67: Proper manual serialization test implementation!

Good approach to manually test serialization/deserialization by comparing field values rather than byte-for-byte equality, which is appropriate given the custom bit vector serialization.


69-85: Comprehensive skip mode coverage!

Tests all four skip modes and verifies they're preserved through serialization.


87-112: Good stress test with large data sets!

Tests realistic large quorum scenarios (400 members) with appropriate patterns. The manual serialization approach is consistent with the bit vector serialization constraints.


172-183: Good default state validation!

Properly tests all fields of CQuorumRotationInfo in their default state. The note about complex serialization being better suited for functional tests is reasonable.


212-233: Comprehensive JSON serialization test!

Properly verifies JSON structure, field presence, and array serialization for skip lists.


235-258: Excellent robustness testing!

Good approach to test deserialization resilience by progressively truncating data. The try-catch properly handles expected exceptions.

src/test/llmq_commitment_tests.cpp (9)

22-36: Good null state validation!

Comprehensive checks for all fields in null state. The note about VerifyNull requiring functional tests is appropriate.


38-66: Thorough counting method tests!

Excellent coverage of edge cases including empty vectors, all true/false, and mixed patterns.


68-87: Comprehensive size verification tests!

Good coverage of both valid and invalid size scenarios.


89-110: Thorough serialization validation!

Excellent field-by-field verification ensuring all commitment data is preserved through serialization.


112-123: Complete version calculation coverage!

Tests all four version combinations based on rotation and scheme flags.


125-147: Comprehensive JSON field validation!

Verifies all expected fields and count values in JSON output.


149-190: Excellent bit vector JSON serialization tests!

Comprehensive coverage including empty vectors, byte patterns, LSB-first ordering, and non-byte-aligned padding. The comment about LSB-first ordering is particularly helpful.


243-253: Good basic tx payload validation!

Tests the essential fields of CFinalCommitmentTxPayload.


255-288: Thorough commitment hash testing!

Good coverage of deterministic behavior and uniqueness with different inputs.

src/test/util/llmq_tests.h (6)

26-35: Useful LLMQ parameter lookup helper!

Good error handling with descriptive exception message.


37-51: Standard BLS test data generators!

Appropriate for creating test keys and signatures.


53-65: Comprehensive commitment test data generator!

Creates fully populated commitments suitable for testing.


73-83: Safe bit vector creation with bounds checking!

Good defensive programming by checking index bounds.


85-100: Well-designed serialization test helper!

Correctly implements byte-for-byte roundtrip verification.


102-105: Simple deterministic test hash generators!

Appropriate for generating predictable test data.

src/test/llmq_params_tests.cpp (6)

24-53: Comprehensive max_cycles calculation tests!

Excellent coverage of both rotated and non-rotated scenarios with edge cases.


55-89: Thorough max_store_depth calculation tests!

Good coverage of different parameter combinations and edge cases.


91-114: Excellent parameter constraint validation!

Verifies important security and consistency constraints between LLMQ parameters.


116-131: Important LLMQ type value verification!

Ensures enum values remain consistent, which is critical for protocol compatibility.


159-181: Good rotation parameter consistency checks!

Verifies expected relationships between keepOldConnections and signingActiveQuorumCount.


183-207: Excellent overflow and edge case testing!

Thoroughly tests calculations with extreme values to ensure no crashes or undefined behavior.

Copy link
Collaborator

@knst knst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM e08d628

Copy link

@UdjinM6 UdjinM6 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK e08d628

@PastaPastaPasta PastaPastaPasta merged commit 68dec34 into dashpay:develop Jul 24, 2025
58 of 61 checks passed
kwvg added a commit that referenced this pull request Jul 28, 2025
…#6775, compile error

0b8fe88 chore: resolve logical conflict between dash#6691 and dash#6775 (Kittywhiskers Van Gogh)

Pull request description:

  ## Additional Information

  [dash#6691](#6691) and [dash#6775](#6775) were merged into `develop` in that order, neither conflicting with the other. [dash#6775](#6775) updated the UniValue subtree before it was unsubtree'd and subsequent improvements were backported. To enable this, a syntax change was required which replaced `get_int()` with `getInt<int>()`, which, the code introduced in [dash#6691](#6691) didn't use as it was merged _before_ [dash#6775](#6775).

  As it was new code, this was not registered as a merge conflict but this logical conflict caused `develop` to fail ([build](https://github.com/dashpay/dash/actions/runs/16546102266)). This pull request remedies that issue.

  ## Breaking Changes

  None expected

  ## Checklist

  - [x] I have performed a self-review of my own code
  - [x] I have commented my code, particularly in hard-to-understand areas **(note: N/A)**
  - [x] I have added or updated relevant unit/integration/functional/e2e tests
  - [x] I have made corresponding changes to the documentation **(note: N/A)**
  - [x] I have assigned this pull request to a milestone _(for repository code-owners and collaborators only)_

ACKs for top commit:
  UdjinM6:
    utACK 0b8fe88
  knst:
    utACK 0b8fe88

Tree-SHA512: 7af4599e38bca5d776766cd8a2acda46d046f5dfe9f9c45586ac1f27fc709bd6ac913709b2c24d133ab57bbf2a6d5cb0630d0e874f62a472e173d61ced2face0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants