Skip to main content

p2panda_core/
serde.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3use std::fmt;
4use std::marker::PhantomData;
5
6use serde::de::{Error as SerdeError, SeqAccess, Visitor};
7use serde::ser::SerializeSeq;
8use serde::{Deserialize, Serialize};
9use serde_bytes::{ByteBuf as SerdeByteBuf, Bytes as SerdeBytes};
10
11use crate::cursor::Cursor;
12use crate::hash::{Hash, HashError};
13use crate::identity::{IdentityError, Signature, SigningKey, VerifyingKey};
14use crate::logs::{LogHeights, LogId};
15use crate::operation::Body;
16use crate::topic::{Topic, TopicError};
17use crate::traits::Author;
18
19/// Helper method for `serde` to serialize bytes into a hex string when using a human readable
20/// encoding (JSON, GraphQL), otherwise it serializes the bytes directly (CBOR).
21pub fn serialize_hex<S>(value: &[u8], serializer: S) -> Result<S::Ok, S::Error>
22where
23    S: serde::Serializer,
24{
25    if serializer.is_human_readable() {
26        hex::serde::serialize(value, serializer)
27    } else {
28        SerdeBytes::new(value).serialize(serializer)
29    }
30}
31
32/// Helper method for `serde` to deserialize from a hex string into bytes when using a human
33/// readable encoding (JSON, GraphQL), otherwise it deserializes the bytes directly (CBOR).
34pub fn deserialize_hex<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
35where
36    D: serde::Deserializer<'de>,
37{
38    if deserializer.is_human_readable() {
39        hex::serde::deserialize(deserializer)
40    } else {
41        let bytes = <SerdeByteBuf>::deserialize(deserializer)?;
42        Ok(bytes.to_vec())
43    }
44}
45
46impl Serialize for Hash {
47    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
48    where
49        S: serde::Serializer,
50    {
51        serialize_hex(self.as_bytes(), serializer)
52    }
53}
54
55impl<'de> Deserialize<'de> for Hash {
56    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
57    where
58        D: serde::Deserializer<'de>,
59    {
60        let bytes = deserialize_hex(deserializer)?;
61
62        bytes
63            .as_slice()
64            .try_into()
65            .map_err(|err: HashError| serde::de::Error::custom(err.to_string()))
66    }
67}
68
69impl Serialize for SigningKey {
70    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
71    where
72        S: serde::Serializer,
73    {
74        serialize_hex(self.as_bytes(), serializer)
75    }
76}
77
78impl<'de> Deserialize<'de> for SigningKey {
79    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
80    where
81        D: serde::Deserializer<'de>,
82    {
83        let bytes = deserialize_hex(deserializer)?;
84
85        bytes
86            .as_slice()
87            .try_into()
88            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
89    }
90}
91
92impl Serialize for VerifyingKey {
93    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94    where
95        S: serde::Serializer,
96    {
97        serialize_hex(self.as_bytes(), serializer)
98    }
99}
100
101impl<'de> Deserialize<'de> for VerifyingKey {
102    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
103    where
104        D: serde::Deserializer<'de>,
105    {
106        let bytes = deserialize_hex(deserializer)?;
107
108        bytes
109            .as_slice()
110            .try_into()
111            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
112    }
113}
114
115impl Serialize for Signature {
116    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
117    where
118        S: serde::Serializer,
119    {
120        serialize_hex(&self.to_bytes(), serializer)
121    }
122}
123
124impl<'de> Deserialize<'de> for Signature {
125    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
126    where
127        D: serde::Deserializer<'de>,
128    {
129        let bytes = deserialize_hex(deserializer)?;
130
131        bytes
132            .as_slice()
133            .try_into()
134            .map_err(|err: IdentityError| serde::de::Error::custom(err.to_string()))
135    }
136}
137
138impl Serialize for Body {
139    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
140    where
141        S: serde::Serializer,
142    {
143        serialize_hex(self.as_bytes(), serializer)
144    }
145}
146
147impl<'de> Deserialize<'de> for Body {
148    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
149    where
150        D: serde::Deserializer<'de>,
151    {
152        let bytes = deserialize_hex(deserializer)?;
153        Ok(Body::from_bytes(bytes))
154    }
155}
156
157impl Serialize for Topic {
158    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
159    where
160        S: serde::Serializer,
161    {
162        serialize_hex(&self.0, serializer)
163    }
164}
165
166impl<'de> Deserialize<'de> for Topic {
167    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
168    where
169        D: serde::Deserializer<'de>,
170    {
171        let bytes = deserialize_hex(deserializer)?;
172
173        bytes
174            .as_slice()
175            .try_into()
176            .map_err(|err: TopicError| serde::de::Error::custom(err.to_string()))
177    }
178}
179
180impl<A, L> Serialize for Cursor<A, L>
181where
182    A: Author,
183    L: LogId,
184{
185    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
186    where
187        S: serde::Serializer,
188    {
189        let mut seq = serializer.serialize_seq(Some(2))?;
190        seq.serialize_element(self.name())?;
191        seq.serialize_element(self.state())?;
192        seq.end()
193    }
194}
195
196impl<'de, A, L> Deserialize<'de> for Cursor<A, L>
197where
198    A: Author,
199    L: LogId,
200{
201    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
202    where
203        D: serde::Deserializer<'de>,
204    {
205        struct CursorVisitor<A, L> {
206            _marker: PhantomData<(A, L)>,
207        }
208
209        impl<'de, A, L> Visitor<'de> for CursorVisitor<A, L>
210        where
211            A: Author,
212            L: LogId,
213        {
214            type Value = Cursor<A, L>;
215
216            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
217                formatter.write_str("Cursor encoded as a sequence")
218            }
219
220            fn visit_seq<T>(self, mut seq: T) -> Result<Self::Value, T::Error>
221            where
222                T: SeqAccess<'de>,
223            {
224                let name: String = seq
225                    .next_element()?
226                    .ok_or(SerdeError::custom("cursor id missing"))?;
227
228                let state: LogHeights<A, L> = seq
229                    .next_element()?
230                    .ok_or(SerdeError::custom("state vector missing"))?;
231
232                Ok(Cursor::new(name, state))
233            }
234        }
235
236        deserializer.deserialize_seq(CursorVisitor::<A, L> {
237            _marker: PhantomData,
238        })
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    use serde::{Deserialize, Serialize};
245
246    use crate::Extensions;
247    use crate::cbor::{decode_cbor, encode_cbor};
248    use crate::hash::Hash;
249    use crate::identity::{SigningKey, VerifyingKey};
250    use crate::operation::{AnyHeader, Header};
251
252    use super::{deserialize_hex, serialize_hex};
253
254    #[derive(Debug, Serialize, Deserialize)]
255    struct Test(
256        #[serde(serialize_with = "serialize_hex", deserialize_with = "deserialize_hex")] Vec<u8>,
257    );
258
259    #[test]
260    fn serialize() {
261        let test = Test(vec![1, 2, 3]);
262
263        // For CBOR the bytes just get serialized straight away as it is not a human readable
264        // encoding.
265        let bytes = encode_cbor(&test).unwrap();
266        assert_eq!(vec![67, 1, 2, 3], bytes);
267    }
268
269    #[test]
270    fn deserialize() {
271        let bytes: Vec<u8> = vec![67, 1, 2, 3];
272
273        // For CBOR the bytes just get deserialized straight away as an array as it is not a human
274        // readable encoding.
275        let test: Test = decode_cbor(&bytes[..]).unwrap();
276        assert_eq!(test.0, vec![1, 2, 3]);
277    }
278
279    #[test]
280    fn serialize_hash() {
281        // Serialize CBOR (non human-readable byte encoding)
282        let hash = Hash::digest([1, 2, 3]);
283        let bytes = encode_cbor(&hash).unwrap();
284        assert_eq!(
285            bytes,
286            vec![
287                88, 32, 177, 119, 236, 27, 242, 109, 251, 59, 112, 16, 212, 115, 230, 212, 71, 19,
288                178, 155, 118, 91, 153, 198, 230, 14, 203, 250, 231, 66, 222, 73, 101, 67
289            ]
290        );
291
292        // Serialize JSON (human-readable hex encoding)
293        let json = serde_json::to_string(&hash).unwrap();
294        assert_eq!(
295            json,
296            "\"b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543\""
297        );
298    }
299
300    #[test]
301    fn deserialize_hash() {
302        // Deserialize CBOR (non human-readable byte encoding)
303        let bytes = [
304            88, 32, 177, 119, 236, 27, 242, 109, 251, 59, 112, 16, 212, 115, 230, 212, 71, 19, 178,
305            155, 118, 91, 153, 198, 230, 14, 203, 250, 231, 66, 222, 73, 101, 67,
306        ];
307        let hash: Hash = decode_cbor(&bytes[..]).unwrap();
308        assert_eq!(hash, Hash::digest([1, 2, 3]));
309
310        // Deserialize JSON (human-readable hex encoding)
311        let json = "\"b177ec1bf26dfb3b7010d473e6d44713b29b765b99c6e60ecbfae742de496543\"";
312        let hash: Hash = serde_json::from_str(json).unwrap();
313        assert_eq!(hash, Hash::digest([1, 2, 3]));
314    }
315
316    #[test]
317    fn serialize_verifying_key() {
318        // Serialize CBOR (non human-readable byte encoding)
319        let verifying_key = VerifyingKey::from_bytes(&[
320            215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14, 225, 114,
321            243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
322        ])
323        .unwrap();
324        let bytes = encode_cbor(&verifying_key).unwrap();
325        assert_eq!(
326            bytes,
327            vec![
328                88, 32, 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, 14,
329                225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26,
330            ]
331        );
332
333        // Serialize JSON (human-readable hex encoding)
334        let json = serde_json::to_string(&verifying_key).unwrap();
335        assert_eq!(
336            json,
337            "\"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a\""
338        );
339    }
340
341    fn assert_serde_roundtrip<E>(header: Header<E>)
342    where
343        E: Extensions + PartialEq,
344    {
345        let bytes = header.encode();
346        let any_header = AnyHeader::decode(&bytes).expect("valid header");
347        let header_again: Header<E> = any_header.try_into().expect("valid extensions");
348
349        assert_eq!(header, header_again);
350    }
351
352    #[test]
353    fn serde_roundtrip_operations() {
354        #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
355        struct CustomExtensions {
356            custom_field: u64,
357        }
358
359        let extensions = CustomExtensions { custom_field: 12 };
360        let signing_key = SigningKey::generate();
361
362        assert_serde_roundtrip(
363            Header::builder()
364                .body(b"test")
365                .build(&signing_key, extensions),
366        );
367        assert_serde_roundtrip(Header::builder().build(&signing_key, ()));
368    }
369
370    #[test]
371    fn fixtures() {
372        let signing_key = SigningKey::from([
373            244, 123, 85, 215, 161, 204, 94, 227, 239, 253, 128, 164, 228, 160, 195, 49, 18, 49,
374            125, 4, 50, 218, 157, 230, 174, 1, 154, 231, 231, 142, 22, 170,
375        ]);
376
377        // header at seq num 0
378        let header = Header::builder().build(&signing_key, ());
379
380        let bytes = vec![
381            133, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
382            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 17,
383            129, 90, 32, 212, 224, 74, 141, 219, 82, 160, 35, 19, 205, 82, 55, 247, 204, 121, 153,
384            128, 203, 123, 102, 108, 90, 60, 23, 223, 176, 251, 154, 243, 131, 177, 54, 142, 210,
385            0, 231, 125, 90, 206, 28, 240, 37, 179, 88, 200, 246, 185, 49, 246, 135, 242, 133, 128,
386            127, 22, 118, 23, 102, 22, 2, 0, 0,
387        ];
388
389        assert_eq!(bytes, header.encode());
390
391        let any_header: AnyHeader = bytes.try_into().expect("valid header");
392        let header_again: Header<()> = any_header.try_into().expect("valid extensions");
393        assert_eq!(header, header_again);
394
395        // header at seq num 0 with body
396        let header = Header::builder()
397            .body(b"Hello, Sloth!")
398            .build(&signing_key, ());
399
400        let bytes = vec![
401            134, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
402            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 187,
403            89, 157, 165, 197, 22, 79, 145, 227, 116, 226, 203, 231, 213, 225, 253, 197, 253, 240,
404            147, 16, 224, 186, 146, 94, 126, 79, 185, 150, 84, 102, 16, 109, 56, 241, 228, 164,
405            191, 153, 47, 142, 189, 12, 71, 159, 143, 81, 204, 108, 124, 22, 39, 222, 122, 88, 198,
406            123, 125, 2, 211, 28, 196, 90, 0, 13, 88, 32, 191, 127, 68, 13, 227, 43, 252, 155, 49,
407            148, 176, 2, 162, 217, 175, 171, 49, 44, 181, 215, 71, 113, 211, 195, 29, 128, 192,
408            169, 5, 138, 160, 142, 0,
409        ];
410
411        assert_eq!(bytes, header.encode());
412
413        let any_header: AnyHeader = bytes.try_into().expect("valid header");
414        let header_again: Header<()> = any_header.try_into().expect("valid extensions");
415        assert_eq!(header, header_again);
416
417        // header at seq num 1 with backlink
418        let header = Header::builder()
419            .chain(1, header.hash())
420            .build(&signing_key, ());
421
422        let bytes = vec![
423            134, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
424            92, 42, 222, 249, 148, 139, 23, 91, 43, 92, 17, 225, 69, 17, 181, 22, 32, 88, 64, 90,
425            241, 219, 179, 113, 96, 207, 245, 193, 3, 115, 166, 84, 177, 236, 191, 194, 134, 34,
426            214, 117, 182, 130, 121, 97, 9, 110, 170, 35, 44, 155, 205, 147, 180, 234, 188, 17, 39,
427            109, 146, 142, 68, 181, 186, 119, 197, 71, 45, 245, 246, 32, 139, 46, 197, 150, 12,
428            255, 110, 134, 99, 5, 139, 223, 13, 0, 1, 88, 32, 68, 43, 250, 251, 47, 151, 121, 58,
429            30, 144, 24, 129, 171, 35, 89, 56, 161, 112, 75, 91, 168, 201, 195, 121, 169, 155, 85,
430            104, 129, 60, 141, 161,
431        ];
432
433        let any_header: AnyHeader = bytes.try_into().expect("valid header");
434        let header_again: Header<()> = any_header.try_into().expect("valid extensions");
435        assert_eq!(header, header_again);
436    }
437
438    #[test]
439    fn unexpected_eof_when_incomplete() {
440        // The CBOR decoder should be able to detect an "Unexpected EOF" error if we're giving it an
441        // incomplete header.
442        let incomplete = [
443            137, 1, 88, 32, 228, 21, 196, 25, 12, 199, 241, 100, 122, 89, 46, 191, 142, 95, 144,
444        ];
445
446        let result = AnyHeader::decode(&incomplete);
447        assert!(result.is_err());
448    }
449
450    #[test]
451    fn zero_sized_extensions() {
452        #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
453        struct Zilch;
454
455        #[derive(Clone, Debug, Serialize, Deserialize)]
456        struct ZeroSizedExtension {
457            field_a: [u8; 0],
458            field_b: (),
459            field_c: Zilch,
460        }
461
462        let signing_key = SigningKey::generate();
463
464        let header = Header::builder().body(b"look, no bytes!").build(
465            &signing_key,
466            ZeroSizedExtension {
467                field_a: [],
468                field_b: (),
469                field_c: Zilch,
470            },
471        );
472
473        let bytes = header.encode();
474
475        // Make sure we skip the extensions field which means we only need 6 fields for the header.
476        //
477        // In CBOR this shows in the first byte where the "array" type + its length is declared
478        // (array(6)). In hex this would be represented by `86`, in decimal its `134`:
479        assert!(bytes[0] == 134);
480
481        // We correctly deserialize to the ZST.
482        let any_header: AnyHeader = bytes.try_into().expect("valid header");
483        let result: Header<ZeroSizedExtension> = any_header.try_into().expect("valid extensions");
484        assert_eq!(result.extensions.field_a.len(), 0);
485        assert_eq!(result.extensions.field_b, ());
486        assert_eq!(result.extensions.field_c, Zilch);
487    }
488}