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,
},
};
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;
#[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)
}
}
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]
fn test_array_serde() {
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();
assert_eq!(buffer.len(), 37);
let mut deserializer = Deserializer::<byteorder::LE>::new(&buffer);
let deserialized: [u8; 37] = array::deserialize(&mut deserializer).unwrap();
assert_eq!(deserialized, [1u8; 37]);
}
#[test]
fn test_array_serde_json() {
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]");
let mut deserializer = serde_json::Deserializer::from_str(&result);
let deserialized: [u8; 7] = array::deserialize(&mut deserializer).unwrap();
assert_eq!(deserialized, [1u8; 7]);
}
#[test]
fn test_pyth_serde() {
use serde::Serialize;
let mut buffer = Vec::new();
let mut cursor = std::io::Cursor::new(&mut buffer);
let mut serializer: Serializer<_, byteorder::LE> = Serializer::new(&mut cursor);
#[derive(serde::Serialize, serde::Deserialize, Debug, PartialEq)]
struct GoldenStruct<'a> {
unit: (),
t_bool: bool,
t_u8: u8,
t_u16: u16,
t_u32: u32,
t_u64: u64,
t_string: String,
t_str: &'a str,
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],
t_tuple: (u8, u16, u32, u64, String, Vec<u8>, &'a [u8]),
t_tuple_nested: ((u8, u16), (u32, u64)),
t_enum_unit: GoldenEnum,
t_enum_newtype: GoldenEnum,
t_enum_tuple: GoldenEnum,
t_enum_struct: GoldenEnum,
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 },
}
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();
assert_eq!(
&buffer,
&[
1, 1, 2, 0, 3, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 1, 57, 2, 49, 48, 3, 11, 12, 13, 0, 2, 3, 14, 15, 16, 3, 17, 18, 19, 2, 0, 0, 3, 20, 21, 22, 0, 29, 30, 0, 31, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 2, 49, 48, 3, 35, 36, 37, 3, 38, 39, 40, 41, 42, 0, 43, 0, 0, 0, 44, 0, 0, 0, 0, 0, 0, 0, 0, 1, 45, 2, 46, 47, 0, 3, 48, 49, 0, 50, 51, 52, 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,
]
);
assert_eq!(
golden_struct,
crate::wire::from_slice::<byteorder::LE, _>(&buffer).unwrap()
);
}
#[test]
#[rustfmt::skip]
fn test_serde_enum_access_behaviour() {
use serde::Deserialize;
use serde::Serialize;
#[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 }
#[derive(PartialEq, Serialize, Deserialize, Debug)]
enum CustomIndices {
A = 33,
B = 55,
C = 255,
}
#[derive(PartialEq, Serialize, Deserialize, Debug)]
enum Complex {
A,
B(u8, u8),
C { a: u8, b: u8 },
}
#[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,
_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 = [
0,
1,
2,
1, 0, 0,
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();
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);
let invalid_buffer = [
1, 0
];
let result = crate::wire::from_slice::<byteorder::BE, Invalid>(&invalid_buffer);
assert!(result.is_err());
}
#[test]
fn test_accumulator_update_data_serde() {
use serde::Serialize;
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();
let deserialized_update = AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
assert_eq!(deserialized_update, empty_update);
}
#[test]
fn test_accumulator_forward_compatibility() {
use serde::Serialize;
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();
buffer[5] = 0x03;
AccumulatorUpdateData::try_from_slice(&buffer).unwrap();
buffer[4] = 0x03;
AccumulatorUpdateData::try_from_slice(&buffer).unwrap_err();
}
}