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}