Skip to main content

dpp/data_contract/v0/serialization/
mod.rs

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