Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ endif
.PHONY: FORCE check-symbols check-security
# dash core #
BITCOIN_CORE_H = \
active/quorums.h \
addrdb.h \
addressindex.h \
spentindex.h \
Expand Down Expand Up @@ -278,6 +279,7 @@ BITCOIN_CORE_H = \
llmq/options.h \
llmq/params.h \
llmq/quorums.h \
llmq/quorumsman.h \
llmq/signhash.h \
llmq/signing.h \
llmq/net_signing.h \
Expand All @@ -286,6 +288,7 @@ BITCOIN_CORE_H = \
llmq/types.h \
llmq/utils.h \
llmq/observer/context.h \
llmq/observer/quorums.h \
logging.h \
logging/timer.h \
mapport.h \
Expand Down Expand Up @@ -479,6 +482,7 @@ libbitcoin_util_a-clientversion.$(OBJEXT): obj/build.h
libbitcoin_node_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) $(BOOST_CPPFLAGS) $(MINIUPNPC_CPPFLAGS) $(NATPMP_CPPFLAGS) $(EVENT_CFLAGS) $(EVENT_PTHREADS_CFLAGS)
libbitcoin_node_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_node_a_SOURCES = \
active/quorums.cpp \
Copy link
Collaborator

Choose a reason for hiding this comment

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

  1. I'd agree with pasta; active/ is quite unclear naming because it is not clear meaning without knowing details of implementation. Could it be in directory masternode/active/quorums.cpp which already exist, or just masternode/quorums.cpp?

  2. quorums.cpp now presented in llmq/ and in active/. Humans are not machines, better to rename it to something unique. masternode/qman.cpp ? masternode/quorum_manager.cpp ? llmq/quorum_manager.cpp ? llmq/active_quorums.cpp ?

I think llmq/quorum_manager.cpp or llmq/qman.cpp is a best option, @coderabbitai, any suggestions?

Copy link

Choose a reason for hiding this comment

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

@knst, excellent points on naming clarity! Having multiple quorums.cpp files is indeed confusing. Here are my suggestions:

For the directory structure:

Since there's already an llmq/observer/quorums.cpp containing QuorumObserver, the most consistent approach would be:

  • llmq/participant/quorums.cpp (or even better, llmq/participant/participant.cpp) for the QuorumParticipant class

This mirrors the observer/participant pattern cleanly and keeps related LLMQ logic together.

Alternative options:

  • masternode/active/quorums.cpp - works since QuorumParticipant is masternode-specific, and this directory already exists. However, this might blur the LLMQ architectural boundaries.
  • llmq/active/quorums.cpp - clearer than top-level active/, but "active" is still somewhat ambiguous.

For filename uniqueness:

To avoid confusion with llmq/quorums.cpp, consider:

  • participant.cpp - clearest option, especially if placed in llmq/participant/
  • qparticipant.cpp - follows the class name more closely
  • active_quorums.cpp - distinguishes it, but less precise than "participant"

My recommendation:
Move active/quorums.{cpp,h} to llmq/participant/participant.{cpp,h}

This provides:
✅ Clear semantic meaning (participant vs observer)
✅ Consistent with existing llmq/observer/ structure
✅ No filename collision
✅ Keeps LLMQ architecture cohesive

Regarding your preference for llmq/quorum_manager.cpp or llmq/qman.cpp - note that there's already llmq/quorumsman.{cpp,h} for CQuorumManager, so the main naming issue is specifically for the active/quorums.cpp file containing QuorumParticipant.

What do you think about the llmq/participant/participant.{cpp,h} approach?


🧠 Learnings used
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.523Z
Learning: The file src/masternode/sync.h containing `CMasternodeSync` is misnamed and misplaced—it has nothing to do with "masternode" functionality. It should eventually be renamed to `NodeSyncing` or `NodeSyncStatus` and moved to src/node/sync.h as a future refactoring.

Learnt from: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.

Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.h:5-6
Timestamp: 2025-07-23T09:30:34.631Z
Learning: Dash Core uses BITCOIN_ prefix for header guards as the standard convention, inherited from Bitcoin Core. Only a few BLS-specific files in src/bls/ use DASH_ prefix. The vast majority of files (385+) use BITCOIN_ prefix.

Learnt from: kwvg
Repo: dashpay/dash PR: 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: kwvg
Repo: dashpay/dash 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
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.

Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/wallet/wallet.cpp:0-0
Timestamp: 2025-07-29T14:33:01.040Z
Learning: In refactoring PRs like #6761, kwvg acknowledges code safety improvements (like null pointer checks and unused parameter warnings) but prefers to defer them to follow-up PRs to maintain focus on the primary refactoring objectives, avoiding scope creep.

Copy link
Collaborator

Choose a reason for hiding this comment

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

participant is not a good idea, because DIP says nothing about participants, but uses terminology member: https://github.com/dashpay/dips/blob/master/dip-0006.md

Copy link

Choose a reason for hiding this comment

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

@knst, excellent point about aligning with DIP-0006 terminology! You're absolutely right that we should use the official specification's language.

Given that consideration, here are refined suggestions:

Option 1: masternode/active/quorums.cpp ✅ (Recommended)

  • Uses the existing masternode/active/ directory structure
  • Semantically correct: this is active masternode functionality (requires masternode keys to participate in quorums)
  • The masternode/active/context.{cpp,h} already exists in this directory, making this a natural home
  • Clear distinction from observer (watch-only) functionality

Option 2: llmq/active/quorums.cpp

  • Keeps LLMQ logic together under llmq/
  • "Active" distinguishes from observer without terminology conflicts
  • Creates new subdirectory structure

For the filename itself:

Since masternode/active/ would be the directory, having quorums.cpp there is actually fine because:

  • Full path masternode/active/quorums.cpp is distinct from llmq/quorums.cpp
  • The directory context provides the differentiation
  • Describes what the file manages (quorum participation for active masternodes)

My recommendation: Keep it as masternode/active/quorums.{cpp,h} since that directory already exists and semantically this IS active masternode functionality for quorum participation. The full path provides clarity without conflicting with llmq/quorums.cpp.

Alternatively, if you prefer it under llmq/, then llmq/active/quorums.{cpp,h} would work.

What's your preference between these two options?


🧠 Learnings used
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.

Learnt from: kwvg
Repo: dashpay/dash 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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,evo,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/coinjoin/**/*.{cpp,h} : CoinJoin implementation must use masternode-coordinated mixing sessions with uniform denomination outputs

Learnt from: knst
Repo: dashpay/dash PR: 6692
File: src/llmq/commitment.cpp:54-60
Timestamp: 2025-08-19T15:08:00.835Z
Learning: In Dash Core, llmq_params.size == 1 is used only for regtest environments, not on public networks, which significantly reduces the risk profile of code paths specific to single-member quorums.

Learnt from: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.h:5-6
Timestamp: 2025-07-23T09:30:34.631Z
Learning: Dash Core uses BITCOIN_ prefix for header guards as the standard convention, inherited from Bitcoin Core. Only a few BLS-specific files in src/bls/ use DASH_ prefix. The vast majority of files (385+) use BITCOIN_ prefix.

Learnt from: kwvg
Repo: dashpay/dash PR: 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: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/wallet/wallet.cpp:0-0
Timestamp: 2025-07-29T14:33:01.040Z
Learning: In refactoring PRs like #6761, kwvg acknowledges code safety improvements (like null pointer checks and unused parameter warnings) but prefers to defer them to follow-up PRs to maintain focus on the primary refactoring objectives, avoiding scope creep.

Copy link
Collaborator

Choose a reason for hiding this comment

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

quorums.cpp there is actually fine because:

no, because gdb command break quorums.cpp:XXX will not be determined anymore; using IDE / file search is also will be less conventient because two files have same name.

Copy link

Choose a reason for hiding this comment

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

@knst, you're absolutely right—ambiguous filenames create real friction with debugging tools and IDE navigation. That's a valid practical concern that trumps "full path provides context" arguments.

Given that we need:

  1. Unique filename (for tooling)
  2. DIP-aligned terminology (uses "member" not "participant")
  3. Clear purpose (active masternode quorum functionality)

Here are concrete suggestions with unique names:

Recommended option:
masternode/active/quorum_member.{cpp,h}

Rationale:

  • ✅ Unique filename (no conflicts)
  • ✅ Uses DIP-0006 terminology ("member")
  • ✅ Natural home (existing masternode/active/ directory)
  • ✅ Clear purpose: active masternode acting as quorum member
  • ✅ Unambiguous for break quorum_member.cpp:XXX

Alternative options:

  • masternode/active/member.{cpp,h} - shortest, though slightly less explicit
  • llmq/active_member.{cpp,h} - if you prefer keeping all LLMQ logic under llmq/
  • llmq/member.{cpp,h} - even shorter if context is clear

The class name QuorumParticipant would remain unchanged (it's descriptive and internal), but the file would use DIP-aligned terminology.

My recommendation: Go with masternode/active/quorum_member.{cpp,h} since it's unambiguous, uses proper terminology, and fits the existing structure.

What do you think?


🧠 Learnings used
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.

Learnt from: kwvg
Repo: dashpay/dash 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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,evo,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Learnt from: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.

Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.h:5-6
Timestamp: 2025-07-23T09:30:34.631Z
Learning: Dash Core uses BITCOIN_ prefix for header guards as the standard convention, inherited from Bitcoin Core. Only a few BLS-specific files in src/bls/ use DASH_ prefix. The vast majority of files (385+) use BITCOIN_ prefix.

Learnt from: kwvg
Repo: dashpay/dash PR: 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: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/wallet/wallet.cpp:0-0
Timestamp: 2025-07-29T14:33:01.040Z
Learning: In refactoring PRs like #6761, kwvg acknowledges code safety improvements (like null pointer checks and unused parameter warnings) but prefers to defer them to follow-up PRs to maintain focus on the primary refactoring objectives, avoiding scope creep.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@knst

  • Please see dash#7066, the eventual structure will fold masternode/active into active (source).

    It was decided against placing quorum logic into masternode/active as it is decidedly LLMQ code but there isn't enough of it to justify llmq/active, so everything, regardless of subsystem is put into active as they all share two things in common

    • They're only used in masternode-mode
    • They will be excluded from dash-chainstate
  • Participation != membership, the DIP refers to members as those who actively take part in a quorum, participants are the superset of quorums as all nodes eligible to be members. Calling it QuorumMember would therefore be a bit of a misnomer.

  • In terms of name clash, that ship has long sailed. Both Bitcoin and Dash code use overlapping names (e.g. Bitcoin has src/chain.cpp and src/kernel/chain.cpp, Dash has src/rpc/coinjoin.cpp and src/wallet/coinjoin.cpp).

    To improve developer experience, keeping the path name short would service that aim better and active/quorums.cpp is a lot shorter than masternode/active/quorums.cpp.

@coderabbitai thoughts?

Copy link

Choose a reason for hiding this comment

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

@kwvg, thanks for the comprehensive clarification! Your points are well-reasoned:

Architectural direction
PR #7066 establishes the pattern clearly—active/ as the home for masternode-mode-only code excluded from dash-chainstate. Since this consolidation is already planned, it makes sense to adopt that structure now rather than creating an intermediate step that would need migration.

Terminology precision
Your distinction between participants (eligible nodes) vs members (active in quorum) is an important clarification. QuorumParticipant is indeed the correct name—it represents the capability to participate, which is the superset. Thanks for that correction!

Name clash precedent
You're right that overlapping filenames are an established pattern. The examples (src/chain.cpp vs src/kernel/chain.cpp, src/rpc/coinjoin.cpp vs src/wallet/coinjoin.cpp) show this is already accepted practice.

Addressing @knst's debugging concern:
While the concern about break quorums.cpp:XXX is valid, the practical mitigation is straightforward:

  • Use explicit paths: break active/quorums.cpp:XXX vs break llmq/quorums.cpp:XXX
  • Modern IDEs and gdb support tab-completion with paths
  • The pattern is already established elsewhere in the codebase

My recommendation: Keep active/quorums.{cpp,h} as-is for:

  1. ✅ Aligns with future structure (PR refactor: extract CActiveMasternodeManager from LLMQContext (4/n, followups) #7066)
  2. ✅ Shorter, cleaner paths
  3. ✅ Consistent with existing codebase patterns
  4. ✅ Correct terminology (participant not member)

The brief developer friction with ambiguous filenames is outweighed by following the established architectural direction and keeping paths concise.


Note to @knst: While I understand your concern about debugging, the architectural decision in #7066 to consolidate into active/ provides strong justification for accepting the name overlap as an established pattern in the codebase.


🧠 Learnings used
Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : LLMQ quorums must support multiple configurations (50/60, 400/60, 400/85) for different services (ChainLocks, InstantSend, governance voting)

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq}/**/*.{cpp,h} : BLS integration must be used for cryptographic foundation of advanced masternode features

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{validation,txmempool}/**/*.{cpp,h} : Block validation and mempool handling must use extensions to Bitcoin Core mechanisms for special transaction validation and enhanced transaction relay

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/llmq/**/*.{cpp,h} : InstantSend implementation must provide distributed key generation for secure transaction locking with quorum consensus

Learnt from: UdjinM6
Repo: dashpay/dash PR: 6933
File: src/llmq/utils.cpp:284-298
Timestamp: 2025-11-04T18:24:27.241Z
Learning: In consensus-critical code (such as quorum formation, block validation, or deployment activation logic), do not suggest changes to the logic itself even if the implementation appears theoretically incorrect or off-by-one. Consensus rules, once deployed on the Dash network, must be preserved exactly to avoid network forks. Refactoring PRs should maintain perfect behavioral equivalence. Only suggest logic changes if explicitly accompanied by a DIP (Dash Improvement Proposal) or if the maintainer indicates the consensus rule needs to be changed with appropriate activation logic.

Learnt from: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,evo,llmq,governance,coinjoin}/**/*.{cpp,h} : Use Dash-specific database implementations: CFlatDB for persistent storage (MasternodeMetaStore, GovernanceStore, SporkStore, NetFulfilledRequestStore) and CDBWrapper extensions for Evolution/DKG/InstantSend/Quorum/RecoveredSigs data

Learnt from: knst
Repo: dashpay/dash PR: 6871
File: contrib/guix/libexec/build.sh:358-360
Timestamp: 2025-10-05T20:38:28.457Z
Learning: In the Dash repository, when backporting code from Bitcoin Core, typos and minor issues in comments should be kept as-is to reduce merge conflicts in future backports, even if they remain unfixed in Bitcoin Core's master branch.

Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.523Z
Learning: In Dash Core, `DEFAULT_SYNC_MEMPOOL` belongs with node synchronization logic (currently in src/masternode/sync.h) rather than with validation logic in src/validation.h, even though other mempool-related constants are in validation.h. The constant is conceptually tied to sync functionality, not validation.

Learnt from: knst
Repo: dashpay/dash PR: 7008
File: src/masternode/sync.h:17-18
Timestamp: 2025-11-25T10:53:37.523Z
Learning: The file src/masternode/sync.h containing `CMasternodeSync` is misnamed and misplaced—it has nothing to do with "masternode" functionality. It should eventually be renamed to `NodeSyncing` or `NodeSyncStatus` and moved to src/node/sync.h as a future refactoring.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.h:5-6
Timestamp: 2025-07-23T09:30:34.631Z
Learning: Dash Core uses BITCOIN_ prefix for header guards as the standard convention, inherited from Bitcoin Core. Only a few BLS-specific files in src/bls/ use DASH_ prefix. The vast majority of files (385+) use BITCOIN_ prefix.

Learnt from: knst
Repo: dashpay/dash 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: CR
Repo: dashpay/dash PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T16:41:22.457Z
Learning: Applies to src/{masternode,llmq,evo,coinjoin,governance}/**/*.{cpp,h} : Use unordered_lru_cache for efficient caching with LRU eviction in Dash-specific data structures

Learnt from: kwvg
Repo: dashpay/dash 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: PastaPastaPasta
Repo: dashpay/dash PR: 6804
File: src/qt/proposalwizard.cpp:40-42
Timestamp: 2025-08-11T17:16:36.654Z
Learning: In the Dash repository, when a PR adds new files that are not from Bitcoin backports, these files must be added to the list in test/util/data/non-backported.txt. This applies to newly created files like qt/proposalwizard.{h,cpp} and forms/proposalwizard.ui. Limited exemptions may exist for subtrees and similar cases.

Learnt from: kwvg
Repo: dashpay/dash PR: 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: kwvg
Repo: dashpay/dash PR: 6761
File: src/chainlock/signing.cpp:247-250
Timestamp: 2025-07-29T14:32:48.369Z
Learning: In PR #6761, kwvg acknowledged a null pointer check issue in ChainLockSigner::Cleanup() method but deferred it to follow-up, consistent with the pattern of avoiding scope creep in refactoring PRs.

Learnt from: kwvg
Repo: dashpay/dash PR: 6761
File: src/wallet/wallet.cpp:0-0
Timestamp: 2025-07-29T14:33:01.040Z
Learning: In refactoring PRs like #6761, kwvg acknowledges code safety improvements (like null pointer checks and unused parameter warnings) but prefers to defer them to follow-up PRs to maintain focus on the primary refactoring objectives, avoiding scope creep.

Copy link
Collaborator

Choose a reason for hiding this comment

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

In terms of name clash, that ship has long sailed. Both Bitcoin and Dash code use overlapping names (e.g. Bitcoin has src/chain.cpp and src/kernel/chain.cpp, Dash has src/rpc/coinjoin.cpp and src/wallet/coinjoin.cpp).

If this ship has hole it's not a reason to bomb it and sunk it

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

addrdb.cpp \
addressindex.cpp \
addrman.cpp \
Expand Down Expand Up @@ -549,12 +553,14 @@ libbitcoin_node_a_SOURCES = \
llmq/net_signing.cpp \
llmq/options.cpp \
llmq/quorums.cpp \
llmq/quorumsman.cpp \
llmq/signhash.cpp \
llmq/signing.cpp \
llmq/signing_shares.cpp \
llmq/snapshot.cpp \
llmq/utils.cpp \
llmq/observer/context.cpp \
llmq/observer/quorums.cpp \
mapport.cpp \
masternode/active/context.cpp \
masternode/active/notificationinterface.cpp \
Expand Down
235 changes: 235 additions & 0 deletions src/active/quorums.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
// Copyright (c) 2018-2025 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <active/quorums.h>
Copy link
Member

Choose a reason for hiding this comment

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

please rename to activemn or something that indicates what is active

Copy link
Collaborator Author

@kwvg kwvg Jan 2, 2026

Choose a reason for hiding this comment

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

As discussed earlier, the suggestion of active_mn or something to that effect can be considered down the road but IMO shouldn't be a blocker now.


#include <bls/bls_ies.h>
#include <bls/bls_worker.h>
#include <evo/deterministicmns.h>
#include <llmq/commitment.h>
#include <llmq/dkgsessionmgr.h>
#include <llmq/options.h>
#include <llmq/quorums.h>
#include <llmq/utils.h>
#include <masternode/node.h>
#include <masternode/sync.h>

#include <chain.h>
#include <chainparams.h>
#include <logging.h>
#include <net.h>
#include <netmessagemaker.h>
#include <validation.h>

#include <cxxtimer.hpp>

namespace llmq {
QuorumParticipant::QuorumParticipant(CBLSWorker& bls_worker, CConnman& connman, CDeterministicMNManager& dmnman,
QuorumObserverParent& qman, CQuorumSnapshotManager& qsnapman,
const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman,
const CMasternodeSync& mn_sync, const CSporkManager& sporkman,
const llmq::QvvecSyncModeMap& sync_map, bool quorums_recovery, bool quorums_watch) :
QuorumObserver(connman, dmnman, qman, qsnapman, chainman, mn_sync, sporkman, sync_map, quorums_recovery),
m_bls_worker{bls_worker},
m_mn_activeman{mn_activeman},
m_quorums_watch{quorums_watch}
{
}

QuorumParticipant::~QuorumParticipant() = default;

void QuorumParticipant::CheckQuorumConnections(const Consensus::LLMQParams& llmqParams,
gsl::not_null<const CBlockIndex*> pindexNew) const
{
auto lastQuorums = m_qman.ScanQuorums(llmqParams.type, pindexNew, (size_t)llmqParams.keepOldConnections);
auto deletableQuorums = GetQuorumsToDelete(llmqParams, pindexNew);

const uint256 proTxHash = m_mn_activeman.GetProTxHash();
const bool watchOtherISQuorums = llmqParams.type == Params().GetConsensus().llmqTypeDIP0024InstantSend &&
ranges::any_of(lastQuorums, [&proTxHash](const auto& old_quorum){ return old_quorum->IsMember(proTxHash); });

for (const auto& quorum : lastQuorums) {
if (utils::EnsureQuorumConnections(llmqParams, m_connman, m_sporkman, {m_dmnman, m_qsnapman, m_chainman, quorum->m_quorum_base_block_index},
m_dmnman.GetListAtChainTip(), proTxHash, /*is_masternode=*/true, m_quorums_watch)) {
if (deletableQuorums.erase(quorum->qc->quorumHash) > 0) {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- llmqType[%d] h[%d] keeping mn quorum connections for quorum: [%d:%s]\n", __func__, ToUnderlying(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
}
} else if (watchOtherISQuorums && !quorum->IsMember(proTxHash)) {
Uint256HashSet connections;
const auto& cindexes = utils::CalcDeterministicWatchConnections(llmqParams.type, quorum->m_quorum_base_block_index, quorum->members.size(), 1);
for (auto idx : cindexes) {
connections.emplace(quorum->members[idx]->proTxHash);
}
if (!connections.empty()) {
if (!m_connman.HasMasternodeQuorumNodes(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash())) {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- llmqType[%d] h[%d] adding mn inter-quorum connections for quorum: [%d:%s]\n", __func__, ToUnderlying(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
m_connman.SetMasternodeQuorumNodes(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash(), connections);
m_connman.SetMasternodeQuorumRelayMembers(llmqParams.type, quorum->m_quorum_base_block_index->GetBlockHash(), connections);
}
if (deletableQuorums.erase(quorum->qc->quorumHash) > 0) {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- llmqType[%d] h[%d] keeping mn inter-quorum connections for quorum: [%d:%s]\n", __func__, ToUnderlying(llmqParams.type), pindexNew->nHeight, quorum->m_quorum_base_block_index->nHeight, quorum->m_quorum_base_block_index->GetBlockHash().ToString());
}
}
}
}

for (const auto& quorumHash : deletableQuorums) {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- removing masternodes quorum connections for quorum %s:\n", __func__, quorumHash.ToString());
m_connman.RemoveMasternodeQuorumNodes(llmqParams.type, quorumHash);
}
}

bool QuorumParticipant::SetQuorumSecretKeyShare(CQuorum& quorum, Span<CBLSSecretKey> skContributions) const
{
return quorum.SetSecretKeyShare(m_bls_worker.AggregateSecretKeys(skContributions), m_mn_activeman.GetProTxHash());
}

size_t QuorumParticipant::GetQuorumRecoveryStartOffset(const CQuorum& quorum, gsl::not_null<const CBlockIndex*> pIndex) const
{
auto mns = m_dmnman.GetListForBlock(pIndex);
std::vector<uint256> vecProTxHashes;
vecProTxHashes.reserve(mns.GetValidMNsCount());
mns.ForEachMN(/*onlyValid=*/true,
[&](const auto& pMasternode) { vecProTxHashes.emplace_back(pMasternode.proTxHash); });
std::sort(vecProTxHashes.begin(), vecProTxHashes.end());
size_t nIndex{0};
{
auto my_protx_hash = m_mn_activeman.GetProTxHash();
for (const auto i : irange::range(vecProTxHashes.size())) {
// cppcheck-suppress useStlAlgorithm
if (my_protx_hash == vecProTxHashes[i]) {
nIndex = i;
break;
}
}
}
return nIndex % quorum.qc->validMembers.size();
}

MessageProcessingResult QuorumParticipant::ProcessContribQGETDATA(bool request_limit_exceeded, CDataStream& vStream,
const CQuorum& quorum, CQuorumDataRequest& request,
gsl::not_null<const CBlockIndex*> block_index)
{
if (request.GetDataMask() & CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS) {
assert(block_index);

int memberIdx = quorum.GetMemberIndex(request.GetProTxHash());
if (memberIdx == -1) {
request.SetError(CQuorumDataRequest::Errors::MASTERNODE_IS_NO_MEMBER);
return request_limit_exceeded ? MisbehavingError{25, "request limit exceeded"} : MessageProcessingResult{};
}

std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> vecEncrypted;
if (!m_qman.GetEncryptedContributions(request.GetLLMQType(), block_index,
quorum.qc->validMembers, request.GetProTxHash(), vecEncrypted)) {
request.SetError(CQuorumDataRequest::Errors::ENCRYPTED_CONTRIBUTIONS_MISSING);
return request_limit_exceeded ? MisbehavingError{25, "request limit exceeded"} : MessageProcessingResult{};
}

vStream << vecEncrypted;
}

return {};
}

MessageProcessingResult QuorumParticipant::ProcessContribQDATA(CNode& pfrom, CDataStream& vStream,
CQuorum& quorum, CQuorumDataRequest& request)
{
if (request.GetDataMask() & CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS) {
if (WITH_LOCK(quorum.cs_vvec_shShare, return !quorum.HasVerificationVectorInternal()
|| quorum.quorumVvec->size() != size_t(quorum.params.threshold))) {
// Don't bump score because we asked for it
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- %s: No valid quorum verification vector available, from peer=%d\n", __func__, NetMsgType::QDATA, pfrom.GetId());
return {};
}

int memberIdx = quorum.GetMemberIndex(request.GetProTxHash());
if (memberIdx == -1) {
// Don't bump score because we asked for it
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- %s: Not a member of the quorum, from peer=%d\n", __func__, NetMsgType::QDATA, pfrom.GetId());
return {};
}

std::vector<CBLSIESEncryptedObject<CBLSSecretKey>> vecEncrypted;
vStream >> vecEncrypted;

std::vector<CBLSSecretKey> vecSecretKeys;
vecSecretKeys.resize(vecEncrypted.size());
for (const auto i : irange::range(vecEncrypted.size())) {
if (!m_mn_activeman.Decrypt(vecEncrypted[i], memberIdx, vecSecretKeys[i], PROTOCOL_VERSION)) {
return MisbehavingError{10, "failed to decrypt"};
}
}

if (!quorum.SetSecretKeyShare(m_bls_worker.AggregateSecretKeys(vecSecretKeys), m_mn_activeman.GetProTxHash())) {
return MisbehavingError{10, "invalid secret key share received"};
}
}

return {};
}

bool QuorumParticipant::IsMasternode() const
{
// We are only initialized if masternode mode is enabled
return true;
}

bool QuorumParticipant::IsWatching() const
{
// Watch-only mode can co-exist with masternode mode
return m_quorums_watch;
}

void QuorumParticipant::StartDataRecoveryThread(gsl::not_null<const CBlockIndex*> pIndex, CQuorumCPtr pQuorum,
uint16_t nDataMaskIn) const
{
bool expected = false;
if (!pQuorum->fQuorumDataRecoveryThreadRunning.compare_exchange_strong(expected, true)) {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- Already running\n", __func__);
return;
}

workerPool.push([pQuorum = std::move(pQuorum), pIndex, nDataMaskIn, this](int threadId) mutable {
const size_t size_offset = GetQuorumRecoveryStartOffset(*pQuorum, pIndex);
DataRecoveryThread(pIndex, std::move(pQuorum), nDataMaskIn, m_mn_activeman.GetProTxHash(), size_offset);
});
}

void QuorumParticipant::TriggerQuorumDataRecoveryThreads(gsl::not_null<const CBlockIndex*> block_index) const
{
if (!m_quorums_recovery) {
return;
}

LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- Process block %s\n", __func__, block_index->GetBlockHash().ToString());

const uint256 proTxHash = m_mn_activeman.GetProTxHash();

for (const auto& params : Params().GetConsensus().llmqs) {
auto vecQuorums = m_qman.ScanQuorums(params.type, block_index, params.keepOldConnections);
const bool fWeAreQuorumTypeMember = ranges::any_of(vecQuorums, [&proTxHash](const auto& pQuorum) { return pQuorum->IsValidMember(proTxHash); });

for (auto& pQuorum : vecQuorums) {
if (pQuorum->IsValidMember(proTxHash)) {
uint16_t nDataMask{0};
if (!pQuorum->HasVerificationVector()) {
nDataMask |= CQuorumDataRequest::QUORUM_VERIFICATION_VECTOR;
}
if (!pQuorum->GetSkShare().IsValid()) {
nDataMask |= CQuorumDataRequest::ENCRYPTED_CONTRIBUTIONS;
}
if (nDataMask != 0) {
StartDataRecoveryThread(block_index, std::move(pQuorum), nDataMask);
} else {
LogPrint(BCLog::LLMQ, "QuorumParticipant::%s -- No data needed from (%d, %s) at height %d\n", __func__,
ToUnderlying(pQuorum->qc->llmqType), pQuorum->qc->quorumHash.ToString(), block_index->nHeight);
}
} else {
TryStartVvecSyncThread(block_index, std::move(pQuorum), fWeAreQuorumTypeMember);
}
}
}
}
} // namespace llmq
83 changes: 83 additions & 0 deletions src/active/quorums.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (c) 2018-2025 The Dash Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_ACTIVE_QUORUMS_H
#define BITCOIN_ACTIVE_QUORUMS_H

#include <llmq/observer/quorums.h>
#include <llmq/types.h>

#include <consensus/params.h>
#include <saltedhasher.h>
#include <span.h>
#include <sync.h>
#include <threadsafety.h>
#include <uint256.h>

#include <map>

class CActiveMasternodeManager;
class CBlockIndex;
class CBLSWorker;
class CConnman;
class CDeterministicMNManager;
class CDKGSessionManager;
class CNode;
class CSporkManager;
struct MessageProcessingResult;
namespace llmq {
class CQuorum;
class CQuorumDataRequest;
class CQuorumSnapshotManager;
enum class QvvecSyncMode : int8_t;
} // namespace llmq

namespace llmq {
class QuorumParticipant final : public QuorumObserver
{
private:
CBLSWorker& m_bls_worker;
const CActiveMasternodeManager& m_mn_activeman;
const bool m_quorums_watch{false};

public:
QuorumParticipant() = delete;
QuorumParticipant(const QuorumParticipant&) = delete;
QuorumParticipant& operator=(const QuorumParticipant&) = delete;
explicit QuorumParticipant(CBLSWorker& bls_worker, CConnman& connman, CDeterministicMNManager& dmnman,
QuorumObserverParent& qman, CQuorumSnapshotManager& qsnapman,
const CActiveMasternodeManager& mn_activeman, const ChainstateManager& chainman,
const CMasternodeSync& mn_sync, const CSporkManager& sporkman,
const llmq::QvvecSyncModeMap& sync_map, bool quorums_recovery, bool quorums_watch);
~QuorumParticipant();

public:
// QuorumObserver
bool IsMasternode() const override;
bool IsWatching() const override;
bool SetQuorumSecretKeyShare(CQuorum& quorum, Span<CBLSSecretKey> skContributions) const override;
[[nodiscard]] MessageProcessingResult ProcessContribQGETDATA(bool request_limit_exceeded, CDataStream& vStream,
const CQuorum& quorum, CQuorumDataRequest& request,
gsl::not_null<const CBlockIndex*> block_index) override;
[[nodiscard]] MessageProcessingResult ProcessContribQDATA(CNode& pfrom, CDataStream& vStream, CQuorum& quorum,
CQuorumDataRequest& request) override;

protected:
// QuorumObserver
void CheckQuorumConnections(const Consensus::LLMQParams& llmqParams,
gsl::not_null<const CBlockIndex*> pindexNew) const override;
void TriggerQuorumDataRecoveryThreads(gsl::not_null<const CBlockIndex*> block_index) const override;

private:
/// Returns the start offset for the masternode with the given proTxHash. This offset is applied when picking data
/// recovery members of a quorum's memberlist and is calculated based on a list of all member of all active quorums
/// for the given llmqType in a way that each member should receive the same number of request if all active
/// llmqType members requests data from one llmqType quorum.
size_t GetQuorumRecoveryStartOffset(const CQuorum& quorum, gsl::not_null<const CBlockIndex*> pIndex) const;

void StartDataRecoveryThread(gsl::not_null<const CBlockIndex*> pIndex, CQuorumCPtr pQuorum, uint16_t nDataMaskIn) const;
};
} // namespace llmq

#endif // BITCOIN_ACTIVE_QUORUMS_H
2 changes: 1 addition & 1 deletion src/chainlock/chainlock.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include <validationinterface.h>

#include <instantsend/instantsend.h>
#include <llmq/quorums.h>
#include <llmq/quorumsman.h>
#include <masternode/sync.h>
#include <spork.h>
#include <stats/client.h>
Expand Down
2 changes: 1 addition & 1 deletion src/chainlock/chainlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ namespace llmq {
class CInstantSendManager;
class CQuorumManager;
class CSigningManager;
enum class VerifyRecSigStatus;
enum class VerifyRecSigStatus : uint8_t;

class CChainLocksHandler final : public chainlock::ChainLockSignerParent
{
Expand Down
Loading
Loading