Skip to main content

dpp/state_transition/state_transitions/document/batch_transition/
mod.rs

1use bincode::{Decode, DecodeUntrusted, Encode};
2
3use std::convert::TryInto;
4
5use derive_more::From;
6
7use platform_value::Value;
8#[cfg(feature = "serde-conversion")]
9use serde::{Deserialize, Serialize};
10
11use crate::ProtocolError;
12use crate::{identity::SecurityLevel, state_transition::StateTransitionFieldTypes};
13
14pub use self::batched_transition::{
15    document_base_transition, document_create_transition,
16    document_create_transition::DocumentCreateTransition, document_delete_transition,
17    document_delete_transition::DocumentDeleteTransition, document_index_only_delete_transition,
18    document_index_only_delete_transition::DocumentIndexOnlyDeleteTransition,
19    document_replace_transition, document_replace_transition::DocumentReplaceTransition,
20    token_base_transition, token_burn_transition, token_burn_transition::TokenBurnTransition,
21    token_claim_transition, token_claim_transition::TokenClaimTransition,
22    token_config_update_transition, token_config_update_transition::TokenConfigUpdateTransition,
23    token_destroy_frozen_funds_transition,
24    token_destroy_frozen_funds_transition::TokenDestroyFrozenFundsTransition,
25    token_direct_purchase_transition,
26    token_direct_purchase_transition::TokenDirectPurchaseTransition,
27    token_emergency_action_transition,
28    token_emergency_action_transition::TokenEmergencyActionTransition, token_freeze_transition,
29    token_freeze_transition::TokenFreezeTransition, token_mint_transition,
30    token_mint_transition::TokenMintTransition, token_set_price_for_direct_purchase_transition,
31    token_set_price_for_direct_purchase_transition::TokenSetPriceForDirectPurchaseTransition,
32    token_transfer_transition, token_transfer_transition::TokenTransferTransition,
33    token_unfreeze_transition, token_unfreeze_transition::TokenUnfreezeTransition,
34};
35
36use platform_serialization_derive::{
37    PlatformDeserializeTrusted, PlatformDeserializeUntrusted, PlatformSerialize, PlatformSignable,
38};
39use platform_versioning::PlatformVersioned;
40
41pub mod accessors;
42pub mod batched_transition;
43pub mod fields;
44mod identity_signed;
45pub mod methods;
46pub mod resolvers;
47mod state_transition_estimated_fee_validation;
48mod state_transition_like;
49mod v0;
50mod v1;
51#[cfg(feature = "validation")]
52mod validation;
53mod version;
54
55use crate::state_transition::data_contract_update_transition::{
56    SIGNATURE, SIGNATURE_PUBLIC_KEY_ID,
57};
58
59use crate::state_transition::batch_transition::fields::property_names;
60
61use crate::identity::state_transition::OptionallyAssetLockProved;
62pub use v0::*;
63pub use v1::*;
64
65#[derive(
66    Debug,
67    Clone,
68    PartialEq,
69    Encode,
70    Decode,
71    PlatformDeserializeTrusted,
72    PlatformDeserializeUntrusted,
73    PlatformSerialize,
74    PlatformSignable,
75    PlatformVersioned,
76    From,
77    DecodeUntrusted,
78)]
79#[cfg_attr(
80    feature = "serde-conversion",
81    derive(Serialize, Deserialize),
82    serde(tag = "$formatVersion")
83)]
84#[platform_serialize(unversioned)] //versioned directly, no need to use platform_version
85#[platform_version_path_bounds(
86    "dpp.state_transition_serialization_versions.batch_state_transition"
87)]
88pub enum BatchTransition {
89    #[cfg_attr(feature = "serde-conversion", serde(rename = "0"))]
90    V0(BatchTransitionV0),
91    #[cfg_attr(feature = "serde-conversion", serde(rename = "1"))]
92    V1(BatchTransitionV1),
93}
94
95#[cfg(all(feature = "json-conversion", feature = "serde-conversion"))]
96impl crate::serialization::JsonConvertible for BatchTransition {}
97
98#[cfg(all(feature = "value-conversion", feature = "serde-conversion"))]
99impl crate::serialization::ValueConvertible for BatchTransition {}
100
101impl StateTransitionFieldTypes for BatchTransition {
102    fn binary_property_paths() -> Vec<&'static str> {
103        vec![SIGNATURE]
104    }
105
106    fn identifiers_property_paths() -> Vec<&'static str> {
107        vec![property_names::OWNER_ID]
108    }
109
110    fn signature_property_paths() -> Vec<&'static str> {
111        vec![SIGNATURE, SIGNATURE_PUBLIC_KEY_ID]
112    }
113}
114
115#[cfg(all(
116    test,
117    feature = "json-conversion",
118    feature = "value-conversion",
119    feature = "serde-conversion"
120))]
121pub(crate) mod json_convertible_tests {
122    use super::*;
123    use platform_value::{platform_value, BinaryData, Identifier};
124    use serde_json::json;
125
126    pub(crate) fn fixture() -> BatchTransition {
127        BatchTransition::V0(BatchTransitionV0 {
128            owner_id: Identifier::new([0xc0; 32]),
129            transitions: vec![], // empty transitions list — sub-types tested separately
130            user_fee_increase: 23,
131            signature_public_key_id: 4,
132            signature: BinaryData::new(vec![0xd0; 65]),
133        })
134    }
135
136    #[test]
137    fn json_round_trip_with_full_wire_shape() {
138        use crate::serialization::JsonConvertible;
139        let original = fixture();
140        let json = original.to_json().expect("to_json");
141        // `BatchTransition` is internally tagged `$formatVersion`; V0 fields use
142        // camelCase. `userFeeIncrease` is `u16`, `signaturePublicKeyId` is `u32`
143        // — JSON has only one number type, so sized variants are erased on the
144        // wire (the value-path test below pins the typed variants). `Identifier`
145        // is base58 in JSON HR; `BinaryData` is base64.
146        assert_eq!(
147            json,
148            json!({
149                "$formatVersion": "0",
150                "ownerId": "DyRkUpQxYG2VnP2SkMdQs5BTsVPeKCpSHLxzByc2Sxvj",
151                "transitions": [],
152                "userFeeIncrease": 23,
153                "signaturePublicKeyId": 4,
154                "signature": "0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NA=",
155            })
156        );
157        let recovered = BatchTransition::from_json(json).expect("from_json");
158        assert_eq!(original, recovered);
159    }
160
161    #[test]
162    fn value_round_trip_with_full_wire_shape() {
163        use crate::serialization::ValueConvertible;
164        use platform_value::Value;
165        let original = fixture();
166        let value = original.to_object().expect("to_object");
167        let owner_id = Identifier::new([0xc0; 32]);
168        // `userFeeIncrease` is `u16` (UserFeeIncrease alias), `signaturePublicKeyId`
169        // is `u32` (KeyID alias) — explicit suffixes lock in the typed variants.
170        // `BinaryData` is `Value::Bytes` in non-HR.
171        assert_eq!(
172            value,
173            platform_value!({
174                "$formatVersion": "0",
175                "ownerId": owner_id,
176                "transitions": Value::Array(vec![]),
177                "userFeeIncrease": 23u16,
178                "signaturePublicKeyId": 4u32,
179                "signature": Value::Bytes(vec![0xd0; 65]),
180            })
181        );
182        let recovered = BatchTransition::from_object(value).expect("from_object");
183        assert_eq!(original, recovered);
184    }
185}
186
187// TODO: Make a DocumentType method
188pub fn get_security_level_requirement(v: &Value, default: SecurityLevel) -> SecurityLevel {
189    let maybe_security_level: Option<u64> = v
190        .get_optional_integer(property_names::SECURITY_LEVEL_REQUIREMENT)
191        // TODO: Data Contract must already valid so there is no chance that this will fail
192        .expect("document schema must be a map");
193
194    match maybe_security_level {
195        Some(some_level) => (some_level as u8).try_into().unwrap_or(default),
196        None => default,
197    }
198}
199
200impl OptionallyAssetLockProved for BatchTransition {}
201
202#[cfg(test)]
203mod tests;