Skip to main content

dpp/serialization/
serialization_traits.rs

1#[cfg(any(
2    feature = "message-signature-verification",
3    feature = "message-signing"
4))]
5use crate::identity::KeyType;
6
7use serde::de::DeserializeOwned;
8use serde::Serialize;
9#[cfg(feature = "json-conversion")]
10use serde_json::Value as JsonValue;
11
12#[cfg(feature = "message-signature-verification")]
13use crate::validation::SimpleConsensusValidationResult;
14use crate::version::PlatformVersion;
15#[cfg(feature = "message-signing")]
16use crate::BlsModule;
17use crate::ProtocolError;
18use platform_value::Value;
19
20pub trait Signable {
21    fn signable_bytes(&self) -> Result<Vec<u8>, ProtocolError>;
22}
23
24pub trait PlatformSerializable {
25    type Error;
26    fn serialize_to_bytes(&self) -> Result<Vec<u8>, Self::Error>;
27
28    /// If the trait is not used just do a simple serialize
29    fn serialize_consume_to_bytes(self) -> Result<Vec<u8>, Self::Error>
30    where
31        Self: Sized,
32    {
33        self.serialize_to_bytes()
34    }
35}
36
37pub trait PlatformSerializableWithPlatformVersion {
38    type Error;
39    /// Version based serialization is done based on the desired structure version.
40    /// For example we have DataContractV0 and DataContractV1 for code based Contracts
41    /// This means objects that will execute code
42    /// And we would have DataContractSerializationFormatV0 and DataContractSerializationFormatV1
43    /// which are the different ways to serialize the concept of a data contract.
44    /// The data contract would call versioned_serialize. There should be a converted for each
45    /// Data contract Version towards each DataContractSerializationFormat
46    fn serialize_to_bytes_with_platform_version(
47        &self,
48        platform_version: &PlatformVersion,
49    ) -> Result<Vec<u8>, Self::Error>;
50
51    /// If the trait is not used just do a simple serialize
52    fn serialize_consume_to_bytes_with_platform_version(
53        self,
54        platform_version: &PlatformVersion,
55    ) -> Result<Vec<u8>, Self::Error>
56    where
57        Self: Sized,
58    {
59        self.serialize_to_bytes_with_platform_version(platform_version)
60    }
61}
62
63/// Deserialization of bytes this node wrote itself: Drive state read back
64/// from GroveDB, wallet storage, locally generated fixtures.
65///
66/// Runs bincode's ordinary decoder, which reserves each collection from its
67/// length prefix, so it must never see bytes that arrived from a peer, a
68/// client, a proof or a host caller; those go through
69/// [`PlatformDeserializableUntrusted`].
70///
71/// The derive implements the two `_with_bytes_len` methods, which report how
72/// many bytes the value took; the other methods are defaults over them.
73pub trait PlatformDeserializableTrusted {
74    /// Decodes under the type's configured byte budget, returning the value
75    /// and the number of bytes it took.
76    fn deserialize_from_bytes_trusted_with_bytes_len(
77        data: &[u8],
78    ) -> Result<(Self, usize), ProtocolError>
79    where
80        Self: Sized;
81
82    /// [`Self::deserialize_from_bytes_trusted_with_bytes_len`] without the
83    /// byte budget.
84    fn deserialize_from_bytes_trusted_no_limit_with_bytes_len(
85        data: &[u8],
86    ) -> Result<(Self, usize), ProtocolError>
87    where
88        Self: Sized;
89
90    /// Decodes under the type's configured byte budget. Bytes left over after
91    /// the value are ignored; [`Self::deserialize_from_bytes_trusted_exact`]
92    /// refuses them.
93    fn deserialize_from_bytes_trusted(data: &[u8]) -> Result<Self, ProtocolError>
94    where
95        Self: Sized,
96    {
97        Self::deserialize_from_bytes_trusted_with_bytes_len(data).map(|(value, _)| value)
98    }
99
100    fn deserialize_from_bytes_trusted_no_limit(data: &[u8]) -> Result<Self, ProtocolError>
101    where
102        Self: Sized,
103    {
104        Self::deserialize_from_bytes_trusted_no_limit_with_bytes_len(data).map(|(value, _)| value)
105    }
106
107    /// [`Self::deserialize_from_bytes_trusted`] that also refuses bytes left
108    /// over after the value.
109    fn deserialize_from_bytes_trusted_exact(data: &[u8]) -> Result<Self, ProtocolError>
110    where
111        Self: Sized,
112    {
113        let (value, consumed) = Self::deserialize_from_bytes_trusted_with_bytes_len(data)?;
114        refuse_left_over_bytes::<Self>(data.len(), consumed)?;
115        Ok(value)
116    }
117}
118
119/// Deserialization of bytes from outside this node: state transitions, query
120/// requests and cursors, proofs, SDK responses, host-supplied input.
121///
122/// Runs bincode's untrusted decoder, which reserves nothing from a length
123/// prefix before the elements it announces have actually been read, so a
124/// short input claiming a huge collection fails instead of allocating.
125///
126/// The derive implements the two `_with_bytes_len` methods, which report how
127/// many bytes the value took; the other methods are defaults over them.
128pub trait PlatformDeserializableUntrusted {
129    /// Decodes under the type's configured byte budget, returning the value
130    /// and the number of bytes it took.
131    fn deserialize_from_bytes_untrusted_with_bytes_len(
132        data: &[u8],
133    ) -> Result<(Self, usize), ProtocolError>
134    where
135        Self: Sized;
136
137    /// [`Self::deserialize_from_bytes_untrusted_with_bytes_len`] without the
138    /// byte budget.
139    fn deserialize_from_bytes_untrusted_no_limit_with_bytes_len(
140        data: &[u8],
141    ) -> Result<(Self, usize), ProtocolError>
142    where
143        Self: Sized;
144
145    /// Decodes under the type's configured byte budget. Bytes left over after
146    /// the value are ignored; [`Self::deserialize_from_bytes_untrusted_exact`]
147    /// refuses them.
148    fn deserialize_from_bytes_untrusted(data: &[u8]) -> Result<Self, ProtocolError>
149    where
150        Self: Sized,
151    {
152        Self::deserialize_from_bytes_untrusted_with_bytes_len(data).map(|(value, _)| value)
153    }
154
155    fn deserialize_from_bytes_untrusted_no_limit(data: &[u8]) -> Result<Self, ProtocolError>
156    where
157        Self: Sized,
158    {
159        Self::deserialize_from_bytes_untrusted_no_limit_with_bytes_len(data).map(|(value, _)| value)
160    }
161
162    /// [`Self::deserialize_from_bytes_untrusted`] that also refuses bytes left
163    /// over after the value.
164    ///
165    /// A value followed by anything decodes loosely as the value alone, so a
166    /// caller that shows a user what the bytes contain and then signs them
167    /// must use this one to know the value is all there is.
168    fn deserialize_from_bytes_untrusted_exact(data: &[u8]) -> Result<Self, ProtocolError>
169    where
170        Self: Sized,
171    {
172        let (value, consumed) = Self::deserialize_from_bytes_untrusted_with_bytes_len(data)?;
173        refuse_left_over_bytes::<Self>(data.len(), consumed)?;
174        Ok(value)
175    }
176}
177
178/// The error for a decode of `T` that took `consumed` of `len` input bytes.
179fn refuse_left_over_bytes<T>(len: usize, consumed: usize) -> Result<(), ProtocolError> {
180    if consumed == len {
181        return Ok(());
182    }
183    Err(ProtocolError::PlatformDeserializationError(format!(
184        "unable to deserialize {}: {} bytes left over after the value",
185        std::any::type_name::<T>(),
186        len.saturating_sub(consumed)
187    )))
188}
189
190/// We will deserialize a versioned structure into a code structure
191/// For example we have DataContractV0 and DataContractV1
192/// The system version will tell which version to deserialize into
193/// This happens by first deserializing the data into a potentially versioned structure
194/// For example we could have DataContractSerializationFormatV0 and DataContractSerializationFormatV1
195/// Both of the structures will be valid in perpetuity as they are saved into the state.
196/// So from the bytes we could get DataContractSerializationFormatV0.
197/// Then the system_version given will tell to transform DataContractSerializationFormatV0 into
198/// DataContractV1 (if system version is 1)
199///
200/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
201pub trait PlatformDeserializableFromVersionedStructureTrusted {
202    fn versioned_deserialize_trusted(
203        data: &[u8],
204        platform_version: &PlatformVersion,
205    ) -> Result<Self, ProtocolError>
206    where
207        Self: Sized;
208}
209
210/// Untrusted twin of [`PlatformDeserializableFromVersionedStructureTrusted`]:
211/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
212pub trait PlatformDeserializableFromVersionedStructureUntrusted {
213    fn versioned_deserialize_untrusted(
214        data: &[u8],
215        platform_version: &PlatformVersion,
216    ) -> Result<Self, ProtocolError>
217    where
218        Self: Sized;
219}
220
221/// Versioned deserialization with optional full validation of the decoded
222/// structure (see [`PlatformDeserializableFromVersionedStructureTrusted`] for
223/// how versioned structures decode).
224///
225/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
226pub trait PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted {
227    fn versioned_deserialize_trusted(
228        data: &[u8],
229        full_validation: bool,
230        platform_version: &PlatformVersion,
231    ) -> Result<Self, ProtocolError>
232    where
233        Self: Sized;
234}
235
236/// Untrusted twin of
237/// [`PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted`]:
238/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
239pub trait PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted {
240    fn versioned_deserialize_untrusted(
241        data: &[u8],
242        full_validation: bool,
243        platform_version: &PlatformVersion,
244    ) -> Result<Self, ProtocolError>
245    where
246        Self: Sized;
247}
248
249/// Versioned deserialization that also reports how many bytes were consumed
250/// (see [`PlatformDeserializableFromVersionedStructureTrusted`] for how
251/// versioned structures decode).
252///
253/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
254pub trait PlatformDeserializableWithBytesLenFromVersionedStructureTrusted {
255    fn versioned_deserialize_with_bytes_len_trusted(
256        data: &[u8],
257        full_validation: bool,
258        platform_version: &PlatformVersion,
259    ) -> Result<(Self, usize), ProtocolError>
260    where
261        Self: Sized;
262}
263
264/// Untrusted twin of
265/// [`PlatformDeserializableWithBytesLenFromVersionedStructureTrusted`]:
266/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
267pub trait PlatformDeserializableWithBytesLenFromVersionedStructureUntrusted {
268    fn versioned_deserialize_with_bytes_len_untrusted(
269        data: &[u8],
270        full_validation: bool,
271        platform_version: &PlatformVersion,
272    ) -> Result<(Self, usize), ProtocolError>
273    where
274        Self: Sized;
275}
276
277/// Versioned deserialization under the type's configured byte limit.
278///
279/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
280pub trait PlatformLimitDeserializableFromVersionedStructureTrusted {
281    fn versioned_limit_deserialize_trusted(
282        data: &[u8],
283        platform_version: &PlatformVersion,
284    ) -> Result<Self, ProtocolError>
285    where
286        Self: Sized;
287}
288
289/// Untrusted twin of [`PlatformLimitDeserializableFromVersionedStructureTrusted`]:
290/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
291pub trait PlatformLimitDeserializableFromVersionedStructureUntrusted {
292    fn versioned_limit_deserialize_untrusted(
293        data: &[u8],
294        platform_version: &PlatformVersion,
295    ) -> Result<Self, ProtocolError>
296    where
297        Self: Sized;
298}
299
300pub trait ValueConvertible: Serialize + DeserializeOwned {
301    fn to_object(&self) -> Result<Value, ProtocolError>
302    where
303        Self: Sized,
304    {
305        platform_value::to_value(self).map_err(ProtocolError::ValueError)
306    }
307
308    fn into_object(self) -> Result<Value, ProtocolError>
309    where
310        Self: Sized,
311    {
312        platform_value::to_value(self).map_err(ProtocolError::ValueError)
313    }
314
315    fn from_object(value: Value) -> Result<Self, ProtocolError>
316    where
317        Self: Sized,
318    {
319        platform_value::from_value(value).map_err(ProtocolError::ValueError)
320    }
321
322    fn from_object_ref(value: &Value) -> Result<Self, ProtocolError>
323    where
324        Self: Sized,
325    {
326        platform_value::from_value(value.clone()).map_err(ProtocolError::ValueError)
327    }
328}
329
330/// Convert to/from JSON using **human-readable** serde (`Identifier` = base58,
331/// binary = base64).
332///
333/// This trait produces clean `serde_json::Value` with native number types.
334/// Any JS-boundary concerns (large number stringification) are handled by the
335/// WASM layer.
336///
337/// # ⚠️ HR / non-HR divergence (Critical-1)
338///
339/// `JsonConvertible` calls `serde_json::to_value`, which uses a serializer
340/// that reports `is_human_readable() == true`. The mirror trait
341/// [`ValueConvertible`] uses `platform_value::to_value`, which reports
342/// `false`. Types whose `Serialize` impl branches on `is_human_readable()`
343/// produce **structurally different output** between the two paths:
344///
345/// | Type | `to_json()` (HR) | `to_object()` (non-HR) |
346/// |---|---|---|
347/// | [`platform_value::Identifier`] | `"5bV6jUfh..."` (bs58 string) | `Value::Identifier([u8; 32])` |
348/// | [`platform_value::BinaryData`] | `"sg=="` (base64 string) | `Value::Bytes(Vec<u8>)` |
349/// | `Bytes20` / `Bytes32` / `Bytes36` | base64 string | `Value::Bytes32([u8; N])` etc. |
350/// | `CoreScript` | `"dqkU..."` (base64 string) | `Value::Bytes(Vec<u8>)` |
351///
352/// **Do not assume** `self.to_object()?.try_into_json()` ≡ `self.to_json()`.
353/// They render the same field as a string in one and a byte array in the
354/// other. Round-trip tests should exercise each path independently.
355///
356/// # ⚠️ `ContentDeserializer` caveat
357///
358/// Manual `Deserialize` impls that branch on `deserializer.is_human_readable()`
359/// must also handle `serde::__private::de::ContentDeserializer`, used
360/// internally by `#[serde(tag = "...")]` enums. ContentDeserializer **always
361/// reports `is_human_readable: true`** regardless of the original source — so
362/// a non-HR `platform_value::Value` flowing into a tagged enum gets shape-
363/// inferred as if it were HR. Recipe: write a dual-shape visitor accepting
364/// both shapes in the HR branch via `deserialize_any`. See
365/// [`platform_value::Bytes32::deserialize`] for the canonical example, and
366/// `rs-dpp/src/serialization/serde_bytes.rs` for `[u8; N]` / `Vec<u8>`.
367#[cfg(feature = "json-conversion")]
368pub trait JsonConvertible: Serialize + DeserializeOwned {
369    fn to_json(&self) -> Result<JsonValue, ProtocolError> {
370        serde_json::to_value(self).map_err(|e| ProtocolError::EncodingError(e.to_string()))
371    }
372
373    fn from_json(json: JsonValue) -> Result<Self, ProtocolError> {
374        serde_json::from_value(json).map_err(|e| ProtocolError::DecodingError(e.to_string()))
375    }
376}
377
378pub trait PlatformMessageSignable {
379    #[cfg(feature = "message-signature-verification")]
380    fn verify_signature(
381        &self,
382        public_key_type: KeyType,
383        public_key_data: &[u8],
384        signature: &[u8],
385    ) -> SimpleConsensusValidationResult;
386
387    #[cfg(feature = "message-signing")]
388    fn sign_by_private_key(
389        &self,
390        private_key: &[u8],
391        key_type: KeyType,
392        bls: &impl BlsModule,
393    ) -> Result<Vec<u8>, ProtocolError>;
394}