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