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