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