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`].
70pub trait PlatformDeserializableTrusted {
71    fn deserialize_from_bytes_trusted(data: &[u8]) -> Result<Self, ProtocolError>
72    where
73        Self: Sized,
74    {
75        Self::deserialize_from_bytes_trusted_no_limit(data)
76    }
77
78    fn deserialize_from_bytes_trusted_no_limit(data: &[u8]) -> Result<Self, ProtocolError>
79    where
80        Self: Sized;
81}
82
83/// Deserialization of bytes from outside this node: state transitions, query
84/// requests and cursors, proofs, SDK responses, host-supplied input.
85///
86/// Runs bincode's untrusted decoder, which reserves nothing from a length
87/// prefix before the elements it announces have actually been read, so a
88/// short input claiming a huge collection fails instead of allocating.
89pub trait PlatformDeserializableUntrusted {
90    fn deserialize_from_bytes_untrusted(data: &[u8]) -> Result<Self, ProtocolError>
91    where
92        Self: Sized,
93    {
94        Self::deserialize_from_bytes_untrusted_no_limit(data)
95    }
96
97    fn deserialize_from_bytes_untrusted_no_limit(data: &[u8]) -> Result<Self, ProtocolError>
98    where
99        Self: Sized;
100}
101
102/// We will deserialize a versioned structure into a code structure
103/// For example we have DataContractV0 and DataContractV1
104/// The system version will tell which version to deserialize into
105/// This happens by first deserializing the data into a potentially versioned structure
106/// For example we could have DataContractSerializationFormatV0 and DataContractSerializationFormatV1
107/// Both of the structures will be valid in perpetuity as they are saved into the state.
108/// So from the bytes we could get DataContractSerializationFormatV0.
109/// Then the system_version given will tell to transform DataContractSerializationFormatV0 into
110/// DataContractV1 (if system version is 1)
111///
112/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
113pub trait PlatformDeserializableFromVersionedStructureTrusted {
114    fn versioned_deserialize_trusted(
115        data: &[u8],
116        platform_version: &PlatformVersion,
117    ) -> Result<Self, ProtocolError>
118    where
119        Self: Sized;
120}
121
122/// Untrusted twin of [`PlatformDeserializableFromVersionedStructureTrusted`]:
123/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
124pub trait PlatformDeserializableFromVersionedStructureUntrusted {
125    fn versioned_deserialize_untrusted(
126        data: &[u8],
127        platform_version: &PlatformVersion,
128    ) -> Result<Self, ProtocolError>
129    where
130        Self: Sized;
131}
132
133/// Versioned deserialization with optional full validation of the decoded
134/// structure (see [`PlatformDeserializableFromVersionedStructureTrusted`] for
135/// how versioned structures decode).
136///
137/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
138pub trait PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted {
139    fn versioned_deserialize_trusted(
140        data: &[u8],
141        full_validation: bool,
142        platform_version: &PlatformVersion,
143    ) -> Result<Self, ProtocolError>
144    where
145        Self: Sized;
146}
147
148/// Untrusted twin of
149/// [`PlatformDeserializableWithPotentialValidationFromVersionedStructureTrusted`]:
150/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
151pub trait PlatformDeserializableWithPotentialValidationFromVersionedStructureUntrusted {
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
161/// Versioned deserialization that also reports how many bytes were consumed
162/// (see [`PlatformDeserializableFromVersionedStructureTrusted`] for how
163/// versioned structures decode).
164///
165/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
166pub trait PlatformDeserializableWithBytesLenFromVersionedStructureTrusted {
167    fn versioned_deserialize_with_bytes_len_trusted(
168        data: &[u8],
169        full_validation: bool,
170        platform_version: &PlatformVersion,
171    ) -> Result<(Self, usize), ProtocolError>
172    where
173        Self: Sized;
174}
175
176/// Untrusted twin of
177/// [`PlatformDeserializableWithBytesLenFromVersionedStructureTrusted`]:
178/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
179pub trait PlatformDeserializableWithBytesLenFromVersionedStructureUntrusted {
180    fn versioned_deserialize_with_bytes_len_untrusted(
181        data: &[u8],
182        full_validation: bool,
183        platform_version: &PlatformVersion,
184    ) -> Result<(Self, usize), ProtocolError>
185    where
186        Self: Sized;
187}
188
189/// Versioned deserialization under the type's configured byte limit.
190///
191/// Trusted twin: bytes this node wrote itself, see [`PlatformDeserializableTrusted`].
192pub trait PlatformLimitDeserializableFromVersionedStructureTrusted {
193    fn versioned_limit_deserialize_trusted(
194        data: &[u8],
195        platform_version: &PlatformVersion,
196    ) -> Result<Self, ProtocolError>
197    where
198        Self: Sized;
199}
200
201/// Untrusted twin of [`PlatformLimitDeserializableFromVersionedStructureTrusted`]:
202/// bytes from outside this node, see [`PlatformDeserializableUntrusted`].
203pub trait PlatformLimitDeserializableFromVersionedStructureUntrusted {
204    fn versioned_limit_deserialize_untrusted(
205        data: &[u8],
206        platform_version: &PlatformVersion,
207    ) -> Result<Self, ProtocolError>
208    where
209        Self: Sized;
210}
211
212pub trait ValueConvertible: Serialize + DeserializeOwned {
213    fn to_object(&self) -> Result<Value, ProtocolError>
214    where
215        Self: Sized,
216    {
217        platform_value::to_value(self).map_err(ProtocolError::ValueError)
218    }
219
220    fn into_object(self) -> Result<Value, ProtocolError>
221    where
222        Self: Sized,
223    {
224        platform_value::to_value(self).map_err(ProtocolError::ValueError)
225    }
226
227    fn from_object(value: Value) -> Result<Self, ProtocolError>
228    where
229        Self: Sized,
230    {
231        platform_value::from_value(value).map_err(ProtocolError::ValueError)
232    }
233
234    fn from_object_ref(value: &Value) -> Result<Self, ProtocolError>
235    where
236        Self: Sized,
237    {
238        platform_value::from_value(value.clone()).map_err(ProtocolError::ValueError)
239    }
240}
241
242/// Convert to/from JSON using **human-readable** serde (`Identifier` = base58,
243/// binary = base64).
244///
245/// This trait produces clean `serde_json::Value` with native number types.
246/// Any JS-boundary concerns (large number stringification) are handled by the
247/// WASM layer.
248///
249/// # ⚠️ HR / non-HR divergence (Critical-1)
250///
251/// `JsonConvertible` calls `serde_json::to_value`, which uses a serializer
252/// that reports `is_human_readable() == true`. The mirror trait
253/// [`ValueConvertible`] uses `platform_value::to_value`, which reports
254/// `false`. Types whose `Serialize` impl branches on `is_human_readable()`
255/// produce **structurally different output** between the two paths:
256///
257/// | Type | `to_json()` (HR) | `to_object()` (non-HR) |
258/// |---|---|---|
259/// | [`platform_value::Identifier`] | `"5bV6jUfh..."` (bs58 string) | `Value::Identifier([u8; 32])` |
260/// | [`platform_value::BinaryData`] | `"sg=="` (base64 string) | `Value::Bytes(Vec<u8>)` |
261/// | `Bytes20` / `Bytes32` / `Bytes36` | base64 string | `Value::Bytes32([u8; N])` etc. |
262/// | `CoreScript` | `"dqkU..."` (base64 string) | `Value::Bytes(Vec<u8>)` |
263///
264/// **Do not assume** `self.to_object()?.try_into_json()` ≡ `self.to_json()`.
265/// They render the same field as a string in one and a byte array in the
266/// other. Round-trip tests should exercise each path independently.
267///
268/// # ⚠️ `ContentDeserializer` caveat
269///
270/// Manual `Deserialize` impls that branch on `deserializer.is_human_readable()`
271/// must also handle `serde::__private::de::ContentDeserializer`, used
272/// internally by `#[serde(tag = "...")]` enums. ContentDeserializer **always
273/// reports `is_human_readable: true`** regardless of the original source — so
274/// a non-HR `platform_value::Value` flowing into a tagged enum gets shape-
275/// inferred as if it were HR. Recipe: write a dual-shape visitor accepting
276/// both shapes in the HR branch via `deserialize_any`. See
277/// [`platform_value::Bytes32::deserialize`] for the canonical example, and
278/// `rs-dpp/src/serialization/serde_bytes.rs` for `[u8; N]` / `Vec<u8>`.
279#[cfg(feature = "json-conversion")]
280pub trait JsonConvertible: Serialize + DeserializeOwned {
281    fn to_json(&self) -> Result<JsonValue, ProtocolError> {
282        serde_json::to_value(self).map_err(|e| ProtocolError::EncodingError(e.to_string()))
283    }
284
285    fn from_json(json: JsonValue) -> Result<Self, ProtocolError> {
286        serde_json::from_value(json).map_err(|e| ProtocolError::DecodingError(e.to_string()))
287    }
288}
289
290pub trait PlatformMessageSignable {
291    #[cfg(feature = "message-signature-verification")]
292    fn verify_signature(
293        &self,
294        public_key_type: KeyType,
295        public_key_data: &[u8],
296        signature: &[u8],
297    ) -> SimpleConsensusValidationResult;
298
299    #[cfg(feature = "message-signing")]
300    fn sign_by_private_key(
301        &self,
302        private_key: &[u8],
303        key_type: KeyType,
304        bls: &impl BlsModule,
305    ) -> Result<Vec<u8>, ProtocolError>;
306}