Repository navigation
p2p_core%feat!: bound inventory, locator and address counts - #119
Conversation
|
No actionable comments were generated in the recent review. Summary
Merge Risk:
|
|
Warning This pull request may have conflicts, please coordinate with the authors of these pull requests. Potential conflicts |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! 🚀 New features to boost your workflow:
|
|
✅ Final review complete — no blockers (commit b9859b6) · triage: normal |
thepastaclaw
left a comment
There was a problem hiding this comment.
Final validation — Phase 1 + Phase 2
Verified the supplied findings against head 06d7b19 and compared the framing checks and constants with the pinned Dash Core source; no actionable in-scope issues remain. The payload-length concern violates an explicit caller precondition, while the diagnostic coverage observation does not identify incorrect behavior. This was a static-only review: current CI reports successful build, test, and cross-compilation checks, with Lint still pending and no failed code checks reported.
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
normalbygpt-6.1-sol(effort low) — Although V1Header::verify_header and verify_payload introduce peer-facing framing validation, the implementation is compact and straightforward rather than large or intricate enough to meet the critical tier. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer
06d7b19 to
85ef0c9
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Independently reviewed the complete diff at 85ef0c9 and found no actionable defects. All eight decoders enforce the Dash Core count limits before allocating or decoding entries, preserve existing encoding and trait behavior, and have boundary and dispatch coverage. Validation was static only; current CI reports passing lint, relevant MSRV build/tests, stable-platform checks and cross-builds, with no pending or failing checks.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
normalbygpt-6.1-sol(effort low) — The diff changes peer-facing deserialization but consists of straightforward, repeated bounded-vector decoding across eight messages, so it is not sufficiently large or intricate to qualify as critical. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
85ef0c9 to
a740455
Compare
It generates `BaseCodec` over a struct's named fields. A field written `field: limit` is read with `decode_vec`, which refuses a count above the limit before any entry is read.
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Reviewed the complete diff at a740455: all eight count limits match Dash Core, and the decoders enforce them before entry allocation or decoding while preserving valid wire encodings. No functional or security blocker was found; two non-blocking suggestions concern shared codec ownership and source citations in documentation. Validation was static only; current CI reports successful applicable MSRV and completed stable-platform checks, no failed checks, and pending lint and additional cross-platform jobs.
🟡 2 suggestion(s)
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
normalbygpt-6.1-sol(effort low) — The diff changes peer-facing deserialization in pkgs/p2p_core/src/codec.rs and eight message decoders, but the shared bounded-vector macro and repetitive limit substitutions are contained rather than large or intricate. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer
🤖 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 `pkgs/p2p_core/src/codec.rs`:
- [SUGGESTION] pkgs/p2p_core/src/codec.rs:28-49: Separate shared bounded-field codec generation from P2P wiring
The new macro repeats the field-by-field BaseCodec generation in dash_primitives::codec_base!, adding optional decode_vec calls, then combines that generic mechanism with the P2P payload limit and Hashable implementation. Keeping the bounded-field generator private to dash-p2p-core prevents lower-level crates such as dash-primitives from reusing it without reversing the dependency direction or adding another implementation. Extract the transport-independent field codec generator into dash-types, alongside BaseCodec and decode_vec, and retain payload-limit selection and hash_impl! composition in a thin P2P wrapper. The current decoder behavior is correct; this is a non-blocking ownership and duplication concern introduced by the new macro.
In `pkgs/p2p_core/src/msg/headers.rs`:
- [SUGGESTION] pkgs/p2p_core/src/msg/headers.rs:53-54: Keep version-specific Core citations in the PR description
The new constant documentation embeds a Core source path and release version here, with equivalent citations on Inv::MAX_COUNT and Addr::MAX_COUNT. These references become stale independently of the constants and conflict with the project's stated convention of keeping reference-implementation citations in PR descriptions rather than code comments. Keep the descriptions of what each constant limits, remove the source/version parentheticals from all three comments, and retain the Core references in the PR description.
Its field codec is the one `impl_vec!` generates with no limited field, so every type decodes and encodes as before.
Each list is read through `dash_types::impl_vec!`, which checks its CompactSize count with `decode_vec` before any entry is read.
a740455 to
b9859b6
Compare
thepastaclaw
left a comment
There was a problem hiding this comment.
Re-review — Final validation — Phase 1 + Phase 2
Verified the complete diff at b9859b6: all eight message decoders enforce Dash Core's count limits before allocating or decoding entries, and the shared codec extraction preserves field order and encoding behavior. Both prior findings are fixed, with no remaining actionable findings. Validation was static only; current CI shows successful Linux cross-build and Windows stable checks, no failed checks, and pending MSRV builds/tests, lint, documentation, and other platform jobs.
🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)
Review provenance
Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)
- Triage:
normalbygpt-6.1-sol(effort low) — Although the diff changes peer-facing network deserialization, the count checks and small shared codec macro are straightforward rather than large or intricate enough to meet the critical tier. - Phase 1 reviewers:
muse-spark-1.3-contributor— general (completed, effort xhigh); agentphase1-reviewer,muse-spark-1.3-contributor— rust-quality (completed, effort xhigh); agentphase1-reviewer - Phase 1 model:
muse-spark-1.3-contributor— not quota-gated; passed overgemini-3.8-flash-high(antigravity quota lookup failed),glm-5.3-flash(not used above high effort; tier asks max) - Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
- Fresh verifier:
gpt-6.1-sol— final-verifier; agentsol-verifier - Phase 2 reviewers:
gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— general (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— rust-quality (completed, effort high); agentphase2-reviewer,gpt-6.1-sol— security-auditor (completed, effort high); agentphase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.
No unresolved findings remain from the prior review on this head.
Brings `impl_vec!` and `codec_base!` on it (dashpay#119's first two commits) and `GovObject` refusing signatures over 96 bytes, with the overlay III corpus holding that refusal.
Motivation
dash-p2p-coredecodes the lists ininv,getdata,notfound,getblocks,getheaders,getheaders2,addrandaddrv2up toMAX_SER_SIZEentries, far more than the reference implementation's limit for any of them. A caller has to check each limit after decoding, by which point the decoder has already read and allocated the whole list. This pull request enforces each limit in the message's own decoder, on the count, before any entry is read.Additional Information
inv,getdataandnotfoundat 50 000 entriesInv::MAX_COUNT, the reference implementation's limit (src/net.h:80at v24.0.0-rc.3).GetData::MAX_COUNTandNotFound::MAX_COUNTtake the same value.getblocks,getheadersandgetheaders2at 101 hashesGetHeaders::MAX_LOCATOR_COUNT, the reference implementation's limit (src/net_processing.cpp:150at v24.0.0-rc.3).GetBlocks::MAX_LOCATOR_COUNTandGetHeaders2::MAX_LOCATOR_COUNTtake the same value.addrandaddrv2at 1 000 addressesAddr::MAX_COUNT, the reference implementation's limit (src/net_processing.cpp:213at v24.0.0-rc.3).AddrV2Msg::MAX_COUNTtakes the same value.impl_vec!todash-typescodecfeature, besideimpl_type!andimpl_bytes!. It generatesBaseCodecover the named fields of a struct, in the order listed. A field writtenfield: limitis read withcodec::decode_vec(data, limit), which checks the CompactSize count withCompactSize::decode_lenand fails withCompactSizeExceedsLimitbefore it reads or allocates an entry. Every other field reads with its ownBaseCodec, and every field encodes with its ownBaseCodec. It generates only the codec: the caller addsEncodeandDecodeunder its own size cap, andHashable.impl_vec!impl_vec!withimpl_p2p!andhash_impl!, the patternheaders,pongandversionalready follow. For example,impl_vec!(GetHeaders, { version, locator_hashes: Self::MAX_LOCATOR_COUNT, hash_stop }). Every field encodes ascodec_p2p!wrote it, so a message within the limit encodes and decodes to the same bytes as before. No codec macro is added todash-p2p-core.codec_base!onimpl_vec!dash-primitives'codec_base!is nowimpl_vec!with no limited field, followed byimpl_type!as before. It generates the same code, so every type built withcodec_base!,codec_type!,codec_payload!orcodec_p2p!decodes and encodes as before.headersandheaders2as they areHeaders::MAX_COUNT,Headers2::MAX_COUNT) throughdecode_count, before any entry is read. Their entries are not decoded by the field type's own codec: aheadersentry carries a transaction count after the header that is read and dropped, and aheaders2entry is restored from the entries before it.decode_countalso fails withEofon a count the input cannot hold at the smallest entry size.impl_vec!would change how their entries are read and which error a short input gives, so they stay ondecode_count.A field can take
field: limitwhen it is a plain struct field, read through its own codec, that the reference implementation bounds at decode. No such field indash-primitivesis bounded today, so none takes afield: limitin this pull request. The ones checked:provider/proregtx.rs) is a one-byte count, and its 8-share limit (provider/share.rs) is a validity rule checked after decode, with its own error.types/netinfo.rs) is limited to 4 per purpose by a validity rule checked after decode, with its own error. Its purpose and entry counts are read againstMAX_SER_SIZEonly.gov/vote.rs), the compact provider signature (provider/sig.rs), theaddrv2address (types/addrv2.rs) and the network info domain (types/netinfo.rs) are already bounded at decode. Each is read by a hand-written codec in which the length picks a variant or sits inside one, so they stay as they are.MAX_SER_SIZEbytes, while the reference implementation refuses one longer than 96 bytes before reading it (src/governance/common.h:37at v24.0.0). It is the one field found that fitsfield: limit, but bounding it is a new refusal indash-primitives, so it is left for a follow-up.Outside these crates, the only other count checked at decode is the recipient count of
BlsIesMultiBytesindash-pkc, whose decoder grows the list as entries arrive rather than reserving it up front, whichdecode_vecwould change. It stays as it is.Breaking Changes
inv,getdata,notfound,getblocks,getheaders,getheaders2,addrandaddrv2refuse lists longer than their limit, which the crate decoded before.How Has This Been Tested?
impl_vec!has its own tests indash-types, on a struct with a limited list between two other fields. A list at the limit decodes. One more entry fails withCompactSizeExceedsLimit, and so does that count with no entry bytes after it. A list field with no limit decodes as its ownBaseCodecdoes, past the other field's limit. The struct encodes as its fields do, one after another.counts_stop_at_the_limitcovers each of the eight messages. A list at the limit decodes and encodes back to the same bytes. One more entry fails withCompactSizeExceedsLimit. That count with no entry bytes after it gives the same error rather thanEof, so the count is checked before any entry is read.dispatch_keeps_the_limitchecks the same error throughP2pMsg::decode_payloadfor each of the eight commands.inv,getblocks,getheaders2,addrandaddrv2still decode and encode to the same bytes, and theheadersandheaders2limit tests pass unchanged.impl_vec!reading its limited fields with no limit,impl_vec!encoding the fields in reverse order, theinvlimit one too high, the locator limit one too low, and thedash-typestest limit one too high and one too low.contrib/git_filter.py --fast-fail <base> HEAD -- bash -c '<cmds>', where<cmds>iscargo clippy -p dash-types -p dash-primitives -p dash-p2p-core --all-features --all-targets -- -D warnings,cargo nextest runfor the same crates with--all-features, and the same clippy and nextest runs with default features, passes on each commit.cargo nextest run --workspace --all-featuresandRUSTDOCFLAGS='-D warnings' cargo doc -p dash-types -p dash-primitives -p dash-p2p-core --all-features --no-depspass on the tip.lint_all.py(without CodeQL),lint_bazel.py graph,lint_commit.pyover the range, semgrep and cargo-deny pass on the tip. CodeQL was not run locally.developpasses the same clippy and nextest runs for the three crates.Checklist
comments and concerns without said assistance. I assume authorship of the code submitted.
Agent disclosure
Code, commit messages and this description were generated with Claude Code using Claude Opus 5.5, running autonomously as an agent on behalf of the author. The change was reviewed by a Claude Code agent using Opus 5.5.
🤖 Generated with Claude Code