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