1use crate::serialization::{
2 PlatformDeserializableWithBytesLenFromVersionedStructureTrusted,
3 PlatformDeserializableWithBytesLenFromVersionedStructureUntrusted,
4 PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted,
5 PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted,
6 PlatformLimitDeserializableFromVersionedStructureTrusted,
7 PlatformLimitDeserializableFromVersionedStructureUntrusted,
8 PlatformSerializableWithPlatformVersion,
9};
10use std::collections::BTreeMap;
11
12use derive_more::From;
13
14use bincode::config::{BigEndian, Config, Configuration, Limit, NoLimit, Varint};
15use once_cell::sync::Lazy;
16
17pub mod errors;
18pub mod extra;
19
20mod generate_data_contract;
21
22#[cfg(any(feature = "state-transitions", feature = "factories"))]
23pub mod created_data_contract;
24pub mod document_type;
25
26pub mod v0;
27pub mod v1;
28
29#[cfg(feature = "factories")]
30pub mod factory;
31#[cfg(feature = "factories")]
32pub use factory::*;
33#[cfg(any(
34 feature = "value-conversion",
35 feature = "data-contract-cbor-conversion",
36 feature = "json-conversion",
37 feature = "serde-conversion"
38))]
39pub mod conversion;
40#[cfg(feature = "client")]
41mod data_contract_facade;
42#[cfg(feature = "client")]
43pub use data_contract_facade::DataContractFacade;
44mod methods;
45pub mod serialized_version;
46pub use methods::*;
47pub mod accessors;
48pub mod associated_token;
49pub mod change_control_rules;
50pub mod config;
51pub mod group;
52pub mod storage_requirements;
53
54use crate::data_contract::serialized_version::{
55 DataContractInSerializationFormat, CONTRACT_DESERIALIZATION_LIMIT,
56};
57use crate::util::hash::hash_double_to_vec;
58
59use crate::version::{FeatureVersion, PlatformVersion};
60use crate::ProtocolError;
61use crate::ProtocolError::{PlatformDeserializationError, PlatformSerializationError};
62
63pub use crate::data_contract::associated_token::token_configuration::TokenConfiguration;
64use crate::data_contract::group::Group;
65use crate::data_contract::v0::DataContractV0;
66use crate::data_contract::v1::DataContractV1;
67use platform_version::TryIntoPlatformVersioned;
68use platform_versioning::PlatformVersioned;
69pub use serde_json::Value as JsonValue;
70
71type JsonSchema = JsonValue;
72type DefinitionName = String;
73pub type DocumentName = String;
74pub type TokenName = String;
75pub type GroupContractPosition = u16;
76pub type TokenContractPosition = u16;
77pub type DataContractWithSerialization = (DataContract, Vec<u8>);
78type PropertyPath = String;
79
80pub const INITIAL_DATA_CONTRACT_VERSION: u32 = 1;
81
82static EMPTY_GROUPS: Lazy<BTreeMap<GroupContractPosition, Group>> = Lazy::new(BTreeMap::new);
84static EMPTY_TOKENS: Lazy<BTreeMap<TokenContractPosition, TokenConfiguration>> =
85 Lazy::new(BTreeMap::new);
86static EMPTY_KEYWORDS: Lazy<Vec<String>> = Lazy::new(Vec::new);
87
88#[derive(Debug, Clone, PartialEq, From, PlatformVersioned)]
111pub enum DataContract {
112 V0(DataContractV0),
113 V1(DataContractV1),
114}
115
116impl PlatformSerializableWithPlatformVersion for DataContract {
142 type Error = ProtocolError;
143
144 fn serialize_to_bytes_with_platform_version(
145 &self,
146 platform_version: &PlatformVersion,
147 ) -> Result<Vec<u8>, ProtocolError> {
148 let serialization_format: DataContractInSerializationFormat =
149 self.try_into_platform_versioned(platform_version)?;
150 let config = bincode::config::standard()
151 .with_big_endian()
152 .with_no_limit();
153 bincode::encode_to_vec(serialization_format, config).map_err(|e| {
154 PlatformSerializationError(format!("unable to serialize DataContract: {}", e))
155 })
156 }
157
158 fn serialize_consume_to_bytes_with_platform_version(
159 self,
160 platform_version: &PlatformVersion,
161 ) -> Result<Vec<u8>, ProtocolError> {
162 let serialization_format: DataContractInSerializationFormat =
163 self.try_into_platform_versioned(platform_version)?;
164 let config = bincode::config::standard()
165 .with_big_endian()
166 .with_no_limit();
167 bincode::encode_to_vec(serialization_format, config).map_err(|e| {
168 PlatformSerializationError(format!("unable to serialize consume DataContract: {}", e))
169 })
170 }
171}
172
173fn decode_serialization_format_trusted<C: Config>(
176 data: &[u8],
177 config: C,
178 what: &str,
179) -> Result<(DataContractInSerializationFormat, usize), ProtocolError> {
180 bincode::borrow_decode_from_slice(data, config)
181 .map_err(|e| PlatformDeserializationError(format!("unable to deserialize {}: {}", what, e)))
182}
183
184fn decode_serialization_format_untrusted<C: Config>(
187 data: &[u8],
188 config: C,
189 what: &str,
190) -> Result<(DataContractInSerializationFormat, usize), ProtocolError> {
191 bincode::borrow_decode_from_slice_untrusted(data, config)
192 .map_err(|e| PlatformDeserializationError(format!("unable to deserialize {}: {}", what, e)))
193}
194
195fn no_limit_config() -> Configuration<BigEndian, Varint, NoLimit> {
196 bincode::config::standard()
197 .with_big_endian()
198 .with_no_limit()
199}
200
201fn contract_limit_config() -> Configuration<BigEndian, Varint, Limit<CONTRACT_DESERIALIZATION_LIMIT>>
202{
203 bincode::config::standard()
204 .with_big_endian()
205 .with_limit::<CONTRACT_DESERIALIZATION_LIMIT>()
206}
207
208impl PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted for DataContract {
209 fn versioned_deserialize_trusted(
210 data: &[u8],
211 full_validation: bool,
212 platform_version: &PlatformVersion,
213 ) -> Result<Self, ProtocolError>
214 where
215 Self: Sized,
216 {
217 let (data_contract_in_serialization_format, _) =
218 decode_serialization_format_trusted(data, no_limit_config(), "DataContract")?;
219 DataContract::try_from_platform_versioned(
220 data_contract_in_serialization_format,
221 full_validation,
222 &mut vec![],
223 platform_version,
224 )
225 }
226}
227
228impl PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted for DataContract {
229 fn versioned_deserialize_untrusted(
230 data: &[u8],
231 full_validation: bool,
232 platform_version: &PlatformVersion,
233 ) -> Result<Self, ProtocolError>
234 where
235 Self: Sized,
236 {
237 let (data_contract_in_serialization_format, _) =
238 decode_serialization_format_untrusted(data, no_limit_config(), "DataContract")?;
239 DataContract::try_from_platform_versioned(
240 data_contract_in_serialization_format,
241 full_validation,
242 &mut vec![],
243 platform_version,
244 )
245 }
246}
247
248impl PlatformDeserializableWithBytesLenFromVersionedStructureTrusted for DataContract {
249 fn versioned_deserialize_with_bytes_len_trusted(
250 data: &[u8],
251 full_validation: bool,
252 platform_version: &PlatformVersion,
253 ) -> Result<(Self, usize), ProtocolError>
254 where
255 Self: Sized,
256 {
257 let (data_contract_in_serialization_format, len) =
258 decode_serialization_format_trusted(data, no_limit_config(), "DataContract")?;
259 Ok((
260 DataContract::try_from_platform_versioned(
261 data_contract_in_serialization_format,
262 full_validation,
263 &mut vec![],
264 platform_version,
265 )?,
266 len,
267 ))
268 }
269}
270
271impl PlatformDeserializableWithBytesLenFromVersionedStructureUntrusted for DataContract {
272 fn versioned_deserialize_with_bytes_len_untrusted(
273 data: &[u8],
274 full_validation: bool,
275 platform_version: &PlatformVersion,
276 ) -> Result<(Self, usize), ProtocolError>
277 where
278 Self: Sized,
279 {
280 let (data_contract_in_serialization_format, len) =
281 decode_serialization_format_untrusted(data, no_limit_config(), "DataContract")?;
282 Ok((
283 DataContract::try_from_platform_versioned(
284 data_contract_in_serialization_format,
285 full_validation,
286 &mut vec![],
287 platform_version,
288 )?,
289 len,
290 ))
291 }
292}
293
294impl PlatformLimitDeserializableFromVersionedStructureTrusted for DataContract {
295 fn versioned_limit_deserialize_trusted(
296 data: &[u8],
297 platform_version: &PlatformVersion,
298 ) -> Result<Self, ProtocolError>
299 where
300 Self: Sized,
301 {
302 let (data_contract_in_serialization_format, _) = decode_serialization_format_trusted(
303 data,
304 contract_limit_config(),
305 "DataContract with limit",
306 )?;
307 DataContract::try_from_platform_versioned(
309 data_contract_in_serialization_format,
310 true,
311 &mut vec![],
312 platform_version,
313 )
314 }
315}
316
317impl PlatformLimitDeserializableFromVersionedStructureUntrusted for DataContract {
318 fn versioned_limit_deserialize_untrusted(
319 data: &[u8],
320 platform_version: &PlatformVersion,
321 ) -> Result<Self, ProtocolError>
322 where
323 Self: Sized,
324 {
325 let (data_contract_in_serialization_format, _) = decode_serialization_format_untrusted(
326 data,
327 contract_limit_config(),
328 "DataContract with limit",
329 )?;
330 DataContract::try_from_platform_versioned(
332 data_contract_in_serialization_format,
333 true,
334 &mut vec![],
335 platform_version,
336 )
337 }
338}
339
340impl DataContract {
341 pub fn as_v0(&self) -> Option<&DataContractV0> {
342 match self {
343 DataContract::V0(v0) => Some(v0),
344 _ => None,
345 }
346 }
347
348 pub fn as_v0_mut(&mut self) -> Option<&mut DataContractV0> {
349 match self {
350 DataContract::V0(v0) => Some(v0),
351 _ => None,
352 }
353 }
354
355 pub fn into_v0(self) -> Option<DataContractV0> {
356 match self {
357 DataContract::V0(v0) => Some(v0),
358 _ => None,
359 }
360 }
361
362 pub fn as_v1(&self) -> Option<&DataContractV1> {
363 match self {
364 DataContract::V1(v1) => Some(v1),
365 _ => None,
366 }
367 }
368
369 pub fn as_v1_mut(&mut self) -> Option<&mut DataContractV1> {
370 match self {
371 DataContract::V1(v1) => Some(v1),
372 _ => None,
373 }
374 }
375
376 pub fn into_v1(self) -> Option<DataContractV1> {
377 match self {
378 DataContract::V1(v1) => Some(v1),
379 _ => None,
380 }
381 }
382
383 #[cfg(test)]
385 pub fn into_latest(self) -> Option<DataContractV1> {
386 self.into_v1()
387 }
388
389 #[cfg(test)]
391 pub fn as_latest(&self) -> Option<&DataContractV1> {
392 match self {
393 DataContract::V1(v1) => Some(v1),
394 _ => None,
395 }
396 }
397
398 #[cfg(test)]
400 pub fn as_latest_mut(&mut self) -> Option<&mut DataContractV1> {
401 match self {
402 DataContract::V1(v1) => Some(v1),
403 _ => None,
404 }
405 }
406
407 pub fn check_version_is_active(
408 protocol_version: u32,
409 data_contract_system_version: FeatureVersion,
410 ) -> Result<bool, ProtocolError> {
411 let platform_version = PlatformVersion::get(protocol_version)?;
412 Ok(platform_version
413 .dpp
414 .contract_versions
415 .contract_structure_version
416 == data_contract_system_version)
417 }
418
419 pub fn hash(&self, platform_version: &PlatformVersion) -> Result<Vec<u8>, ProtocolError> {
420 Ok(hash_double_to_vec(
421 self.serialize_to_bytes_with_platform_version(platform_version)?,
422 ))
423 }
424}
425
426#[cfg(test)]
427mod tests {
428 use crate::data_contract::accessors::v0::DataContractV0Getters;
429 use crate::data_contract::config::v0::DataContractConfigGettersV0;
430 use crate::data_contract::document_type::accessors::DocumentTypeV0Getters;
431 use crate::data_contract::storage_requirements::keys_for_document_type::StorageKeyRequirements;
432 use crate::data_contract::DataContract;
433 use crate::serialization::{
434 PlatformDeserializableWithBytesLenFromVersionedStructureTrusted,
435 PlatformDeserializableWithBytesLenFromVersionedStructureUntrusted,
436 PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted,
437 PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted,
438 PlatformLimitDeserializableFromVersionedStructureTrusted,
439 PlatformLimitDeserializableFromVersionedStructureUntrusted,
440 PlatformSerializableWithPlatformVersion,
441 };
442 use crate::system_data_contracts::load_system_data_contract;
443 use crate::tests::fixtures::{
444 get_dashpay_contract_fixture, get_dashpay_contract_with_generalized_encryption_key_fixture,
445 };
446 use crate::version::PlatformVersion;
447 use crate::ProtocolError;
448 use data_contracts::SystemDataContract::Dashpay;
449
450 #[test]
451 fn test_contract_serialization() {
452 let platform_version = PlatformVersion::latest();
453 let data_contract = load_system_data_contract(Dashpay, platform_version)
454 .expect("expected dashpay contract");
455 let serialized = data_contract
456 .serialize_to_bytes_with_platform_version(platform_version)
457 .expect("expected to serialize data contract");
458 assert_eq!(
459 serialized[0],
460 platform_version
461 .dpp
462 .contract_versions
463 .contract_serialization_version
464 .default_current_version as u8
465 );
466
467 let unserialized =
468 DataContract::versioned_deserialize_untrusted(&serialized, true, platform_version)
469 .expect("expected to deserialize data contract");
470
471 assert_eq!(data_contract, unserialized);
472 }
473
474 #[test]
478 fn trusted_and_untrusted_versioned_deserialize_agree() {
479 let platform_version = PlatformVersion::latest();
480 let data_contract = load_system_data_contract(Dashpay, platform_version)
481 .expect("expected dashpay contract");
482 let serialized = data_contract
483 .serialize_to_bytes_with_platform_version(platform_version)
484 .expect("expected to serialize data contract");
485
486 let trusted =
487 DataContract::versioned_deserialize_trusted(&serialized, true, platform_version)
488 .expect("trusted deserialize");
489 let untrusted =
490 DataContract::versioned_deserialize_untrusted(&serialized, true, platform_version)
491 .expect("untrusted deserialize");
492 assert_eq!(trusted, untrusted);
493 assert_eq!(trusted, data_contract);
494
495 let (trusted, trusted_len) = DataContract::versioned_deserialize_with_bytes_len_trusted(
496 &serialized,
497 true,
498 platform_version,
499 )
500 .expect("trusted deserialize with bytes len");
501 let (untrusted, untrusted_len) =
502 DataContract::versioned_deserialize_with_bytes_len_untrusted(
503 &serialized,
504 true,
505 platform_version,
506 )
507 .expect("untrusted deserialize with bytes len");
508 assert_eq!(trusted, untrusted);
509 assert_eq!(trusted_len, untrusted_len);
510 assert_eq!(trusted_len, serialized.len());
511
512 let trusted =
513 DataContract::versioned_limit_deserialize_trusted(&serialized, platform_version)
514 .expect("trusted limit deserialize");
515 let untrusted =
516 DataContract::versioned_limit_deserialize_untrusted(&serialized, platform_version)
517 .expect("untrusted limit deserialize");
518 assert_eq!(trusted, untrusted);
519 assert_eq!(trusted, data_contract);
520 }
521
522 #[test]
523 fn trusted_versioned_deserialize_rejects_malformed_input() {
524 let platform_version = PlatformVersion::latest();
525 for input in [vec![0xFFu8; 16], vec![]] {
526 assert!(matches!(
527 DataContract::versioned_deserialize_trusted(&input, true, platform_version),
528 Err(ProtocolError::PlatformDeserializationError(_))
529 ));
530 assert!(matches!(
531 DataContract::versioned_deserialize_with_bytes_len_trusted(
532 &input,
533 true,
534 platform_version
535 ),
536 Err(ProtocolError::PlatformDeserializationError(_))
537 ));
538 assert!(matches!(
539 DataContract::versioned_limit_deserialize_trusted(&input, platform_version),
540 Err(ProtocolError::PlatformDeserializationError(_))
541 ));
542 }
543 }
544
545 #[test]
546 fn test_contract_can_have_specialized_contract_encryption_decryption_keys() {
547 let data_contract =
548 get_dashpay_contract_with_generalized_encryption_key_fixture(None, 0, 1)
549 .data_contract_owned();
550 assert_eq!(
551 data_contract
552 .config()
553 .requires_identity_decryption_bounded_key(),
554 Some(StorageKeyRequirements::Unique)
555 );
556 assert_eq!(
557 data_contract
558 .config()
559 .requires_identity_encryption_bounded_key(),
560 Some(StorageKeyRequirements::Unique)
561 );
562 }
563
564 #[test]
565 fn test_contract_document_type_can_have_specialized_contract_encryption_decryption_keys() {
566 let data_contract = get_dashpay_contract_fixture(None, 0, 1).data_contract_owned();
567 assert_eq!(
568 data_contract
569 .document_type_for_name("contactRequest")
570 .expect("expected document type")
571 .requires_identity_decryption_bounded_key(),
572 Some(StorageKeyRequirements::MultipleReferenceToLatest)
573 );
574 assert_eq!(
575 data_contract
576 .document_type_for_name("contactRequest")
577 .expect("expected document type")
578 .requires_identity_encryption_bounded_key(),
579 Some(StorageKeyRequirements::MultipleReferenceToLatest)
580 );
581 }
582}