pythnet_sdk/
wire.rs

1//! Pyth Wire Format
2//!
3//! Pyth uses a custom wire format when moving data between programs and chains. This module
4//! provides the serialization and deserialization logic for this format as well as definitions of
5//! data structures used in the PythNet ecosystem.
6//!
7//! See the `ser` submodule for a description of the Pyth Wire format.
8
9pub mod array;
10mod de;
11mod prefixed_vec;
12mod ser;
13
14pub use {
15    de::{
16        from_slice,
17        Deserializer,
18        DeserializerError,
19    },
20    prefixed_vec::PrefixedVec,
21    ser::{
22        to_vec,
23        to_writer,
24        Serializer,
25        SerializerError,
26    },
27};
28
29// Proof Format (V1)
30// --------------------------------------------------------------------------------
31// The definitions within each module can be updated with append-only data without requiring a new
32// module to be defined. So for example, it is possible to add new fields can be added to the end
33// of the `AccumulatorAccount` without moving to a `v1`.
34pub mod v1 {
35    use {
36        super::*,
37        crate::{
38            accumulators::merkle::MerklePath,
39            error::Error,
40            hashers::keccak256_160::Keccak160,
41            require,
42        },
43        borsh::{
44            BorshDeserialize,
45            BorshSerialize,
46        },
47        serde::{
48            Deserialize,
49            Serialize,
50        },
51    };
52    pub const PYTHNET_ACCUMULATOR_UPDATE_MAGIC: &[u8; 4] = b"PNAU";
53    pub const CURRENT_MINOR_VERSION: u8 = 0;
54
55    // Transfer Format.
56    // --------------------------------------------------------------------------------
57    // This definition is what will be sent over the wire (I.E, pulled from PythNet and submitted
58    // to target chains).
59    #[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
60    pub struct AccumulatorUpdateData {
61        magic:         [u8; 4],
62        major_version: u8,
63        minor_version: u8,
64        trailing:      Vec<u8>,
65        pub proof:     Proof,
66    }
67
68    impl AccumulatorUpdateData {
69        pub fn new(proof: Proof) -> Self {
70            Self {
71                magic: *PYTHNET_ACCUMULATOR_UPDATE_MAGIC,
72                major_version: 1,
73                minor_version: 0,
74                trailing: vec![],
75                proof,
76            }
77        }
78
79        pub fn try_from_slice(bytes: &[u8]) -> Result<Self, Error> {
80            let message = from_slice::<byteorder::BE, Self>(bytes)
81                .map_err(|_| Error::DeserializationError)?;
82            require!(
83                &message.magic[..] == PYTHNET_ACCUMULATOR_UPDATE_MAGIC,
84                Error::InvalidMagic
85            );
86            require!(message.major_version == 1, Error::InvalidVersion);
87            require!(
88                message.minor_version >= CURRENT_MINOR_VERSION,
89                Error::InvalidVersion
90            );
91            Ok(message)
92        }
93    }
94
95    // A hash of some data.
96    pub type Hash = [u8; 20];
97
98    #[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
99    pub enum Proof {
100        WormholeMerkle {
101            vaa:     PrefixedVec<u16, u8>,
102            updates: Vec<MerklePriceUpdate>,
103        },
104    }
105
106    #[derive(
107        Clone, Debug, Hash, PartialEq, Serialize, Deserialize, BorshDeserialize, BorshSerialize,
108    )]
109    pub struct MerklePriceUpdate {
110        pub message: PrefixedVec<u16, u8>,
111        pub proof:   MerklePath<Keccak160>,
112    }
113
114    #[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
115    pub struct WormholeMessage {
116        pub magic:   [u8; 4],
117        pub payload: WormholePayload,
118    }
119
120    pub const ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC: &[u8; 4] = b"AUWV";
121
122    impl WormholeMessage {
123        pub fn new(payload: WormholePayload) -> Self {
124            Self {
125                magic: *ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC,
126                payload,
127            }
128        }
129
130        pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
131            let message = from_slice::<byteorder::BE, Self>(bytes.as_ref())
132                .map_err(|_| Error::DeserializationError)?;
133            require!(
134                &message.magic[..] == ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC,
135                Error::InvalidMagic
136            );
137            Ok(message)
138        }
139    }
140
141    #[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
142    pub enum WormholePayload {
143        Merkle(WormholeMerkleRoot),
144    }
145
146    #[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
147    pub struct WormholeMerkleRoot {
148        pub slot:      u64,
149        pub ring_size: u32,
150        pub root:      Hash,
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use crate::wire::{
157        array,
158        v1::{
159            AccumulatorUpdateData,
160            Proof,
161        },
162        Deserializer,
163        PrefixedVec,
164        Serializer,
165    };
166
167    // Test the arbitrary fixed sized array serialization implementation.
168    #[test]
169    fn test_array_serde() {
170        // Serialize an array into a buffer.
171        let mut buffer = Vec::new();
172        let mut cursor = std::io::Cursor::new(&mut buffer);
173        let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
174        array::serialize(&[1u8; 37], &mut serializer).unwrap();
175
176        // The result should not have been prefixed with a length byte.
177        assert_eq!(buffer.len(), 37);
178
179        // We should also be able to deserialize it back.
180        let mut deserializer = Deserializer::<byteorder::LE>::new(&buffer);
181        let deserialized: [u8; 37] = array::deserialize(&mut deserializer).unwrap();
182
183        // The deserialized array should be the same as the original.
184        assert_eq!(deserialized, [1u8; 37]);
185    }
186
187    // The array serializer should not interfere with other serializers. Here we
188    // check serde_json to make sure an array is written as expected.
189    #[test]
190    fn test_array_serde_json() {
191        // Serialize an array into a buffer.
192        let mut buffer = Vec::new();
193        let mut cursor = std::io::Cursor::new(&mut buffer);
194        let mut serialized = serde_json::Serializer::new(&mut cursor);
195        array::serialize(&[1u8; 7], &mut serialized).unwrap();
196        let result = String::from_utf8(buffer).unwrap();
197        assert_eq!(result, "[1,1,1,1,1,1,1]");
198
199        // Deserializing should also work.
200        let mut deserializer = serde_json::Deserializer::from_str(&result);
201        let deserialized: [u8; 7] = array::deserialize(&mut deserializer).unwrap();
202        assert_eq!(deserialized, [1u8; 7]);
203    }
204
205    // Golden Structure Test
206    //
207    // This test serializes a struct containing all the expected types we should
208    // be able to handle and checks the output is as expected. The reason I
209    // opted to serialize all in one struct instead of with separate tests is to
210    // ensure that the positioning of elements when in relation to others is
211    // also as expected. Especially when it comes to things such as nesting and
212    // length prefixing.
213    #[test]
214    fn test_pyth_serde() {
215        use serde::Serialize;
216
217        // Setup Serializer.
218        let mut buffer = Vec::new();
219        let mut cursor = std::io::Cursor::new(&mut buffer);
220        let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
221
222        // Golden Test Value. As binary data can be fickle to understand in
223        // tests this should be kept commented with detail.
224        #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
225        struct GoldenStruct<'a> {
226            // Test `unit` is not serialized to anything.
227            unit: (),
228
229            // Test `bool` is serialized to a single byte.
230            t_bool: bool,
231
232            // Test integer serializations.
233            t_u8:  u8,
234            t_u16: u16,
235            t_u32: u32,
236            t_u64: u64,
237
238            // Test `str` is serialized to a variable length array.
239            t_string: String,
240            t_str:    &'a str,
241
242            // Test `Vec` is serialized to a variable length array.
243            t_vec:              Vec<u8>,
244            t_vec_empty:        Vec<u8>,
245            t_vec_nested:       Vec<Vec<u8>>,
246            t_vec_nested_empty: Vec<Vec<u8>>,
247            t_slice:            &'a [u8],
248            t_slice_empty:      &'a [u8],
249
250            // Test tuples serialize as expected.
251            t_tuple:        (u8, u16, u32, u64, String, Vec<u8>, &'a [u8]),
252            t_tuple_nested: ((u8, u16), (u32, u64)),
253
254            // Test enum serializations.
255            t_enum_unit:    GoldenEnum,
256            t_enum_newtype: GoldenEnum,
257            t_enum_tuple:   GoldenEnum,
258            t_enum_struct:  GoldenEnum,
259
260            // Test nested structs, which includes our PrefixedVec implementations work as we expect.
261            t_struct:   GoldenNested<u8>,
262            t_prefixed: PrefixedVec<u16, u8>,
263        }
264
265        #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
266        struct GoldenNested<T> {
267            nested_u8:    T,
268            nested_tuple: (u8, u8),
269        }
270
271        #[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
272        enum GoldenEnum {
273            Unit,
274            Newtype(u8),
275            Tuple(u8, u16),
276            Struct { a: u8, b: u16 },
277        }
278
279        // Serialize the golden test value.
280        let golden_struct = GoldenStruct {
281            unit:               (),
282            t_bool:             true,
283            t_u8:               1,
284            t_u16:              2,
285            t_u32:              3,
286            t_u64:              4,
287            t_string:           "9".to_string(),
288            t_str:              "10",
289            t_vec:              vec![11, 12, 13],
290            t_vec_empty:        vec![],
291            t_vec_nested:       vec![vec![14, 15, 16], vec![17, 18, 19]],
292            t_vec_nested_empty: vec![vec![], vec![]],
293            t_slice:            &[20, 21, 22],
294            t_slice_empty:      &[],
295            t_tuple:            (
296                29,
297                30,
298                31,
299                32,
300                "10".to_string(),
301                vec![35, 36, 37],
302                &[38, 39, 40],
303            ),
304            t_tuple_nested:     ((41, 42), (43, 44)),
305            t_enum_unit:        GoldenEnum::Unit,
306            t_enum_newtype:     GoldenEnum::Newtype(45),
307            t_enum_tuple:       GoldenEnum::Tuple(46, 47),
308            t_enum_struct:      GoldenEnum::Struct { a: 48, b: 49 },
309            t_struct:           GoldenNested {
310                nested_u8:    50,
311                nested_tuple: (51, 52),
312            },
313            t_prefixed:         vec![0u8; 512].into(),
314        };
315
316        golden_struct.serialize(&mut serializer).unwrap();
317
318        // The serialized output should be as expected.
319        assert_eq!(
320            &buffer,
321            &[
322                1, // t_bool
323                1, // t_u8
324                2, 0, // t_u16
325                3, 0, 0, 0, // t_u32
326                4, 0, 0, 0, 0, 0, 0, 0, // t_u64
327                1, 57, // t_string
328                2, 49, 48, // t_str
329                3, 11, 12, 13, // t_vec
330                0,  // t_vec_empty
331                2, 3, 14, 15, 16, 3, 17, 18, 19, // t_vec_nested
332                2, 0, 0, // t_vec_nested_empty
333                3, 20, 21, 22, // t_slice
334                0,  // t_slice_empty
335                29, // t_tuple
336                30, 0, // u8
337                31, 0, 0, 0, // u16
338                32, 0, 0, 0, 0, 0, 0, 0, // u32
339                2, 49, 48, // "10"
340                3, 35, 36, 37, // [35, 36, 37]
341                3, 38, 39, 40, // [38, 39, 40]
342                41, 42, 0, 43, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, // t_tuple_nested
343                0, // t_enum_unit
344                1, 45, // t_enum_newtype
345                2, 46, 47, 0, // t_enum_tuple
346                3, 48, 49, 0, // t_enum_struct
347                50, 51, 52, // t_nested
348                0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
349                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
350                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
351                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
352                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
353                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
354                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
355                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
356                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
357                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
358                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
359                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
360                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
361                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
362                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
363                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
364                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
365                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
366                0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
367            ]
368        );
369
370        // We should also be able to deserialize back into the original type.
371        assert_eq!(
372            golden_struct,
373            crate::wire::from_slice::<byteorder::LE, _>(&buffer).unwrap()
374        );
375    }
376
377    #[test]
378    #[rustfmt::skip]
379    /// This method tests that our EnumAccess workaround does not violate any memory safety rules.
380    /// In particular we want to make sure we avoid transmuting to any type that is not a u8 (we do
381    /// not support > 255 variants anyway).
382    fn test_serde_enum_access_behaviour() {
383        use serde::Deserialize;
384        use serde::Serialize;
385
386        // Small-sized enums should all deserialize safely as single u8.
387        #[derive(PartialEq, Serialize, Deserialize, Debug)]
388        enum Singleton { A }
389
390        #[derive(PartialEq, Serialize, Deserialize, Debug)]
391        enum Pair { A, B }
392
393        #[derive(PartialEq, Serialize, Deserialize, Debug)]
394        enum Triple { A, B, C }
395
396        // Intentionally numbered enums with primitive representation (as long as u8) are safe.
397        #[derive(PartialEq, Serialize, Deserialize, Debug)]
398        enum CustomIndices {
399            A = 33,
400            B = 55,
401            C = 255,
402        }
403
404        // Complex enum's should still serialize as u8, and we expect the serde EnumAccess to work
405        // the same.
406        #[derive(PartialEq, Serialize, Deserialize, Debug)]
407        enum Complex {
408            A,
409            B(u8, u8),
410            C { a: u8, b: u8 },
411        }
412
413        // Forces the compiler to use a 16-bit discriminant. This must force the serde EnumAccess
414        // implementation to return an error. Otherwise we run the risk of the __Field enum in our
415        // transmute workaround becoming trash memory leading to UB.
416        #[derive(PartialEq, Serialize, Deserialize, Debug)]
417        enum ManyVariants {
418            _000, _001, _002, _003, _004, _005, _006, _007, _008, _009, _00A, _00B, _00C, _00D,
419            _00E, _00F, _010, _011, _012, _013, _014, _015, _016, _017, _018, _019, _01A, _01B,
420            _01C, _01D, _01E, _01F, _020, _021, _022, _023, _024, _025, _026, _027, _028, _029,
421            _02A, _02B, _02C, _02D, _02E, _02F, _030, _031, _032, _033, _034, _035, _036, _037,
422            _038, _039, _03A, _03B, _03C, _03D, _03E, _03F, _040, _041, _042, _043, _044, _045,
423            _046, _047, _048, _049, _04A, _04B, _04C, _04D, _04E, _04F, _050, _051, _052, _053,
424            _054, _055, _056, _057, _058, _059, _05A, _05B, _05C, _05D, _05E, _05F, _060, _061,
425            _062, _063, _064, _065, _066, _067, _068, _069, _06A, _06B, _06C, _06D, _06E, _06F,
426            _070, _071, _072, _073, _074, _075, _076, _077, _078, _079, _07A, _07B, _07C, _07D,
427            _07E, _07F, _080, _081, _082, _083, _084, _085, _086, _087, _088, _089, _08A, _08B,
428            _08C, _08D, _08E, _08F, _090, _091, _092, _093, _094, _095, _096, _097, _098, _099,
429            _09A, _09B, _09C, _09D, _09E, _09F, _0A0, _0A1, _0A2, _0A3, _0A4, _0A5, _0A6, _0A7,
430            _0A8, _0A9, _0AA, _0AB, _0AC, _0AD, _0AE, _0AF, _0B0, _0B1, _0B2, _0B3, _0B4, _0B5,
431            _0B6, _0B7, _0B8, _0B9, _0BA, _0BB, _0BC, _0BD, _0BE, _0BF, _0C0, _0C1, _0C2, _0C3,
432            _0C4, _0C5, _0C6, _0C7, _0C8, _0C9, _0CA, _0CB, _0CC, _0CD, _0CE, _0CF, _0D0, _0D1,
433            _0D2, _0D3, _0D4, _0D5, _0D6, _0D7, _0D8, _0D9, _0DA, _0DB, _0DC, _0DD, _0DE, _0DF,
434            _0E0, _0E1, _0E2, _0E3, _0E4, _0E5, _0E6, _0E7, _0E8, _0E9, _0EA, _0EB, _0EC, _0ED,
435            _0EE, _0EF, _0F0, _0F1, _0F2, _0F3, _0F4, _0F5, _0F6, _0F7, _0F8, _0F9, _0FA, _0FB,
436            _0FC, _0FD, _0FE, _0FF,
437
438            // > 255
439            _100
440        }
441
442        #[derive(PartialEq, Serialize, Deserialize, Debug)]
443        struct AllValid {
444            singleton:  Singleton,
445            pair:       Pair,
446            triple:     Triple,
447            complex:    Complex,
448            custom:     CustomIndices,
449        }
450
451        #[derive(PartialEq, Serialize, Deserialize, Debug)]
452        struct Invalid {
453            many_variants: ManyVariants,
454        }
455
456        let valid_buffer = [
457            // Singleton (A)
458            0,
459            // Pair (B)
460            1,
461            // Triple (C)
462            2,
463            // Complex
464            1, 0, 0,
465            // Custom
466            2,
467        ];
468
469        let valid_struct = AllValid {
470            singleton:  Singleton::A,
471            pair:       Pair::B,
472            triple:     Triple::C,
473            complex:    Complex::B(0, 0),
474            custom:     CustomIndices::C,
475        };
476
477        let valid_serialized = crate::wire::ser::to_vec::<_, byteorder::BE>(&valid_struct).unwrap();
478
479        // Confirm that the valid buffer can be deserialized.
480        let valid = crate::wire::from_slice::<byteorder::BE, AllValid>(&valid_buffer).unwrap();
481        let valid_deserialized = crate::wire::from_slice::<byteorder::BE, AllValid>(&valid_serialized).unwrap();
482        assert_eq!(valid, valid_struct);
483        assert_eq!(valid_deserialized, valid_struct);
484
485        // Invalid buffer tests that types > u8 fail to deserialize, it's important to note that
486        // there is nothing stopping someone compiling a program with an invalid enum deserialize
487        // but we can at least ensure an error in deserialization occurs.
488        let invalid_buffer = [
489            // ManyVariants (256)
490            1, 0
491        ];
492
493        let result = crate::wire::from_slice::<byteorder::BE, Invalid>(&invalid_buffer);
494        assert!(result.is_err());
495    }
496
497    // Test if the AccumulatorUpdateData type can be serialized and deserialized
498    // and still be the same as the original.
499    #[test]
500    fn test_accumulator_update_data_serde() {
501        use serde::Serialize;
502        // Serialize an empty update into a buffer.
503        let empty_update = AccumulatorUpdateData::new(Proof::WormholeMerkle {
504            vaa:     PrefixedVec::from(vec![]),
505            updates: vec![],
506        });
507        let mut buffer = Vec::new();
508        let mut cursor = std::io::Cursor::new(&mut buffer);
509        let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
510        empty_update.serialize(&mut serializer).unwrap();
511
512        // Test if it can be deserialized back into the original type.
513        let deserialized_update = AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
514
515        // The deserialized value should be the same as the original.
516        assert_eq!(deserialized_update, empty_update);
517    }
518
519    // Test if the AccumulatorUpdateData major and minor version increases work as expected
520    #[test]
521    fn test_accumulator_forward_compatibility() {
522        use serde::Serialize;
523        // Serialize an empty update into a buffer.
524
525        let empty_update = AccumulatorUpdateData::new(Proof::WormholeMerkle {
526            vaa:     PrefixedVec::from(vec![]),
527            updates: vec![],
528        });
529        let mut buffer = Vec::new();
530        let mut cursor = std::io::Cursor::new(&mut buffer);
531        let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
532        empty_update.serialize(&mut serializer).unwrap();
533
534        // Test if bumping minor version is still compatible
535        buffer[5] = 0x03;
536        AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
537
538        // Test if bumping major version makes it incompatible
539        buffer[4] = 0x03;
540        AccumulatorUpdateData::try_from_slice(&buffer).unwrap_err();
541    }
542}