Skip to content

Conversation

@PastaPastaPasta
Copy link
Member

Issue being fixed or feature implemented

See commits

What was done?

How Has This Been Tested?

ran unit tests

Breaking Changes

None

Checklist:

Go over all the following points, and put an x in all the boxes that apply.

  • 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.1 milestone Oct 22, 2025
@PastaPastaPasta PastaPastaPasta marked this pull request as ready for review October 22, 2025 20:43
@github-actions
Copy link

github-actions bot commented Oct 22, 2025

✅ No Merge Conflicts Detected

This PR currently has no conflicts with other open PRs.

@coderabbitai
Copy link

coderabbitai bot commented Oct 22, 2025

Walkthrough

This PR replaces the out-parameter boolean verification path for batched signature shares with a structured return type. It adds PreVerifyResult (enum) and PreVerifyBatchedResult (struct with result, should_ban, and IsSuccess()), changes PreVerifyBatchedSigShares to return PreVerifyBatchedResult, and updates callers (e.g., ProcessMessageBatchedSigShares) to use IsSuccess()/should_ban. It also makes VerifySigSharesInv public, adds a new test file src/test/llmq_signing_shares_tests.cpp, and includes that test in the test Makefile.

Sequence Diagram(s)

sequenceDiagram
    participant Net as Network / Message Receiver
    participant Proc as ProcessMessageBatchedSigShares
    participant Pre as PreVerifyBatchedSigShares
    participant QM as QuorumManager / Node State

    rect rgba(220,240,255,0.5)
    Net->>Proc: Receive BatchedSigShares message
    end

    Proc->>Pre: PreVerifyBatchedSigShares(session, batchedSigShares)
    Pre->>QM: Check quorum, members, verification vector
    alt Validation success
        Pre-->>Proc: PreVerifyBatchedResult{result: Success, should_ban: false}
        Proc->>Proc: IsSuccess() == true
        Proc-->>Net: Accept / process batch
    else Validation failure
        Pre-->>Proc: PreVerifyBatchedResult{result: <Error>, should_ban: <bool>}
        Proc->>Proc: IsSuccess() == false
        alt should_ban == true
            Proc-->>Net: Reject and mark peer for ban
        else should_ban == false
            Proc-->>Net: Reject without ban
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay attention to changes in src/llmq/signing_shares.cpp and src/llmq/signing_shares.h (API and control-flow refactor, new enum/struct, public/private visibility changes).
  • Review updated call sites for correct handling of PreVerifyBatchedResult::IsSuccess() and should_ban.
  • Review new tests src/test/llmq_signing_shares_tests.cpp for coverage, correctness, and any test-only assumptions.
  • Check src/Makefile.test.include for correct inclusion of the new test.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 54.55% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title Check ✅ Passed The title "refactor: PreVerifyBatchedSigShares structured return and unit tests" directly relates to the main change in the changeset. The primary modifications involve refactoring the PreVerifyBatchedSigShares function from returning a bool with an out-parameter to returning a structured PreVerifyBatchedResult type, which is clearly captured in the title. The title also appropriately references the addition of unit tests, which is evident in the new src/test/llmq_signing_shares_tests.cpp file. The title is concise, specific, and would allow a teammate reviewing the repository history to understand the core purpose of this pull request without additional context.
Description Check ✅ Passed The pull request description is related to the changeset, though it could be more detailed. The description references running unit tests, which aligns with the addition of the comprehensive test suite in src/test/llmq_signing_shares_tests.cpp. It also explicitly states there are no breaking changes, which is relevant context for a refactoring pull request. While the "What was done?" field is empty and the description is somewhat sparse, it is not completely off-topic or unrelated to the actual changes being made. The description provides sufficient context that it is clearly associated with the refactoring work described in the title.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4f5a823 and b8c344b.

📒 Files selected for processing (3)
  • src/llmq/signing_shares.cpp (2 hunks)
  • src/llmq/signing_shares.h (2 hunks)
  • src/test/llmq_signing_shares_tests.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/llmq/signing_shares.h
  • src/test/llmq_signing_shares_tests.cpp
🧰 Additional context used
📓 Path-based instructions (1)
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/llmq/signing_shares.cpp
🧬 Code graph analysis (1)
src/llmq/signing_shares.cpp (1)
src/llmq/signing.cpp (2)
  • IsQuorumActive (751-760)
  • IsQuorumActive (751-751)
⏰ 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_ubsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: mac-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (1)
src/llmq/signing_shares.cpp (1)

427-430: Structured return handling looks correct.

The refactored call site correctly maps the structured result to ban decisions: when verification fails with should_ban=true, returning false triggers the ban at the caller (line 308); when should_ban=false, returning true avoids the ban.


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

Comment @coderabbitai help to get the list of available commands and usage tips.

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

🧹 Nitpick comments (5)
src/llmq/signing_shares.h (1)

371-376: Make result type hard to ignore and document ban semantics.

Mark the struct [[nodiscard]] and add a brief comment clarifying should_ban semantics.

-struct PreVerifyBatchedResult {
+// Preverification outcome for QBSIGSHARES. When should_ban==true, callers should
+// abort processing and ban the peer at the higher-level message loop.
+struct [[nodiscard]] PreVerifyBatchedResult {
     PreVerifyResult result;
     bool should_ban;
 
-    [[nodiscard]] bool IsSuccess() const { return result == PreVerifyResult::Success; }
+    [[nodiscard]] bool IsSuccess() const noexcept { return result == PreVerifyResult::Success; }
 };
src/test/llmq_signing_shares_tests.cpp (3)

5-17: Include what you use.

Add <unordered_set> for std::unordered_set.

 #include <test/util/llmq_tests.h>
 
+#include <unordered_set>
 #include <bls/bls.h>

101-191: These tests don’t exercise the preverification function.

They validate structure locally but don’t assert PreVerifyBatchedSigShares outcomes (Success/should_ban). Consider:

  • Adding an integration-style test that feeds a QBSIGSHARES message through ProcessMessage and observes ban/no‑ban.
  • Or, add a test seam (e.g., expose a test-only helper that runs the structural checks used by PreVerifyBatchedSigShares) so unit tests can assert DuplicateMember/OutOfBounds/NotValid map to should_ban=true.

I can draft either an integration test or a small test-only helper to cover these branches.


236-254: Empty batch: assert expected Success explicitly (if a seam is added).

Once a seam or integration path exists, assert result.result==Success and should_ban==false for empty batches.

src/llmq/signing_shares.cpp (1)

514-549: Add a log for duplicate-member bans and pre-size the set.

Helps diagnose bans and avoids a couple of rehashes for larger batches.

-    std::unordered_set<uint16_t> dupMembers;
+    std::unordered_set<uint16_t> dupMembers;
+    dupMembers.reserve(batchedSigShares.sigShares.size());
 
     for (const auto& [quorumMember, _] : batchedSigShares.sigShares) {
         if (!dupMembers.emplace(quorumMember).second) {
-            return {PreVerifyResult::DuplicateMember, true};
+            LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- duplicate quorumMember in batch\n", __func__);
+            return {PreVerifyResult::DuplicateMember, true};
         }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e5ce1f0 and 99df68b.

📒 Files selected for processing (4)
  • src/Makefile.test.include (1 hunks)
  • src/llmq/signing_shares.cpp (2 hunks)
  • src/llmq/signing_shares.h (2 hunks)
  • src/test/llmq_signing_shares_tests.cpp (1 hunks)
🧰 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_signing_shares_tests.cpp
  • src/llmq/signing_shares.h
  • src/llmq/signing_shares.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_signing_shares_tests.cpp
🧬 Code graph analysis (3)
src/test/llmq_signing_shares_tests.cpp (2)
src/test/util/llmq_tests.h (1)
  • testutils (26-35)
src/test/util/setup_common.h (1)
  • InsecureRand256 (80-80)
src/llmq/signing_shares.h (1)
src/llmq/signing_shares.cpp (2)
  • PreVerifyBatchedSigShares (514-549)
  • PreVerifyBatchedSigShares (514-515)
src/llmq/signing_shares.cpp (1)
src/llmq/signing.cpp (2)
  • IsQuorumActive (831-840)
  • IsQuorumActive (831-831)
🪛 GitHub Actions: Clang Diff Format Check
src/test/llmq_signing_shares_tests.cpp

[error] 1-1: Clang format differences found in src/test/llmq_signing_shares_tests.cpp. Run './contrib/devtools/clang-format-diff.py -p1' to fix formatting. Command failed with exit code 1.

src/llmq/signing_shares.h

[error] 1-1: Clang format differences found in src/llmq/signing_shares.h. Run './contrib/devtools/clang-format-diff.py -p1' to fix formatting. Command failed with exit code 1.

src/llmq/signing_shares.cpp

[error] 1-1: Clang format differences found in src/llmq/signing_shares.cpp. Run './contrib/devtools/clang-format-diff.py -p1' to fix formatting. Command failed with exit code 1.

⏰ 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: mac-build / Build source
  • GitHub Check: arm-linux-build / Build source
  • GitHub Check: linux64_tsan-build / Build source
  • GitHub Check: linux64_ubsan-build / Build source
  • GitHub Check: linux64_sqlite-build / Build source
  • GitHub Check: linux64_fuzz-build / Build source
  • GitHub Check: linux64-build / Build source
  • GitHub Check: linux64_nowallet-build / Build source
  • GitHub Check: win64-build / Build source
  • GitHub Check: Lint / Run linters
🔇 Additional comments (7)
src/Makefile.test.include (1)

140-140: Test added to suite — good.

The new llmq_signing_shares test is properly wired into BITCOIN_TESTS.

src/llmq/signing_shares.h (3)

361-369: Result taxonomy looks sane.

Enum covers expected branches (success, age, membership, vvec, dup, OOB, invalid).


471-473: PreVerifyBatchedSigShares: no stale call sites: All usages now return PreVerifyBatchedResult; no bool return or retBan out-param remains.


361-377: No formatting issues detected. clang-format-diff reports no differences for this change.

src/test/llmq_signing_shares_tests.cpp (2)

23-97: Good fixture scaffolding.

Fixture builds minimal quorums and batches cleanly; helpful for edge cases.


1-4: Run clang‐format and commit fixes
CI reports formatting issues in this file—please run:

./contrib/devtools/clang-format-diff.py -p1  

and commit the resulting changes.

src/llmq/signing_shares.cpp (1)

413-416: Call-site semantics are correct.

Returning !should_ban integrates with the all_of() + BanNode flow as intended.

Add a negative-path test later to confirm DuplicateMember triggers a ban via QBSIGSHARES (integration).

@UdjinM6
Copy link

UdjinM6 commented Oct 22, 2025

  • linter found lots of trailing spaces
  • tests look a bit... pointless? they simply create (in)valid data and then confirm it with their own logic. Should instead use PreVerifyBatchedSigShares() and verify that it produces expected results imo.

Comment on lines 127 to 133
// We can test the duplicate detection logic by checking the batch structure
std::unordered_set<uint16_t> seen;
bool hasDuplicate = false;
for (const auto& [member, _] : batchedSigShares.sigShares) {
if (!seen.insert(member).second) {
hasDuplicate = true;
break;
Copy link
Collaborator

@knst knst Oct 22, 2025

Choose a reason for hiding this comment

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

it looks for me as unit test preverify_duplicate_member instead of testing llmq's code tests validates that helper CreateTestBatchedSigShares works.

Becase this helper changes member of CBatchedSigShares:

        for (uint16_t member : members) {
            CBLSLazySignature lazySig;
            batched.sigShares.emplace_back(member, lazySig);
        }

(that's not the only regression test here that does something similar in this PR)

@github-actions
Copy link

This pull request has conflicts, please rebase.

@PastaPastaPasta PastaPastaPasta force-pushed the refac/PreVerifyBatchedSigShares branch from 99df68b to 4f5a823 Compare October 24, 2025 17:05
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: 2

♻️ Duplicate comments (1)
src/llmq/signing_shares.cpp (1)

1-1: Fix clang-format diff failure for this file.

Run the project’s formatting script locally and commit the result.

#!/bin/bash
set -euo pipefail
# From repo root
git diff -U0 | ./contrib/devtools/clang-format-diff.py -p1 -i || true
# Show any remaining format diffs (should be empty)
git diff --exit-code || true
🧹 Nitpick comments (5)
src/llmq/signing_shares.h (2)

372-377: Unify naming style and make the API return [[nodiscard]].

  • Field name should follow project’s lowerCamelCase (e.g., recvSessionId). Rename should_ban → shouldBan.
  • Mark PreVerifyBatchedSigShares return as [[nodiscard]] to enforce handling.

Apply in this header:

 struct PreVerifyBatchedResult {
     PreVerifyResult result;
-    bool should_ban;
+    bool shouldBan;
 
     [[nodiscard]] bool IsSuccess() const { return result == PreVerifyResult::Success; }
 };

-    static PreVerifyBatchedResult PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager,
-                                                             const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares);
+    [[nodiscard]] static PreVerifyBatchedResult PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager,
+                                                                          const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares);

Also update usages in src/llmq/signing_shares.cpp and tests (see inline comments in those files for minimal diffs).

Also applies to: 475-478


362-370: Enum looks good; consider brief docs for each value.

Add 1-line comments per enum value to clarify ban/no-ban intent for future maintainers. Keeps tests and call sites aligned.

src/llmq/signing_shares.cpp (1)

427-429: If renaming should_ban → shouldBan (consistency), update uses here.

@@
-    if (!verifyResult.IsSuccess()) {
-        return !verifyResult.should_ban;
+    if (!verifyResult.IsSuccess()) {
+        return !verifyResult.shouldBan;
     }
@@
-        return {PreVerifyResult::QuorumTooOld, false};
+        return {PreVerifyResult::QuorumTooOld, false};
@@
-        return {PreVerifyResult::NotAMember, false};
+        return {PreVerifyResult::NotAMember, false};
@@
-        return {PreVerifyResult::MissingVerificationVector, false};
+        return {PreVerifyResult::MissingVerificationVector, false};
@@
-            return {PreVerifyResult::DuplicateMember, true};
+            return {PreVerifyResult::DuplicateMember, true};
@@
-            return {PreVerifyResult::QuorumMemberOutOfBounds, true};
+            return {PreVerifyResult::QuorumMemberOutOfBounds, true};
@@
-            return {PreVerifyResult::QuorumMemberNotValid, true};
+            return {PreVerifyResult::QuorumMemberNotValid, true};
@@
-    return {PreVerifyResult::Success, false};
+    return {PreVerifyResult::Success, false};

Note: Only uses of the field change (shouldBan); the initializer brace order remains the same.

Also applies to: 531-558, 560-560

src/test/llmq_signing_shares_tests.cpp (2)

143-167: Strengthen assertions to verify exact outcomes (not just !IsSuccess).

Once IsMember() and IsQuorumActive() are satisfied, assert specific PreVerifyResult and ban flag for each scenario (DuplicateMember, QuorumMemberOutOfBounds, QuorumMemberNotValid, Success/empty batch).

Example for duplicate:

-    BOOST_CHECK(!result.IsSuccess());
-    if (result.result == PreVerifyResult::DuplicateMember) {
-        BOOST_CHECK(result.should_ban);
-    }
+    BOOST_CHECK_MESSAGE(!result.IsSuccess(), "Expected failure for duplicate member");
+    BOOST_CHECK_EQUAL(result.result, PreVerifyResult::DuplicateMember);
+    BOOST_CHECK(result.shouldBan);

Apply similar tightening for:

  • preverify_member_out_of_bounds → expect QuorumMemberOutOfBounds + shouldBan
  • preverify_invalid_quorum_member → expect QuorumMemberNotValid + shouldBan
  • preverify_empty_batch → expect Success (or at least not a ban-worthy structure failure)
  • preverify_boundary_max_member → expect Success when early checks are satisfied

Note: if you keep the original field name should_ban, adjust accordingly; if you accept the rename, use shouldBan.

Also applies to: 171-194, 197-222, 225-254, 257-282, 285-308, 311-332, 335-360


165-166: Adjust field access if should_ban → shouldBan.

-        BOOST_CHECK(result.should_ban);
+        BOOST_CHECK(result.shouldBan);
@@
-        BOOST_CHECK(result.should_ban);
+        BOOST_CHECK(result.shouldBan);
@@
-        BOOST_CHECK(result.should_ban);
+        BOOST_CHECK(result.shouldBan);
@@
-        BOOST_CHECK(ban_result.should_ban);
+        BOOST_CHECK(ban_result.shouldBan);
@@
-    BOOST_CHECK(!no_ban_result.should_ban);
+    BOOST_CHECK(!no_ban_result.shouldBan);

Also applies to: 191-193, 219-221, 305-307, 367-377

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99df68b and 4f5a823.

📒 Files selected for processing (4)
  • src/Makefile.test.include (1 hunks)
  • src/llmq/signing_shares.cpp (2 hunks)
  • src/llmq/signing_shares.h (2 hunks)
  • src/test/llmq_signing_shares_tests.cpp (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Makefile.test.include
🧰 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/llmq/signing_shares.cpp
  • src/llmq/signing_shares.h
  • src/test/llmq_signing_shares_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_signing_shares_tests.cpp
🧬 Code graph analysis (3)
src/llmq/signing_shares.cpp (1)
src/llmq/signing.cpp (2)
  • IsQuorumActive (751-760)
  • IsQuorumActive (751-751)
src/llmq/signing_shares.h (1)
src/llmq/signing_shares.cpp (2)
  • PreVerifyBatchedSigShares (526-561)
  • PreVerifyBatchedSigShares (526-527)
src/test/llmq_signing_shares_tests.cpp (2)
src/test/util/llmq_tests.h (1)
  • testutils (26-35)
src/test/util/setup_common.h (1)
  • InsecureRand256 (80-80)
🪛 GitHub Actions: Clang Diff Format Check
src/llmq/signing_shares.cpp

[error] 1-1: Clang-format differences found. Run the formatting script to fix: git diff ... | ./contrib/devtools/clang-format-diff.py -p1 > diff_output.txt and apply clang-format.

src/llmq/signing_shares.h

[error] 1-1: Clang-format differences found. Run the formatting script to fix: git diff ... | ./contrib/devtools/clang-format-diff.py -p1 > diff_output.txt and apply clang-format.

src/test/llmq_signing_shares_tests.cpp

[error] 1-1: Clang-format differences found. Run the formatting script to fix: git diff ... | ./contrib/devtools/clang-format-diff.py -p1 > diff_output.txt and apply clang-format.

⏰ 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). (1)
  • GitHub Check: Build container / Build container
🔇 Additional comments (3)
src/llmq/signing_shares.cpp (1)

427-429: Return semantics are correct against caller’s ban flow.

Returning !verifyResult.should_ban ensures ranges::all_of short-circuits to BanNode() only on ban-worthy failures.

Please run unit tests covering both ban and non-ban paths once the tests are strengthened (see test file comments).

src/test/llmq_signing_shares_tests.cpp (2)

1-1: Cannot verify clang-format compliance in this environment.

The sandbox lacks the necessary tools (clang-format, python3) to execute the original verification script. However, git shows that the working tree is clean with no pending changes for this file, suggesting the formatting concern may already be addressed or not currently applicable.

Manual verification of formatting compliance is recommended using the project's formatting script locally: git diff -U0 | ./contrib/devtools/clang-format-diff.py -p1 -i


24-37: Make the quorum “active” in tests to bypass QuorumTooOld.

PreVerifyBatchedSigShares first calls IsQuorumActive(), which consults CQuorumManager::ScanQuorums. Seed the test quorum into the manager so IsQuorumActive() returns true.

Search for existing helpers you can reuse:

If a helper like AddAndCacheQuorumForTesting exists, call it with your constructed quorum and its hash so IsQuorumActive() and GetQuorum() can find it. Otherwise, we can introduce a small test-only hook in CQuorumManager guarded by UNIT_TESTS to register synthetic quorums.

Also applies to: 84-109

Comment on lines 526 to 561
PreVerifyBatchedResult CSigSharesManager::PreVerifyBatchedSigShares(const CActiveMasternodeManager& mn_activeman, const CQuorumManager& quorum_manager,
const CSigSharesNodeState::SessionInfo& session, const CBatchedSigShares& batchedSigShares)
{
retBan = false;

if (!IsQuorumActive(session.llmqType, quorum_manager, session.quorum->qc->quorumHash)) {
// quorum is too old
return false;
return {PreVerifyResult::QuorumTooOld, false};
}
if (!session.quorum->IsMember(mn_activeman.GetProTxHash())) {
// we're not a member so we can't verify it (we actually shouldn't have received it)
return false;
return {PreVerifyResult::NotAMember, false};
}
if (!session.quorum->HasVerificationVector()) {
// TODO we should allow to ask other nodes for the quorum vvec if we missed it in the DKG
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- we don't have the quorum vvec for %s, no verification possible.\n", __func__,
session.quorumHash.ToString());
return false;
return {PreVerifyResult::MissingVerificationVector, false};
}

std::unordered_set<uint16_t> dupMembers;

for (const auto& [quorumMember, _] : batchedSigShares.sigShares) {
if (!dupMembers.emplace(quorumMember).second) {
retBan = true;
return false;
return {PreVerifyResult::DuplicateMember, true};
}

if (quorumMember >= session.quorum->members.size()) {
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- quorumMember out of bounds\n", __func__);
retBan = true;
return false;
return {PreVerifyResult::QuorumMemberOutOfBounds, true};
}
if (!session.quorum->qc->validMembers[quorumMember]) {
LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- quorumMember not valid\n", __func__);
retBan = true;
return false;
return {PreVerifyResult::QuorumMemberNotValid, true};
}
}
return true;
return {PreVerifyResult::Success, false};
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add missing include for std::unordered_set and log DuplicateMember for parity.

  • std::unordered_set is used but not included here; rely on explicit include to avoid transitive-dependency breakage.
  • Emit a LogPrint on DuplicateMember like the other branches.

Apply:

@@
-#include <util/time.h>
+#include <util/time.h>
+#include <unordered_set>
@@
-    for (const auto& [quorumMember, _] : batchedSigShares.sigShares) {
+    for (const auto& [quorumMember, _] : batchedSigShares.sigShares) {
         if (!dupMembers.emplace(quorumMember).second) {
-            return {PreVerifyResult::DuplicateMember, true};
+            LogPrint(BCLog::LLMQ_SIGS, "CSigSharesManager::%s -- duplicate quorumMember in batch\n", __func__);
+            return {PreVerifyResult::DuplicateMember, true};
         }

If you applied the header rename, update this function’s returns and call sites accordingly (see next comment).

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/llmq/signing_shares.cpp around lines 526 to 561, the function uses
std::unordered_set but the header is not included and the DuplicateMember branch
lacks a log call for parity with other error branches; add #include
<unordered_set> at the top of this file and insert a LogPrint call immediately
before the DuplicateMember return (matching the style/format used in the other
branches, including context such as __func__ and session.quorumHash or
quorumMember as appropriate), then return {PreVerifyResult::DuplicateMember,
true}; and if you have applied the header rename mentioned elsewhere, update
this function’s return type/values and all its call sites accordingly.

Comment on lines 40 to 43
CQuorumCPtr CreateMinimalTestQuorum(int size, bool hasVerificationVector = true,
const std::vector<bool>& validMembers = {},
bool includeOurProTxHash = false)
{
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

includeOurProTxHash is unused; tests won’t reach structure checks. Implement it to satisfy IsMember().

Without adding our ProTxHash to quorum->members, PreVerifyBatchedSigShares exits early with NotAMember, so duplicate/out-of-bounds/invalid tests don’t actually test structure validation.

Sketch (adjust to available constructors/utilities in-tree):

@@
-    CQuorumCPtr CreateMinimalTestQuorum(int size, bool hasVerificationVector = true,
-                                         const std::vector<bool>& validMembers = {},
-                                         bool includeOurProTxHash = false)
+    CQuorumCPtr CreateMinimalTestQuorum(int size, bool hasVerificationVector = true,
+                                        const std::vector<bool>& validMembers = {},
+                                        bool includeOurProTxHash = false)
@@
-        // Create members
-        std::vector<CDeterministicMNCPtr> members;
-        for (int i = 0; i < size; ++i) {
-            // For simplicity, use nullptr members since we're testing pre-verification logic
-            // The actual member checking happens in IsMember() which we can't fully mock
-            members.push_back(nullptr);
-        }
+        // Create members. To satisfy IsMember(), optionally inject our MN at index 0.
+        std::vector<CDeterministicMNCPtr> members;
+        members.resize(size, nullptr);
+        if (includeOurProTxHash) {
+            // Use a minimal deterministic MN with our proTxHash.
+            // Prefer an existing test helper if available (see verification script below).
+            auto state = std::make_shared<CDeterministicMNState>();
+            state->pubKeyOperator = bls::LegacySchemeKeyPair::FromSecret(sk).first; // or appropriate pubkey
+            auto dmn = std::make_shared<CDeterministicMN>();
+            dmn->proTxHash = mn_activeman->GetProTxHash();
+            dmn->pdmnState = state;
+            members[0] = dmn;
+            if (qc_ptr->validMembers.size() < static_cast<size_t>(size)) {
+                qc_ptr->validMembers.resize(size, true);
+            }
+            qc_ptr->validMembers[0] = true;
+        }

If constructors differ, I can adapt to the codebase’s actual APIs once you confirm which test helpers exist.

Also applies to: 60-67, 68-82

🤖 Prompt for AI Agents
In src/test/llmq_signing_shares_tests.cpp around lines 40-43 (also apply similar
changes at 60-67 and 68-82), the includeOurProTxHash parameter is unused causing
PreVerifyBatchedSigShares to early-return NotAMember; update
CreateMinimalTestQuorum to, when includeOurProTxHash is true, insert the test's
local proTxHash into the quorum->members (or the appropriate members container)
so IsMember() returns true for the test node; ensure this uses existing test
helpers/constructors to build a CQuorumCPtr with members containing that
proTxHash and preserves hasVerificationVector/validMembers behavior so
subsequent structure/duplicate/out-of-bounds/invalid tests actually exercise the
validation logic.

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.

tests are more complex now but still useless 🤷‍♂️ consider smth like 89f4a4d


// Helper to create a minimal test quorum
CQuorumCPtr CreateMinimalTestQuorum(int size, bool hasVerificationVector = true,
const std::vector<bool>& validMembers = {}, bool includeOurProTxHash = false)
Copy link

Choose a reason for hiding this comment

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

don't see how includeOurProTxHash is used

Suggested change
const std::vector<bool>& validMembers = {}, bool includeOurProTxHash = false)
const std::vector<bool>& validMembers = {})

Comment on lines +131 to +132
// The actual result will likely be QuorumTooOld, NotAMember, or MissingVerificationVector
// depending on which check fails first
Copy link

Choose a reason for hiding this comment

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

Shouldn't it be deterministic? Why having a test like that if we can't get the expected MissingVerificationVector error?

Comment on lines +154 to +155
// If we get to the duplicate check (past QuorumTooOld and NotAMember checks),
// we should get DuplicateMember with should_ban=true
Copy link

Choose a reason for hiding this comment

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

Same, I don't get this "If"... Same for all the tests below basically.

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