dpp/document/serialization_traits/platform_serialization_conversion/
mod.rs

1pub(in crate::document) mod deserialize;
2pub(in crate::document) mod serialize;
3mod v0;
4
5use crate::data_contract::document_type::DocumentTypeRef;
6use crate::data_contract::DataContract;
7use crate::document::{Document, DocumentV0};
8#[cfg(feature = "validation")]
9use crate::prelude::ConsensusValidationResult;
10use crate::ProtocolError;
11use platform_version::version::{FeatureVersion, PlatformVersion};
12pub use v0::*;
13
14impl DocumentPlatformConversionMethodsV0 for Document {
15    /// Serializes the document.
16    ///
17    /// The serialization of a document follows the pattern:
18    /// id 32 bytes + owner_id 32 bytes + encoded values byte arrays
19    fn serialize(
20        &self,
21        document_type: DocumentTypeRef,
22        data_contract: &DataContract,
23        platform_version: &PlatformVersion,
24    ) -> Result<Vec<u8>, ProtocolError> {
25        match self {
26            Document::V0(document_v0) => {
27                document_v0.serialize(document_type, data_contract, platform_version)
28            }
29        }
30    }
31
32    fn serialize_specific_version(
33        &self,
34        document_type: DocumentTypeRef,
35        data_contract: &DataContract,
36        feature_version: FeatureVersion,
37    ) -> Result<Vec<u8>, ProtocolError> {
38        match self {
39            Document::V0(document_v0) => document_v0.serialize_specific_version(
40                document_type,
41                data_contract,
42                feature_version,
43            ),
44        }
45    }
46
47    /// Reads a serialized document and creates a Document from it.
48    fn from_bytes(
49        serialized_document: &[u8],
50        document_type: DocumentTypeRef,
51        platform_version: &PlatformVersion,
52    ) -> Result<Self, ProtocolError> {
53        match platform_version
54            .dpp
55            .document_versions
56            .document_structure_version
57        {
58            0 => Ok(
59                DocumentV0::from_bytes(serialized_document, document_type, platform_version)?
60                    .into(),
61            ),
62            version => Err(ProtocolError::UnknownVersionMismatch {
63                method: "Document::from_bytes".to_string(),
64                known_versions: vec![0],
65                received: version,
66            }),
67        }
68    }
69
70    #[cfg(feature = "validation")]
71    fn from_bytes_in_consensus(
72        serialized_document: &[u8],
73        document_type: DocumentTypeRef,
74        platform_version: &PlatformVersion,
75    ) -> Result<ConsensusValidationResult<Self>, ProtocolError>
76    where
77        Self: Sized,
78    {
79        match platform_version
80            .dpp
81            .document_versions
82            .document_structure_version
83        {
84            0 => Ok(DocumentV0::from_bytes_in_consensus(
85                serialized_document,
86                document_type,
87                platform_version,
88            )?
89            .map(|document_v0| document_v0.into())),
90            version => Err(ProtocolError::UnknownVersionMismatch {
91                method: "Document::from_bytes_in_consensus".to_string(),
92                known_versions: vec![0],
93                received: version,
94            }),
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::data_contract::accessors::v0::DataContractV0Getters;
102    use crate::data_contract::document_type::random_document::CreateRandomDocument;
103    use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0;
104    use crate::document::Document;
105    use crate::tests::json_document::json_document_to_contract;
106    use platform_version::version::PlatformVersion;
107
108    #[test]
109    fn test_serialization() {
110        let platform_version = PlatformVersion::first();
111        let contract = json_document_to_contract(
112            "../rs-drive/tests/supporting_files/contract/dashpay/dashpay-contract.json",
113            false,
114            platform_version,
115        )
116        .expect("expected to get dashpay contract");
117
118        let document_type = contract
119            .document_type_for_name("contactRequest")
120            .expect("expected to get profile document type");
121        let document = document_type
122            .random_document(Some(3333), platform_version)
123            .expect("expected to get a random document");
124
125        let serialized_document = document
126            .serialize(document_type, &contract, platform_version)
127            .expect("expected to serialize");
128
129        let deserialized_document = Document::from_bytes(
130            serialized_document.as_slice(),
131            document_type,
132            platform_version,
133        )
134        .expect("expected to deserialize a document");
135        assert_eq!(document, deserialized_document);
136        for _i in 0..10000 {
137            let document = document_type
138                .random_document(Some(3333), platform_version)
139                .expect("expected to get a random document");
140            document
141                .serialize(document_type, &contract, platform_version)
142                .expect("expected to serialize consume");
143        }
144    }
145
146    #[test]
147    fn test_withdrawal_deserialization() {
148        let platform_version = PlatformVersion::latest();
149        let contract = json_document_to_contract(
150            "../rs-drive/tests/supporting_files/contract/withdrawals/withdrawals-contract.json",
151            false,
152            platform_version,
153        )
154        .expect("expected to get withdrawals contract");
155
156        //  Header (65 bytes)
157        //
158        //   - 01 - Document Version (1 byte): Value = 1
159        //   - 0053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9 - Document ID (32 bytes)
160        //   - fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de2856 - Owner ID (32 bytes)
161        //
162        //   Metadata (19 bytes)
163        //
164        //   - 01 - Revision (1 byte): Value = 1
165        //   - 0003 - Bitwise flags (2 bytes): Binary 0000000000000011
166        //     - Bit 0 set: createdAt present
167        //     - Bit 1 set: updatedAt present
168        //   - 0000019782b96d14 - createdAt timestamp (8 bytes): 1750244879636
169        //   - 0000019782b96d14 - updatedAt timestamp (8 bytes): 1750244879636
170        //
171        //   User Properties (42 bytes)
172        //
173        //   - 00 - transactionIndex marker (1 byte): 0 = absent
174        //   - 00 - transactionSignHeight marker (1 byte): 0 = absent
175        //   - 00000002540be400 - amount (8 bytes): 10000000000 duffs (100 DASH)
176        //   - 00000001 - coreFeePerByte (4 bytes): 1 duff/byte
177        //   - 00 - pooling (1 byte): 0 (Never pool)
178        //   - 19 - outputScript length (1 byte varint): 25 bytes
179        //   - 76a9149e3292d2612122d81613fdb893dd36a04df3355588ac - outputScript data (25 bytes)
180        //     - This is a standard Bitcoin P2PKH script:
181        //         - 76 = OP_DUP
182        //       - a9 = OP_HASH160
183        //       - 14 = Push 20 bytes
184        //       - 9e3292d2612122d81613fdb893dd36a04df33555 = recipient's pubkey hash
185        //       - 88 = OP_EQUALVERIFY
186        //       - ac = OP_CHECKSIG
187        //   - 00 - status (1 byte): 0 (QUEUED)
188
189        let document_type = contract
190            .document_type_for_name("withdrawal")
191            .expect("expected to get profile document type");
192        let serialized_document = hex::decode("010053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de28560100030000019782b96d140000019782b96d14000000000002540be40000000001001976a9149e3292d2612122d81613fdb893dd36a04df3355588ac00").expect("expected document hex bytes");
193
194        let _deserialized_document = Document::from_bytes(
195            serialized_document.as_slice(),
196            document_type,
197            platform_version,
198        )
199        .expect("expected to deserialize a document");
200    }
201}