543 lines
21 KiB
Rust
543 lines
21 KiB
Rust
//! Pyth Wire Format
|
|
//!
|
|
//! Pyth uses a custom wire format when moving data between programs and chains. This module
|
|
//! provides the serialization and deserialization logic for this format as well as definitions of
|
|
//! data structures used in the PythNet ecosystem.
|
|
//!
|
|
//! See the `ser` submodule for a description of the Pyth Wire format.
|
|
|
|
pub mod array;
|
|
mod de;
|
|
mod prefixed_vec;
|
|
mod ser;
|
|
|
|
pub use {
|
|
de::{
|
|
from_slice,
|
|
Deserializer,
|
|
DeserializerError,
|
|
},
|
|
prefixed_vec::PrefixedVec,
|
|
ser::{
|
|
to_vec,
|
|
to_writer,
|
|
Serializer,
|
|
SerializerError,
|
|
},
|
|
};
|
|
|
|
// Proof Format (V1)
|
|
// --------------------------------------------------------------------------------
|
|
// The definitions within each module can be updated with append-only data without requiring a new
|
|
// module to be defined. So for example, it is possible to add new fields can be added to the end
|
|
// of the `AccumulatorAccount` without moving to a `v1`.
|
|
pub mod v1 {
|
|
use {
|
|
super::*,
|
|
crate::{
|
|
accumulators::merkle::MerklePath,
|
|
error::Error,
|
|
hashers::keccak256_160::Keccak160,
|
|
require,
|
|
},
|
|
borsh::{
|
|
BorshDeserialize,
|
|
BorshSerialize,
|
|
},
|
|
serde::{
|
|
Deserialize,
|
|
Serialize,
|
|
},
|
|
};
|
|
pub const PYTHNET_ACCUMULATOR_UPDATE_MAGIC: &[u8; 4] = b"PNAU";
|
|
pub const CURRENT_MINOR_VERSION: u8 = 0;
|
|
|
|
// Transfer Format.
|
|
// --------------------------------------------------------------------------------
|
|
// This definition is what will be sent over the wire (I.E, pulled from PythNet and submitted
|
|
// to target chains).
|
|
#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub struct AccumulatorUpdateData {
|
|
magic: [u8; 4],
|
|
major_version: u8,
|
|
minor_version: u8,
|
|
trailing: Vec<u8>,
|
|
pub proof: Proof,
|
|
}
|
|
|
|
impl AccumulatorUpdateData {
|
|
pub fn new(proof: Proof) -> Self {
|
|
Self {
|
|
magic: *PYTHNET_ACCUMULATOR_UPDATE_MAGIC,
|
|
major_version: 1,
|
|
minor_version: 0,
|
|
trailing: vec![],
|
|
proof,
|
|
}
|
|
}
|
|
|
|
pub fn try_from_slice(bytes: &[u8]) -> Result<Self, Error> {
|
|
let message = from_slice::<byteorder::BE, Self>(bytes)
|
|
.map_err(|_| Error::DeserializationError)?;
|
|
require!(
|
|
&message.magic[..] == PYTHNET_ACCUMULATOR_UPDATE_MAGIC,
|
|
Error::InvalidMagic
|
|
);
|
|
require!(message.major_version == 1, Error::InvalidVersion);
|
|
require!(
|
|
message.minor_version >= CURRENT_MINOR_VERSION,
|
|
Error::InvalidVersion
|
|
);
|
|
Ok(message)
|
|
}
|
|
}
|
|
|
|
// A hash of some data.
|
|
pub type Hash = [u8; 20];
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub enum Proof {
|
|
WormholeMerkle {
|
|
vaa: PrefixedVec<u16, u8>,
|
|
updates: Vec<MerklePriceUpdate>,
|
|
},
|
|
}
|
|
|
|
#[derive(
|
|
Clone, Debug, Hash, PartialEq, Serialize, Deserialize, BorshDeserialize, BorshSerialize,
|
|
)]
|
|
pub struct MerklePriceUpdate {
|
|
pub message: PrefixedVec<u16, u8>,
|
|
pub proof: MerklePath<Keccak160>,
|
|
}
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub struct WormholeMessage {
|
|
pub magic: [u8; 4],
|
|
pub payload: WormholePayload,
|
|
}
|
|
|
|
pub const ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC: &[u8; 4] = b"AUWV";
|
|
|
|
impl WormholeMessage {
|
|
pub fn new(payload: WormholePayload) -> Self {
|
|
Self {
|
|
magic: *ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC,
|
|
payload,
|
|
}
|
|
}
|
|
|
|
pub fn try_from_bytes(bytes: impl AsRef<[u8]>) -> Result<Self, Error> {
|
|
let message = from_slice::<byteorder::BE, Self>(bytes.as_ref())
|
|
.map_err(|_| Error::DeserializationError)?;
|
|
require!(
|
|
&message.magic[..] == ACCUMULATOR_UPDATE_WORMHOLE_VERIFICATION_MAGIC,
|
|
Error::InvalidMagic
|
|
);
|
|
Ok(message)
|
|
}
|
|
}
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub enum WormholePayload {
|
|
Merkle(WormholeMerkleRoot),
|
|
}
|
|
|
|
#[derive(Clone, Debug, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub struct WormholeMerkleRoot {
|
|
pub slot: u64,
|
|
pub ring_size: u32,
|
|
pub root: Hash,
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::wire::{
|
|
array,
|
|
v1::{
|
|
AccumulatorUpdateData,
|
|
Proof,
|
|
},
|
|
Deserializer,
|
|
PrefixedVec,
|
|
Serializer,
|
|
};
|
|
|
|
// Test the arbitrary fixed sized array serialization implementation.
|
|
#[test]
|
|
fn test_array_serde() {
|
|
// Serialize an array into a buffer.
|
|
let mut buffer = Vec::new();
|
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
|
let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
|
|
array::serialize(&[1u8; 37], &mut serializer).unwrap();
|
|
|
|
// The result should not have been prefixed with a length byte.
|
|
assert_eq!(buffer.len(), 37);
|
|
|
|
// We should also be able to deserialize it back.
|
|
let mut deserializer = Deserializer::<byteorder::LE>::new(&buffer);
|
|
let deserialized: [u8; 37] = array::deserialize(&mut deserializer).unwrap();
|
|
|
|
// The deserialized array should be the same as the original.
|
|
assert_eq!(deserialized, [1u8; 37]);
|
|
}
|
|
|
|
// The array serializer should not interfere with other serializers. Here we
|
|
// check serde_json to make sure an array is written as expected.
|
|
#[test]
|
|
fn test_array_serde_json() {
|
|
// Serialize an array into a buffer.
|
|
let mut buffer = Vec::new();
|
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
|
let mut serialized = serde_json::Serializer::new(&mut cursor);
|
|
array::serialize(&[1u8; 7], &mut serialized).unwrap();
|
|
let result = String::from_utf8(buffer).unwrap();
|
|
assert_eq!(result, "[1,1,1,1,1,1,1]");
|
|
|
|
// Deserializing should also work.
|
|
let mut deserializer = serde_json::Deserializer::from_str(&result);
|
|
let deserialized: [u8; 7] = array::deserialize(&mut deserializer).unwrap();
|
|
assert_eq!(deserialized, [1u8; 7]);
|
|
}
|
|
|
|
// Golden Structure Test
|
|
//
|
|
// This test serializes a struct containing all the expected types we should
|
|
// be able to handle and checks the output is as expected. The reason I
|
|
// opted to serialize all in one struct instead of with separate tests is to
|
|
// ensure that the positioning of elements when in relation to others is
|
|
// also as expected. Especially when it comes to things such as nesting and
|
|
// length prefixing.
|
|
#[test]
|
|
fn test_pyth_serde() {
|
|
use serde::Serialize;
|
|
|
|
// Setup Serializer.
|
|
let mut buffer = Vec::new();
|
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
|
let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
|
|
|
|
// Golden Test Value. As binary data can be fickle to understand in
|
|
// tests this should be kept commented with detail.
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
|
|
struct GoldenStruct<'a> {
|
|
// Test `unit` is not serialized to anything.
|
|
unit: (),
|
|
|
|
// Test `bool` is serialized to a single byte.
|
|
t_bool: bool,
|
|
|
|
// Test integer serializations.
|
|
t_u8: u8,
|
|
t_u16: u16,
|
|
t_u32: u32,
|
|
t_u64: u64,
|
|
|
|
// Test `str` is serialized to a variable length array.
|
|
t_string: String,
|
|
t_str: &'a str,
|
|
|
|
// Test `Vec` is serialized to a variable length array.
|
|
t_vec: Vec<u8>,
|
|
t_vec_empty: Vec<u8>,
|
|
t_vec_nested: Vec<Vec<u8>>,
|
|
t_vec_nested_empty: Vec<Vec<u8>>,
|
|
t_slice: &'a [u8],
|
|
t_slice_empty: &'a [u8],
|
|
|
|
// Test tuples serialize as expected.
|
|
t_tuple: (u8, u16, u32, u64, String, Vec<u8>, &'a [u8]),
|
|
t_tuple_nested: ((u8, u16), (u32, u64)),
|
|
|
|
// Test enum serializations.
|
|
t_enum_unit: GoldenEnum,
|
|
t_enum_newtype: GoldenEnum,
|
|
t_enum_tuple: GoldenEnum,
|
|
t_enum_struct: GoldenEnum,
|
|
|
|
// Test nested structs, which includes our PrefixedVec implementations work as we expect.
|
|
t_struct: GoldenNested<u8>,
|
|
t_prefixed: PrefixedVec<u16, u8>,
|
|
}
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
|
|
struct GoldenNested<T> {
|
|
nested_u8: T,
|
|
nested_tuple: (u8, u8),
|
|
}
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
|
|
enum GoldenEnum {
|
|
Unit,
|
|
Newtype(u8),
|
|
Tuple(u8, u16),
|
|
Struct { a: u8, b: u16 },
|
|
}
|
|
|
|
// Serialize the golden test value.
|
|
let golden_struct = GoldenStruct {
|
|
unit: (),
|
|
t_bool: true,
|
|
t_u8: 1,
|
|
t_u16: 2,
|
|
t_u32: 3,
|
|
t_u64: 4,
|
|
t_string: "9".to_string(),
|
|
t_str: "10",
|
|
t_vec: vec![11, 12, 13],
|
|
t_vec_empty: vec![],
|
|
t_vec_nested: vec![vec![14, 15, 16], vec![17, 18, 19]],
|
|
t_vec_nested_empty: vec![vec![], vec![]],
|
|
t_slice: &[20, 21, 22],
|
|
t_slice_empty: &[],
|
|
t_tuple: (
|
|
29,
|
|
30,
|
|
31,
|
|
32,
|
|
"10".to_string(),
|
|
vec![35, 36, 37],
|
|
&[38, 39, 40],
|
|
),
|
|
t_tuple_nested: ((41, 42), (43, 44)),
|
|
t_enum_unit: GoldenEnum::Unit,
|
|
t_enum_newtype: GoldenEnum::Newtype(45),
|
|
t_enum_tuple: GoldenEnum::Tuple(46, 47),
|
|
t_enum_struct: GoldenEnum::Struct { a: 48, b: 49 },
|
|
t_struct: GoldenNested {
|
|
nested_u8: 50,
|
|
nested_tuple: (51, 52),
|
|
},
|
|
t_prefixed: vec![0u8; 512].into(),
|
|
};
|
|
|
|
golden_struct.serialize(&mut serializer).unwrap();
|
|
|
|
// The serialized output should be as expected.
|
|
assert_eq!(
|
|
&buffer,
|
|
&[
|
|
1, // t_bool
|
|
1, // t_u8
|
|
2, 0, // t_u16
|
|
3, 0, 0, 0, // t_u32
|
|
4, 0, 0, 0, 0, 0, 0, 0, // t_u64
|
|
1, 57, // t_string
|
|
2, 49, 48, // t_str
|
|
3, 11, 12, 13, // t_vec
|
|
0, // t_vec_empty
|
|
2, 3, 14, 15, 16, 3, 17, 18, 19, // t_vec_nested
|
|
2, 0, 0, // t_vec_nested_empty
|
|
3, 20, 21, 22, // t_slice
|
|
0, // t_slice_empty
|
|
29, // t_tuple
|
|
30, 0, // u8
|
|
31, 0, 0, 0, // u16
|
|
32, 0, 0, 0, 0, 0, 0, 0, // u32
|
|
2, 49, 48, // "10"
|
|
3, 35, 36, 37, // [35, 36, 37]
|
|
3, 38, 39, 40, // [38, 39, 40]
|
|
41, 42, 0, 43, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, // t_tuple_nested
|
|
0, // t_enum_unit
|
|
1, 45, // t_enum_newtype
|
|
2, 46, 47, 0, // t_enum_tuple
|
|
3, 48, 49, 0, // t_enum_struct
|
|
50, 51, 52, // t_nested
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
]
|
|
);
|
|
|
|
// We should also be able to deserialize back into the original type.
|
|
assert_eq!(
|
|
golden_struct,
|
|
crate::wire::from_slice::<byteorder::LE, _>(&buffer).unwrap()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
#[rustfmt::skip]
|
|
/// This method tests that our EnumAccess workaround does not violate any memory safety rules.
|
|
/// In particular we want to make sure we avoid transmuting to any type that is not a u8 (we do
|
|
/// not support > 255 variants anyway).
|
|
fn test_serde_enum_access_behaviour() {
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
|
|
// Small-sized enums should all deserialize safely as single u8.
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum Singleton { A }
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum Pair { A, B }
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum Triple { A, B, C }
|
|
|
|
// Intentionally numbered enums with primitive representation (as long as u8) are safe.
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum CustomIndices {
|
|
A = 33,
|
|
B = 55,
|
|
C = 255,
|
|
}
|
|
|
|
// Complex enum's should still serialize as u8, and we expect the serde EnumAccess to work
|
|
// the same.
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum Complex {
|
|
A,
|
|
B(u8, u8),
|
|
C { a: u8, b: u8 },
|
|
}
|
|
|
|
// Forces the compiler to use a 16-bit discriminant. This must force the serde EnumAccess
|
|
// implementation to return an error. Otherwise we run the risk of the __Field enum in our
|
|
// transmute workaround becoming trash memory leading to UB.
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
enum ManyVariants {
|
|
_000, _001, _002, _003, _004, _005, _006, _007, _008, _009, _00A, _00B, _00C, _00D,
|
|
_00E, _00F, _010, _011, _012, _013, _014, _015, _016, _017, _018, _019, _01A, _01B,
|
|
_01C, _01D, _01E, _01F, _020, _021, _022, _023, _024, _025, _026, _027, _028, _029,
|
|
_02A, _02B, _02C, _02D, _02E, _02F, _030, _031, _032, _033, _034, _035, _036, _037,
|
|
_038, _039, _03A, _03B, _03C, _03D, _03E, _03F, _040, _041, _042, _043, _044, _045,
|
|
_046, _047, _048, _049, _04A, _04B, _04C, _04D, _04E, _04F, _050, _051, _052, _053,
|
|
_054, _055, _056, _057, _058, _059, _05A, _05B, _05C, _05D, _05E, _05F, _060, _061,
|
|
_062, _063, _064, _065, _066, _067, _068, _069, _06A, _06B, _06C, _06D, _06E, _06F,
|
|
_070, _071, _072, _073, _074, _075, _076, _077, _078, _079, _07A, _07B, _07C, _07D,
|
|
_07E, _07F, _080, _081, _082, _083, _084, _085, _086, _087, _088, _089, _08A, _08B,
|
|
_08C, _08D, _08E, _08F, _090, _091, _092, _093, _094, _095, _096, _097, _098, _099,
|
|
_09A, _09B, _09C, _09D, _09E, _09F, _0A0, _0A1, _0A2, _0A3, _0A4, _0A5, _0A6, _0A7,
|
|
_0A8, _0A9, _0AA, _0AB, _0AC, _0AD, _0AE, _0AF, _0B0, _0B1, _0B2, _0B3, _0B4, _0B5,
|
|
_0B6, _0B7, _0B8, _0B9, _0BA, _0BB, _0BC, _0BD, _0BE, _0BF, _0C0, _0C1, _0C2, _0C3,
|
|
_0C4, _0C5, _0C6, _0C7, _0C8, _0C9, _0CA, _0CB, _0CC, _0CD, _0CE, _0CF, _0D0, _0D1,
|
|
_0D2, _0D3, _0D4, _0D5, _0D6, _0D7, _0D8, _0D9, _0DA, _0DB, _0DC, _0DD, _0DE, _0DF,
|
|
_0E0, _0E1, _0E2, _0E3, _0E4, _0E5, _0E6, _0E7, _0E8, _0E9, _0EA, _0EB, _0EC, _0ED,
|
|
_0EE, _0EF, _0F0, _0F1, _0F2, _0F3, _0F4, _0F5, _0F6, _0F7, _0F8, _0F9, _0FA, _0FB,
|
|
_0FC, _0FD, _0FE, _0FF,
|
|
|
|
// > 255
|
|
_100
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
struct AllValid {
|
|
singleton: Singleton,
|
|
pair: Pair,
|
|
triple: Triple,
|
|
complex: Complex,
|
|
custom: CustomIndices,
|
|
}
|
|
|
|
#[derive(PartialEq, Serialize, Deserialize, Debug)]
|
|
struct Invalid {
|
|
many_variants: ManyVariants,
|
|
}
|
|
|
|
let valid_buffer = [
|
|
// Singleton (A)
|
|
0,
|
|
// Pair (B)
|
|
1,
|
|
// Triple (C)
|
|
2,
|
|
// Complex
|
|
1, 0, 0,
|
|
// Custom
|
|
2,
|
|
];
|
|
|
|
let valid_struct = AllValid {
|
|
singleton: Singleton::A,
|
|
pair: Pair::B,
|
|
triple: Triple::C,
|
|
complex: Complex::B(0, 0),
|
|
custom: CustomIndices::C,
|
|
};
|
|
|
|
let valid_serialized = crate::wire::ser::to_vec::<_, byteorder::BE>(&valid_struct).unwrap();
|
|
|
|
// Confirm that the valid buffer can be deserialized.
|
|
let valid = crate::wire::from_slice::<byteorder::BE, AllValid>(&valid_buffer).unwrap();
|
|
let valid_deserialized = crate::wire::from_slice::<byteorder::BE, AllValid>(&valid_serialized).unwrap();
|
|
assert_eq!(valid, valid_struct);
|
|
assert_eq!(valid_deserialized, valid_struct);
|
|
|
|
// Invalid buffer tests that types > u8 fail to deserialize, it's important to note that
|
|
// there is nothing stopping someone compiling a program with an invalid enum deserialize
|
|
// but we can at least ensure an error in deserialization occurs.
|
|
let invalid_buffer = [
|
|
// ManyVariants (256)
|
|
1, 0
|
|
];
|
|
|
|
let result = crate::wire::from_slice::<byteorder::BE, Invalid>(&invalid_buffer);
|
|
assert!(result.is_err());
|
|
}
|
|
|
|
// Test if the AccumulatorUpdateData type can be serialized and deserialized
|
|
// and still be the same as the original.
|
|
#[test]
|
|
fn test_accumulator_update_data_serde() {
|
|
use serde::Serialize;
|
|
// Serialize an empty update into a buffer.
|
|
let empty_update = AccumulatorUpdateData::new(Proof::WormholeMerkle {
|
|
vaa: PrefixedVec::from(vec![]),
|
|
updates: vec![],
|
|
});
|
|
let mut buffer = Vec::new();
|
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
|
let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
|
|
empty_update.serialize(&mut serializer).unwrap();
|
|
|
|
// Test if it can be deserialized back into the original type.
|
|
let deserialized_update = AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
|
|
|
|
// The deserialized value should be the same as the original.
|
|
assert_eq!(deserialized_update, empty_update);
|
|
}
|
|
|
|
// Test if the AccumulatorUpdateData major and minor version increases work as expected
|
|
#[test]
|
|
fn test_accumulator_forward_compatibility() {
|
|
use serde::Serialize;
|
|
// Serialize an empty update into a buffer.
|
|
|
|
let empty_update = AccumulatorUpdateData::new(Proof::WormholeMerkle {
|
|
vaa: PrefixedVec::from(vec![]),
|
|
updates: vec![],
|
|
});
|
|
let mut buffer = Vec::new();
|
|
let mut cursor = std::io::Cursor::new(&mut buffer);
|
|
let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
|
|
empty_update.serialize(&mut serializer).unwrap();
|
|
|
|
// Test if bumping minor version is still compatible
|
|
buffer[5] = 0x03;
|
|
AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
|
|
|
|
// Test if bumping major version makes it incompatible
|
|
buffer[4] = 0x03;
|
|
AccumulatorUpdateData::try_from_slice(&buffer).unwrap_err();
|
|
}
|
|
}
|