Skip to content

feat(dpp)!: encode typed array elements as their scalar property type (PV14) - #4923

Merged
QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/typed-array-scalar-element-encoding
Sep 22, 2026
Merged

QuantumExplorer merged 1 commit into
v4.2-devfrom
claude/typed-array-scalar-element-encoding

Conversation

@QuantumExplorer

@QuantumExplorer QuantumExplorer commented Sep 22, 2026 •

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

#4922 added typed scalar arrays at protocol version 14 and stored their elements in the legacy ArrayItemType encoding, which is not how the same types are stored as scalar properties:

  • an identifier element carried a 0x20 length byte in front of its 32 bytes
  • every integer element took 8 bytes, whatever its bounds
  • a fixed-size byte array element carried a length byte

That array encoding had never been used for a stored document: #1851 (v1.0.0) made non-byte arrays unparsable, and #4922 is not in any release. So this is the last point where the element layout can change without a migration.

What was done?

A typed array element is now a scalar property in every respect:

  • Parse: the items schema goes through DocumentPropertyType::try_from_value_map with the contract's parsing options, the same parse a scalar property schema gets. TypedArrayProperty::item_type is now Box<DocumentPropertyType>. An element that parses to anything other than a scalar (U8..I128, F64, String, ByteArray, Identifier, Boolean) is refused. Objects, arrays of arrays, $ref and refersTo are refused as before.

  • Encode / decode: a varint count, then each element via encode_value_ref_with_size(element, true) / read_optionally_from(buf, true), i.e. exactly as a required scalar property:

    Element Before Now
    identifier 20 + 32 bytes 32 raw bytes
    integer 0..100 8 bytes 1 byte (U8)
    integer, contract without sizedIntegerTypes 8 bytes 8 bytes (I64)
    fixed 20-byte array 14 + 20 bytes 20 raw bytes
    string / variable byte array varint length + bytes unchanged
  • Decoder bound: a serialized count above maxItems is refused before any element is read. This bounds the loop even for zero-width elements (a byte array pinned to 0 bytes).

  • Encoder check: a raw element (identifier, fixed-size byte array) whose bytes are not exactly its width is refused. Without the check, a short element would shift every element after it. Schema validation already catches this for real documents; the check stops the serializer itself from writing a misaligned list.

  • Update guard: the schema compatibility rules allow raising maximum, adding enum values and unpinning a byte array's size, and each of these can change an element's width. validate_update v1 (new at PV14, edited in place) now runs validate_typed_array_element_encoding_stability after the byte-array stability check. It refuses with DocumentTypeUpdateError when an element's stored encoding would change, e.g. u8 -> u16 or a fixed 20-byte array -> a length-prefixed byte array. A longer maxLength, a larger maxItems, and a raised maximum that keeps the width are all accepted.

  • Fee sizing: min_byte_size / max_byte_size of a typed array are the count prefix plus min/maxItems times the element's scalar byte size, plus its varint length when it has one.

  • Removed: ArrayItemType keeps only what the legacy DocumentPropertyType::Array codec uses. The typed-array-only helpers from feat(dpp)!: typed scalar arrays in document schemas (PV14) #4922 are gone.

  • wasm-dpp2: documentTypeTypedArrays maps the scalar element type back to the same JS shape (integer / number / boolean / string / byteArray / identifier), so the TS surface is unchanged.

  • Docs: v14 changelog item 25 was edited in place. The book's serialization table row, a new pitfall entry, and the Typed Arrays section in the documents chapter now describe the scalar element layout and the update guard.

Note: an element inherits the scalar integer sizing exactly, including maximum without minimum choosing an unsigned type. The scalar integer width-change guard on contract update is a separate PR (claude/integer-width-update-guard). Whichever PR lands second should replace this PR's nested element_encoding with that PR's shared DocumentPropertyType::stored_encoding().

How Has This Been Tested?

  • New tests (dpp):
    • should_encode_each_typed_array_element_as_a_required_scalar_property_of_its_type: exact bytes for identifier, U8, I64, fixed and variable byte array, string and boolean elements
    • should_round_trip_every_typed_array_element_type_through_encode_and_read_optionally_from: every element type, required and behind a presence flag, with no bytes left over
    • should_refuse_a_serialized_typed_array_counting_more_elements_than_its_max_items: including zero-width elements
    • should_refuse_to_encode_a_typed_array_value_that_is_not_a_list_of_its_elements: including a 31-byte identifier and a short fixed-size element
    • should_type_an_element_as_a_scalar_property_of_its_schema: U8, I16, I64 when sized_integer_types is off, identifier
    • should_reject_an_update_that_changes_how_typed_array_elements_are_encoded / should_accept_an_update_that_keeps_how_typed_array_elements_are_encoded
  • The feat(dpp)!: typed scalar arrays in document schemas (PV14) #4922 tests were updated to the new element types and sizes (e.g. 0..100 integers are now 2..11 bytes, not 9..81).
  • cargo test -p dpp --all-features --lib -- typed_array parse_typed_array validate_update property:: document: 1872 passed.
  • cargo clippy -p dpp --all-features --all-targets -- -D warnings, cargo clippy -p wasm-dpp2 --target wasm32-unknown-unknown --all-targets -- -D warnings and cargo check -p drive --all-features are clean; cargo fmt --all applied.
  • Not run locally: the wasm-dpp2 JS spec (DocumentTypedArrays.spec.ts), whose output shape is unchanged, and the drive-abci suites; CI covers these.

Breaking Changes

Protocol version 14 is unreleased, so no stored document changes:

  • The document serialization of a typed array property changes (element layout above).
  • TypedArrayProperty::item_type changes type from ArrayItemType to Box<DocumentPropertyType>, and TypedArrayProperty no longer derives Eq.
  • parse_typed_array takes the property's DocumentPropertyTypeParsingOptions.
  • A contract update that changes a typed array element's encoding is now refused.

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/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · 9f2497d

  • Bots — coderabbitai not yet · thepastaclaw not yet — /skip-bots proceeds without the ones not yet reported
  • Self-review — post /self-reviewed once the bots are done
  • Within your 5 open PRs
  • Build running
  • Approvals — you own every area touched; none needed

When every box is checked the PR Hygiene check passes and this can merge.

… (PV14)

A typed array element is now parsed from its items schema exactly as a
scalar property schema is (DocumentPropertyType::try_from_value_map with
the contract's parsing options) and encoded exactly as a required scalar
property of that type. An identifier element is 32 raw bytes instead of
a 0x20 length byte and 32 bytes, an integer element takes the width its
bounds give it instead of always 8 bytes, and a fixed-size byte array
element is raw. Strings and variable-size byte arrays keep their varint
length.

TypedArrayProperty::item_type becomes Box<DocumentPropertyType>. The
decoder refuses a serialized count above maxItems before reading any
element, and the encoder refuses a raw identifier or fixed-size byte
element of the wrong length.

The schema compatibility rules allow raising maximum, adding enum values
and unpinning a byte array's size, which would change an element's
width, so validate_update v1 refuses a change in how an element encodes.

Typed arrays have never shipped (#4922 is unreleased), so no stored
document uses the old element encoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

Next included review available in 28 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Repository: dashpay/platform/.coderabbit.yaml

Review profile: CHILL

Plan: Advanced

Run ID: 0b81b363-b257-443e-9c1f-d60c7cbf55ca

📥 Commits

Reviewing files that changed from the base of the PR and between 5c047d2 and 9f2497d.

📒 Files selected for processing (13)
  • book/src/data-model/documents.md
  • book/src/serialization/document-serialization.md
  • packages/rs-dpp/src/data_contract/document_type/class_methods/parse_typed_array/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/parse_typed_array/v0/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/class_methods/try_from_schema/v3/typed_array_tests.rs
  • packages/rs-dpp/src/data_contract/document_type/methods/validate_update/v1/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/property/array.rs
  • packages/rs-dpp/src/data_contract/document_type/property/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/schema/find_identifier_and_binary_paths/v1/mod.rs
  • packages/rs-dpp/src/data_contract/document_type/v0/random_document_type.rs
  • packages/rs-platform-version/src/version/v14.rs
  • packages/wasm-dpp2/src/data_contract/document_type_typed_arrays.rs

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.

❤️ Share

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

@github-actions github-actions Bot added this to the v4.2.0 milestone Sep 22, 2026
@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Sep 22, 2026
@thepastaclaw

thepastaclaw commented Sep 22, 2026 •

Copy link
Copy Markdown
Collaborator

⚠️ DEGRADED — Queued for automated review — 36th in line, estimated start in ~39 h (commit 9f2497d)
Estimated review time once started: ~2.3 h (two-phase automated review; median of recent runs).
The primary review models are currently out of quota; this review will run on stand-in models and be marked as degraded.

  • Request priority review — click to move this review to the front of the queue.

@github-actions

Copy link
Copy Markdown
Contributor

📖 Book Preview built successfully.

Download the preview from the workflow artifacts.
To view locally: download the artifact, unzip, and open index.html.

Updated at 2026-09-22T22:06:40.911Z

@QuantumExplorer
QuantumExplorer merged commit f2c39aa into v4.2-dev Sep 22, 2026
18 of 19 checks passed
@QuantumExplorer
QuantumExplorer deleted the claude/typed-array-scalar-element-encoding branch September 22, 2026 22:24
QuantumExplorer added a commit that referenced this pull request Sep 22, 2026
…m parse

Typed array elements are their scalar property type since #4923.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Sep 22, 2026
…h or signedness (PV14)

A sized integer property takes its type (u8 ... i64) from its `minimum`,
`maximum` or `enum`, and the schema compatibility rules allow raising
`maximum`, lowering or removing `minimum`, removing the bounds and adding
`enum` values; the contract config allows turning `sizedIntegerTypes` on.
Each can move the type, and documents stored at the old width then no
longer decode against the updated document type (or read back other
values), while their index entries stay under keys of the old width.

validate_update v1 (protocol version 14 only) now refuses any change of
an integer property's type, nested properties included, with a
DocumentTypeUpdateError, as validate_byte_array_encoding_stability
refuses a byte array's fixed-size change. A bound change that keeps the
type is still allowed. validate_update v0 is unchanged for replay.

The layout description moves to DocumentPropertyType::stored_encoding,
and the typed array element check (#4923) calls it instead of its own
copy, so both checks describe a scalar's layout the same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
QuantumExplorer added a commit that referenced this pull request Sep 22, 2026
…pe) into fix/typed-array-review-fixes

The element constraints now sit on the boxed scalar item type and random
integer elements come back in the element type's own value kind.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

waiting-bots Waiting for the review bots to report on this head

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants