Skip to main content

dpp/data_contract/v0/serialization/
mod.rs

1use crate::data_contract::document_type::DocumentType;
2use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0;
3use crate::data_contract::serialized_version::DataContractInSerializationFormat;
4use crate::data_contract::v0::DataContractV0;
5use crate::data_contract::DataContract;
6use crate::version::{PlatformVersion, PlatformVersionCurrentVersion};
7use crate::ProtocolError;
8use std::collections::BTreeMap;
9
10use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1;
11use crate::validation::operations::ProtocolValidationOperation;
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14impl Serialize for DataContractV0 {
15    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
16    where
17        S: Serializer,
18    {
19        let data_contract: DataContract = self.clone().into();
20        let serialization_format = DataContractInSerializationFormatV0::from(data_contract);
21        serialization_format.serialize(serializer)
22    }
23}
24
25impl<'de> Deserialize<'de> for DataContractV0 {
26    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
27    where
28        D: Deserializer<'de>,
29    {
30        let serialization_format = DataContractInSerializationFormatV0::deserialize(deserializer)?;
31        let current_version = PlatformVersion::get_version_or_current_or_latest(None)
32            .map_err(|e| serde::de::Error::custom(e.to_string()))?;
33        // when deserializing from json/platform_value/cbor we always want to validate (as this is not coming from the state)
34        DataContractV0::try_from_platform_versioned_v0(
35            serialization_format,
36            true,
37            &mut vec![],
38            current_version,
39        )
40        .map_err(serde::de::Error::custom)
41    }
42}
43
44impl DataContractV0 {
45    pub(in crate::data_contract) fn try_from_platform_versioned(
46        value: DataContractInSerializationFormat,
47        full_validation: bool,
48        validation_operations: &mut Vec<ProtocolValidationOperation>,
49        platform_version: &PlatformVersion,
50    ) -> Result<Self, ProtocolError> {
51        match value {
52            DataContractInSerializationFormat::V0(serialization_format_v0) => {
53                let data_contract = DataContractV0::try_from_platform_versioned_v0(
54                    serialization_format_v0,
55                    full_validation,
56                    validation_operations,
57                    platform_version,
58                )?;
59
60                Ok(data_contract)
61            }
62            DataContractInSerializationFormat::V1(serialization_format_v1) => {
63                let data_contract = DataContractV0::try_from_platform_versioned_v1(
64                    serialization_format_v1,
65                    full_validation,
66                    validation_operations,
67                    platform_version,
68                )?;
69
70                Ok(data_contract)
71            }
72        }
73    }
74
75    pub(in crate::data_contract) fn try_from_platform_versioned_v0(
76        data_contract_data: DataContractInSerializationFormatV0,
77        full_validation: bool,
78        validation_operations: &mut Vec<ProtocolValidationOperation>,
79        platform_version: &PlatformVersion,
80    ) -> Result<Self, ProtocolError> {
81        let DataContractInSerializationFormatV0 {
82            id,
83            config,
84            version,
85            owner_id,
86            document_schemas,
87            schema_defs,
88        } = data_contract_data;
89
90        let document_types = DocumentType::create_document_types_from_document_schemas(
91            id,
92            0,
93            data_contract_data.config.version(),
94            document_schemas,
95            schema_defs.as_ref(),
96            &BTreeMap::new(),
97            &config,
98            full_validation,
99            false,
100            validation_operations,
101            platform_version,
102        )?;
103
104        let data_contract = DataContractV0 {
105            id,
106            version,
107            owner_id,
108            document_types,
109            metadata: None,
110            config,
111            schema_defs,
112        };
113
114        Ok(data_contract)
115    }
116
117    pub(in crate::data_contract) fn try_from_platform_versioned_v1(
118        data_contract_data: DataContractInSerializationFormatV1,
119        full_validation: bool,
120        validation_operations: &mut Vec<ProtocolValidationOperation>,
121        platform_version: &PlatformVersion,
122    ) -> Result<Self, ProtocolError> {
123        let DataContractInSerializationFormatV1 {
124            id,
125            config,
126            version,
127            owner_id,
128            document_schemas,
129            schema_defs,
130            ..
131        } = data_contract_data;
132
133        let document_types = DocumentType::create_document_types_from_document_schemas(
134            id,
135            0,
136            data_contract_data.config.version(),
137            document_schemas,
138            schema_defs.as_ref(),
139            &BTreeMap::new(),
140            &config,
141            full_validation,
142            false,
143            validation_operations,
144            platform_version,
145        )?;
146
147        let data_contract = DataContractV0 {
148            id,
149            version,
150            owner_id,
151            document_types,
152            metadata: None,
153            config,
154            schema_defs,
155        };
156
157        Ok(data_contract)
158    }
159}
160
161#[cfg(test)]
162mod tests {
163    use crate::data_contract::DataContract;
164    use crate::identity::accessors::IdentityGettersV0;
165    use crate::identity::Identity;
166    use crate::serialization::{
167        PlatformDeserializableWithPotentialValidationFromVersionedStructure,
168        PlatformSerializableWithPlatformVersion,
169    };
170    use crate::tests::fixtures::get_data_contract_fixture;
171    use crate::version::PlatformVersion;
172    use platform_version::version::LATEST_PLATFORM_VERSION;
173
174    #[test]
175    #[cfg(feature = "random-identities")]
176    fn data_contract_ser_de() {
177        let platform_version = PlatformVersion::first();
178        let identity = Identity::random_identity(5, Some(5), platform_version)
179            .expect("expected a random identity");
180        let contract =
181            get_data_contract_fixture(Some(identity.id()), 0, platform_version.protocol_version)
182                .data_contract_owned();
183        let bytes = contract
184            .serialize_to_bytes_with_platform_version(LATEST_PLATFORM_VERSION)
185            .expect("expected to serialize");
186        let recovered_contract =
187            DataContract::versioned_deserialize(&bytes, false, platform_version)
188                .expect("expected to deserialize state transition");
189        assert_eq!(contract, recovered_contract);
190    }
191
192    #[test]
193    #[cfg(feature = "random-identities")]
194    fn data_contract_v0_serde_json_roundtrip() {
195        use crate::data_contract::accessors::v0::DataContractV0Getters;
196        use crate::data_contract::v0::DataContractV0;
197
198        let platform_version = PlatformVersion::first();
199        let identity = Identity::random_identity(5, Some(5), platform_version)
200            .expect("expected a random identity");
201        let contract =
202            get_data_contract_fixture(Some(identity.id()), 0, platform_version.protocol_version)
203                .data_contract_owned();
204        let v0 = contract.into_v0().expect("expected V0 contract");
205
206        let json = serde_json::to_string(&v0).expect("expected to serialize to JSON");
207        let recovered: DataContractV0 =
208            serde_json::from_str(&json).expect("expected to deserialize from JSON");
209
210        // Schema normalization during deserialization means full equality may differ;
211        // verify stable identity fields to confirm a successful roundtrip.
212        assert_eq!(v0.id(), recovered.id());
213        assert_eq!(v0.owner_id(), recovered.owner_id());
214        assert_eq!(v0.version(), recovered.version());
215    }
216}