fix: bound DKG contribution blob intake - #7408
Conversation
✅ No Merge Conflicts DetectedThis PR currently has no conflicts with other open PRs. |
|
✅ Review complete (commit 439fb7d) |
WalkthroughThe change tightens QCONTRIB structural validation in Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/llmq/net_dkg.cpp (1)
84-94: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueMinor style inconsistency:
params.minSizecast without the same negative-guard assize/threshold.Lines 84-85 guard
params.size/params.thresholdwithparam > 0 ? static_cast<size_t>(param) : 0before use, but the new check at line 93 castsparams.minSizedirectly. IfminSizewere ever negative, this would wrap to a hugesize_tand always reject QCONTRIB for that quorum, whereas the guarded locals fail safe to 0. GivenminSizeis a trusted, statically-defined config value this is unlikely to bite, but for consistency with the surrounding defensive style it may be worth applying the same guard.♻️ Optional consistency fix
const size_t size = params.size > 0 ? static_cast<size_t>(params.size) : 0; const size_t threshold = params.threshold > 0 ? static_cast<size_t>(params.threshold) : 0; + const size_t minSize = params.minSize > 0 ? static_cast<size_t>(params.minSize) : 0; try { CDataStream s(vRecv); // copy; deserialization does not advance the caller's stream if (msg_type == NetMsgType::QCONTRIB) { CDKGContribution qc; s >> qc; return qc.vvec != nullptr && qc.vvec->size() == threshold && qc.contributions != nullptr && - qc.contributions->blobs.size() >= static_cast<size_t>(params.minSize) && + qc.contributions->blobs.size() >= minSize && qc.contributions->blobs.size() <= size;🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/llmq/net_dkg.cpp` around lines 84 - 94, The QCONTRIB validation in the DKG message parsing path uses params.minSize without the same negative-value guard applied to params.size and params.threshold. Update the check in the CDKGContribution handling inside the NetMsgType::QCONTRIB branch to normalize params.minSize to a size_t with a non-negative guard, matching the defensive pattern used for size and threshold, so the comparison stays consistent and avoids unsigned wraparound.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/llmq/net_dkg.cpp`:
- Around line 84-94: The QCONTRIB validation in the DKG message parsing path
uses params.minSize without the same negative-value guard applied to params.size
and params.threshold. Update the check in the CDKGContribution handling inside
the NetMsgType::QCONTRIB branch to normalize params.minSize to a size_t with a
non-negative guard, matching the defensive pattern used for size and threshold,
so the comparison stays consistent and avoids unsigned wraparound.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: 650680e3-c0be-4021-a55a-44508aa34d43
📥 Commits
Reviewing files that changed from the base of the PR and between 4af395d and 10d7a5806d6109fad3c08dd593239eff379ca227.
📒 Files selected for processing (1)
src/llmq/net_dkg.cpp
There was a problem hiding this comment.
Code Review
Source: reviewers: claude-dash-core-commit-history (opus, ok), claude-general (opus, ok), codex-dash-core-commit-history (gpt-5.5, ok), codex-general (gpt-5.5, ok); verifier: claude (opus).
Small, correct hardening of the QCONTRIB intake structural check that adds a lower bound (>= params.minSize) on the encrypted contributions blob count, complementing the existing upper bound and matching the DIP-6 envelope enforced later in CDKGSession::PreVerifyMessage. No consensus behavior change; only per-peer intake rejection with misbehavior score 100. Both agents converge on a single test-coverage suggestion; no blocking issues.
🟡 1 suggestion(s) | 💬 1 nitpick(s)
Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `test/functional/feature_llmq_dkg_intake.py`:
- [SUGGESTION] test/functional/feature_llmq_dkg_intake.py:134-145: Add functional coverage for under-minSize QCONTRIB rejection
The new `qc.contributions->blobs.size() >= params.minSize` bound in `CheckDKGMessageStructure` (src/llmq/net_dkg.cpp:93) is not exercised by any test. `test_malformed_rejected` only covers a truncated payload (which fails during deserialization) and `test_oversized_rejected` covers the >1 MiB path, so neither catches a regression that drops or weakens the lower bound. `feature_llmq_dkg_intake.py` is the natural home for a case that constructs a well-formed `CDKGContribution` with `vvec->size() == threshold` but `blobs.size()` in `[0, minSize)`, sends it via `msg_dkg_raw(b"qcontrib", ...)`, and asserts the `"malformed DKG message"` debug log plus a misbehavior score of 100. Without this, a future regression that reintroduces retention of under-minSize contribution blobs would go unnoticed.
In `src/llmq/net_dkg.cpp`:
- [NITPICK] src/llmq/net_dkg.cpp:91-94: Cast of signed `params.minSize` is inconsistent with adjacent clamping
Lines 84-85 of the same function defensively clamp `params.size`/`params.threshold` before casting to `size_t`, and `MaxDKGMessageSize` (lines 51-52) does the same. Line 93 instead bare-casts `params.minSize` to `size_t`. Every configured `minSize` in `src/llmq/params.h` is >= 2, so this is safe today, but the local style divergence stands out and a future misconfigured 0/negative value would silently accept anything (0) or become unreachable (huge). A `std::max(0, params.minSize)`-style clamp would match the surrounding pattern with no observable behavior change. Not required for this PR.
| return qc.vvec != nullptr && qc.vvec->size() == threshold && | ||
| qc.contributions != nullptr && qc.contributions->blobs.size() <= size; | ||
| qc.contributions != nullptr && | ||
| qc.contributions->blobs.size() >= static_cast<size_t>(params.minSize) && | ||
| qc.contributions->blobs.size() <= size; |
There was a problem hiding this comment.
💬 Nitpick: Cast of signed params.minSize is inconsistent with adjacent clamping
Lines 84-85 of the same function defensively clamp params.size/params.threshold before casting to size_t, and MaxDKGMessageSize (lines 51-52) does the same. Line 93 instead bare-casts params.minSize to size_t. Every configured minSize in src/llmq/params.h is >= 2, so this is safe today, but the local style divergence stands out and a future misconfigured 0/negative value would silently accept anything (0) or become unreachable (huge). A std::max(0, params.minSize)-style clamp would match the surrounding pattern with no observable behavior change. Not required for this PR.
source: ['claude-general']
There was a problem hiding this comment.
Resolved in this update — Cast of signed params.minSize is inconsistent with adjacent clamping no longer present.
Auto-resolved by the review system based on the latest commit diff. If you believe this was closed in error, reopen the thread.
a4664e4 to
439fb7d
Compare
There was a problem hiding this comment.
Code Review
Source: reviewers: claude-general (opus, ok), codex-general (gpt-5.5, ok), claude-dash-core-commit-history (opus, ok), codex-dash-core-commit-history (gpt-5.5, ok); verifier: claude (opus, ok).
Cumulative revalidation at head 439fb7d0. The latest delta from a4664e40 to 439fb7d0 has no tree changes, so this pass revalidated the current head and the prior findings rather than treating the empty delta as a clean slate.
Prior Findings Reconciliation:
- prior-1: FIXED. LLMQ_TEST uses
size=3andminSize=2, while the test sendsblob_count=1; the all-zero BLS bytes deserialize far enough to reach the blob-count return path, so removing the new lower bound makes the test fail instead of passing via a deserialization exception. - prior-2: STILL VALID. The current
test:commit still contains the productionsrc/llmq/net_dkg.cpphunk that introduces the clampedmin_sizelocal.
Carried-Forward Prior Findings:
- prior-2 is carried forward below as the only current-head finding.
New Findings In Latest Delta:
- None.
1 suggestion
Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `src/llmq/net_dkg.cpp`:
- [SUGGESTION] src/llmq/net_dkg.cpp:85-94: Production min_size clamp is landing in a test-prefixed commit
Commit 439fb7d0a7 has subject `test: cover undersized DKG contribution intake` but its diff also edits `src/llmq/net_dkg.cpp`: it introduces `const size_t min_size = params.minSize > 0 ? static_cast<size_t>(params.minSize) : 0;` and rewrites the intake check to consume that local, replacing the raw `static_cast<size_t>(params.minSize)` that fix commit 35d4480367 introduced. That is a defensive production behavior change unrelated to the test being added. Because Dash keeps PR commits unsquashed on merge, `git log --oneline` and `git blame` on this consensus-adjacent intake path will report a `test:` commit for a real code change. Two clean options: squash the `net_dkg.cpp` hunk into 35d4480367 so the fix commit is self-contained with its final clamped form, or split it into its own commit (for example, `fix: clamp negative params.minSize in DKG intake check`) and leave the `test:` commit touching only `test/functional/feature_llmq_dkg_intake.py`.
| const size_t min_size = params.minSize > 0 ? static_cast<size_t>(params.minSize) : 0; | ||
| const size_t threshold = params.threshold > 0 ? static_cast<size_t>(params.threshold) : 0; | ||
| try { | ||
| CDataStream s(vRecv); // copy; deserialization does not advance the caller's stream | ||
| if (msg_type == NetMsgType::QCONTRIB) { | ||
| CDKGContribution qc; | ||
| s >> qc; | ||
| return qc.vvec != nullptr && qc.vvec->size() == threshold && | ||
| qc.contributions != nullptr && qc.contributions->blobs.size() <= size; | ||
| qc.contributions != nullptr && | ||
| qc.contributions->blobs.size() >= min_size && |
There was a problem hiding this comment.
🟡 Suggestion: Production min_size clamp is landing in a test-prefixed commit
Commit 439fb7d has subject test: cover undersized DKG contribution intake but its diff also edits src/llmq/net_dkg.cpp: it introduces const size_t min_size = params.minSize > 0 ? static_cast<size_t>(params.minSize) : 0; and rewrites the intake check to consume that local, replacing the raw static_cast<size_t>(params.minSize) that fix commit 35d4480 introduced. That is a defensive production behavior change (clamping negative/zero params.minSize) unrelated to the test being added. Because Dash keeps PR commits unsquashed on merge, git log --oneline and git blame on this consensus-adjacent intake path will report a test: commit for a real code change — a bisect/blame hazard. Two clean options: squash the net_dkg.cpp hunk into 35d4480 so the fix commit is self-contained with its final clamped form, or split it into its own commit (e.g. fix: clamp negative params.minSize in DKG intake check) and leave the test: commit touching only test/functional/feature_llmq_dkg_intake.py.
source: ['claude', 'codex']
439fb7d test: cover undersized DKG contribution intake (pasta) 35d4480 fix: bound DKG contribution blob intake (pasta) Pull request description: ## Issue being fixed or feature implemented The DKG intake hardening on `develop` pre-validates pushed `qcontrib` messages before retaining them. The valid configured envelope is `params.minSize <= actual members <= params.size`; the later DKG session worker still checks the exact `members.size()` once it has session context. Without the lower bound, structurally well-formed but undersized qcontrib payloads can pass the cheap intake check and reach retention before the worker rejects them. ## What was done? Tightened the cheap qcontrib structure check in `NetDKG` so encrypted contribution blob counts must be within the configured quorum bounds: - at least `params.minSize` - at most `params.size` The exact member-count validation remains in the DKG worker. Also added functional coverage for a qcontrib payload that deserializes cleanly but has fewer encrypted contribution blobs than `params.minSize`. ## How Has This Been Tested? Run feature_asset_locks.py multiple times that has been faulty in the first place (by knst). ## Breaking Changes None. ## Checklist: - [x] I have performed a self-review of my own code - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] I have assigned this pull request to a milestone This pull request was created by Codex. ACKs for top commit: knst: tACK 439fb7d UdjinM6: utACK 439fb7d Tree-SHA512: 32de8ac4775cc066de53761de17f7df4c6126214d1cff245e97fc8eeb6222703f26e8bba32d64f8c2b1eae25e79f058766d640658cd801830fe196361e8a4726
DKG contributions encrypt one blob per actual selected member. Requiring blobs.size() == params.size rejects valid contributions whenever the selected set is smaller than the configured quorum size, which breaks regtest DKG for asset locks and simplepose with undersized MN sets. Restore the dashpay#7408 range check: minSize <= blobs <= size. Co-Authored-By: Claude <noreply@anthropic.com>
439fb7d test: cover undersized DKG contribution intake (pasta) 35d4480 fix: bound DKG contribution blob intake (pasta) Pull request description: ## Issue being fixed or feature implemented The DKG intake hardening on `develop` pre-validates pushed `qcontrib` messages before retaining them. The valid configured envelope is `params.minSize <= actual members <= params.size`; the later DKG session worker still checks the exact `members.size()` once it has session context. Without the lower bound, structurally well-formed but undersized qcontrib payloads can pass the cheap intake check and reach retention before the worker rejects them. ## What was done? Tightened the cheap qcontrib structure check in `NetDKG` so encrypted contribution blob counts must be within the configured quorum bounds: - at least `params.minSize` - at most `params.size` The exact member-count validation remains in the DKG worker. Also added functional coverage for a qcontrib payload that deserializes cleanly but has fewer encrypted contribution blobs than `params.minSize`. ## How Has This Been Tested? Run feature_asset_locks.py multiple times that has been faulty in the first place (by knst). ## Breaking Changes None. ## Checklist: - [x] I have performed a self-review of my own code - [x] I have added or updated relevant unit/integration/functional/e2e tests - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] I have assigned this pull request to a milestone This pull request was created by Codex. ACKs for top commit: knst: tACK 439fb7d UdjinM6: utACK 439fb7d Tree-SHA512: 32de8ac4775cc066de53761de17f7df4c6126214d1cff245e97fc8eeb6222703f26e8bba32d64f8c2b1eae25e79f058766d640658cd801830fe196361e8a4726
The simplepose hardening folded into the dashpay#7408 merge made wait_for_quorum_commitment() count MNs exposing a minable commitment and let mine_quorum() pass its expected_commitments through as that threshold. Those are different units. mine_quorum()'s expected_commitments is a per-MN count of received premature-commitment *messages* (it is forwarded to wait_for_quorum_phase as check_received_messages_count for phase 5), whereas the new threshold counts *masternodes*. Wherever a caller passes a value below len(mninfos_online) the final-commitment gate silently weakened: with feature_llmq_dkgerrors' commit-omit/commit-lie cases (3 MNs, expected_commitments=2) mine_quorum would accept 2 of 3 MNs having a minable commitment where develop requires all 3. mine_quorum() has no deaf/probe-fail MNs, so restore the "every listed MN" requirement there. Keep the count-based threshold for mine_quorum_less_checks(), which is the close_mn_port caller that needs it, and rename the parameter to min_committing_mns so the unit is explicit at the call site. Reported-by: UdjinM6 Co-Authored-By: Claude <noreply@anthropic.com>
Backport of dashpay#7408 (upstream merge 72f53da). v23.1.x adaptations: (1) develop's CheckDKGMessageStructure lives in src/llmq/net_dkg.cpp, which does not exist on this branch - the same change is applied to the identical function in src/llmq/dkgsessionmgr.cpp (where the earlier intake hardening 31142da placed it). (2) This branch's QCONTRIB condition was 'blobs.size() == size' where develop pre-PR had '<= size'; the condition is updated to upstream's post-PR form 'blobs.size() >= min_size && <= size', making the resulting code match develop exactly. The functional test change applied cleanly and is unchanged from upstream. (cherry picked from commit 72f53dad67f00c1c62b119765f8c33a19d55c0d9)
24920a0 chore: prepare v23.1.8 release (pasta) 2194248 Merge #7348: fix: penalize oversized notfound messages (pasta) f5c72c3 Merge #7347: fix: punish invalid dstx messages (pasta) 550caf7 Merge #7465: fix(qt): handle pixel-sized fonts when scaling widgets (pasta) e203710 Merge #7419: fix(net): bound CoinJoin message vector intake (pasta) 5f5b960 Merge #7418: fix(net): bound signing message vector intake (Pasta) 7cc2cca Merge #7450: test: make governance vote fixtures wire-valid (Pasta) f011c80 Merge #7440: fix(net): bound governance vote signature deserialization (Pasta) 4b4d96a Merge #7442: fix(net): authorize governance inv responses via the net-layer per-peer request tracker (Pasta) f855b13 Merge #7444: fix(net): bound bloom message vectors before allocation (Pasta) 5b5c6fb Merge #7415: fix: bound pending sig share queue (Pasta) 9bbe808 Merge #7416: fix(net): bound quorum data response vectors (Pasta) da42f50 Merge #7424: fix: bound ChainLock seen cache (Pasta) 5b310df Merge #7438: fix: bound SPORK signature deserialization (Pasta) e118d0c Merge #7259: fix: dangling point to cj client (Pasta) 9921621 Merge #7439: refactor: add bounded vector deserialization (Pasta) 89bdf7c Merge #7414: fix(net): throttle per-object governance vote sync requests (Pasta) 44c396d Merge #7402: fix: bound pending recovered sig queue to prevent remote OOM (Pasta) 05cfe27 Merge #7351: fix: limit signing share sessions per peer (pasta) 3ef3a5b Merge #7408: fix: bound DKG contribution blob intake (pasta) 0ea6532 Merge #7387: test: migrate governance inv cache coverage to unit tests (Pasta) 8ffdf7f Merge #7398: backport: compact block relay hardening (bitcoin#26898, bitcoin#27626, bitcoin#27743, bitcoin#26969, bitcoin#29412, bitcoin#32646, bitcoin#33296) (Pasta) 2915142 backport: bitcoin#27608 - p2p: Avoid prematurely clearing download state for other peers (PastaClaw) 90b5473 Merge #7396: fix: run of circular-dependencies with python3.15 (Pasta) b003cdc Merge #7395: ci: update GitHub Actions pins for Node 24 (pasta) 97c3dd1 Merge #7394: fix: stabilize par help text in manpages (pasta) 8f8616b Merge #7372: backport: bitcoin#32693: depends: fix cmake compatibility error for freetype (pasta) 48f72be Merge #7360: fix: empty platformP2PPort deprecated field in protx listdiff results (pasta) a8cccff Merge #7298: fix(qt): keep PoSe score visible when hiding banned masternodes (pasta) Pull request description: Release PR for Dash Core v23.1.8, a patch release on top of v23.1.7. Fast-forwards from `v23.1.x` (currently at `chore: prepare v23.1.7 release`), 29 commits, no merge commits, no conflicts. ## Contents Backports of PRs already reviewed and merged on `develop`: `#7259` `#7347` `#7348` `#7351` `#7298` `#7360` `#7372` `#7387` `#7394` `#7395` `#7396` `#7398` `#7402` `#7408` `#7414` `#7415` `#7416` `#7418` `#7419` `#7424` `#7438` `#7439` `#7440` `#7442` `#7444` `#7450` `#7465` Plus `backport: bitcoin#27608`, a single commit taken from Dash #7237 because #7398's compact-block hardening depends on it. The rest of that v0.26 batch is intentionally not included on v23.1.x. The commit is byte-identical to its reviewed counterpart inside #7237. And release preparation: version bump, regenerated man pages, release notes, archived 23.1.7 notes. ## Note for reviewers: this branch was rebuilt An earlier revision of this PR was discarded and the branch rebuilt from scratch. Review comments on the previous revision point at commits that no longer exist, though the feedback itself was carried over (see below). The reason: several commits titled `Merge #NNNN` in the earlier revision contained substantial code that exists nowhere upstream — apparently written from a description of each PR rather than ported from its diff. For example, `feature_llmq_simplepose.py` is byte-identical between v23.1.7 and `develop`, yet the earlier `Merge #7408` rewrote 66 lines of it; `test/functional/p2p_governance_invs.py` does not exist on `develop` at all, yet had grown from 62 to 148 lines. That mislabeling matters because a commit titled `Merge #NNNN` invites less scrutiny, not more. It also had consequences: the earlier revision was **missing #7440 entirely**, and contained eleven consecutive commits that did not compile (code written against newer upstream APIs this branch does not have — `Misbehaving(Peer&)`, and `PeerIsBanned` used five commits before it was declared). Every commit on this branch has now been diffed against its upstream merge commit. Where a backport differs, it is because v23.1.x predates an upstream refactor and the change had to be applied to the pre-refactor file — for example #7418 and #7438 patch `signing_shares.cpp` / `spork.cpp` where upstream patches `net_signing.cpp` / `net_processing.cpp`. ## Dropped from this branch - **#7350** (`net: don't lock cs_main while reading blocks`) — dropped on review feedback. It is a 110-line lock-structure refactor of `ProcessGetBlockData` with no measured benefit, and it would add avoidable churn to the eventual master→develop merge-back. Nothing on this branch depends on it: #7398's compact-block work precedes it, and the remaining 14 commits replay with zero conflicts once it is removed. Thanks @knst. ## Added after the initial review pass - **#7351** (`fix: limit signing share sessions per peer`) — cherry-picked as a single commit and placed before #7402, matching upstream's merge order. The include block additionally carries `<ranges>`: upstream's diff adds only `<algorithm>` because develop already had it, whereas v23.1.x did not and the backported `GetSessionCount()` / `GetAnnouncementSessionCount()` use `std::ranges::count_if`. - **#7465** (`fix(qt): handle pixel-sized fonts when scaling widgets`) — cherry-picked from the five upstream commits. `optiontests.cpp` additionally includes `qt/guiutil_font.h`, because `fontsLoaded()` and `updateFonts()` are declared there on v23.1.x while develop declares them in `qt/guiutil.h`, which is all the upstream test includes. Two further backports were added later and applied without any adaptation -- their diffs are byte-for-byte identical to upstream: - **#7347** (`fix: punish invalid dstx messages`) - **#7348** (`fix: penalize oversized notfound messages`) ## Adaptations worth flagging - **#7360** — upstream gates `platformP2PPort` / `platformHTTPPort` in `protx listdiff` behind `IsServiceDeprecatedRPCEnabled()`. On 23.x those deprecated fields are deliberately not enforced through gating (see `bbcd9d543e6`), so shipping the gate as-is would silently drop two fields that v23.1.7 always returned. Changed to `if (true)` with a comment, per review feedback, keeping the block aligned with `develop`. The substantive fix from #7360 — reading the live port from `netInfo` instead of the always-zero scalar — is retained. - **#7415** — the pending-map caps (`MAX_PENDING_SIG_SHARES_PER_NODE`, `MAX_PENDING_SIG_SHARES_TOTAL`) are backported. The additional bound upstream places on batches awaiting verification is not, because it guards a condition that does not exist here: upstream's dispatcher pushes one task per batch inside an inner loop, whereas v23.1.x pushes a single looping worker per 10 ms tick. There is no unbounded task queue to bound. - **Man pages** — regenerated without the `lock` debug category, which only exists under `DEBUG_LOCKCONTENTION` and so is absent from release binaries. Thanks @UdjinM6 for catching this. ## Known CI failure macOS jobs are expected to fail. `actions/upload-artifact@v6` rejects filenames containing `:`, and the Xcode SDK ships Perl man pages with `::` in the name. A release-branch-only workaround existed on the earlier revision but was dropped as it corresponds to no upstream PR. This is accepted for this release. ## Testing - Every commit through #7465 compiles individually (verified for 27 of the 29; the three additions below were verified at the tip) — verified individually, not just at the tip. - Full build clean; no new warnings. - Unit tests pass. - Functional tests pass: `feature_llmq_signing` (both variants), `feature_llmq_chainlocks`, `feature_llmq_dkgerrors`, `feature_llmq_is_cl_conflicts`, `p2p_instantsend`, `feature_dip3_deterministicmns` (both wallet types), `rpc_coinjoin`. - Qt unit tests pass (32 cases, run under the `cocoa` platform plugin so the pixel-sized font regression from #7465 actually executes rather than self-skipping). - Lint: one pre-existing `lint-cppcheck-dash` failure, identical on v23.1.7, in files this branch does not touch. Top commit has no ACKs. Tree-SHA512: 0fa469c9a33820aa85fbb8b90c5877409d09490f746f1300b05ceda470a600765f900bec42e5aad5d90a2d46b44e28c20e44dc4a8fe719553a072298069eaec4
Issue being fixed or feature implemented
The DKG intake hardening on
developpre-validates pushedqcontribmessages before retaining them. The valid configured envelope isparams.minSize <= actual members <= params.size; the later DKG session worker still checks the exactmembers.size()once it has session context.Without the lower bound, structurally well-formed but undersized qcontrib payloads can pass the cheap intake check and reach retention before the worker rejects them.
What was done?
Tightened the cheap qcontrib structure check in
NetDKGso encrypted contribution blob counts must be within the configured quorum bounds:params.minSizeparams.sizeThe exact member-count validation remains in the DKG worker.
Also added functional coverage for a qcontrib payload that deserializes cleanly but has fewer encrypted contribution blobs than
params.minSize.How Has This Been Tested?
Run feature_asset_locks.py multiple times that has been faulty in the first place (by knst).
Breaking Changes
None.
Checklist:
This pull request was created by Codex.