Skip to content

feat: implement StateTransitionJsonConvert and fix PlatformAddress map key serialization#3110

Closed
Copilot wants to merge 19 commits intov3.1-devfrom
copilot/fix-state-transition-json-conversion
Closed

feat: implement StateTransitionJsonConvert and fix PlatformAddress map key serialization#3110
Copilot wants to merge 19 commits intov3.1-devfrom
copilot/fix-state-transition-json-conversion

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 19, 2026

Problem

StateTransition enum lacked StateTransitionJsonConvert implementation, forcing manual variant matching. Additionally, JSON serialization failed for address-based state transitions containing BTreeMap<PlatformAddress, V> with error "key must be a string" because PlatformAddress (enum with data) serializes as a complex object, violating JSON's string-key requirement.

Investigation revealed both serde_json::to_string_pretty() and to_json() fail identically since to_json() uses platform_value::to_value() internally, which relies on serde.

Changes

StateTransition trait implementations:

  • Created json_conversion.rs - dispatches to_json() to variant implementations
  • Created value_conversion.rs - dispatches conversion methods to variants
  • Implemented StateTransitionFieldTypes returning empty vectors (paths are variant-specific)
  • Added state-transition-json-conversion to dash-sdk-features

PlatformAddress map key serialization fix:

  • Created platform_address_map_serde.rs - custom serde helpers that serialize PlatformAddress keys as Display strings ("P2PKH(hex...)") and deserialize via FromStr
  • Applied to all transitions with BTreeMap<PlatformAddress, ...>:
    • AddressFundsTransferTransitionV0 (inputs, outputs)
    • AddressFundingFromAssetLockTransitionV0 (inputs, outputs)
    • AddressCreditWithdrawalTransitionV0 (inputs)
    • IdentityTopUpFromAddressesTransitionV0 (inputs)
    • IdentityCreateFromAddressesTransitionV0 (inputs)
    • IdentityCreditTransferToAddressesTransitionV0 (recipient_addresses)

WASM bindings update:

  • Added state-transition-json-conversion feature to wasm-dpp2 Cargo.toml to maintain feature parity with wasm-dpp

Result

Both serialization paths now work:

// Serde (now works)
let json = serde_json::to_string_pretty(&state_transition)?;

// Custom (now works)
let json = state_transition.to_json(JsonStateTransitionSerializationOptions::default())?;
{
  "inputs": {
    "P2PKH(0101010101010101010101010101010101010101)": [1, 1000]
  }
}
Original prompt

This section details on the original issue you should resolve

<issue_title>feat: implement StateTransitionJsonConvert for top-level StateTransition enum</issue_title>
<issue_description>## Problem

In packages/rs-dpp/src/state_transition/mod.rs, the StateTransition enum derives Serialize (behind state-transition-serde-conversion feature), but serde_json::to_string_pretty(&state_transition) fails with "key must be a string" for any variant that contains BTreeMap<PlatformAddress, ...> (e.g. AddressFundsTransfer, AddressFundingFromAssetLock, AddressCreditWithdrawal, IdentityCreateFromAddresses, IdentityTopUpFromAddresses, IdentityCreditTransferToAddresses).

This happens because PlatformAddress is an enum that serializes as a complex structure, not a string, and JSON requires all object keys to be strings.

Every individual variant type already implements StateTransitionJsonConvert (which has a to_json() method that properly converts through platform_value::Value, stringifying identifiers and binary data). But the top-level StateTransition enum itself does NOT implement it, forcing consumers to match on all 15 variants manually.

Proposed Fix

Add an impl StateTransitionJsonConvert<'_> for StateTransition that dispatches to each variant's to_json(). This should go in a new file packages/rs-dpp/src/state_transition/json_conversion.rs (gated behind #[cfg(feature = "state-transition-json-conversion")]), similar to how value_conversion.rs or other dispatch files are structured. The implementation:

#[cfg(feature = "state-transition-json-conversion")]
impl StateTransitionJsonConvert<'_> for StateTransition {
    fn to_json(
        &self,
        options: JsonStateTransitionSerializationOptions,
    ) -> Result<serde_json::Value, ProtocolError> {
        match self {
            StateTransition::DataContractCreate(st) => st.to_json(options),
            StateTransition::DataContractUpdate(st) => st.to_json(options),
            StateTransition::Batch(st) => st.to_json(options),
            StateTransition::IdentityCreate(st) => st.to_json(options),
            StateTransition::IdentityTopUp(st) => st.to_json(options),
            StateTransition::IdentityCreditWithdrawal(st) => st.to_json(options),
            StateTransition::IdentityUpdate(st) => st.to_json(options),
            StateTransition::IdentityCreditTransfer(st) => st.to_json(options),
            StateTransition::MasternodeVote(st) => st.to_json(options),
            StateTransition::IdentityCreditTransferToAddresses(st) => st.to_json(options),
            StateTransition::IdentityCreateFromAddresses(st) => st.to_json(options),
            StateTransition::IdentityTopUpFromAddresses(st) => st.to_json(options),
            StateTransition::AddressFundsTransfer(st) => st.to_json(options),
            StateTransition::AddressFundingFromAssetLock(st) => st.to_json(options),
            StateTransition::AddressCreditWithdrawal(st) => st.to_json(options),
        }
    }
}

Note: StateTransitionJsonConvert has a blanket default to_json() that calls self.to_object() (from StateTransitionValueConvert). Since StateTransitionValueConvert is also not implemented for the top-level enum, the explicit override above is needed. It may also make sense to implement StateTransitionValueConvert for StateTransition with the same dispatch pattern.

Also consider adding state-transition-json-conversion to the dash-sdk-features list in packages/rs-dpp/Cargo.toml so SDK consumers get it by default.</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

…for StateTransition enum

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix state transition JSON conversion for enum variants feat: implement StateTransitionJsonConvert for top-level StateTransition enum Feb 19, 2026
Copilot AI requested a review from lklimek February 19, 2026 12:13
@github-actions github-actions Bot added this to the v3.1.0 milestone Feb 19, 2026
@lklimek lklimek marked this pull request as ready for review February 19, 2026 14:24
@lklimek lklimek changed the title feat: implement StateTransitionJsonConvert for top-level StateTransition enum feat(dpp): implement StateTransitionJsonConvert for top-level StateTransition enum Feb 19, 2026
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Copilot AI changed the title feat(dpp): implement StateTransitionJsonConvert for top-level StateTransition enum feat: implement StateTransitionJsonConvert for top-level StateTransition enum Feb 19, 2026
Copilot AI and others added 3 commits February 19, 2026 15:47
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Copilot AI changed the title feat: implement StateTransitionJsonConvert for top-level StateTransition enum feat: implement StateTransitionJsonConvert and fix PlatformAddress map key serialization Feb 19, 2026
Copy link
Copy Markdown
Collaborator

@shumkov shumkov left a comment

Choose a reason for hiding this comment

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

Please update wasm-dpp2 as well then

@lklimek
Copy link
Copy Markdown
Contributor

lklimek commented Feb 20, 2026

@copilot Please update wasm-dpp2 to match changes in this PR.

Co-authored-by: lklimek <842586+lklimek@users.noreply.github.com>
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Feb 20, 2026

Please update wasm-dpp2 as well then

Updated in commit 314a1c6. Added state-transition-json-conversion feature to wasm-dpp2 Cargo.toml to match wasm-dpp.

@copilot Please update wasm-dpp2 to match changes in this PR.

Done in commit 314a1c6. Added state-transition-json-conversion feature to wasm-dpp2/Cargo.toml dependencies.

…then docs

Replace verbose println-based tests with proper assertion-based tests
that validate both to_json() and serde_json serialization paths produce
correct string keys for BTreeMap<PlatformAddress, V> fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lklimek lklimek force-pushed the copilot/fix-state-transition-json-conversion branch from 61a90c0 to 5a43766 Compare February 23, 2026 12:47
lklimek and others added 4 commits February 23, 2026 13:50
Remove duplicated test functions, keep the consolidated versions
with shared helper, proper assertions, and given/when/then docstrings.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Verify that StateTransition::to_json() and serde_json serialization
work correctly in the wasm-dpp2 context with its enabled features,
including string keys for BTreeMap<PlatformAddress, V> fields.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@lklimek lklimek removed their request for review February 23, 2026 13:38
lklimek added 2 commits March 6, 2026 13:17
…-transition-json-conversion

# Conflicts:
#	packages/rs-dpp/Cargo.toml
#	packages/rs-dpp/src/state_transition/state_transitions/identity/identity_credit_transfer_to_addresses_transition/v0/mod.rs
#	packages/wasm-dpp2/Cargo.toml
@lklimek
Copy link
Copy Markdown
Contributor

lklimek commented Mar 11, 2026

Merge Base Report — v3.1-devcopilot/fix-state-transition-json-conversion

Merge commit: fafac36d43
Risk Factor: 45%

Conflicts Resolved

File Ours Theirs Resolution
rs-dpp/Cargo.toml (dash-sdk-features) 4 separate features: data-contract-json-conversion, identity-value-conversion, state-transition-value-conversion, state-transition-json-conversion Single unified json-conversion Theirs — unified feature subsumes all separate ones
identity_credit_transfer_to_addresses/v0/mod.rs feature = "state-transition-serde-conversion" + custom platform_address_map_serde feature = "json-conversion" + centralized json_safe_generic_u64_value_map Theirs — upstream provides a better generalized serializer
wasm-dpp2/Cargo.toml Many separate features + custom ones Unified json-conversion + minimal features Theirs — unified feature covers everything

Safe Changes

  • rs-dpp/Cargo.toml — Unified json-conversion correctly subsumes all old per-type features. Old feature names still exist as aliases, so existing #[cfg] guards still compile.
  • wasm-dpp2/Cargo.toml — Slimmed to unified json-conversion. Covers all previously separate features.
  • identity_credit_transfer_to_addresses/v0/mod.rs — Now uses upstream's centralized json_safe_generic_u64_value_map serializer. Functionally equivalent for BTreeMap<PlatformAddress, Credits>.
  • 628 auto-merged upstream files — Disjoint from this PR's 15-file change set. No textual overlap.

⚠️ Changes Requiring Attention

  • Inconsistent serde approach — Custom platform_address_map_serde is still used in 7 locations across address_funds and identity transitions (topup_from_addresses, create_from_addresses, address_credit_withdrawal, address_funding_from_asset_lock, address_funds_transfer). Only identity_credit_transfer_to_addresses was switched to the upstream serializer. Same data type (BTreeMap<PlatformAddress, _>) serialized two different ways depending on which transition.

  • Stale feature guardsjson_conversion.rs and value_conversion.rs still use #[cfg(feature = "state-transition-json-conversion")] / #[cfg(feature = "state-transition-value-conversion")]. These work today (aliases exist in Cargo.toml), but diverge from the upstream convention of using json-conversion / value-conversion directly.

Recommended Follow-up

  • Migrate remaining platform_address_map_serde usages to json_safe_generic_u64_value_map (7 files)
  • Update #[cfg] guards in json_conversion.rs and value_conversion.rs to use unified feature names
  • Verify if custom platform_address_map_serde module can be removed after migration
  • Run cargo test -p dpp and cargo test -p wasm-dpp2 to confirm no runtime serialization mismatches

Relevant Upstream Contributors

Author Key Changes
@shumkov Unified JSON/Object conversion #3167 (root cause of all 3 conflicts), platform address WASM bindings #3147

🤖 Co-authored by Claudius the Magnificent AI Agent

@lklimek
Copy link
Copy Markdown
Contributor

lklimek commented Mar 12, 2026

replaced by #3167

@lklimek lklimek closed this Mar 12, 2026
@github-actions
Copy link
Copy Markdown
Contributor

✅ 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: "eff095b277c9589cd3bf250568a3eba514a575fe6e0d12791db5df995a772bf9"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 12, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 56.95%. Comparing base (512db4b) to head (fafac36).
⚠️ Report is 5 commits behind head on v3.1-dev.

Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3110      +/-   ##
============================================
+ Coverage     50.39%   56.95%   +6.55%     
============================================
  Files          3089     1955    -1134     
  Lines        219104   158147   -60957     
============================================
- Hits         110426    90069   -20357     
+ Misses       108678    68078   -40600     
Components Coverage Δ
dpp ∅ <ø> (∅)
drive 42.38% <ø> (-0.13%) ⬇️
drive-abci 79.21% <ø> (-0.03%) ⬇️
sdk 32.13% <ø> (ø)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value ∅ <ø> (∅)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier ∅ <ø> (∅)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

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.

feat: implement StateTransitionJsonConvert for top-level StateTransition enum

3 participants