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