1use crate::data_contract::document_type::{DocumentPropertyType, DocumentTypeRef};
2use crate::data_contract::errors::DataContractError;
3
4use crate::document::property_names::{
5 CREATED_AT, CREATED_AT_BLOCK_HEIGHT, CREATED_AT_CORE_BLOCK_HEIGHT, PRICE, TRANSFERRED_AT,
6 TRANSFERRED_AT_BLOCK_HEIGHT, TRANSFERRED_AT_CORE_BLOCK_HEIGHT, UPDATED_AT,
7 UPDATED_AT_BLOCK_HEIGHT, UPDATED_AT_CORE_BLOCK_HEIGHT,
8};
9
10#[cfg(feature = "validation")]
11use crate::prelude::ConsensusValidationResult;
12
13use crate::prelude::{DataContract, Revision};
14
15use crate::ProtocolError;
16
17use crate::data_contract::document_type::accessors::DocumentTypeV0Getters;
18use crate::data_contract::document_type::methods::DocumentTypeBasicMethods;
19use crate::document::serialization_traits::deserialize::v0::DocumentPlatformDeserializationMethodsV0;
20use crate::document::serialization_traits::serialize::v0::DocumentPlatformSerializationMethodsV0;
21use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0;
22use crate::document::v0::DocumentV0;
23use crate::version::PlatformVersion;
24use byteorder::{BigEndian, ReadBytesExt};
25use integer_encoding::{VarInt, VarIntReader};
26
27use platform_value::{Identifier, Value};
28use platform_version::version::FeatureVersion;
29
30use std::collections::BTreeMap;
31
32use crate::consensus::basic::decode::DecodingError;
33#[cfg(feature = "validation")]
34use crate::consensus::basic::BasicError;
35#[cfg(feature = "validation")]
36use crate::consensus::ConsensusError;
37use crate::data_contract::accessors::v0::DataContractV0Getters;
38use crate::data_contract::config::DataContractConfig;
39use crate::nft::TradeMode;
40use std::io::{BufReader, Read};
41
42impl DocumentPlatformSerializationMethodsV0 for DocumentV0 {
43 fn serialize_v0(&self, document_type: DocumentTypeRef) -> Result<Vec<u8>, ProtocolError> {
49 let mut buffer: Vec<u8> = 0u64.encode_var_vec(); buffer.extend(self.id.as_slice());
53
54 buffer.extend(self.owner_id.as_slice());
56
57 if let Some(revision) = self.revision {
59 buffer.extend(revision.encode_var_vec())
60 } else if document_type.requires_revision() {
61 buffer.extend((1 as Revision).encode_var_vec())
62 }
63
64 let mut bitwise_exists_flag: u16 = 0;
65
66 let mut time_fields_data_buffer = vec![];
67
68 if let Some(created_at) = &self.created_at {
70 bitwise_exists_flag |= 1;
71 time_fields_data_buffer.extend(created_at.to_be_bytes());
73 } else if document_type.required_fields().contains(CREATED_AT) {
74 return Err(ProtocolError::DataContractError(
75 DataContractError::MissingRequiredKey(
76 "created at field is not present".to_string(),
77 ),
78 ));
79 }
80
81 if let Some(updated_at) = &self.updated_at {
83 bitwise_exists_flag |= 2;
84 time_fields_data_buffer.extend(updated_at.to_be_bytes());
86 } else if document_type.required_fields().contains(UPDATED_AT) {
87 return Err(ProtocolError::DataContractError(
88 DataContractError::MissingRequiredKey(
89 "updated at field is not present".to_string(),
90 ),
91 ));
92 }
93
94 if let Some(transferred_at) = &self.transferred_at {
96 bitwise_exists_flag |= 4;
97 time_fields_data_buffer.extend(transferred_at.to_be_bytes());
99 } else if document_type.required_fields().contains(TRANSFERRED_AT) {
100 return Err(ProtocolError::DataContractError(
101 DataContractError::MissingRequiredKey(
102 "transferred at field is not present".to_string(),
103 ),
104 ));
105 }
106
107 if let Some(created_at_block_height) = &self.created_at_block_height {
109 bitwise_exists_flag |= 8;
110 time_fields_data_buffer.extend(created_at_block_height.to_be_bytes());
111 } else if document_type
112 .required_fields()
113 .contains(CREATED_AT_BLOCK_HEIGHT)
114 {
115 return Err(ProtocolError::DataContractError(
116 DataContractError::MissingRequiredKey(
117 "created_at_block_height field is not present".to_string(),
118 ),
119 ));
120 }
121
122 if let Some(updated_at_block_height) = &self.updated_at_block_height {
124 bitwise_exists_flag |= 16;
125 time_fields_data_buffer.extend(updated_at_block_height.to_be_bytes());
126 } else if document_type
127 .required_fields()
128 .contains(UPDATED_AT_BLOCK_HEIGHT)
129 {
130 return Err(ProtocolError::DataContractError(
131 DataContractError::MissingRequiredKey(
132 "updated_at_block_height field is not present".to_string(),
133 ),
134 ));
135 }
136
137 if let Some(transferred_at_block_height) = &self.transferred_at_block_height {
139 bitwise_exists_flag |= 32;
140 time_fields_data_buffer.extend(transferred_at_block_height.to_be_bytes());
141 } else if document_type
142 .required_fields()
143 .contains(TRANSFERRED_AT_BLOCK_HEIGHT)
144 {
145 return Err(ProtocolError::DataContractError(
146 DataContractError::MissingRequiredKey(
147 "transferred_at_block_height field is not present".to_string(),
148 ),
149 ));
150 }
151
152 if let Some(created_at_core_block_height) = &self.created_at_core_block_height {
154 bitwise_exists_flag |= 64;
155 time_fields_data_buffer.extend(created_at_core_block_height.to_be_bytes());
156 } else if document_type
157 .required_fields()
158 .contains(CREATED_AT_CORE_BLOCK_HEIGHT)
159 {
160 return Err(ProtocolError::DataContractError(
161 DataContractError::MissingRequiredKey(
162 "created_at_core_block_height field is not present".to_string(),
163 ),
164 ));
165 }
166
167 if let Some(updated_at_core_block_height) = &self.updated_at_core_block_height {
169 bitwise_exists_flag |= 128;
170 time_fields_data_buffer.extend(updated_at_core_block_height.to_be_bytes());
171 } else if document_type
172 .required_fields()
173 .contains(UPDATED_AT_CORE_BLOCK_HEIGHT)
174 {
175 return Err(ProtocolError::DataContractError(
176 DataContractError::MissingRequiredKey(
177 "updated_at_core_block_height field is not present".to_string(),
178 ),
179 ));
180 }
181
182 if let Some(transferred_at_core_block_height) = &self.transferred_at_core_block_height {
184 bitwise_exists_flag |= 256;
185 time_fields_data_buffer.extend(transferred_at_core_block_height.to_be_bytes());
186 } else if document_type
187 .required_fields()
188 .contains(TRANSFERRED_AT_CORE_BLOCK_HEIGHT)
189 {
190 return Err(ProtocolError::DataContractError(
191 DataContractError::MissingRequiredKey(
192 "transferred_at_core_block_height field is not present".to_string(),
193 ),
194 ));
195 }
196
197 buffer.extend(bitwise_exists_flag.to_be_bytes().as_slice());
198 buffer.append(&mut time_fields_data_buffer);
199
200 if document_type.trade_mode().seller_sets_price() {
203 if let Some(price) = self.properties.get(PRICE) {
204 buffer.push(1);
205 let price_as_u64: u64 = price.to_integer().map_err(ProtocolError::ValueError)?;
206 buffer.append(&mut price_as_u64.to_be_bytes().to_vec());
207 } else {
208 buffer.push(0);
209 }
210 }
211
212 document_type
214 .properties()
215 .iter()
216 .try_for_each(|(field_name, property)| {
217 if let Some(value) = self.properties.get(field_name) {
218 if value.is_null() {
219 if property.required && !property.transient {
220 Err(ProtocolError::DataContractError(
221 DataContractError::MissingRequiredKey(
222 "a required field is not present".to_string(),
223 ),
224 ))
225 } else {
226 buffer.push(0);
229 Ok(())
230 }
231 } else {
232 if !property.required || property.transient {
233 buffer.push(1);
235 }
236 let value = if property.property_type.is_integer() {
237 DocumentPropertyType::I64
238 .encode_value_ref_with_size(value, property.required)
239 } else {
240 property
241 .property_type
242 .encode_value_ref_with_size(value, property.required)
243 }?;
244
245 buffer.extend(value.as_slice());
247 Ok(())
248 }
249 } else if property.required && !property.transient {
250 Err(ProtocolError::DataContractError(
251 DataContractError::MissingRequiredKey(format!(
252 "a required field {field_name} is not present"
253 )),
254 ))
255 } else {
256 buffer.push(0);
259 Ok(())
260 }
261 })?;
262
263 Ok(buffer)
264 }
265
266 fn serialize_v1(&self, document_type: DocumentTypeRef) -> Result<Vec<u8>, ProtocolError> {
273 let mut buffer: Vec<u8> = 1u64.encode_var_vec(); buffer.extend(self.id.as_slice());
277
278 buffer.extend(self.owner_id.as_slice());
280
281 if let Some(revision) = self.revision {
283 buffer.extend(revision.encode_var_vec())
284 } else if document_type.requires_revision() {
285 buffer.extend((1 as Revision).encode_var_vec())
286 }
287
288 let mut bitwise_exists_flag: u16 = 0;
289
290 let mut time_fields_data_buffer = vec![];
291
292 if let Some(created_at) = &self.created_at {
294 bitwise_exists_flag |= 1;
295 time_fields_data_buffer.extend(created_at.to_be_bytes());
297 } else if document_type.required_fields().contains(CREATED_AT) {
298 return Err(ProtocolError::DataContractError(
299 DataContractError::MissingRequiredKey(
300 "created at field is not present".to_string(),
301 ),
302 ));
303 }
304
305 if let Some(updated_at) = &self.updated_at {
307 bitwise_exists_flag |= 2;
308 time_fields_data_buffer.extend(updated_at.to_be_bytes());
310 } else if document_type.required_fields().contains(UPDATED_AT) {
311 return Err(ProtocolError::DataContractError(
312 DataContractError::MissingRequiredKey(
313 "updated at field is not present".to_string(),
314 ),
315 ));
316 }
317
318 if let Some(transferred_at) = &self.transferred_at {
320 bitwise_exists_flag |= 4;
321 time_fields_data_buffer.extend(transferred_at.to_be_bytes());
323 } else if document_type.required_fields().contains(TRANSFERRED_AT) {
324 return Err(ProtocolError::DataContractError(
325 DataContractError::MissingRequiredKey(
326 "transferred at field is not present".to_string(),
327 ),
328 ));
329 }
330
331 if let Some(created_at_block_height) = &self.created_at_block_height {
333 bitwise_exists_flag |= 8;
334 time_fields_data_buffer.extend(created_at_block_height.to_be_bytes());
335 } else if document_type
336 .required_fields()
337 .contains(CREATED_AT_BLOCK_HEIGHT)
338 {
339 return Err(ProtocolError::DataContractError(
340 DataContractError::MissingRequiredKey(
341 "created_at_block_height field is not present".to_string(),
342 ),
343 ));
344 }
345
346 if let Some(updated_at_block_height) = &self.updated_at_block_height {
348 bitwise_exists_flag |= 16;
349 time_fields_data_buffer.extend(updated_at_block_height.to_be_bytes());
350 } else if document_type
351 .required_fields()
352 .contains(UPDATED_AT_BLOCK_HEIGHT)
353 {
354 return Err(ProtocolError::DataContractError(
355 DataContractError::MissingRequiredKey(
356 "updated_at_block_height field is not present".to_string(),
357 ),
358 ));
359 }
360
361 if let Some(transferred_at_block_height) = &self.transferred_at_block_height {
363 bitwise_exists_flag |= 32;
364 time_fields_data_buffer.extend(transferred_at_block_height.to_be_bytes());
365 } else if document_type
366 .required_fields()
367 .contains(TRANSFERRED_AT_BLOCK_HEIGHT)
368 {
369 return Err(ProtocolError::DataContractError(
370 DataContractError::MissingRequiredKey(
371 "transferred_at_block_height field is not present".to_string(),
372 ),
373 ));
374 }
375
376 if let Some(created_at_core_block_height) = &self.created_at_core_block_height {
378 bitwise_exists_flag |= 64;
379 time_fields_data_buffer.extend(created_at_core_block_height.to_be_bytes());
380 } else if document_type
381 .required_fields()
382 .contains(CREATED_AT_CORE_BLOCK_HEIGHT)
383 {
384 return Err(ProtocolError::DataContractError(
385 DataContractError::MissingRequiredKey(
386 "created_at_core_block_height field is not present".to_string(),
387 ),
388 ));
389 }
390
391 if let Some(updated_at_core_block_height) = &self.updated_at_core_block_height {
393 bitwise_exists_flag |= 128;
394 time_fields_data_buffer.extend(updated_at_core_block_height.to_be_bytes());
395 } else if document_type
396 .required_fields()
397 .contains(UPDATED_AT_CORE_BLOCK_HEIGHT)
398 {
399 return Err(ProtocolError::DataContractError(
400 DataContractError::MissingRequiredKey(
401 "updated_at_core_block_height field is not present".to_string(),
402 ),
403 ));
404 }
405
406 if let Some(transferred_at_core_block_height) = &self.transferred_at_core_block_height {
408 bitwise_exists_flag |= 256;
409 time_fields_data_buffer.extend(transferred_at_core_block_height.to_be_bytes());
410 } else if document_type
411 .required_fields()
412 .contains(TRANSFERRED_AT_CORE_BLOCK_HEIGHT)
413 {
414 return Err(ProtocolError::DataContractError(
415 DataContractError::MissingRequiredKey(
416 "transferred_at_core_block_height field is not present".to_string(),
417 ),
418 ));
419 }
420
421 buffer.extend(bitwise_exists_flag.to_be_bytes().as_slice());
422 buffer.append(&mut time_fields_data_buffer);
423
424 if document_type.trade_mode().seller_sets_price() {
427 if let Some(price) = self.properties.get(PRICE) {
428 buffer.push(1);
429 let price_as_u64: u64 = price.to_integer().map_err(ProtocolError::ValueError)?;
430 buffer.append(&mut price_as_u64.to_be_bytes().to_vec());
431 } else {
432 buffer.push(0);
433 }
434 }
435
436 document_type
438 .properties()
439 .iter()
440 .try_for_each(|(field_name, property)| {
441 if let Some(value) = self.properties.get(field_name) {
442 if value.is_null() {
443 if property.required && !property.transient {
444 Err(ProtocolError::DataContractError(
445 DataContractError::MissingRequiredKey(
446 "a required field is not present".to_string(),
447 ),
448 ))
449 } else {
450 buffer.push(0);
453 Ok(())
454 }
455 } else {
456 if !property.required || property.transient {
457 buffer.push(1);
459 }
460 let value = property
461 .property_type
462 .encode_value_ref_with_size(value, property.required)?;
463 buffer.extend(value.as_slice());
465 Ok(())
466 }
467 } else if property.required && !property.transient {
468 Err(ProtocolError::DataContractError(
469 DataContractError::MissingRequiredKey(format!(
470 "a required field {field_name} is not present"
471 )),
472 ))
473 } else {
474 buffer.push(0);
477 Ok(())
478 }
479 })?;
480
481 Ok(buffer)
482 }
483
484 fn serialize_v2(&self, document_type: DocumentTypeRef) -> Result<Vec<u8>, ProtocolError> {
490 let mut buffer: Vec<u8> = 2u64.encode_var_vec(); buffer.extend(self.id.as_slice());
494
495 buffer.extend(self.owner_id.as_slice());
497
498 if document_type.trade_mode() != TradeMode::None
499 || document_type.documents_transferable().is_transferable()
500 {
501 if let Some(creator_id) = self.creator_id {
502 buffer.push(1);
503 buffer.extend(creator_id.as_slice());
504 } else {
505 buffer.push(0);
506 }
507 }
508
509 if let Some(revision) = self.revision {
511 buffer.extend(revision.encode_var_vec())
512 } else if document_type.requires_revision() {
513 buffer.extend((1 as Revision).encode_var_vec())
514 }
515
516 let mut bitwise_exists_flag: u16 = 0;
517
518 let mut time_fields_data_buffer = vec![];
519
520 if let Some(created_at) = &self.created_at {
522 bitwise_exists_flag |= 1;
523 time_fields_data_buffer.extend(created_at.to_be_bytes());
525 } else if document_type.required_fields().contains(CREATED_AT) {
526 return Err(ProtocolError::DataContractError(
527 DataContractError::MissingRequiredKey(
528 "created at field is not present".to_string(),
529 ),
530 ));
531 }
532
533 if let Some(updated_at) = &self.updated_at {
535 bitwise_exists_flag |= 2;
536 time_fields_data_buffer.extend(updated_at.to_be_bytes());
538 } else if document_type.required_fields().contains(UPDATED_AT) {
539 return Err(ProtocolError::DataContractError(
540 DataContractError::MissingRequiredKey(
541 "updated at field is not present".to_string(),
542 ),
543 ));
544 }
545
546 if let Some(transferred_at) = &self.transferred_at {
548 bitwise_exists_flag |= 4;
549 time_fields_data_buffer.extend(transferred_at.to_be_bytes());
551 } else if document_type.required_fields().contains(TRANSFERRED_AT) {
552 return Err(ProtocolError::DataContractError(
553 DataContractError::MissingRequiredKey(
554 "transferred at field is not present".to_string(),
555 ),
556 ));
557 }
558
559 if let Some(created_at_block_height) = &self.created_at_block_height {
561 bitwise_exists_flag |= 8;
562 time_fields_data_buffer.extend(created_at_block_height.to_be_bytes());
563 } else if document_type
564 .required_fields()
565 .contains(CREATED_AT_BLOCK_HEIGHT)
566 {
567 return Err(ProtocolError::DataContractError(
568 DataContractError::MissingRequiredKey(
569 "created_at_block_height field is not present".to_string(),
570 ),
571 ));
572 }
573
574 if let Some(updated_at_block_height) = &self.updated_at_block_height {
576 bitwise_exists_flag |= 16;
577 time_fields_data_buffer.extend(updated_at_block_height.to_be_bytes());
578 } else if document_type
579 .required_fields()
580 .contains(UPDATED_AT_BLOCK_HEIGHT)
581 {
582 return Err(ProtocolError::DataContractError(
583 DataContractError::MissingRequiredKey(
584 "updated_at_block_height field is not present".to_string(),
585 ),
586 ));
587 }
588
589 if let Some(transferred_at_block_height) = &self.transferred_at_block_height {
591 bitwise_exists_flag |= 32;
592 time_fields_data_buffer.extend(transferred_at_block_height.to_be_bytes());
593 } else if document_type
594 .required_fields()
595 .contains(TRANSFERRED_AT_BLOCK_HEIGHT)
596 {
597 return Err(ProtocolError::DataContractError(
598 DataContractError::MissingRequiredKey(
599 "transferred_at_block_height field is not present".to_string(),
600 ),
601 ));
602 }
603
604 if let Some(created_at_core_block_height) = &self.created_at_core_block_height {
606 bitwise_exists_flag |= 64;
607 time_fields_data_buffer.extend(created_at_core_block_height.to_be_bytes());
608 } else if document_type
609 .required_fields()
610 .contains(CREATED_AT_CORE_BLOCK_HEIGHT)
611 {
612 return Err(ProtocolError::DataContractError(
613 DataContractError::MissingRequiredKey(
614 "created_at_core_block_height field is not present".to_string(),
615 ),
616 ));
617 }
618
619 if let Some(updated_at_core_block_height) = &self.updated_at_core_block_height {
621 bitwise_exists_flag |= 128;
622 time_fields_data_buffer.extend(updated_at_core_block_height.to_be_bytes());
623 } else if document_type
624 .required_fields()
625 .contains(UPDATED_AT_CORE_BLOCK_HEIGHT)
626 {
627 return Err(ProtocolError::DataContractError(
628 DataContractError::MissingRequiredKey(
629 "updated_at_core_block_height field is not present".to_string(),
630 ),
631 ));
632 }
633
634 if let Some(transferred_at_core_block_height) = &self.transferred_at_core_block_height {
636 bitwise_exists_flag |= 256;
637 time_fields_data_buffer.extend(transferred_at_core_block_height.to_be_bytes());
638 } else if document_type
639 .required_fields()
640 .contains(TRANSFERRED_AT_CORE_BLOCK_HEIGHT)
641 {
642 return Err(ProtocolError::DataContractError(
643 DataContractError::MissingRequiredKey(
644 "transferred_at_core_block_height field is not present".to_string(),
645 ),
646 ));
647 }
648
649 buffer.extend(bitwise_exists_flag.to_be_bytes().as_slice());
650 buffer.append(&mut time_fields_data_buffer);
651
652 if document_type.trade_mode().seller_sets_price() {
655 if let Some(price) = self.properties.get(PRICE) {
656 buffer.push(1);
657 let price_as_u64: u64 = price.to_integer().map_err(ProtocolError::ValueError)?;
658 buffer.append(&mut price_as_u64.to_be_bytes().to_vec());
659 } else {
660 buffer.push(0);
661 }
662 }
663
664 document_type
666 .properties()
667 .iter()
668 .try_for_each(|(field_name, property)| {
669 if let Some(value) = self.properties.get(field_name) {
670 if value.is_null() {
671 if property.required && !property.transient {
672 Err(ProtocolError::DataContractError(
673 DataContractError::MissingRequiredKey(
674 "a required field is not present".to_string(),
675 ),
676 ))
677 } else {
678 buffer.push(0);
681 Ok(())
682 }
683 } else {
684 if !property.required || property.transient {
685 buffer.push(1);
687 }
688 let value = property
689 .property_type
690 .encode_value_ref_with_size(value, property.required)?;
691 buffer.extend(value.as_slice());
693 Ok(())
694 }
695 } else if property.required && !property.transient {
696 Err(ProtocolError::DataContractError(
697 DataContractError::MissingRequiredKey(format!(
698 "a required field {field_name} is not present"
699 )),
700 ))
701 } else {
702 buffer.push(0);
705 Ok(())
706 }
707 })?;
708
709 Ok(buffer)
710 }
711}
712
713impl DocumentPlatformDeserializationMethodsV0 for DocumentV0 {
714 fn from_bytes_v0(
716 serialized_document: &[u8],
717 document_type: DocumentTypeRef,
718 _platform_version: &PlatformVersion,
719 ) -> Result<Self, DataContractError> {
720 let mut buf = BufReader::new(serialized_document);
721 if serialized_document.len() < 64 {
722 return Err(DataContractError::DecodingDocumentError(
723 DecodingError::new(
724 "serialized document is too small, must have id and owner id".to_string(),
725 ),
726 ));
727 }
728
729 let mut id = [0; 32];
731 buf.read_exact(&mut id).map_err(|_| {
732 DataContractError::DecodingDocumentError(DecodingError::new(
733 "error reading from serialized document for id".to_string(),
734 ))
735 })?;
736
737 let mut owner_id = [0; 32];
739 buf.read_exact(&mut owner_id).map_err(|_| {
740 DataContractError::DecodingDocumentError(DecodingError::new(
741 "error reading from serialized document for owner id".to_string(),
742 ))
743 })?;
744
745 let revision: Option<Revision> = if document_type.requires_revision() {
748 let revision = buf.read_varint().map_err(|_| {
749 DataContractError::DecodingDocumentError(DecodingError::new(
750 "error reading revision from serialized document for revision".to_string(),
751 ))
752 })?;
753 Some(revision)
754 } else {
755 None
756 };
757
758 let timestamp_flags = buf.read_u16::<BigEndian>().map_err(|_| {
759 DataContractError::CorruptedSerialization(
760 "error reading timestamp flags from serialized document".to_string(),
761 )
762 })?;
763
764 let created_at = if timestamp_flags & 1 > 0 {
765 Some(buf.read_u64::<BigEndian>().map_err(|_| {
766 DataContractError::CorruptedSerialization(
767 "error reading created_at timestamp from serialized document".to_string(),
768 )
769 })?)
770 } else {
771 None
772 };
773
774 let updated_at = if timestamp_flags & 2 > 0 {
775 Some(buf.read_u64::<BigEndian>().map_err(|_| {
776 DataContractError::CorruptedSerialization(
777 "error reading updated_at timestamp from serialized document".to_string(),
778 )
779 })?)
780 } else {
781 None
782 };
783
784 let transferred_at = if timestamp_flags & 4 > 0 {
785 Some(buf.read_u64::<BigEndian>().map_err(|_| {
786 DataContractError::CorruptedSerialization(
787 "error reading transferred_at timestamp from serialized document".to_string(),
788 )
789 })?)
790 } else {
791 None
792 };
793
794 let created_at_block_height = if timestamp_flags & 8 > 0 {
795 Some(buf.read_u64::<BigEndian>().map_err(|_| {
796 DataContractError::CorruptedSerialization(
797 "error reading created_at_block_height from serialized document".to_string(),
798 )
799 })?)
800 } else {
801 None
802 };
803
804 let updated_at_block_height = if timestamp_flags & 16 > 0 {
805 Some(buf.read_u64::<BigEndian>().map_err(|_| {
806 DataContractError::CorruptedSerialization(
807 "error reading updated_at_block_height from serialized document".to_string(),
808 )
809 })?)
810 } else {
811 None
812 };
813
814 let transferred_at_block_height = if timestamp_flags & 32 > 0 {
815 Some(buf.read_u64::<BigEndian>().map_err(|_| {
816 DataContractError::CorruptedSerialization(
817 "error reading transferred_at_block_height from serialized document"
818 .to_string(),
819 )
820 })?)
821 } else {
822 None
823 };
824
825 let created_at_core_block_height = if timestamp_flags & 64 > 0 {
826 Some(buf.read_u32::<BigEndian>().map_err(|_| {
827 DataContractError::CorruptedSerialization(
828 "error reading created_at_core_block_height from serialized document"
829 .to_string(),
830 )
831 })?)
832 } else {
833 None
834 };
835
836 let updated_at_core_block_height = if timestamp_flags & 128 > 0 {
837 Some(buf.read_u32::<BigEndian>().map_err(|_| {
838 DataContractError::CorruptedSerialization(
839 "error reading updated_at_core_block_height from serialized document"
840 .to_string(),
841 )
842 })?)
843 } else {
844 None
845 };
846
847 let transferred_at_core_block_height = if timestamp_flags & 256 > 0 {
848 Some(buf.read_u32::<BigEndian>().map_err(|_| {
849 DataContractError::CorruptedSerialization(
850 "error reading updated_at_core_block_height from serialized document"
851 .to_string(),
852 )
853 })?)
854 } else {
855 None
856 };
857
858 let price = if document_type.trade_mode().seller_sets_price() {
861 let has_price = buf.read_u8().map_err(|_| {
862 DataContractError::CorruptedSerialization(
863 "error reading has price bool from serialized document".to_string(),
864 )
865 })?;
866 if has_price > 0 {
867 let price = buf.read_u64::<BigEndian>().map_err(|_| {
868 DataContractError::CorruptedSerialization(
869 "error reading price u64 from serialized document".to_string(),
870 )
871 })?;
872 Some(price)
873 } else {
874 None
875 }
876 } else {
877 None
878 };
879
880 let mut finished_buffer = false;
881
882 let mut properties = document_type
883 .properties()
884 .iter()
885 .filter_map(|(key, property)| {
886 if finished_buffer {
887 return if property.required && !property.transient {
888 Some(Err(DataContractError::CorruptedSerialization(
889 "required field after finished buffer".to_string(),
890 )))
891 } else {
892 None
893 };
894 }
895
896 let read_value = if property.property_type.is_integer() {
898 DocumentPropertyType::I64
899 .read_optionally_from(&mut buf, property.required & !property.transient)
900 } else {
901 property
902 .property_type
903 .read_optionally_from(&mut buf, property.required & !property.transient)
904 };
905
906 match read_value {
907 Ok(read_value) => {
908 finished_buffer |= read_value.1;
909 read_value.0.map(|read_value| Ok((key.clone(), read_value)))
910 }
911 Err(e) => Some(Err(e)),
912 }
913 })
914 .collect::<Result<BTreeMap<String, Value>, DataContractError>>()?;
915
916 if let Some(price) = price {
917 properties.insert(PRICE.to_string(), price.into());
918 }
919
920 Ok(DocumentV0 {
921 id: Identifier::new(id),
922 properties,
923 owner_id: Identifier::new(owner_id),
924 revision,
925 created_at,
926 updated_at,
927 transferred_at,
928 created_at_block_height,
929 updated_at_block_height,
930 transferred_at_block_height,
931 created_at_core_block_height,
932 updated_at_core_block_height,
933 transferred_at_core_block_height,
934 creator_id: None,
935 })
936 }
937
938 fn from_bytes_v1(
940 serialized_document: &[u8],
941 document_type: DocumentTypeRef,
942 _platform_version: &PlatformVersion,
943 ) -> Result<Self, DataContractError> {
944 let mut buf = BufReader::new(serialized_document);
945 if serialized_document.len() < 64 {
946 return Err(DataContractError::DecodingDocumentError(
947 DecodingError::new(
948 "serialized document is too small, must have id and owner id".to_string(),
949 ),
950 ));
951 }
952
953 let mut id = [0; 32];
955 buf.read_exact(&mut id).map_err(|_| {
956 DataContractError::DecodingDocumentError(DecodingError::new(
957 "error reading from serialized document for id".to_string(),
958 ))
959 })?;
960
961 let mut owner_id = [0; 32];
963 buf.read_exact(&mut owner_id).map_err(|_| {
964 DataContractError::DecodingDocumentError(DecodingError::new(
965 "error reading from serialized document for owner id".to_string(),
966 ))
967 })?;
968
969 let revision: Option<Revision> = if document_type.requires_revision() {
972 let revision = buf.read_varint().map_err(|_| {
973 DataContractError::DecodingDocumentError(DecodingError::new(
974 "error reading revision from serialized document for revision".to_string(),
975 ))
976 })?;
977 Some(revision)
978 } else {
979 None
980 };
981
982 let timestamp_flags = buf.read_u16::<BigEndian>().map_err(|_| {
983 DataContractError::CorruptedSerialization(
984 "error reading timestamp flags from serialized document".to_string(),
985 )
986 })?;
987
988 let created_at = if timestamp_flags & 1 > 0 {
989 Some(buf.read_u64::<BigEndian>().map_err(|_| {
990 DataContractError::CorruptedSerialization(
991 "error reading created_at timestamp from serialized document".to_string(),
992 )
993 })?)
994 } else {
995 None
996 };
997
998 let updated_at = if timestamp_flags & 2 > 0 {
999 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1000 DataContractError::CorruptedSerialization(
1001 "error reading updated_at timestamp from serialized document".to_string(),
1002 )
1003 })?)
1004 } else {
1005 None
1006 };
1007
1008 let transferred_at = if timestamp_flags & 4 > 0 {
1009 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1010 DataContractError::CorruptedSerialization(
1011 "error reading transferred_at timestamp from serialized document".to_string(),
1012 )
1013 })?)
1014 } else {
1015 None
1016 };
1017
1018 let created_at_block_height = if timestamp_flags & 8 > 0 {
1019 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1020 DataContractError::CorruptedSerialization(
1021 "error reading created_at_block_height from serialized document".to_string(),
1022 )
1023 })?)
1024 } else {
1025 None
1026 };
1027
1028 let updated_at_block_height = if timestamp_flags & 16 > 0 {
1029 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1030 DataContractError::CorruptedSerialization(
1031 "error reading updated_at_block_height from serialized document".to_string(),
1032 )
1033 })?)
1034 } else {
1035 None
1036 };
1037
1038 let transferred_at_block_height = if timestamp_flags & 32 > 0 {
1039 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1040 DataContractError::CorruptedSerialization(
1041 "error reading transferred_at_block_height from serialized document"
1042 .to_string(),
1043 )
1044 })?)
1045 } else {
1046 None
1047 };
1048
1049 let created_at_core_block_height = if timestamp_flags & 64 > 0 {
1050 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1051 DataContractError::CorruptedSerialization(
1052 "error reading created_at_core_block_height from serialized document"
1053 .to_string(),
1054 )
1055 })?)
1056 } else {
1057 None
1058 };
1059
1060 let updated_at_core_block_height = if timestamp_flags & 128 > 0 {
1061 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1062 DataContractError::CorruptedSerialization(
1063 "error reading updated_at_core_block_height from serialized document"
1064 .to_string(),
1065 )
1066 })?)
1067 } else {
1068 None
1069 };
1070
1071 let transferred_at_core_block_height = if timestamp_flags & 256 > 0 {
1072 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1073 DataContractError::CorruptedSerialization(
1074 "error reading updated_at_core_block_height from serialized document"
1075 .to_string(),
1076 )
1077 })?)
1078 } else {
1079 None
1080 };
1081
1082 let price = if document_type.trade_mode().seller_sets_price() {
1085 let has_price = buf.read_u8().map_err(|_| {
1086 DataContractError::CorruptedSerialization(
1087 "error reading has price bool from serialized document".to_string(),
1088 )
1089 })?;
1090 if has_price > 0 {
1091 let price = buf.read_u64::<BigEndian>().map_err(|_| {
1092 DataContractError::CorruptedSerialization(
1093 "error reading price u64 from serialized document".to_string(),
1094 )
1095 })?;
1096 Some(price)
1097 } else {
1098 None
1099 }
1100 } else {
1101 None
1102 };
1103
1104 let mut finished_buffer = false;
1105
1106 let mut properties = document_type
1107 .properties()
1108 .iter()
1109 .filter_map(|(key, property)| {
1110 if finished_buffer {
1111 return if property.required && !property.transient {
1112 Some(Err(DataContractError::CorruptedSerialization(
1113 "required field after finished buffer".to_string(),
1114 )))
1115 } else {
1116 None
1117 };
1118 }
1119 let read_value = property
1120 .property_type
1121 .read_optionally_from(&mut buf, property.required & !property.transient);
1122
1123 match read_value {
1124 Ok(read_value) => {
1125 finished_buffer |= read_value.1;
1126 read_value.0.map(|read_value| Ok((key.clone(), read_value)))
1127 }
1128 Err(e) => Some(Err(e)),
1129 }
1130 })
1131 .collect::<Result<BTreeMap<String, Value>, DataContractError>>()?;
1132
1133 if let Some(price) = price {
1134 properties.insert(PRICE.to_string(), price.into());
1135 }
1136
1137 Ok(DocumentV0 {
1138 id: Identifier::new(id),
1139 properties,
1140 owner_id: Identifier::new(owner_id),
1141 revision,
1142 created_at,
1143 updated_at,
1144 transferred_at,
1145 created_at_block_height,
1146 updated_at_block_height,
1147 transferred_at_block_height,
1148 created_at_core_block_height,
1149 updated_at_core_block_height,
1150 transferred_at_core_block_height,
1151 creator_id: None,
1152 })
1153 }
1154
1155 fn from_bytes_v2(
1157 serialized_document: &[u8],
1158 document_type: DocumentTypeRef,
1159 _platform_version: &PlatformVersion,
1160 ) -> Result<Self, DataContractError> {
1161 let mut buf = BufReader::new(serialized_document);
1162 if serialized_document.len() < 64 {
1163 return Err(DataContractError::DecodingDocumentError(
1164 DecodingError::new(
1165 "serialized document is too small, must have id and owner id".to_string(),
1166 ),
1167 ));
1168 }
1169
1170 let mut id = [0; 32];
1172 buf.read_exact(&mut id).map_err(|_| {
1173 DataContractError::DecodingDocumentError(DecodingError::new(
1174 "error reading from serialized document for id".to_string(),
1175 ))
1176 })?;
1177
1178 let mut owner_id = [0; 32];
1180 buf.read_exact(&mut owner_id).map_err(|_| {
1181 DataContractError::DecodingDocumentError(DecodingError::new(
1182 "error reading from serialized document for owner id".to_string(),
1183 ))
1184 })?;
1185
1186 let creator_id: Option<Identifier> = if document_type.trade_mode() != TradeMode::None
1188 || document_type.documents_transferable().is_transferable()
1189 {
1190 let has_creator_id = buf.read_u8().map_err(|_| {
1191 DataContractError::CorruptedSerialization(
1192 "error reading has creator id bool from serialized document".to_string(),
1193 )
1194 })?;
1195 if has_creator_id > 0 {
1196 let mut known_owner_id = [0; 32];
1198 buf.read_exact(&mut known_owner_id).map_err(|_| {
1199 DataContractError::DecodingDocumentError(DecodingError::new(
1200 "error reading from serialized document for creator id".to_string(),
1201 ))
1202 })?;
1203 Some(known_owner_id.into())
1204 } else {
1205 None
1206 }
1207 } else {
1208 None
1209 };
1210
1211 let revision: Option<Revision> = if document_type.requires_revision() {
1214 let revision = buf.read_varint().map_err(|_| {
1215 DataContractError::DecodingDocumentError(DecodingError::new(
1216 "error reading revision from serialized document for revision".to_string(),
1217 ))
1218 })?;
1219 Some(revision)
1220 } else {
1221 None
1222 };
1223
1224 let timestamp_flags = buf.read_u16::<BigEndian>().map_err(|_| {
1225 DataContractError::CorruptedSerialization(
1226 "error reading timestamp flags from serialized document".to_string(),
1227 )
1228 })?;
1229
1230 let created_at = if timestamp_flags & 1 > 0 {
1231 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1232 DataContractError::CorruptedSerialization(
1233 "error reading created_at timestamp from serialized document".to_string(),
1234 )
1235 })?)
1236 } else {
1237 None
1238 };
1239
1240 let updated_at = if timestamp_flags & 2 > 0 {
1241 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1242 DataContractError::CorruptedSerialization(
1243 "error reading updated_at timestamp from serialized document".to_string(),
1244 )
1245 })?)
1246 } else {
1247 None
1248 };
1249
1250 let transferred_at = if timestamp_flags & 4 > 0 {
1251 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1252 DataContractError::CorruptedSerialization(
1253 "error reading transferred_at timestamp from serialized document".to_string(),
1254 )
1255 })?)
1256 } else {
1257 None
1258 };
1259
1260 let created_at_block_height = if timestamp_flags & 8 > 0 {
1261 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1262 DataContractError::CorruptedSerialization(
1263 "error reading created_at_block_height from serialized document".to_string(),
1264 )
1265 })?)
1266 } else {
1267 None
1268 };
1269
1270 let updated_at_block_height = if timestamp_flags & 16 > 0 {
1271 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1272 DataContractError::CorruptedSerialization(
1273 "error reading updated_at_block_height from serialized document".to_string(),
1274 )
1275 })?)
1276 } else {
1277 None
1278 };
1279
1280 let transferred_at_block_height = if timestamp_flags & 32 > 0 {
1281 Some(buf.read_u64::<BigEndian>().map_err(|_| {
1282 DataContractError::CorruptedSerialization(
1283 "error reading transferred_at_block_height from serialized document"
1284 .to_string(),
1285 )
1286 })?)
1287 } else {
1288 None
1289 };
1290
1291 let created_at_core_block_height = if timestamp_flags & 64 > 0 {
1292 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1293 DataContractError::CorruptedSerialization(
1294 "error reading created_at_core_block_height from serialized document"
1295 .to_string(),
1296 )
1297 })?)
1298 } else {
1299 None
1300 };
1301
1302 let updated_at_core_block_height = if timestamp_flags & 128 > 0 {
1303 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1304 DataContractError::CorruptedSerialization(
1305 "error reading updated_at_core_block_height from serialized document"
1306 .to_string(),
1307 )
1308 })?)
1309 } else {
1310 None
1311 };
1312
1313 let transferred_at_core_block_height = if timestamp_flags & 256 > 0 {
1314 Some(buf.read_u32::<BigEndian>().map_err(|_| {
1315 DataContractError::CorruptedSerialization(
1316 "error reading updated_at_core_block_height from serialized document"
1317 .to_string(),
1318 )
1319 })?)
1320 } else {
1321 None
1322 };
1323
1324 let price = if document_type.trade_mode().seller_sets_price() {
1327 let has_price = buf.read_u8().map_err(|_| {
1328 DataContractError::CorruptedSerialization(
1329 "error reading has price bool from serialized document".to_string(),
1330 )
1331 })?;
1332 if has_price > 0 {
1333 let price = buf.read_u64::<BigEndian>().map_err(|_| {
1334 DataContractError::CorruptedSerialization(
1335 "error reading price u64 from serialized document".to_string(),
1336 )
1337 })?;
1338 Some(price)
1339 } else {
1340 None
1341 }
1342 } else {
1343 None
1344 };
1345
1346 let mut finished_buffer = false;
1347
1348 let mut properties = document_type
1349 .properties()
1350 .iter()
1351 .filter_map(|(key, property)| {
1352 if finished_buffer {
1353 return if property.required && !property.transient {
1354 Some(Err(DataContractError::CorruptedSerialization(
1355 "required field after finished buffer".to_string(),
1356 )))
1357 } else {
1358 None
1359 };
1360 }
1361 let read_value = property
1362 .property_type
1363 .read_optionally_from(&mut buf, property.required & !property.transient);
1364
1365 match read_value {
1366 Ok(read_value) => {
1367 finished_buffer |= read_value.1;
1368 read_value.0.map(|read_value| Ok((key.clone(), read_value)))
1369 }
1370 Err(e) => Some(Err(e)),
1371 }
1372 })
1373 .collect::<Result<BTreeMap<String, Value>, DataContractError>>()?;
1374
1375 if let Some(price) = price {
1376 properties.insert(PRICE.to_string(), price.into());
1377 }
1378
1379 Ok(DocumentV0 {
1380 id: Identifier::new(id),
1381 properties,
1382 owner_id: Identifier::new(owner_id),
1383 revision,
1384 created_at,
1385 updated_at,
1386 transferred_at,
1387 created_at_block_height,
1388 updated_at_block_height,
1389 transferred_at_block_height,
1390 created_at_core_block_height,
1391 updated_at_core_block_height,
1392 transferred_at_core_block_height,
1393 creator_id,
1394 })
1395 }
1396}
1397
1398impl DocumentPlatformConversionMethodsV0 for DocumentV0 {
1399 fn serialize(
1404 &self,
1405 document_type: DocumentTypeRef,
1406 contract: &DataContract,
1407 platform_version: &PlatformVersion,
1408 ) -> Result<Vec<u8>, ProtocolError> {
1409 if matches!(contract, DataContract::V0(_))
1410 || matches!(contract.config(), DataContractConfig::V0(_))
1411 {
1412 self.serialize_v0(document_type)
1418 } else {
1419 match platform_version
1420 .dpp
1421 .document_versions
1422 .document_serialization_version
1423 .default_current_version
1424 {
1425 0 => self.serialize_v0(document_type),
1426 1 => self.serialize_v1(document_type),
1430 2 => self.serialize_v2(document_type),
1431 version => Err(ProtocolError::UnknownVersionMismatch {
1432 method: "DocumentV0::serialize".to_string(),
1433 known_versions: vec![0, 1, 2],
1434 received: version,
1435 }),
1436 }
1437 }
1438 }
1439
1440 fn serialize_specific_version(
1441 &self,
1442 document_type: DocumentTypeRef,
1443 contract: &DataContract,
1444 feature_version: FeatureVersion,
1445 ) -> Result<Vec<u8>, ProtocolError> {
1446 if (matches!(contract, DataContract::V0(_))
1447 || matches!(contract.config(), DataContractConfig::V0(_)))
1448 && feature_version != 0
1449 {
1450 return Err(ProtocolError::NotSupported("Serializing with data contract version 0 or data contract config version 0 is not supported outside of feature version 0".to_string()));
1456 };
1457 match feature_version {
1458 0 => self.serialize_v0(document_type),
1459 1 => self.serialize_v1(document_type),
1460 2 => self.serialize_v2(document_type),
1461 version => Err(ProtocolError::UnknownVersionMismatch {
1462 method: "DocumentV0::serialize".to_string(),
1463 known_versions: vec![0, 1, 2],
1464 received: version,
1465 }),
1466 }
1467 }
1468
1469 fn from_bytes(
1471 mut serialized_document: &[u8],
1472 document_type: DocumentTypeRef,
1473 platform_version: &PlatformVersion,
1474 ) -> Result<Self, ProtocolError> {
1475 let serialized_version = serialized_document.read_varint().map_err(|_| {
1476 DataContractError::DecodingDocumentError(DecodingError::new(
1477 "error reading revision from serialized document for revision".to_string(),
1478 ))
1479 })?;
1480 match serialized_version {
1481 0 => {
1482 match DocumentV0::from_bytes_v0(
1483 serialized_document,
1484 document_type,
1485 platform_version,
1486 )
1487 .map_err(ProtocolError::DataContractError)
1488 {
1489 Ok(document) => Ok(document),
1490 Err(first_err) => {
1491 match DocumentV0::from_bytes_v1(
1497 serialized_document,
1498 document_type,
1499 platform_version,
1500 ) {
1501 Ok(document_from_version_1_deserialization) => {
1502 Ok(document_from_version_1_deserialization)
1503 }
1504 Err(_) => Err(first_err),
1505 }
1506 }
1507 }
1508 }
1509 1 => DocumentV0::from_bytes_v1(serialized_document, document_type, platform_version)
1510 .map_err(ProtocolError::DataContractError),
1511 2 => DocumentV0::from_bytes_v2(serialized_document, document_type, platform_version)
1512 .map_err(ProtocolError::DataContractError),
1513 version => Err(ProtocolError::UnknownVersionMismatch {
1514 method: "Document::from_bytes (deserialization)".to_string(),
1515 known_versions: vec![0, 1, 2],
1516 received: version,
1517 }),
1518 }
1519 }
1520
1521 #[cfg(feature = "validation")]
1523 fn from_bytes_in_consensus(
1524 mut serialized_document: &[u8],
1525 document_type: DocumentTypeRef,
1526 platform_version: &PlatformVersion,
1527 ) -> Result<ConsensusValidationResult<Self>, ProtocolError> {
1528 let serialized_version = serialized_document.read_varint().map_err(|_| {
1529 DataContractError::DecodingDocumentError(DecodingError::new(
1530 "error reading revision from serialized document for revision".to_string(),
1531 ))
1532 })?;
1533 match serialized_version {
1534 0 => {
1535 match DocumentV0::from_bytes_v0(
1536 serialized_document,
1537 document_type,
1538 platform_version,
1539 ) {
1540 Ok(document) => Ok(ConsensusValidationResult::new_with_data(document)),
1541 Err(first_err) => {
1542 match DocumentV0::from_bytes_v1(
1548 serialized_document,
1549 document_type,
1550 platform_version,
1551 ) {
1552 Ok(document_from_version_1_deserialization) => {
1553 Ok(ConsensusValidationResult::new_with_data(
1554 document_from_version_1_deserialization,
1555 ))
1556 }
1557 Err(_) => Ok(ConsensusValidationResult::new_with_error(
1558 ConsensusError::BasicError(BasicError::ContractError(first_err)),
1559 )),
1560 }
1561 }
1562 }
1563 }
1564 1 => {
1565 match DocumentV0::from_bytes_v1(
1566 serialized_document,
1567 document_type,
1568 platform_version,
1569 ) {
1570 Ok(document) => Ok(ConsensusValidationResult::new_with_data(document)),
1571 Err(err) => Ok(ConsensusValidationResult::new_with_error(
1572 ConsensusError::BasicError(BasicError::ContractError(err)),
1573 )),
1574 }
1575 }
1576 2 => {
1577 match DocumentV0::from_bytes_v2(
1578 serialized_document,
1579 document_type,
1580 platform_version,
1581 ) {
1582 Ok(document) => Ok(ConsensusValidationResult::new_with_data(document)),
1583 Err(err) => Ok(ConsensusValidationResult::new_with_error(
1584 ConsensusError::BasicError(BasicError::ContractError(err)),
1585 )),
1586 }
1587 }
1588 version => Err(ProtocolError::UnknownVersionMismatch {
1589 method: "Document::from_bytes (deserialization)".to_string(),
1590 known_versions: vec![0, 1, 2],
1591 received: version,
1592 }),
1593 }
1594 }
1595}
1596
1597#[cfg(test)]
1598mod tests {
1599 use super::*;
1600 use crate::data_contract::accessors::v0::DataContractV0Getters;
1601 use crate::data_contract::document_type::random_document::CreateRandomDocument;
1602 use crate::tests::json_document::json_document_to_contract;
1603 use integer_encoding::VarInt;
1604 use platform_version::version::PlatformVersion;
1605
1606 fn dashpay_contract_and_type(
1611 platform_version: &PlatformVersion,
1612 ) -> (crate::prelude::DataContract, String) {
1613 let contract = json_document_to_contract(
1614 "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
1615 false,
1616 platform_version,
1617 )
1618 .expect("expected to load dashpay contract");
1619 (contract, "contactRequest".to_string())
1620 }
1621
1622 fn family_contract(platform_version: &PlatformVersion) -> crate::prelude::DataContract {
1623 json_document_to_contract(
1624 "../rs-drive/tests/supporting_files/contract/family/family-contract.json",
1625 false,
1626 platform_version,
1627 )
1628 .expect("expected to load family contract")
1629 }
1630
1631 fn withdrawals_contract(platform_version: &PlatformVersion) -> crate::prelude::DataContract {
1632 json_document_to_contract(
1633 "../rs-drive/tests/supporting_files/contract/withdrawals/withdrawals-contract.json",
1634 false,
1635 platform_version,
1636 )
1637 .expect("expected to load withdrawals contract")
1638 }
1639
1640 #[test]
1645 fn round_trip_serialize_v0_dashpay_contact_request() {
1646 let platform_version = PlatformVersion::first();
1647 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1648 let document_type = contract
1649 .document_type_for_name(&type_name)
1650 .expect("expected document type");
1651
1652 let document = document_type
1653 .random_document(Some(42), platform_version)
1654 .expect("expected random document");
1655
1656 let doc_v0 = match &document {
1657 crate::document::Document::V0(d) => d,
1658 };
1659
1660 let serialized = doc_v0
1661 .serialize(document_type, &contract, platform_version)
1662 .expect("serialize should succeed");
1663
1664 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1665 .expect("from_bytes should succeed");
1666
1667 assert_eq!(*doc_v0, deserialized);
1668 }
1669
1670 #[test]
1671 fn round_trip_serialize_v0_family_person() {
1672 let platform_version = PlatformVersion::first();
1673 let contract = family_contract(platform_version);
1674 let document_type = contract
1675 .document_type_for_name("person")
1676 .expect("expected person document type");
1677
1678 for seed in 0..20u64 {
1679 let document = document_type
1680 .random_document(Some(seed), platform_version)
1681 .expect("expected random document");
1682 let doc_v0 = match &document {
1683 crate::document::Document::V0(d) => d,
1684 };
1685 let serialized = doc_v0
1686 .serialize(document_type, &contract, platform_version)
1687 .expect("serialize should succeed");
1688 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1689 .expect("from_bytes should succeed");
1690 assert_eq!(*doc_v0, deserialized, "round-trip failed for seed {seed}");
1691 }
1692 }
1693
1694 #[test]
1695 fn round_trip_serialize_v1_family_person() {
1696 let platform_version =
1698 PlatformVersion::get(9).unwrap_or_else(|_| PlatformVersion::latest());
1699
1700 let contract = json_document_to_contract(
1703 "../rs-drive/tests/supporting_files/contract/family/family-contract.json",
1704 false,
1705 platform_version,
1706 )
1707 .expect("expected to load family contract");
1708
1709 let document_type = contract
1710 .document_type_for_name("person")
1711 .expect("expected person document type");
1712
1713 if matches!(&contract, DataContract::V0(_)) {
1716 let document = document_type
1718 .random_document(Some(99), platform_version)
1719 .expect("expected random document");
1720 let doc_v0 = match &document {
1721 crate::document::Document::V0(d) => d,
1722 };
1723 let serialized = doc_v0
1724 .serialize(document_type, &contract, platform_version)
1725 .expect("serialize should succeed");
1726 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1727 .expect("from_bytes should succeed");
1728 assert_eq!(*doc_v0, deserialized);
1729 } else {
1730 let document = document_type
1731 .random_document(Some(99), platform_version)
1732 .expect("expected random document");
1733 let doc_v0 = match &document {
1734 crate::document::Document::V0(d) => d,
1735 };
1736 let serialized = doc_v0
1737 .serialize(document_type, &contract, platform_version)
1738 .expect("serialize should succeed");
1739 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1740 .expect("from_bytes should succeed");
1741 assert_eq!(*doc_v0, deserialized);
1742 }
1743 }
1744
1745 #[test]
1746 fn round_trip_serialize_v2_latest_platform() {
1747 let platform_version = PlatformVersion::latest();
1748 let contract = json_document_to_contract(
1749 "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
1750 false,
1751 platform_version,
1752 )
1753 .expect("expected to load dashpay contract");
1754
1755 let document_type = contract
1756 .document_type_for_name("contactRequest")
1757 .expect("expected contactRequest document type");
1758
1759 let document = document_type
1760 .random_document(Some(7), platform_version)
1761 .expect("expected random document");
1762 let doc_v0 = match &document {
1763 crate::document::Document::V0(d) => d,
1764 };
1765 let serialized = doc_v0
1766 .serialize(document_type, &contract, platform_version)
1767 .expect("serialize should succeed");
1768 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1769 .expect("from_bytes should succeed");
1770 assert_eq!(*doc_v0, deserialized);
1771 }
1772
1773 #[test]
1774 fn round_trip_withdrawals_document() {
1775 let platform_version = PlatformVersion::latest();
1776 let contract = withdrawals_contract(platform_version);
1777 let document_type = contract
1778 .document_type_for_name("withdrawal")
1779 .expect("expected withdrawal document type");
1780
1781 let document = document_type
1782 .random_document(Some(55), platform_version)
1783 .expect("expected random document");
1784 let doc_v0 = match &document {
1785 crate::document::Document::V0(d) => d,
1786 };
1787 let serialized = doc_v0
1788 .serialize(document_type, &contract, platform_version)
1789 .expect("serialize should succeed");
1790 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
1791 .expect("from_bytes should succeed");
1792 assert_eq!(*doc_v0, deserialized);
1793 }
1794
1795 #[test]
1800 fn serialize_specific_version_v0_produces_version_0_prefix() {
1801 let platform_version = PlatformVersion::first();
1802 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1803 let document_type = contract
1804 .document_type_for_name(&type_name)
1805 .expect("expected document type");
1806
1807 let document = document_type
1808 .random_document(Some(1), platform_version)
1809 .expect("expected random document");
1810 let doc_v0 = match &document {
1811 crate::document::Document::V0(d) => d,
1812 };
1813
1814 let serialized = doc_v0
1815 .serialize_specific_version(document_type, &contract, 0)
1816 .expect("serialize_specific_version v0 should succeed");
1817
1818 let (version, _) = u64::decode_var(&serialized).expect("expected varint");
1820 assert_eq!(version, 0, "serialization version prefix should be 0");
1821 }
1822
1823 #[test]
1824 fn serialize_specific_version_rejects_v1_for_v0_contract() {
1825 let platform_version = PlatformVersion::first();
1826 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1827
1828 if matches!(&contract, DataContract::V0(_)) {
1830 let document_type = contract
1831 .document_type_for_name(&type_name)
1832 .expect("expected document type");
1833
1834 let document = document_type
1835 .random_document(Some(1), platform_version)
1836 .expect("expected random document");
1837 let doc_v0 = match &document {
1838 crate::document::Document::V0(d) => d,
1839 };
1840
1841 let result = doc_v0.serialize_specific_version(document_type, &contract, 1);
1842 assert!(
1843 result.is_err(),
1844 "V0 contract should reject serialize_specific_version with feature_version != 0"
1845 );
1846 }
1847 }
1848
1849 #[test]
1850 fn serialize_specific_version_unknown_version_returns_error() {
1851 let platform_version = PlatformVersion::latest();
1852 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1853 let document_type = contract
1854 .document_type_for_name(&type_name)
1855 .expect("expected document type");
1856
1857 let document = document_type
1858 .random_document(Some(1), platform_version)
1859 .expect("expected random document");
1860 let doc_v0 = match &document {
1861 crate::document::Document::V0(d) => d,
1862 };
1863
1864 let result = doc_v0.serialize_specific_version(document_type, &contract, 255);
1865 assert!(
1866 result.is_err(),
1867 "unknown feature version should produce an error"
1868 );
1869 match result.unwrap_err() {
1873 ProtocolError::UnknownVersionMismatch { received, .. } => {
1874 assert_eq!(received, 255);
1875 }
1876 ProtocolError::NotSupported(_) => {
1877 }
1879 other => panic!(
1880 "expected UnknownVersionMismatch or NotSupported, got {:?}",
1881 other
1882 ),
1883 }
1884 }
1885
1886 #[test]
1891 fn from_bytes_v0_rejects_too_small_buffer() {
1892 let platform_version = PlatformVersion::first();
1893 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1894 let document_type = contract
1895 .document_type_for_name(&type_name)
1896 .expect("expected document type");
1897
1898 let mut small_buf = 0u64.encode_var_vec();
1900 small_buf.extend_from_slice(&[0u8; 10]);
1901
1902 let result = DocumentV0::from_bytes(&small_buf, document_type, platform_version);
1903 assert!(
1904 result.is_err(),
1905 "buffer shorter than 64 bytes after version prefix should fail"
1906 );
1907 }
1908
1909 #[test]
1910 fn from_bytes_empty_buffer_fails() {
1911 let platform_version = PlatformVersion::first();
1912 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1913 let document_type = contract
1914 .document_type_for_name(&type_name)
1915 .expect("expected document type");
1916
1917 let result = DocumentV0::from_bytes(&[], document_type, platform_version);
1918 assert!(result.is_err(), "empty buffer should fail deserialization");
1919 }
1920
1921 #[test]
1922 fn from_bytes_unknown_serialization_version_fails() {
1923 let platform_version = PlatformVersion::first();
1924 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1925 let document_type = contract
1926 .document_type_for_name(&type_name)
1927 .expect("expected document type");
1928
1929 let mut buf = 200u64.encode_var_vec();
1931 buf.extend_from_slice(&[0u8; 100]); let result = DocumentV0::from_bytes(&buf, document_type, platform_version);
1934 assert!(result.is_err(), "unknown version should be rejected");
1935 match result.unwrap_err() {
1936 ProtocolError::UnknownVersionMismatch { received, .. } => {
1937 assert_eq!(received, 200);
1938 }
1939 other => panic!("expected UnknownVersionMismatch, got {:?}", other),
1940 }
1941 }
1942
1943 #[test]
1944 fn from_bytes_truncated_after_ids_fails() {
1945 let platform_version = PlatformVersion::first();
1946 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1947 let document_type = contract
1948 .document_type_for_name(&type_name)
1949 .expect("expected document type");
1950
1951 let mut buf = 0u64.encode_var_vec();
1954 buf.extend_from_slice(&[0xAA; 64]); let result = DocumentV0::from_bytes(&buf, document_type, platform_version);
1957 assert!(
1958 result.is_err(),
1959 "truncated buffer after ids should fail deserialization"
1960 );
1961 }
1962
1963 #[test]
1968 fn serialization_starts_with_correct_version_varint() {
1969 let platform_version = PlatformVersion::first();
1970 let (contract, type_name) = dashpay_contract_and_type(platform_version);
1971 let document_type = contract
1972 .document_type_for_name(&type_name)
1973 .expect("expected document type");
1974
1975 let document = document_type
1976 .random_document(Some(100), platform_version)
1977 .expect("expected random document");
1978 let doc_v0 = match &document {
1979 crate::document::Document::V0(d) => d,
1980 };
1981
1982 let bytes = doc_v0
1984 .serialize_v0(document_type)
1985 .expect("serialize_v0 should succeed");
1986 let (ver, _) = u64::decode_var(&bytes).expect("varint decode");
1987 assert_eq!(ver, 0);
1988
1989 let bytes = doc_v0
1991 .serialize_v1(document_type)
1992 .expect("serialize_v1 should succeed");
1993 let (ver, _) = u64::decode_var(&bytes).expect("varint decode");
1994 assert_eq!(ver, 1);
1995
1996 let bytes = doc_v0
1998 .serialize_v2(document_type)
1999 .expect("serialize_v2 should succeed");
2000 let (ver, _) = u64::decode_var(&bytes).expect("varint decode");
2001 assert_eq!(ver, 2);
2002 }
2003
2004 #[test]
2005 fn serialized_id_and_owner_id_are_embedded_after_version() {
2006 let platform_version = PlatformVersion::first();
2007 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2008 let document_type = contract
2009 .document_type_for_name(&type_name)
2010 .expect("expected document type");
2011
2012 let document = document_type
2013 .random_document(Some(42), platform_version)
2014 .expect("expected random document");
2015 let doc_v0 = match &document {
2016 crate::document::Document::V0(d) => d,
2017 };
2018
2019 let bytes = doc_v0
2020 .serialize_v0(document_type)
2021 .expect("serialize should succeed");
2022
2023 let (_, varint_len) = u64::decode_var(&bytes).expect("varint decode");
2025 let after_version = &bytes[varint_len..];
2026
2027 assert_eq!(
2029 &after_version[..32],
2030 doc_v0.id.as_slice(),
2031 "id should be at offset after version"
2032 );
2033 assert_eq!(
2035 &after_version[32..64],
2036 doc_v0.owner_id.as_slice(),
2037 "owner_id should follow id"
2038 );
2039 }
2040
2041 #[test]
2046 fn serialization_is_deterministic() {
2047 let platform_version = PlatformVersion::first();
2048 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2049 let document_type = contract
2050 .document_type_for_name(&type_name)
2051 .expect("expected document type");
2052
2053 let document = document_type
2054 .random_document(Some(99), platform_version)
2055 .expect("expected random document");
2056 let doc_v0 = match &document {
2057 crate::document::Document::V0(d) => d,
2058 };
2059
2060 let bytes1 = doc_v0
2061 .serialize(document_type, &contract, platform_version)
2062 .expect("first serialize");
2063 let bytes2 = doc_v0
2064 .serialize(document_type, &contract, platform_version)
2065 .expect("second serialize");
2066 assert_eq!(bytes1, bytes2, "serialization must be deterministic");
2067 }
2068
2069 #[test]
2074 fn round_trip_many_random_documents() {
2075 let platform_version = PlatformVersion::first();
2076 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2077 let document_type = contract
2078 .document_type_for_name(&type_name)
2079 .expect("expected document type");
2080
2081 for seed in 0..50u64 {
2082 let document = document_type
2083 .random_document(Some(seed), platform_version)
2084 .expect("expected random document");
2085 let doc_v0 = match &document {
2086 crate::document::Document::V0(d) => d,
2087 };
2088 let serialized = doc_v0
2089 .serialize(document_type, &contract, platform_version)
2090 .expect("serialize should succeed");
2091 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
2092 .expect("from_bytes should succeed");
2093 assert_eq!(*doc_v0, deserialized, "round-trip mismatch for seed {seed}");
2094 }
2095 }
2096
2097 #[cfg(feature = "validation")]
2102 #[test]
2103 fn from_bytes_in_consensus_valid_data_returns_valid_result() {
2104 let platform_version = PlatformVersion::first();
2105 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2106 let document_type = contract
2107 .document_type_for_name(&type_name)
2108 .expect("expected document type");
2109
2110 let document = document_type
2111 .random_document(Some(77), platform_version)
2112 .expect("expected random document");
2113 let doc_v0 = match &document {
2114 crate::document::Document::V0(d) => d,
2115 };
2116 let serialized = doc_v0
2117 .serialize(document_type, &contract, platform_version)
2118 .expect("serialize should succeed");
2119
2120 let result =
2121 DocumentV0::from_bytes_in_consensus(&serialized, document_type, platform_version)
2122 .expect("from_bytes_in_consensus should not return ProtocolError");
2123
2124 assert!(result.is_valid(), "consensus result should be valid");
2125 let deserialized = result.into_data().expect("should have data");
2126 assert_eq!(*doc_v0, deserialized);
2127 }
2128
2129 #[cfg(feature = "validation")]
2130 #[test]
2131 fn from_bytes_in_consensus_invalid_data_returns_consensus_error() {
2132 let platform_version = PlatformVersion::first();
2133 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2134 let document_type = contract
2135 .document_type_for_name(&type_name)
2136 .expect("expected document type");
2137
2138 let mut buf = 0u64.encode_var_vec();
2140 buf.extend_from_slice(&[0u8; 10]);
2141
2142 let result = DocumentV0::from_bytes_in_consensus(&buf, document_type, platform_version)
2143 .expect("should not return ProtocolError for consensus-level decode");
2144
2145 assert!(
2146 !result.is_valid(),
2147 "consensus result should contain errors for malformed data"
2148 );
2149 }
2150
2151 #[cfg(feature = "validation")]
2152 #[test]
2153 fn from_bytes_in_consensus_unknown_version_returns_protocol_error() {
2154 let platform_version = PlatformVersion::first();
2155 let (contract, type_name) = dashpay_contract_and_type(platform_version);
2156 let document_type = contract
2157 .document_type_for_name(&type_name)
2158 .expect("expected document type");
2159
2160 let mut buf = 200u64.encode_var_vec();
2161 buf.extend_from_slice(&[0u8; 100]);
2162
2163 let result = DocumentV0::from_bytes_in_consensus(&buf, document_type, platform_version);
2164 assert!(
2165 result.is_err(),
2166 "unknown version should produce a ProtocolError, not a consensus error"
2167 );
2168 }
2169
2170 #[test]
2175 fn deserialize_known_withdrawal_bytes() {
2176 let platform_version = PlatformVersion::latest();
2177 let contract = withdrawals_contract(platform_version);
2178
2179 let document_type = contract
2180 .document_type_for_name("withdrawal")
2181 .expect("expected withdrawal document type");
2182
2183 let serialized = hex::decode(
2185 "010053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9\
2186 fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de285601\
2187 00030000019782b96d140000019782b96d14000000000002540be40000000001\
2188 001976a9149e3292d2612122d81613fdb893dd36a04df3355588ac00",
2189 )
2190 .expect("expected valid hex");
2191
2192 let deserialized = DocumentV0::from_bytes(&serialized, document_type, platform_version)
2193 .expect("expected deserialization to succeed");
2194
2195 assert_eq!(
2197 hex::encode(deserialized.id.as_slice()),
2198 "0053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9"
2199 );
2200 assert_eq!(
2201 hex::encode(deserialized.owner_id.as_slice()),
2202 "fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de2856"
2203 );
2204 assert_eq!(deserialized.revision, Some(1));
2205 assert_eq!(deserialized.created_at, Some(1750244879636));
2206 assert_eq!(deserialized.updated_at, Some(1750244879636));
2207 }
2208}