refactor(dpp)!: cleanup and unify JSON/Object conversion#3167
refactor(dpp)!: cleanup and unify JSON/Object conversion#3167QuantumExplorer merged 32 commits intov3.1-devfrom
Conversation
|
Important Review skippedToo many files! This PR contains 298 files, which is 148 over the limit of 150. ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (298)
You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ 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 |
❌ gRPC Query Coverage ReportTotal: 53 queries — 50 implemented, 2 ignored, 1 missing ❌ Missing
⏭️ Ignored (@sdk-ignore) (2)
✅ Implemented (50)
|
1dbe9d3 to
9a72612
Compare
|
✅ DashSDKFFI.xcframework built for this PR.
SwiftPM (host the zip at a stable URL, then use): .binaryTarget(
name: "DashSDKFFI",
url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
checksum: "9e6eab6deb1210d9214034ce6e7d2af10938bca164cacf6cb1141eccf4a8c637"
)Xcode manual integration:
|
Audit Findings (informational — no code changes needed)Finding 2 (Medium):
|
Suggestion: Replace empty
|
5f607ea to
9d99ef6
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## v3.1-dev #3167 +/- ##
=============================================
+ Coverage 30.67% 50.39% +19.71%
=============================================
Files 105 3089 +2984
Lines 9356 219068 +209712
=============================================
+ Hits 2870 110394 +107524
- Misses 6486 108674 +102188
🚀 New features to boost your workflow:
|
904d261 to
7c7bb8a
Compare
…d TokenPaymentInfo conversions
Use serde(tag = "type", content = "data", rename_all = "camelCase") for
semantic enums (Vote, VotePoll, ResourceVoteChoice, TokenEvent,
GroupActionEvent, ContestedDocumentVotePollWinnerInfo) instead of the
default externally-tagged format. This produces JS-friendly output like
{ type: "mint", data: [...] } instead of { Mint: [...] }.
Add $formatVersion tag to TokenPaymentInfo and rename_all = "camelCase"
to its V0 struct. Add toJSON/fromJSON/toObject/fromObject conversion
methods via impl_wasm_conversions_serde! macro.
Update all affected wasm-dpp2 and wasm-sdk test fixtures.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…nd test vectors - Run cargo fmt on dpp, wasm-dpp2, wasm-sdk - Feature-gate JsonConvertible import in token_configuration/mod.rs - Update $version -> $formatVersion in extended_document test fixture - Update $format_version -> $formatVersion in rs-sdk test vectors (6 DocumentQuery mock files still had old snake_case tag) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Collapse nested if-let blocks using let-chains syntax - Allow unused ValueConvertible import in macro (shadowed by inherent methods) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ype modules Tests were co-located in serialization_traits.rs but they test specific types, not the traits themselves. Moved 26 tests to 11 type modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use object destructuring, remove unused Buffer import, and remove unnecessary non-null assertion. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… proc macros Introduce `#[json_safe_fields]` attribute macro and `#[derive(JsonConvertible)]` derive macro that automatically add `#[serde(with = "json_safe_u64")]` to u64/i64 fields. Uses `serializer.is_human_readable()` so JSON stringifies values exceeding JS MAX_SAFE_INTEGER while platform_value stays native. Includes compile-time enforcement via `JsonSafeFields` marker trait with recursive assertions on nested types. Adds safe serializers for BTreeMap<u64, u64>, BTreeMap<Identifier, u64>, and nested map variants. Removes manual stringify/unstringify from wasm-dpp2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- `JsonConvertible::to_json` now maps to `EncodingError` instead of
`DecodingError` since it's a serialization operation.
- Replace `.unwrap()` with `.expect("guard guarantees len == 1")` in
platform-value enum deserializer.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Gate `#[json_safe_fields]` with `#[cfg_attr(feature = "json-conversion", ...)]` so the macro only runs when the feature is active. Feature-gate the `json` serialization module and its re-exports. Gate all `json_safe_fields` imports and manual `serde(with)` map serializer annotations with `cfg(feature)`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e docs Remove `impl JsonSafeFields for u64/i64` so unprotected type aliases like `type Foo = u64` and containers like `Vec<u64>` trigger compile errors. Skip JsonSafeFields assertion for fields with `#[serde(with)]` (including inside cfg_attr) since the developer explicitly handles serialization. Add generic `json_safe_generic_u64_value_map` serde module for `BTreeMap<AnyKey, u64>` and apply it to recipient_addresses field. Add README to proc macro crate documenting the problem, solution, compile-time safety guarantees, and maintenance guide. Improve doc blocks across all json serialization modules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… macro - `serde_with_suffix_for_type` now uses last path segment, handling qualified paths like `std::option::Option<u64>` and `crate::prelude::Credits` - `has_serde_default` now detects `default = "custom_fn"` in addition to bare `default`, preventing duplicate serde attribute errors - Add tests for `json_safe_option_i64` (none, large, large negative, missing field) - Add tests for `json_safe_option_u64` missing field deserialization - Add tests for `json_safe_generic_u64_value_map` (small, large, mixed values) - Fix README: expand skip row, clarify serde(with) skips both annotation and assertion, clarify Vec<u64> has no module, fix serde Content terminology Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Flat enums (not versioned V0/V1) and enums with u64-alias tuple variants can't use #[derive(JsonConvertible)] and need manual impl with explanation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The new proc macro crate was missing from Docker build context, causing cargo metadata to fail with "No such file or directory". Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…lters Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The auto-commit step causes push conflicts on active branches. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The test expected "Insufficient" but the error class uses "Unsufficient". Match the test to the actual error message. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…odules - Error paths: negative i64→u64, overflow, invalid strings, wrong types - Platform_value round-trips: non-HR path for u64, i64, Option variants - Edge cases: empty maps, small Option values, i64 visit on u64 deserialize Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… unified flags Replace 18 per-entity conversion feature flags (document-serde-conversion, data-contract-value-conversion, identity-json-conversion, etc.) with 3 unified flags: serde-conversion, value-conversion, json-conversion. Old flags are kept as backwards-compatible aliases. This simplifies feature management and reduces CI build matrix time. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…version feature Move ValueConvertible trait definition, derive macro re-export, and all derive(ValueConvertible) usages behind #[cfg(feature = "value-conversion")] instead of serde-conversion or no gate. This properly separates the three conversion levels: serde-conversion (Serialize/Deserialize derives), value-conversion (platform_value conversion), json-conversion (JSON conversion). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
533c7d5 to
efe591b
Compare
Issue being fixed or feature implemented
The WASM SDK (wasm-dpp2, wasm-sdk) historically used ad-hoc JavaScript workarounds for JSON serialization — manually converting identifiers, large numbers,
and enum tags at the JS boundary. This led to inconsistent behavior, duplicated logic, and fragile workarounds like
numericStringsToNumbers. Additionally,versioned enums used two inconsistent tagging patterns:
$version(20 types) and$formatVersion(17 types), plus 2 types using raw enum wrappers ({ v0: {...} }/{ V0: {...} }).JavaScript's
Numbertype uses IEEE 754 double-precision floats, which can only safely represent integers up to2^53 - 1(Number.MAX_SAFE_INTEGER). Many DPP types useu64for credits, timestamps, block heights, and token amounts — values that routinely exceed this limit. When serialized to JSON without protection, these values silently lose precision in JavaScript clients.What was done?
rs-dpp: Pure serde JSON/Value conversion traits
JsonConvertibletrait (serialization_traits.rs) using pureserde_json— no JS workarounds at the Rust layerValueConvertible(ValueConvertible<'a>→ValueConvertible) usingDeserializeOwnedplatform-value-json→json-conversionJsonConvertible+ValueConvertibleimpls to ~40 versioned enums across blocks, tokens, voting, identity, state transitions, and data contracttypes
rs-dpp-json-convertible-derive: Compile-safe large integer handling via proc macros
New proc macro crate providing compile-time safety for JS-safe JSON serialization of
u64/i64fields:#[json_safe_fields]attribute macro for V0 structs: auto-adds#[serde(with = "json_safe_u64")]to u64/i64 fields, implementsJsonSafeFieldsmarker trait, generates compile-time assertions that all other field types also implementJsonSafeFields#[derive(JsonConvertible)]derive macro for versioned enums: implementsJsonConvertible+JsonSafeFields, asserts all inner V0 types implementJsonSafeFields#[derive(ValueConvertible)]derive macro: implementsValueConvertible(no safety checks needed — platform_value handles u64 natively)JsonSafeFieldsmarker trait (safe_fields.rs): recursive proof chain — primitives implement it, u64/i64 intentionally do NOT, collections delegate to inner types. This catches unprotected type aliases (type Foo = u64) and containers (Vec<u64>) at compile timewithmodules (safe_integer.rs,safe_integer_map.rs): useserializer.is_human_readable()to stringify values >MAX_SAFE_INTEGERin JSON while keeping native integers in platform_value/bincodejson-conversionwithcfg_attrTokenEvent) use manual impls with documented reasoningrs-platform-value: Identifier and enum deserialization fixes
deserialize_enuminde.rsto handle Text→unit and Map→externally-tagged variantsIdentifier(base58 in JSON, raw bytes in binary)Valueserializationwasm-dpp2: Two-macro conversion architecture
impl_wasm_conversions_inner!— delegates to rs-dppJsonConvertible/ValueConvertibletraits with JS-boundary large number handling(
stringify_large_numbers/unstringify_large_numbers)impl_wasm_conversions_serde!— direct serde path via#[serde(transparent)]for simple wrapper typesStandardize
$formatVersiontag across all versioned enumsserde(tag = "$version")→serde(tag = "$formatVersion")in 20 rs-dpp files (Identity, IdentityPublicKey, Document, ResourceVote, all statetransitions)
serde(tag = "$formatVersion")toContenderWithSerializedDocument(wasrename_all = "camelCase"producing{ v0: {...} }) andGroupAction(wasuntagged producing
{ V0: {...} })Test coverage
GroupAction/GroupActionEvent/TokenEvent, GroupStateTransitionInfoStatus, MasternodeVoteTransition, TokenContractInfo, TokenPaymentInfo, VerifiedDataContract)
json_convertible_testsmodule with round-trip tests for all migrated typeswithmodules: u64/i64/Option variants, tagged enum round-trips, platform_value native handling, map modulesnumericStringsToNumbersJS workaround from BatchTransition, DataContractCreateStateTransition, and DataContractUpdateStateTransitiontests
How Has This Been Tested?
cargo check -p dpp --features json-conversion,state-transition-serde-conversion,vote-serde-conversion— compiles cleanlycargo test -p dpp --lib --features json-conversion,state-transition-serde-conversion,vote-serde-conversion— 539 tests passingpackages/wasm-dpp2:yarn test— 917 passing, 0 failingpackages/wasm-sdk:yarn test— 385 passing, 0 failing#[json_safe_fields]→ compile error; unknown type aliases → compile errorBreaking Changes
$version→$formatVersion: All versioned enums now use$formatVersionas the serde tag instead of$version. Any code that parses JSON outputfrom these types and looks for
$versionmust be updated to$formatVersion. Affected types: Identity, IdentityPublicKey, Document, ResourceVote, all statetransitions (BatchTransition, DataContractCreateTransition, DataContractUpdateTransition, IdentityCreateTransition, IdentityUpdateTransition,
IdentityCreditWithdrawalTransition, IdentityTopUpTransition, IdentityCreditTransferTransition, MasternodeVoteTransition, PublicKeyInCreation, and
address-based transitions).
{ "v0": { "identityId": "...", ... } }to{ "$formatVersion": "0", "identityId": "...", ... }{ "V0": { "contract_id": "...", ... } }to{ "$formatVersion": "0", "contract_id": "...", ... }ContractBounds::SingleContractDocumentTypefield rename:document_type_namenow serializes asdocumentTypeName(camelCase). Any code parsing identity public key contract bounds JSON must update the field name.BlockInfofield names changed to camelCase:time_ms→timeMs,height(unchanged),core_height→coreHeight,epoch(unchanged). Any code parsingBlockInfoJSON must update field names.Vote,VotePoll,ResourceVoteChoice,TokenEvent,GroupActionEvent, andContestedDocumentVotePollWinnerInfochanged from externally-tagged ({ "TowardsIdentity": "..." }) to adjacently-tagged ({ "type": "towardsIdentity", "data": "..." }). Any code parsing these enum types from JSON must update to the new shape.ChangeControlRulesJSON shape changed: from externally-tagged with snake_case ({ "V0": { "authorized_to_make_change": ... } }) to internally-tagged with camelCase ({ "$formatVersion": "0", "authorizedToMakeChange": ... }).GroupV0field rename:required_powernow serializes asrequiredPower(camelCase).Number.MAX_SAFE_INTEGER(2^53 - 1) are now serialized as strings in JSON output. Deserialization accepts both numbers and strings. This affects all types with u64/i64 fields (credits, timestamps, token amounts, block heights, etc.).platform-value-jsonnow impliesjson-conversionChecklist:
For repository code-owners and collaborators only