dpp/data_contract/serialized_version/
mod.rs1use super::EMPTY_KEYWORDS;
2use crate::data_contract::associated_token::token_configuration::TokenConfiguration;
3use crate::data_contract::config::DataContractConfig;
4use crate::data_contract::group::Group;
5use crate::data_contract::serialized_version::v0::DataContractInSerializationFormatV0;
6use crate::data_contract::serialized_version::v1::DataContractInSerializationFormatV1;
7use crate::data_contract::v0::DataContractV0;
8use crate::data_contract::v1::DataContractV1;
9use crate::data_contract::{
10 DataContract, DefinitionName, DocumentName, GroupContractPosition, TokenContractPosition,
11 EMPTY_GROUPS, EMPTY_TOKENS,
12};
13#[cfg(feature = "json-conversion")]
14use crate::serialization::JsonConvertible;
15use crate::validation::operations::ProtocolValidationOperation;
16use crate::version::PlatformVersion;
17use crate::ProtocolError;
18use bincode::{Decode, Encode};
19use derive_more::From;
20use platform_value::{Identifier, Value};
21use platform_version::{IntoPlatformVersioned, TryFromPlatformVersioned};
22use platform_versioning::PlatformVersioned;
23#[cfg(feature = "serde-conversion")]
24use serde::{Deserialize, Serialize};
25use std::collections::BTreeMap;
26use std::fmt;
27
28pub(in crate::data_contract) mod v0;
29pub(in crate::data_contract) mod v1;
30
31pub mod property_names {
32 pub const ID: &str = "id";
33 pub const OWNER_ID: &str = "ownerId";
34 pub const VERSION: &str = "version";
35 pub const DEFINITIONS: &str = "$defs";
36}
37
38pub const CONTRACT_DESERIALIZATION_LIMIT: usize = 15000;
39
40#[derive(Debug, PartialEq, Eq, Clone, Copy)]
46pub enum DataContractMismatch {
47 Id,
49 Config,
51 Version,
53 OwnerId,
55 SchemaDefs,
57 DocumentSchemas,
59 Groups,
61 Tokens,
63 Keywords,
65 Description,
67 FormatVersionMismatch,
69 V0Mismatch,
71}
72
73impl fmt::Display for DataContractMismatch {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 let description = match self {
77 DataContractMismatch::Id => "ID fields differ",
78 DataContractMismatch::Config => "Config fields differ",
79 DataContractMismatch::Version => "Version fields differ",
80 DataContractMismatch::OwnerId => "Owner ID fields differ",
81 DataContractMismatch::SchemaDefs => "Schema definitions differ",
82 DataContractMismatch::DocumentSchemas => "Document schemas differ",
83 DataContractMismatch::Groups => "Groups differ",
84 DataContractMismatch::Tokens => "Tokens differ",
85 DataContractMismatch::Keywords => "Keywords differ",
86 DataContractMismatch::Description => "Description fields differ",
87 DataContractMismatch::FormatVersionMismatch => {
88 "Serialization format versions differ (e.g., V0 vs V1)"
89 }
90 DataContractMismatch::V0Mismatch => "V0 versions differ",
91 };
92 write!(f, "{}", description)
93 }
94}
95
96#[cfg_attr(
97 all(feature = "json-conversion", feature = "serde-conversion"),
98 derive(JsonConvertible)
99)]
100#[derive(Debug, Clone, Encode, Decode, PartialEq, PlatformVersioned, From)]
101#[cfg_attr(
102 feature = "serde-conversion",
103 derive(Serialize, Deserialize),
104 serde(tag = "$formatVersion")
105)]
106pub enum DataContractInSerializationFormat {
107 #[cfg_attr(feature = "serde-conversion", serde(rename = "0"))]
108 V0(DataContractInSerializationFormatV0),
109 #[cfg_attr(feature = "serde-conversion", serde(rename = "1"))]
110 V1(DataContractInSerializationFormatV1),
111}
112
113impl DataContractInSerializationFormat {
114 pub fn id(&self) -> Identifier {
116 match self {
117 DataContractInSerializationFormat::V0(v0) => v0.id,
118 DataContractInSerializationFormat::V1(v1) => v1.id,
119 }
120 }
121
122 pub fn owner_id(&self) -> Identifier {
124 match self {
125 DataContractInSerializationFormat::V0(v0) => v0.owner_id,
126 DataContractInSerializationFormat::V1(v1) => v1.owner_id,
127 }
128 }
129
130 pub fn document_schemas(&self) -> &BTreeMap<DocumentName, Value> {
131 match self {
132 DataContractInSerializationFormat::V0(v0) => &v0.document_schemas,
133 DataContractInSerializationFormat::V1(v1) => &v1.document_schemas,
134 }
135 }
136
137 pub fn schema_defs(&self) -> Option<&BTreeMap<DefinitionName, Value>> {
138 match self {
139 DataContractInSerializationFormat::V0(v0) => v0.schema_defs.as_ref(),
140 DataContractInSerializationFormat::V1(v1) => v1.schema_defs.as_ref(),
141 }
142 }
143
144 pub fn version(&self) -> u32 {
145 match self {
146 DataContractInSerializationFormat::V0(v0) => v0.version,
147 DataContractInSerializationFormat::V1(v1) => v1.version,
148 }
149 }
150
151 pub fn config(&self) -> &DataContractConfig {
153 match self {
154 DataContractInSerializationFormat::V0(v0) => &v0.config,
155 DataContractInSerializationFormat::V1(v1) => &v1.config,
156 }
157 }
158
159 pub fn groups(&self) -> &BTreeMap<GroupContractPosition, Group> {
160 match self {
161 DataContractInSerializationFormat::V0(_) => &EMPTY_GROUPS,
162 DataContractInSerializationFormat::V1(v1) => &v1.groups,
163 }
164 }
165 pub fn tokens(&self) -> &BTreeMap<TokenContractPosition, TokenConfiguration> {
166 match self {
167 DataContractInSerializationFormat::V0(_) => &EMPTY_TOKENS,
168 DataContractInSerializationFormat::V1(v1) => &v1.tokens,
169 }
170 }
171
172 pub fn keywords(&self) -> &Vec<String> {
173 match self {
174 DataContractInSerializationFormat::V0(_) => &EMPTY_KEYWORDS,
175 DataContractInSerializationFormat::V1(v1) => &v1.keywords,
176 }
177 }
178
179 pub fn description(&self) -> &Option<String> {
180 match self {
181 DataContractInSerializationFormat::V0(_) => &None,
182 DataContractInSerializationFormat::V1(v1) => &v1.description,
183 }
184 }
185
186 pub fn first_mismatch(&self, other: &Self) -> Option<DataContractMismatch> {
199 match (self, other) {
200 (
201 DataContractInSerializationFormat::V0(v0_self),
202 DataContractInSerializationFormat::V0(v0_other),
203 ) => {
204 if v0_self != v0_other {
205 Some(DataContractMismatch::V0Mismatch)
206 } else {
207 None
208 }
209 }
210 (
211 DataContractInSerializationFormat::V1(v1_self),
212 DataContractInSerializationFormat::V1(v1_other),
213 ) => {
214 if v1_self.id != v1_other.id {
215 Some(DataContractMismatch::Id)
216 } else if v1_self.config != v1_other.config {
217 Some(DataContractMismatch::Config)
218 } else if v1_self.version != v1_other.version {
219 Some(DataContractMismatch::Version)
220 } else if v1_self.owner_id != v1_other.owner_id {
221 Some(DataContractMismatch::OwnerId)
222 } else if v1_self.schema_defs != v1_other.schema_defs {
223 Some(DataContractMismatch::SchemaDefs)
224 } else if v1_self.document_schemas != v1_other.document_schemas {
225 Some(DataContractMismatch::DocumentSchemas)
226 } else if v1_self.groups != v1_other.groups {
227 Some(DataContractMismatch::Groups)
228 } else if v1_self.tokens != v1_other.tokens {
229 Some(DataContractMismatch::Tokens)
230 } else if v1_self.keywords.len() != v1_other.keywords.len()
231 || v1_self
232 .keywords
233 .iter()
234 .zip(v1_other.keywords.iter())
235 .any(|(a, b)| a.to_lowercase() != b.to_lowercase())
236 {
237 Some(DataContractMismatch::Keywords)
238 } else if v1_self.description != v1_other.description {
239 Some(DataContractMismatch::Description)
240 } else {
241 None
242 }
243 }
244 _ => Some(DataContractMismatch::FormatVersionMismatch),
245 }
246 }
247}
248
249impl TryFromPlatformVersioned<DataContractV0> for DataContractInSerializationFormat {
250 type Error = ProtocolError;
251
252 fn try_from_platform_versioned(
253 value: DataContractV0,
254 platform_version: &PlatformVersion,
255 ) -> Result<Self, Self::Error> {
256 match platform_version
257 .dpp
258 .contract_versions
259 .contract_serialization_version
260 .default_current_version
261 {
262 0 => {
263 let v0_format: DataContractInSerializationFormatV0 =
264 DataContract::V0(value).into_platform_versioned(platform_version);
265 Ok(v0_format.into())
266 }
267 1 => {
268 let v1_format: DataContractInSerializationFormatV1 =
269 DataContract::V0(value).into_platform_versioned(platform_version);
270 Ok(v1_format.into())
271 }
272 version => Err(ProtocolError::UnknownVersionMismatch {
273 method: "DataContract::serialize_to_default_current_version".to_string(),
274 known_versions: vec![0, 1],
275 received: version,
276 }),
277 }
278 }
279}
280
281impl TryFromPlatformVersioned<&DataContractV0> for DataContractInSerializationFormat {
282 type Error = ProtocolError;
283
284 fn try_from_platform_versioned(
285 value: &DataContractV0,
286 platform_version: &PlatformVersion,
287 ) -> Result<Self, Self::Error> {
288 match platform_version
289 .dpp
290 .contract_versions
291 .contract_serialization_version
292 .default_current_version
293 {
294 0 => {
295 let v0_format: DataContractInSerializationFormatV0 =
296 DataContract::V0(value.to_owned()).into_platform_versioned(platform_version);
297 Ok(v0_format.into())
298 }
299 1 => {
300 let v1_format: DataContractInSerializationFormatV1 =
301 DataContract::V0(value.to_owned()).into_platform_versioned(platform_version);
302 Ok(v1_format.into())
303 }
304 version => Err(ProtocolError::UnknownVersionMismatch {
305 method: "DataContract::serialize_to_default_current_version".to_string(),
306 known_versions: vec![0, 1],
307 received: version,
308 }),
309 }
310 }
311}
312
313impl TryFromPlatformVersioned<DataContractV1> for DataContractInSerializationFormat {
314 type Error = ProtocolError;
315
316 fn try_from_platform_versioned(
317 value: DataContractV1,
318 platform_version: &PlatformVersion,
319 ) -> Result<Self, Self::Error> {
320 match platform_version
321 .dpp
322 .contract_versions
323 .contract_serialization_version
324 .default_current_version
325 {
326 0 => {
327 let v0_format: DataContractInSerializationFormatV0 =
328 DataContract::V1(value).into_platform_versioned(platform_version);
329 Ok(v0_format.into())
330 }
331 1 => {
332 let v1_format: DataContractInSerializationFormatV1 =
333 DataContract::V1(value).into_platform_versioned(platform_version);
334 Ok(v1_format.into())
335 }
336 version => Err(ProtocolError::UnknownVersionMismatch {
337 method: "DataContract::serialize_to_default_current_version".to_string(),
338 known_versions: vec![0, 1],
339 received: version,
340 }),
341 }
342 }
343}
344
345impl TryFromPlatformVersioned<&DataContractV1> for DataContractInSerializationFormat {
346 type Error = ProtocolError;
347
348 fn try_from_platform_versioned(
349 value: &DataContractV1,
350 platform_version: &PlatformVersion,
351 ) -> Result<Self, Self::Error> {
352 match platform_version
353 .dpp
354 .contract_versions
355 .contract_serialization_version
356 .default_current_version
357 {
358 0 => {
359 let v0_format: DataContractInSerializationFormatV0 =
360 DataContract::V1(value.to_owned()).into_platform_versioned(platform_version);
361 Ok(v0_format.into())
362 }
363 1 => {
364 let v1_format: DataContractInSerializationFormatV1 =
365 DataContract::V1(value.to_owned()).into_platform_versioned(platform_version);
366 Ok(v1_format.into())
367 }
368 version => Err(ProtocolError::UnknownVersionMismatch {
369 method: "DataContract::serialize_to_default_current_version".to_string(),
370 known_versions: vec![0, 1],
371 received: version,
372 }),
373 }
374 }
375}
376
377impl TryFromPlatformVersioned<&DataContract> for DataContractInSerializationFormat {
378 type Error = ProtocolError;
379
380 fn try_from_platform_versioned(
381 value: &DataContract,
382 platform_version: &PlatformVersion,
383 ) -> Result<Self, Self::Error> {
384 match platform_version
385 .dpp
386 .contract_versions
387 .contract_serialization_version
388 .default_current_version
389 {
390 0 => {
391 let v0_format: DataContractInSerializationFormatV0 =
392 value.clone().into_platform_versioned(platform_version);
393 Ok(v0_format.into())
394 }
395 1 => {
396 let v1_format: DataContractInSerializationFormatV1 =
397 value.clone().into_platform_versioned(platform_version);
398 Ok(v1_format.into())
399 }
400 version => Err(ProtocolError::UnknownVersionMismatch {
401 method: "DataContract::serialize_to_default_current_version".to_string(),
402 known_versions: vec![0, 1],
403 received: version,
404 }),
405 }
406 }
407}
408
409impl TryFromPlatformVersioned<DataContract> for DataContractInSerializationFormat {
410 type Error = ProtocolError;
411
412 fn try_from_platform_versioned(
413 value: DataContract,
414 platform_version: &PlatformVersion,
415 ) -> Result<Self, Self::Error> {
416 match platform_version
417 .dpp
418 .contract_versions
419 .contract_serialization_version
420 .default_current_version
421 {
422 0 => {
423 let v0_format: DataContractInSerializationFormatV0 =
424 value.into_platform_versioned(platform_version);
425 Ok(v0_format.into())
426 }
427 1 => {
428 let v1_format: DataContractInSerializationFormatV1 =
429 value.into_platform_versioned(platform_version);
430 Ok(v1_format.into())
431 }
432 version => Err(ProtocolError::UnknownVersionMismatch {
433 method: "DataContract::serialize_consume_to_default_current_version".to_string(),
434 known_versions: vec![0, 1],
435 received: version,
436 }),
437 }
438 }
439}
440
441impl DataContract {
442 pub fn try_from_platform_versioned(
443 value: DataContractInSerializationFormat,
444 full_validation: bool,
445 validation_operations: &mut Vec<ProtocolValidationOperation>,
446 platform_version: &PlatformVersion,
447 ) -> Result<Self, ProtocolError> {
448 match platform_version
449 .dpp
450 .contract_versions
451 .contract_structure_version
452 {
453 0 => DataContractV0::try_from_platform_versioned(
454 value,
455 full_validation,
456 validation_operations,
457 platform_version,
458 )
459 .map(|contract| contract.into()),
460 1 => DataContractV1::try_from_platform_versioned(
461 value,
462 full_validation,
463 validation_operations,
464 platform_version,
465 )
466 .map(|contract| contract.into()),
467 version => Err(ProtocolError::UnknownVersionMismatch {
468 method: "DataContract::try_from_platform_versioned".to_string(),
469 known_versions: vec![0, 1],
470 received: version,
471 }),
472 }
473 }
474}