Skip to content

types%feat(secret): extract array-bound codec paths to dedicated module, add new macros dlgt_scodec! and derive_sbytes!, expand derive_{,s}bytes! scope, extract CompactSize - #24

Merged
kwvg merged 14 commits into
dashpay:developfrom
kwvg:scodec
Aug 8, 2026

Conversation

@kwvg

@kwvg kwvg commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Additional Information

  • The macro helpers have been mirrored to match both public and secret types, see table below

    Public (entity.rs) Secret (secret.rs) Emits Withholds
    impl_type! impl_stype! Encodable + Decodable, staged through VecEncoder/VecDecoder or the wiping ArrEncoder/ArrDecoder -
    impl_bytes! impl_sbytes! BaseCodec + From<[u8; N]> for a fixed-size byte newtype + impl_type! -
    derive_bytes! derive_sbytes! (Public) Clone, Copy, Default, Eq, PartialEq, Ord, PartialOrd, Hash, AsRef<[u8]>, AsRef<[u8; N]>, From<Self> for [u8; N], is_null, Debug, Display, Serialize, Deserialize (Secret) Drop, ZeroizeOnDrop, AsRef<[u8]>, AsRef<[u8; N]>, is_null, Debug, Display (Public) None (Secret) Copy, Default, Ord, PartialOrd, Hash, From<Self> for [u8; N], Serialize, Deserialize
    dlgt_codec! dlgt_scodec! Bridge code to another type's BaseCodec and Hashable -
    make_bytes! - No usage candidates for hypothetical make_sbytes! -
  • Macro generics are now forwarded bare (@parse [$($g)*]) with the impl template supplying the brackets (impl<$($g)*>), rather than mixing two conventions. The previous mixture meant dlgt_codec! could not hand its generics off to impl_type! at all, so it was usable only on concrete types. Two semgrep rules (types-macro-generics-bracketed, types-macro-impl-unbracketed) hold the convention in place.

    • type_cvrt! and dlgt_codec! consequently gain the for[...] prefix in line with other macros.

Breaking Changes

  • dash_types::ArrayBuf no longer implements PartialEq, Eq or Hash, and its Debug prints ArrayBuf { len: n } instead of the backing array. Comparing two buffers, keying a map on one, or deriving those traits on a struct holding one will no longer compile.

  • Debug and Display for byte newtypes are now emitted by derive_{,s}bytes! rather than written per-type, and resolve the type name through core::any::type_name.

  • impl_bytes! and impl_sbytes! take the type first and the length second, matching every other macro in the family. Invocations must be updated from impl_bytes!(16, Example) to impl_bytes!(Example, 16).

  • Both now accept exactly one type per invocation and construct through Self::from_bytes rather than the tuple field. A newtype passed to either must therefore expose from_bytes and as_bytes;

  • The Decodable read limit for impl_bytes! types is now N rather than MAX_SER_SIZE (32 MiB). impl_bytes! previously forwarded to impl_type!($name) without a maximum, so a 12-byte CommandString was willing to buffer 32 MiB before it decoded. Over-long streaming input now stops at the limit instead of reaching DecodeError::TrailingBytes.

  • derive_bytes! and derive_sbytes! now emit is_null, Debug and Display.

Old New Notes
dash_types::BufferDecoder<T, E> dash_types::VecDecoder<T, E> Renamed to pair with VecEncoder
dash_types::codec::ArrayBuf<N> dash_types::ArrayBuf<N> -
dash_types::impl_sbyte! dash_types::impl_sbytes! Pluralized to match impl_bytes!
dash_types::codec::read_compact_u64 dash_types::CompactSize::decode(_)?.get() -
dash_types::codec::read_compact_size dash_types::CompactSize::decode(_)?.into_len(limit)? The limit is now applied by the caller, not the reader
dash_types::codec::write_compact_u64, dash_types::codec::write_compact_size dash_types::CompactSize::from(_).encode(buf) -

How Has This Been Tested?

cargo fmt --check
cargo test --features full
cargo clippy --features full --all-targets
./contrib/lint_all.py --exclude lint_codeql
./contrib/lint/lint_codeql.py --with-suite rust-security-and-quality

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional tests
  • I have made corresponding changes to the documentation (note: N/A)
  • I have assigned this pull request to a milestone (for repository code-owners and collaborators only)

@kwvg kwvg added this to the 0.1 milestone Aug 8, 2026
@kwvg kwvg self-assigned this Aug 8, 2026
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 53834721-72d2-4916-b740-5f0ed8b8beab

📥 Commits

Reviewing files that changed from the base of the PR and between 2149eca and 0ed7f3e.

📒 Files selected for processing (13)
  • contrib/semgrep/types.yml
  • contrib/semgrep/workspace.yml
  • pkgs/num/src/hash.rs
  • pkgs/num/src/lib.rs
  • pkgs/num/src/util.rs
  • pkgs/pkc/src/common/bls/mod.rs
  • pkgs/pow/src/jh/scalar.rs
  • pkgs/types/src/entity.rs
  • pkgs/types/src/lib.rs
  • pkgs/types/src/macros.rs
  • pkgs/types/src/secret.rs
  • pkgs/types/src/serialize.rs
  • pkgs/types/src/uint.rs
🚧 Files skipped from review as they are similar to previous changes (4)
  • pkgs/types/src/serialize.rs
  • contrib/semgrep/types.yml
  • pkgs/types/src/lib.rs
  • pkgs/types/src/secret.rs

📝 Walkthrough

Walkthrough

Changes

The PR adds CompactSize, vector-backed codecs, and zeroizing secret codecs. It replaces legacy compact-size helpers, updates byte macros and BLS/ECDSA types, adds BLS secret-key conversions, and updates macro hygiene rules.

Codec modernization

Layer / File(s) Summary
Codec core and byte macros
pkgs/types/src/compact.rs, pkgs/types/src/entity.rs, pkgs/types/src/codec.rs, pkgs/types/src/lib.rs, pkgs/types/src/serialize.rs, pkgs/types/src/adapters.rs
Adds CompactSize, vector-backed encoders and decoders, byte macros, updated exports, and hex serialization support.
Secret codec and macro support
pkgs/types/src/secret.rs, pkgs/types/src/macros.rs, pkgs/types/Cargo.toml, contrib/semgrep/*.yml, contrib/codeql/zeroize.ql
Adds zeroizing fixed-size codecs and secret byte macros. Updates generic macro handling, macro hygiene rules, and the documented macro name.
Byte-type implementations
pkgs/pkc/src/bls/*, pkgs/pkc/src/ecdsa/*, pkgs/primitives/src/types/addrv1.rs, pkgs/p2p_core/src/primitives/command.rs
Migrates byte types to the new macros and adds AddrV1 byte conversion methods.
BLS secret-key conversions
pkgs/pkc/src/bls_chia/sk.rs, pkgs/pkc/src/bls_ietf/sk.rs
Adds serialization delegation and checked conversions for Chia and IETF BLS secret keys.
Protocol and primitive consumers
pkgs/p2p_core/src/msg/*, pkgs/p2p_core/src/primitives/*, pkgs/primitives/src/{payload,types}/*, pkgs/primitives/src/{support,transaction}.rs
Replaces legacy compact-size helpers with direct CompactSize encoding, decoding, and limit validation.

Fixed issue severity: Not emitted because the provided context does not state the impact of a pre-existing defect.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the PR's main changes, including secret codec extraction, new macros, expanded byte derivation, and CompactSize.
Description check ✅ Passed The description directly explains the macro changes, breaking changes, implementation details, and reported validation for this changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

@github-actions

github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

Warning

This pull request may have conflicts, please coordinate with the authors of these pull requests.

Potential conflicts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (5)
pkgs/types/src/secret.rs (1)

51-61: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

State that ArrayBuf does not wipe itself on drop.

ArrayBuf implements Zeroize but not Drop. A bare ArrayBuf that goes out of scope leaves its contents in memory. The wipe only happens when the buffer is moved into ArrEncoder or ArrDecoder, or when the caller wraps it in Zeroizing. pkgs/pkc/src/ecdsa/secret_ops.rs already relies on the Zeroizing wrapper and documents that requirement at its own call site.

The type is exported at the crate root and is the crate's staging buffer for key material, so the obligation belongs in this doc comment. The omission of Drop is correct, because pkgs/types/src/adapters.rs uses ArrayBuf for public Base58 data; only the documentation needs the addition.

📝 Proposed doc addition
 /// Fixed-size encode buffer backed by `[u8; N]`.
 ///
+/// Does not wipe on drop. For secret material either move the buffer into
+/// [`ArrEncoder`], or wrap it in `Zeroizing`; a bare drop leaves the bytes
+/// in memory.
+///
 /// # Panics
 ///
 /// Writing more than `N` bytes (via the [`EncodeBuf`] impl) panics with an
 /// index-out-of-bounds.
🤖 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 `@pkgs/types/src/secret.rs` around lines 51 - 61, Update the documentation
comment for the exported ArrayBuf type to explicitly state that it does not wipe
its contents when dropped, and that callers must use Zeroizing or move it into
ArrEncoder or ArrDecoder when cleanup is required. Do not add a Drop
implementation or change the existing behavior.
pkgs/types/src/entity.rs (2)

383-385: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Exported macros resolve names against the invoking crate. Both sites emit code whose name resolution depends on what the caller imported, rather than routing through $crate or an absolute path. The macros compile today only because the current call sites happen to have the right items in scope. Route every generated path through $crate:: or a leading ::.

  • pkgs/types/src/entity.rs#L383-L385: replace the .encode(buf) method call with $crate::codec::BaseCodec::encode(&..., buf), matching the fully qualified decode at line 379 and Hashable::hash at line 392.
  • pkgs/types/src/macros.rs#L262-L285: change the four core::convert::From and core::convert::TryFrom paths to ::core::convert::From and ::core::convert::TryFrom.
🤖 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 `@pkgs/types/src/entity.rs` around lines 383 - 385, Update
pkgs/types/src/entity.rs lines 383-385 in the generated encode method to call
BaseCodec::encode through $crate::codec::BaseCodec, matching the existing fully
qualified decode and Hashable calls. In pkgs/types/src/macros.rs lines 262-285,
prefix all four core::convert::From and core::convert::TryFrom paths with :: so
exported macros resolve independently of caller imports.

296-313: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use dash-types-owned serde gating in the exported byte macros.

All current in-repository callers declare a local serde feature and direct serde dependency. When a downstream crate invokes the macro with only dash-types/serde, the generated implementations are omitted. Use a $crate::__private serde re-export and a dash-types-side cfg marker for these implementations.

🤖 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 `@pkgs/types/src/entity.rs` around lines 296 - 313, Update both generated
Serialize and Deserialize implementations in the exported byte macros to use the
dash-types-owned serde cfg marker instead of cfg(feature = "serde"), so
downstream invocations honor dash-types/serde. Replace direct ::serde references
with the serde re-export under $crate::__private, including Serializer,
Deserializer, and de::Error paths, while preserving the existing hex encoding
and decoding behavior.
pkgs/types/src/macros.rs (1)

262-285: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use ::core::convert for the exported macro paths.

The generated impls reference core::convert::From and core::convert::TryFrom without the leading ::. In an exported macro these paths resolve against the invoking crate's scope, so a local item named core shadows them. Every other macro added in this PR uses ::core:: (see derive_bytes! and derive_sbytes!). Align type_cvrt! with that convention.

♻️ Proposed fix
-    impl<$($impl_generics)*> core::convert::From<&$src> for $dst {
+    impl<$($impl_generics)*> ::core::convert::From<&$src> for $dst {
       fn from($v: &$src) -> Self {
         $body
       }
     }
-    impl<$($impl_generics)*> core::convert::From<$src> for $dst {
+    impl<$($impl_generics)*> ::core::convert::From<$src> for $dst {
       fn from(v: $src) -> Self {
         Self::from(&v)
       }
     }
   };
   (`@parse` [$($impl_generics:tt)*] TryFrom<$src:ty> for $dst:ty, $err:ty, |$v:ident| $body:expr) => {
-    impl<$($impl_generics)*> core::convert::TryFrom<&$src> for $dst {
+    impl<$($impl_generics)*> ::core::convert::TryFrom<&$src> for $dst {
       type Error = $err;
       fn try_from($v: &$src) -> Result<Self, Self::Error> {
         $body
       }
     }
-    impl<$($impl_generics)*> core::convert::TryFrom<$src> for $dst {
+    impl<$($impl_generics)*> ::core::convert::TryFrom<$src> for $dst {
       type Error = $err;
       fn try_from(v: $src) -> Result<Self, Self::Error> {
         Self::try_from(&v)
       }
     }
🤖 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 `@pkgs/types/src/macros.rs` around lines 262 - 285, Update the generated impl
paths in the type_cvrt! parsing arms to use absolute ::core::convert::From and
::core::convert::TryFrom, including their associated Result references, so
invocation-crate items named core cannot shadow them. Keep the conversion
behavior unchanged and align both borrowed and owned implementations.
contrib/semgrep/types.yml (1)

8-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Match parenthesis-form invocations in types-macro-no-codec.

The pattern requires { after the macro name. make_bytes!(Foo, 20); and impl_bytes!(Foo, 20); use parentheses and evade the rule. This PR adds parenthesis-form invocations of these macros across the workspace, so the brace-only form is now the less common spelling. Widen the delimiter class to keep the guard rail effective inside pkgs/types/src.

Note that pkgs/types/src/entity.rs defines make_bytes! and calls $crate::impl_bytes! and $crate::derive_bytes! inside it. A widened pattern would fire there, so that file needs a nosemgrep comment or a path exclusion.

♻️ Proposed change
-    pattern-regex: '\b(?:make|impl)_(?:bytes|num|type)!\s*\{'
+    pattern-regex: '\b(?:make|impl)_(?:bytes|num|type)!\s*[({]'
🤖 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 `@contrib/semgrep/types.yml` around lines 8 - 9, Update the pattern-regex in
types-macro-no-codec to match both brace- and parenthesis-delimited invocations
after make_bytes, impl_bytes, and related macros, while preserving the existing
macro-name scope. Add a nosemgrep annotation to the intentional definitions and
internal calls in entity.rs, or exclude that file, so the widened rule remains
limited to unintended usage under pkgs/types/src.
🤖 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.

Inline comments:
In `@pkgs/p2p_core/src/msg/headers.rs`:
- Around line 70-71: Constrain encoding in Headers::encode
(pkgs/p2p_core/src/msg/headers.rs, lines 70-71) and Headers2::encode
(pkgs/p2p_core/src/msg/headers2.rs, lines 59-60) to MAX_HEADERS: compute the
bounded header count, write that count, and encode exactly the corresponding
number of headers rather than the full collection.

In `@pkgs/primitives/src/types/addrv1.rs`:
- Around line 64-67: Rename the consuming conversion method from to_bytes to
into_bytes in the address type implementation, preserving its const behavior,
return type, and direct self.0 conversion.

In `@pkgs/types/src/serialize.rs`:
- Around line 9-24: Update the `hex` module documentation to describe only
`Vec<u8>` support, and add `# Errors` sections to both `hex::serialize` and
`hex::deserialize` documenting their possible serialization or hex-parsing
failures, matching the style used by the `utf8` module.

---

Nitpick comments:
In `@contrib/semgrep/types.yml`:
- Around line 8-9: Update the pattern-regex in types-macro-no-codec to match
both brace- and parenthesis-delimited invocations after make_bytes, impl_bytes,
and related macros, while preserving the existing macro-name scope. Add a
nosemgrep annotation to the intentional definitions and internal calls in
entity.rs, or exclude that file, so the widened rule remains limited to
unintended usage under pkgs/types/src.

In `@pkgs/types/src/entity.rs`:
- Around line 383-385: Update pkgs/types/src/entity.rs lines 383-385 in the
generated encode method to call BaseCodec::encode through
$crate::codec::BaseCodec, matching the existing fully qualified decode and
Hashable calls. In pkgs/types/src/macros.rs lines 262-285, prefix all four
core::convert::From and core::convert::TryFrom paths with :: so exported macros
resolve independently of caller imports.
- Around line 296-313: Update both generated Serialize and Deserialize
implementations in the exported byte macros to use the dash-types-owned serde
cfg marker instead of cfg(feature = "serde"), so downstream invocations honor
dash-types/serde. Replace direct ::serde references with the serde re-export
under $crate::__private, including Serializer, Deserializer, and de::Error
paths, while preserving the existing hex encoding and decoding behavior.

In `@pkgs/types/src/macros.rs`:
- Around line 262-285: Update the generated impl paths in the type_cvrt! parsing
arms to use absolute ::core::convert::From and ::core::convert::TryFrom,
including their associated Result references, so invocation-crate items named
core cannot shadow them. Keep the conversion behavior unchanged and align both
borrowed and owned implementations.

In `@pkgs/types/src/secret.rs`:
- Around line 51-61: Update the documentation comment for the exported ArrayBuf
type to explicitly state that it does not wipe its contents when dropped, and
that callers must use Zeroizing or move it into ArrEncoder or ArrDecoder when
cleanup is required. Do not add a Drop implementation or change the existing
behavior.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 62c8e037-f6b7-40f0-a946-b09954a67c9d

📥 Commits

Reviewing files that changed from the base of the PR and between efd8332 and 2149eca.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/*.lock
📒 Files selected for processing (37)
  • contrib/codeql/zeroize.ql
  • contrib/semgrep/types.yml
  • pkgs/p2p_core/src/msg/addr.rs
  • pkgs/p2p_core/src/msg/headers.rs
  • pkgs/p2p_core/src/msg/headers2.rs
  • pkgs/p2p_core/src/primitives/command.rs
  • pkgs/p2p_core/src/primitives/user_agent.rs
  • pkgs/pkc/src/bls/public_bytes.rs
  • pkgs/pkc/src/bls/schemes.rs
  • pkgs/pkc/src/bls/secret_bytes.rs
  • pkgs/pkc/src/bls/sig_bytes.rs
  • pkgs/pkc/src/bls_chia/sk.rs
  • pkgs/pkc/src/bls_ietf/sk.rs
  • pkgs/pkc/src/ecdsa/public_bytes.rs
  • pkgs/pkc/src/ecdsa/public_hash.rs
  • pkgs/pkc/src/ecdsa/secret_bytes.rs
  • pkgs/pkc/src/ecdsa/secret_ops.rs
  • pkgs/pkc/src/ecdsa/sig_bytes.rs
  • pkgs/pkc/src/ecdsa/sig_rec_bytes.rs
  • pkgs/primitives/src/block.rs
  • pkgs/primitives/src/gov.rs
  • pkgs/primitives/src/payload/cbtx.rs
  • pkgs/primitives/src/support.rs
  • pkgs/primitives/src/transaction.rs
  • pkgs/primitives/src/types/addrv1.rs
  • pkgs/primitives/src/types/addrv2.rs
  • pkgs/primitives/src/types/netinfo.rs
  • pkgs/types/Cargo.toml
  • pkgs/types/src/adapters.rs
  • pkgs/types/src/codec.rs
  • pkgs/types/src/compact.rs
  • pkgs/types/src/entity.rs
  • pkgs/types/src/hex.rs
  • pkgs/types/src/lib.rs
  • pkgs/types/src/macros.rs
  • pkgs/types/src/secret.rs
  • pkgs/types/src/serialize.rs
💤 Files with no reviewable changes (2)
  • pkgs/types/src/hex.rs
  • pkgs/pkc/src/bls/schemes.rs

Comment thread pkgs/p2p_core/src/msg/headers.rs
Comment thread pkgs/primitives/src/types/addrv1.rs
Comment thread pkgs/types/src/serialize.rs Outdated
@kwvg
kwvg merged commit b08855c into dashpay:develop Aug 8, 2026
55 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant