-
Notifications
You must be signed in to change notification settings - Fork 9
fix: store historical rotating quorums by cycle boundary hash #409
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
base: v0.42-dev
Are you sure you want to change the base?
Conversation
Adds infrastructure for storing historical rotating quorums keyed by cycle boundary hash instead of quorum hash. This enables InstantLock verification for previous cycles by: - Adding `WORK_DIFF_DEPTH` constant (8 blocks offset to cycle boundary) - Adding `store_rotating_quorums_for_cycle()` to extract and store quorums - Collecting work block hashes from `QRInfo` diffs (`h-4c`, `h-3c`, `h-2c`, `h-c`) - Using cycle boundary hash as the key for `rotated_quorums_per_cycle`
📝 WalkthroughWalkthroughA public constant Changes
Sequence DiagramsequenceDiagram
participant QRInfo as QRInfo Processing
participant MNList as Masternode List Engine
participant CycleBound as Cycle Boundary Calculator
participant QRStorage as Rotating Quorum Storage
participant VerifyStatus as Verification Status
QRInfo->>MNList: Apply QRInfo diffs (series)
MNList->>MNList: Update masternode state
QRInfo->>CycleBound: Compute cycle boundary hash<br/>(from work block height)
CycleBound-->>QRInfo: Return cycle boundary hash
QRInfo->>MNList: Extract rotating quorums<br/>(at work block height)
MNList-->>QRInfo: Return rotating quorums
QRInfo->>QRStorage: Store rotating quorums<br/>(keyed by cycle boundary hash)
QRStorage->>QRStorage: Check if cycle already exists<br/>(skip if present)
QRStorage->>QRStorage: Store non-empty quorum set
QRStorage-->>QRInfo: Storage complete
QRInfo->>VerifyStatus: Propagate verification status<br/>(across heights)
VerifyStatus-->>QRInfo: Status update applied
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
|
@coderabbitai review Ensure you take into consideration this DIP https://github.com/dashpay/dips/blob/master/dip-0022.md and it's prior work, to understand system design. |
🧩 Analysis chain
🏁 Script executed: Length of output: 84079 🏁 Script executed: Length of output: 8821 🏁 Script executed: Length of output: 812
🏁 Script executed: Length of output: 12201 🏁 Script executed: Length of output: 10580 🏁 Script executed: Length of output: 3144 🏁 Script executed: Length of output: 5282 🏁 Script executed: Length of output: 4839 🏁 Script executed: Length of output: 8707
✅ Correct Implementation of DIP-0022 & DIP-0024The PR correctly addresses the requirement that InstantLock messages must be verified using Key Strengths
Architecture ObservationsCycle Boundary Calculation let cycle_boundary_height = work_block_height + WORK_DIFF_DEPTH;This correctly maps the work block (where masternode lists are selected) to the cycle boundary (where the cycle begins), matching DIP-0024's requirement that "the masternode list at this height is used 8 blocks prior to the current height" Duplicate Prevention
Minor Suggestions
Questions
SummaryThis PR correctly implements the critical infrastructure needed for deterministic InstantSend lock verification per DIP-0022 and DIP-0024. The shift from quorum hash to cycle hash as the storage key is essential because "any quorum could sign any islock even if it were not responsible to do so for that quorum cycle" under the old approach. The new implementation ensures that "nodes can follow the steps required to determine the appropriate quorumHash and verify the signature" for InstantLocks from any cycle. 🧠 Learnings used✅ Actions performedReview triggered.
|
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this 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
🤖 Fix all issues with AI agents
In `@dash/src/sml/masternode_list_engine/mod.rs`:
- Around line 708-713: The current call to get_hash(...) returns an Err
constructed with
QuorumValidationError::RequiredBlockNotPresent(BlockHash::all_zeros(), ...)
which uses an all-zero sentinel that is misleading; update the error to either
add and use a new variant (e.g., RequiredBlockHeightNotPresent(CoreBlockHeight,
String)) or pass a meaningful related hash (for example work_block_hash) instead
of BlockHash::all_zeros(), and update the match arms that handle
QuorumValidationError::RequiredBlockNotPresent (or add handling for the new
variant) so downstream code sees the real context (reference symbols:
block_container.get_hash, cycle_boundary_height,
QuorumValidationError::RequiredBlockNotPresent, BlockHash::all_zeros(),
work_block_hash).
🧹 Nitpick comments (3)
dash/src/sml/masternode_list_engine/mod.rs (3)
412-449: Silent early returns may mask data inconsistencies.All four early-return paths silently discard failures. While this is reasonable for historical cycles where data might genuinely be absent, it can make debugging harder when the block container or masternode list should have been populated but wasn't (e.g., a prior
apply_difffailed silently or the block height wasn't fed).Consider returning a
bool(or logging attrace/debuglevel) so callers or operators can distinguish "nothing to store" from "unexpected missing data."
671-675: Nit:work_block_hashandmn_list_diff_at_h_block_hashhold the same value.Both capture
mn_list_diff_h.block_hashunder#[cfg(feature = "quorum_validation")]. This is fine for readability since they serve different semantic roles, but worth noting they're always identical.
1208-1213: Consider adding targeted tests for the new cycle boundary logic.The existing tests implicitly exercise
store_rotating_quorums_for_cyclethroughfeed_qr_info, but there's no direct test for:
- Cycle boundary height calculation (
work_block_height + WORK_DIFF_DEPTH)- The
contains_keyguard preventing duplicate storage- Behavior when historical masternode lists or block hashes are absent
A focused unit test for
store_rotating_quorums_for_cyclewould improve confidence in edge cases (e.g., missing block mappings, empty quorum lists, repeated calls).
| *self.block_container.get_hash(&cycle_boundary_height).ok_or( | ||
| QuorumValidationError::RequiredBlockNotPresent( | ||
| BlockHash::all_zeros(), | ||
| format!("getting cycle boundary hash at height {}", cycle_boundary_height), | ||
| ), | ||
| )? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BlockHash::all_zeros() in error is semantically misleading.
RequiredBlockNotPresent expects the missing block's hash, but here the hash is what's missing. Any error handler pattern-matching on the hash value would see the genesis-like all-zeros sentinel instead of meaningful data. The format string mitigates this for logs, but downstream match arms could be confused.
Consider introducing a dedicated error variant (e.g., RequiredBlockHeightNotPresent(CoreBlockHeight, String)) or passing work_block_hash with a message noting the derived height wasn't found, since the work block is the closest related known hash.
🤖 Prompt for AI Agents
In `@dash/src/sml/masternode_list_engine/mod.rs` around lines 708 - 713, The
current call to get_hash(...) returns an Err constructed with
QuorumValidationError::RequiredBlockNotPresent(BlockHash::all_zeros(), ...)
which uses an all-zero sentinel that is misleading; update the error to either
add and use a new variant (e.g., RequiredBlockHeightNotPresent(CoreBlockHeight,
String)) or pass a meaningful related hash (for example work_block_hash) instead
of BlockHash::all_zeros(), and update the match arms that handle
QuorumValidationError::RequiredBlockNotPresent (or add handling for the new
variant) so downstream code sees the real context (reference symbols:
block_container.get_hash, cycle_boundary_height,
QuorumValidationError::RequiredBlockNotPresent, BlockHash::all_zeros(),
work_block_hash).
This fixes issues in InstantSend lock verification where we miss the selected quorums. It adds infrastructure for storing historical rotating quorums keyed by cycle boundary hash instead of quorum hash. This enables InstantLock verification for previous cycles by:
WORK_DIFF_DEPTHconstant (8 blocks offset to cycle boundary)store_rotating_quorums_for_cycle()to extract and store quorumsQRInfodiffs (h-4c,h-3c,h-2c,h-c)rotated_quorums_per_cycleSummary by CodeRabbit