-
Notifications
You must be signed in to change notification settings - Fork 47
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.