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