fix(dpp)!: contract updates may not change an integer property's width or signedness (PV14) - #4925
Conversation
|
Warning Review limit reachedNext included review available in 58 minutes. View limit detailsLimit 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. Review configuration: ⚙️ Run configurationConfiguration used: Repository: dashpay/platform/.coderabbit.yaml Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (2)
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 |
…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>
5006801 to
84cb144
Compare
|
🕓 Review not started yet because the new head is waiting for the 30-minute push debounce.
Commit 84cb144. Normal review starts when eligible; priority review starts as soon as a slot is available. |
Issue being fixed or feature implemented
With
sizedIntegerTypeson (the default since config V1, protocol version 9), an integer property's type (u8toi64) comes from itsminimumandmaximum, or from itsenumvalues when it has no bounds (find_integer_type_for_subschema_value). The JSON schema compatibility rules allow every change that moves that type on a contract update:maximum({"minimum": 0, "maximum": 100}is au8,"maximum": 1000makes it au16)minimumbelow zero, which also changes the signednessminimum,maximumor bothenumvalues past the widthThe contract config also lets an update turn
sizedIntegerTypeson for a config V1 contract created with it off. The config check only refuses turning it off. Turning it on changes every bounded integer fromi64.Documents and index keys store an integer at the width of its type. After such an update, documents already stored no longer decode against the updated document type:
U8.encode_value_ref_with_size(&Value::U8(7), true)is[7], and theu16reader returnsCorruptedSerialization("error reading u16 from serialized document"). Documents written under serialization v1/v2 can also read back as other values, and their index entries stay under keys of the old width. Every later transition on such a document fails, whoever owns the document, and so does every query that decodes it. Nothing lets the contract owner undo it: loweringmaximumback is refused by the same compatibility rules.validate_byte_array_encoding_stabilityalready refuses the analogous change for byte arrays (a fixed-size array turning length-prefixed). Nothing held the integer type.What was done?
validate_updatev1 (selected only by protocol version 14's tables, still unreleased) runs a newvalidate_integer_encoding_stability. The check sits right after the byte array one and before the schema compatibility check.DocumentTypeUpdateError:document type can not change the integer encoding of property 'score': its values are stored as u8 and would be read as u16.u8withmaximumraised from 100 to 200) is still allowed. A change to a non-integer type is left to the schema compatibility check, which already refuses atypechange.u8capped at 100 reads the same as ani8, but au64that becomes ani64(minimumlowered from 0 to -1) misreads anything abovei64::MAX. One comparison keeps the rule simple.validate_updatev0 (protocol versions 1 to 13) is unchanged, byte for byte, for replay.DocumentPropertyType::stored_encoding()describes how a scalar value is laid out: an integer by its type, and a byte array as fixed raw bytes or length-prefixed.element_encodingfunction. It now callsstored_encoding()instead, so both checks describe a scalar's layout the same way. The integer check runs just before the typed array one.How Has This Been Tested?
New tests in
validate_update/v1(integer_encoding_update). All go through the publicvalidate_updatedispatcher atPlatformVersion::latest()unless stated:should_not_read_a_stored_u8_back_as_the_u16_a_raised_maximum_gives: the parsed types areU8andU16, and the encoded[7]fails to read back.should_reject_raising_maximum_past_the_width_of_the_type(u8 to u16)should_reject_lowering_minimum_below_zero(u64 to i64)should_reject_removing_the_bounds(u8 to i64)should_reject_adding_an_enum_value_past_the_width_of_the_type(u8 to u16)should_reject_a_width_change_of_a_nested_integer_property(stats.level)should_reject_turning_sized_integer_types_on(i64 to u8)should_accept_a_bound_change_that_keeps_the_typeshould_accept_raising_maximum_without_sized_integer_typesshould_still_accept_a_width_change_at_protocol_version_13: the other side of the gate, where v0 is frozen.Locally:
cargo test -p dpp --lib validate_update, after rebasing onto feat(dpp)!: encode typed array elements as their scalar property type (PV14) #4923: 103 passed, including the new tests and feat(dpp)!: encode typed array elements as their scalar property type (PV14) #4923's typed array element tests.cargo clippy -p dpp --all-featureswith-D warningsis clean on the lib, the lib unit tests (test profile) and the integration tests.cargo fmt --all.Not run locally: drive-abci, and an end-to-end
process_raw_state_transitionstest of a contract update. CI runs the drive-abci suite.Breaking Changes
Consensus change at protocol version 14: a data contract update that changes the integer type of an existing property of an existing document type is now refused with
DocumentTypeUpdateError, where protocol versions up to 13 accepted it. No new error code or variant.Checklist:
structure.rs, regeneratedgrovedb-structure.json, and checked the structure viewer link posted on this pull requestFor repository code-owners and collaborators only
🤖 Generated with Claude Code
PR Hygiene ·
84cb144/skip-botsproceeds without the ones not yet reported/self-reviewedonce the bots are doneWhen every box is checked the
PR Hygienecheck passes and this can merge.