dpp/data_contract/created_data_contract/
mod.rs1mod fields;
2pub mod v0;
3
4use crate::data_contract::created_data_contract::v0::{
5 CreatedDataContractInSerializationFormatV0, CreatedDataContractV0,
6};
7use crate::prelude::{DataContract, IdentityNonce};
8use crate::version::PlatformVersion;
9use crate::ProtocolError;
10use bincode::{Decode, DecodeUntrusted, Encode};
11use derive_more::From;
12
13use crate::data_contract::serialized_version::DataContractInSerializationFormat;
14use crate::serialization::{
15 PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted,
16 PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted,
17 PlatformSerializableWithPlatformVersion,
18};
19use crate::ProtocolError::{PlatformDeserializationError, PlatformSerializationError};
20use platform_version::TryIntoPlatformVersioned;
21
22#[derive(Clone, Debug, PartialEq, From)]
28pub enum CreatedDataContract {
29 V0(CreatedDataContractV0),
30}
31
32#[derive(Clone, Debug, Encode, Decode, From, DecodeUntrusted)]
33pub enum CreatedDataContractInSerializationFormat {
34 V0(CreatedDataContractInSerializationFormatV0),
35}
36
37impl PlatformSerializableWithPlatformVersion for CreatedDataContract {
38 type Error = ProtocolError;
39
40 fn serialize_to_bytes_with_platform_version(
41 &self,
42 platform_version: &PlatformVersion,
43 ) -> Result<Vec<u8>, ProtocolError> {
44 self.clone()
45 .serialize_consume_to_bytes_with_platform_version(platform_version)
46 }
47
48 fn serialize_consume_to_bytes_with_platform_version(
49 self,
50 platform_version: &PlatformVersion,
51 ) -> Result<Vec<u8>, ProtocolError> {
52 let (data_contract, identity_nonce) = self.data_contract_and_identity_nonce();
53 let data_contract_serialization_format: DataContractInSerializationFormat =
54 data_contract.try_into_platform_versioned(platform_version)?;
55 let created_data_contract_in_serialization_format = match platform_version
56 .dpp
57 .contract_versions
58 .created_data_contract_structure
59 {
60 0 => Ok(CreatedDataContractInSerializationFormat::V0(
61 CreatedDataContractInSerializationFormatV0 {
62 data_contract: data_contract_serialization_format,
63 identity_nonce,
64 },
65 )),
66 version => Err(ProtocolError::UnknownVersionMismatch {
67 method: "CreatedDataContract::serialize_to_bytes_with_platform_version".to_string(),
68 known_versions: vec![0],
69 received: version,
70 }),
71 }?;
72 let config = bincode::config::standard()
73 .with_big_endian()
74 .with_no_limit();
75 bincode::encode_to_vec(created_data_contract_in_serialization_format, config).map_err(|e| {
76 PlatformSerializationError(format!("unable to serialize CreatedDataContract: {}", e))
77 })
78 }
79}
80
81impl CreatedDataContract {
82 fn from_serialization_format(
86 created_data_contract_in_serialization_format: CreatedDataContractInSerializationFormat,
87 full_validation: bool,
88 platform_version: &PlatformVersion,
89 method: &str,
90 ) -> Result<Self, ProtocolError> {
91 let (data_contract_in_serialization_format, identity_nonce) =
92 created_data_contract_in_serialization_format.data_contract_and_identity_nonce_owned();
93 let data_contract = DataContract::try_from_platform_versioned(
94 data_contract_in_serialization_format,
95 full_validation,
96 &mut vec![],
97 platform_version,
98 )?;
99 match platform_version
100 .dpp
101 .contract_versions
102 .created_data_contract_structure
103 {
104 0 => Ok(CreatedDataContract::V0(CreatedDataContractV0 {
105 data_contract,
106 identity_nonce,
107 })),
108 version => Err(ProtocolError::UnknownVersionMismatch {
109 method: method.to_string(),
110 known_versions: vec![0],
111 received: version,
112 }),
113 }
114 }
115}
116
117impl PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted
118 for CreatedDataContract
119{
120 fn versioned_deserialize_trusted(
121 data: &[u8],
122 full_validation: bool,
123 platform_version: &PlatformVersion,
124 ) -> Result<Self, ProtocolError>
125 where
126 Self: Sized,
127 {
128 let config = bincode::config::standard()
129 .with_big_endian()
130 .with_no_limit();
131 let created_data_contract_in_serialization_format: CreatedDataContractInSerializationFormat =
132 bincode::borrow_decode_from_slice(data, config)
133 .map_err(|e| {
134 PlatformDeserializationError(format!(
135 "unable to deserialize DataContract: {}",
136 e
137 ))
138 })?
139 .0;
140 Self::from_serialization_format(
141 created_data_contract_in_serialization_format,
142 full_validation,
143 platform_version,
144 "CreatedDataContract::versioned_deserialize_trusted",
145 )
146 }
147}
148
149impl PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted
150 for CreatedDataContract
151{
152 fn versioned_deserialize_untrusted(
153 data: &[u8],
154 full_validation: bool,
155 platform_version: &PlatformVersion,
156 ) -> Result<Self, ProtocolError>
157 where
158 Self: Sized,
159 {
160 let config = bincode::config::standard()
161 .with_big_endian()
162 .with_no_limit();
163 let created_data_contract_in_serialization_format: CreatedDataContractInSerializationFormat =
164 bincode::borrow_decode_from_slice_untrusted(data, config)
165 .map_err(|e| {
166 PlatformDeserializationError(format!(
167 "unable to deserialize DataContract: {}",
168 e
169 ))
170 })?
171 .0;
172 Self::from_serialization_format(
173 created_data_contract_in_serialization_format,
174 full_validation,
175 platform_version,
176 "CreatedDataContract::versioned_deserialize_untrusted",
177 )
178 }
179}
180
181impl From<CreatedDataContract> for DataContract {
182 fn from(value: CreatedDataContract) -> Self {
183 match value {
184 CreatedDataContract::V0(created_data_contract) => created_data_contract.data_contract,
185 }
186 }
187}
188
189impl CreatedDataContract {
190 pub fn data_contract_owned(self) -> DataContract {
191 match self {
192 CreatedDataContract::V0(v0) => v0.data_contract,
193 }
194 }
195
196 pub fn data_contract_and_identity_nonce(self) -> (DataContract, IdentityNonce) {
197 match self {
198 CreatedDataContract::V0(v0) => (v0.data_contract, v0.identity_nonce),
199 }
200 }
201
202 pub fn data_contract(&self) -> &DataContract {
203 match self {
204 CreatedDataContract::V0(v0) => &v0.data_contract,
205 }
206 }
207
208 pub fn data_contract_mut(&mut self) -> &mut DataContract {
209 match self {
210 CreatedDataContract::V0(v0) => &mut v0.data_contract,
211 }
212 }
213
214 pub fn identity_nonce(&self) -> IdentityNonce {
215 match self {
216 CreatedDataContract::V0(v0) => v0.identity_nonce,
217 }
218 }
219
220 #[cfg(test)]
221 pub fn set_identity_nonce(&mut self, identity_nonce: IdentityNonce) {
222 match self {
223 CreatedDataContract::V0(v0) => v0.identity_nonce = identity_nonce,
224 }
225 }
226
227 pub fn from_contract_and_identity_nonce(
228 data_contract: DataContract,
229 identity_nonce: IdentityNonce,
230 platform_version: &PlatformVersion,
231 ) -> Result<CreatedDataContract, ProtocolError> {
232 match platform_version
233 .dpp
234 .contract_versions
235 .created_data_contract_structure
236 {
237 0 => Ok(CreatedDataContractV0 {
238 data_contract,
239 identity_nonce,
240 }
241 .into()),
242 version => Err(ProtocolError::UnknownVersionMismatch {
243 method: "CreatedDataContract::from_contract_and_entropy".to_string(),
244 known_versions: vec![0],
245 received: version,
246 }),
247 }
248 }
249}
250
251impl CreatedDataContractInSerializationFormat {
252 pub fn data_contract_and_identity_nonce_owned(
253 self,
254 ) -> (DataContractInSerializationFormat, IdentityNonce) {
255 match self {
256 CreatedDataContractInSerializationFormat::V0(v0) => {
257 (v0.data_contract, v0.identity_nonce)
258 }
259 }
260 }
261}
262
263#[cfg(test)]
264mod tests {
265 use super::*;
266 use crate::data_contract::accessors::v0::{DataContractV0Getters, DataContractV0Setters};
267 use crate::tests::fixtures::get_data_contract_fixture;
268 use crate::version::PlatformVersion;
269
270 fn sample_created() -> CreatedDataContract {
271 get_data_contract_fixture(None, 42, 1)
272 }
273
274 #[test]
279 fn from_contract_and_identity_nonce_wraps_v0() {
280 let platform_version = PlatformVersion::latest();
281 let created = sample_created();
282 let contract = created.data_contract().clone();
283 let wrapped = CreatedDataContract::from_contract_and_identity_nonce(
284 contract.clone(),
285 99,
286 platform_version,
287 )
288 .expect("should wrap successfully on latest version");
289 assert_eq!(wrapped.identity_nonce(), 99);
290 assert_eq!(wrapped.data_contract().id(), contract.id());
291 assert!(matches!(wrapped, CreatedDataContract::V0(_)));
293 }
294
295 #[test]
296 fn identity_nonce_getter_returns_underlying_value() {
297 let created = sample_created();
298 assert_eq!(created.identity_nonce(), 42);
299 }
300
301 #[test]
302 fn data_contract_getter_returns_same_id() {
303 let created = sample_created();
304 let via_getter = created.data_contract();
305 let expected_id = via_getter.id();
306 let owned = created.clone().data_contract_owned();
308 assert_eq!(owned.id(), expected_id);
309 }
310
311 #[test]
312 fn data_contract_mut_allows_mutation() {
313 let mut created = sample_created();
314 let original_id = created.data_contract().id();
315 let new_id = platform_value::Identifier::from([7u8; 32]);
316 created.data_contract_mut().set_id(new_id);
318 assert_ne!(created.data_contract().id(), original_id);
319 assert_eq!(created.data_contract().id(), new_id);
320 }
321
322 #[test]
323 fn data_contract_and_identity_nonce_extracts_both() {
324 let created = sample_created();
325 let (contract, nonce) = created.clone().data_contract_and_identity_nonce();
326 assert_eq!(nonce, 42);
327 assert_eq!(contract.id(), created.data_contract().id());
328 }
329
330 #[test]
331 fn set_identity_nonce_updates_value() {
332 let mut created = sample_created();
333 created.set_identity_nonce(777);
334 assert_eq!(created.identity_nonce(), 777);
335 }
336
337 #[test]
342 fn from_created_to_data_contract() {
343 let created = sample_created();
344 let expected_id = created.data_contract().id();
345 let dc: DataContract = created.into();
346 assert_eq!(dc.id(), expected_id);
347 }
348
349 #[test]
356 fn serialize_roundtrip_via_platform_version() {
357 let platform_version = PlatformVersion::latest();
358 let created = sample_created();
359 let bytes = created
360 .serialize_to_bytes_with_platform_version(platform_version)
361 .expect("serialize should succeed");
362 assert!(!bytes.is_empty());
363
364 let restored =
365 CreatedDataContract::versioned_deserialize_untrusted(&bytes, false, platform_version)
366 .expect("deserialize should succeed");
367 assert_eq!(restored.identity_nonce(), created.identity_nonce());
368 assert_eq!(restored.data_contract().id(), created.data_contract().id());
369 }
370
371 #[test]
372 fn serialize_consume_to_bytes_matches_clone_path() {
373 let platform_version = PlatformVersion::latest();
374 let created = sample_created();
375 let via_ref = created
376 .serialize_to_bytes_with_platform_version(platform_version)
377 .expect("ref serialize should succeed");
378 let via_consume = created
379 .clone()
380 .serialize_consume_to_bytes_with_platform_version(platform_version)
381 .expect("consume serialize should succeed");
382 assert_eq!(via_ref, via_consume);
385 }
386
387 #[test]
388 fn versioned_deserialize_rejects_garbage() {
389 let platform_version = PlatformVersion::latest();
390 let garbage = vec![0xFFu8; 16];
391 let err =
392 CreatedDataContract::versioned_deserialize_untrusted(&garbage, false, platform_version)
393 .expect_err("random bytes should not deserialize");
394 match err {
395 ProtocolError::PlatformDeserializationError(_) => {}
396 other => panic!("expected PlatformDeserializationError, got {other:?}"),
397 }
398 }
399
400 #[test]
401 fn versioned_deserialize_rejects_empty_input() {
402 let platform_version = PlatformVersion::latest();
403 let err =
404 CreatedDataContract::versioned_deserialize_untrusted(&[], false, platform_version)
405 .expect_err("empty input should not deserialize");
406 assert!(matches!(
407 err,
408 ProtocolError::PlatformDeserializationError(_)
409 ));
410 }
411
412 #[test]
413 fn versioned_deserialize_trusted_agrees_with_untrusted() {
414 let platform_version = PlatformVersion::latest();
415 let created = sample_created();
416 let bytes = created
417 .serialize_to_bytes_with_platform_version(platform_version)
418 .expect("serialize should succeed");
419
420 let trusted =
421 CreatedDataContract::versioned_deserialize_trusted(&bytes, false, platform_version)
422 .expect("trusted deserialize should succeed");
423 let untrusted =
424 CreatedDataContract::versioned_deserialize_untrusted(&bytes, false, platform_version)
425 .expect("untrusted deserialize should succeed");
426 assert_eq!(trusted, untrusted);
427 assert_eq!(trusted.identity_nonce(), created.identity_nonce());
428 assert_eq!(trusted.data_contract().id(), created.data_contract().id());
429 }
430
431 #[test]
432 fn versioned_deserialize_trusted_rejects_garbage_and_empty_input() {
433 let platform_version = PlatformVersion::latest();
434 for input in [vec![0xFFu8; 16], vec![]] {
435 let err =
436 CreatedDataContract::versioned_deserialize_trusted(&input, false, platform_version)
437 .expect_err("malformed input should not deserialize");
438 assert!(matches!(
439 err,
440 ProtocolError::PlatformDeserializationError(_)
441 ));
442 }
443 }
444
445 #[test]
450 fn in_serialization_format_data_contract_and_identity_nonce_owned() {
451 let platform_version = PlatformVersion::latest();
452 let created = sample_created();
453 let bytes = created
456 .clone()
457 .serialize_consume_to_bytes_with_platform_version(platform_version)
458 .expect("serialize");
459 let config = bincode::config::standard()
460 .with_big_endian()
461 .with_no_limit();
462 let (decoded, _consumed) = bincode::borrow_decode_from_slice_untrusted::<
463 CreatedDataContractInSerializationFormat,
464 _,
465 >(&bytes, config)
466 .expect("raw bincode decode should succeed");
467 let (_contract_fmt, nonce) = decoded.data_contract_and_identity_nonce_owned();
468 assert_eq!(nonce, created.identity_nonce());
469 }
470
471 #[test]
477 fn clone_and_equality() {
478 let a = sample_created();
479 let b = a.clone();
480 assert_eq!(a, b);
481 }
482
483 #[test]
484 fn different_nonce_breaks_equality() {
485 let a = sample_created();
486 let mut b = a.clone();
487 b.set_identity_nonce(a.identity_nonce().wrapping_add(1));
488 assert_ne!(a, b);
489 }
490}