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