From 94a0a783127f4d14fb40ce1f86fba5f015a20100 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 27 Jul 2023 12:56:13 -0400 Subject: [PATCH 1/2] add wormhole-io --- crates/io/Cargo.toml | 18 +++ crates/io/src/lib.rs | 5 + crates/io/src/payload.rs | 55 +++++++++ crates/io/src/read_write.rs | 237 ++++++++++++++++++++++++++++++++++++ 4 files changed, 315 insertions(+) create mode 100644 crates/io/Cargo.toml create mode 100644 crates/io/src/lib.rs create mode 100644 crates/io/src/payload.rs create mode 100644 crates/io/src/read_write.rs diff --git a/crates/io/Cargo.toml b/crates/io/Cargo.toml new file mode 100644 index 0000000..fd0c3e8 --- /dev/null +++ b/crates/io/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "wormhole-io" +description = "Traits for Wormhole payload serialization/deserialization" + +version.workspace = true +edition.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +repository.workspace = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +alloy-primitives = { workspace = true, optional = true } + +[features] +alloy = ["dep:alloy-primitives"] \ No newline at end of file diff --git a/crates/io/src/lib.rs b/crates/io/src/lib.rs new file mode 100644 index 0000000..35be3e5 --- /dev/null +++ b/crates/io/src/lib.rs @@ -0,0 +1,5 @@ +mod payload; +pub use payload::TypePrefixedPayload; + +mod read_write; +pub use read_write::{Readable, Writeable}; diff --git a/crates/io/src/payload.rs b/crates/io/src/payload.rs new file mode 100644 index 0000000..4a0867b --- /dev/null +++ b/crates/io/src/payload.rs @@ -0,0 +1,55 @@ +use std::io; + +use crate::{Readable, Writeable}; + +/// Trait to capture common payload behavior. We do not recommend overwriting +/// any trait methods. Simply set the type constant and implement [`Readable`] +/// and [`Writeable`]. +pub trait TypePrefixedPayload: Readable + Writeable + Clone + std::fmt::Debug { + const TYPE: Option; + + /// Read the payload, including the type prefix. + fn read_typed(reader: &mut R) -> Result { + let payload_type = u8::read(reader)?; + if payload_type == Self::TYPE.expect("Called write_typed on untyped payload") { + Self::read(reader) + } else { + Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid payload type", + )) + } + } + + /// Write the payload, including the type prefix. + fn write_typed(&self, writer: &mut W) -> Result<(), io::Error> { + Self::TYPE + .expect("Called write_typed on untyped payload") + .write(writer)?; + Writeable::write(self, writer) + } + + /// Read the payload, including the type prefix if applicable. + fn read_payload(reader: &mut R) -> Result { + match Self::TYPE { + Some(_) => Self::read_typed(reader), + None => Readable::read(reader), + } + } + + /// Write the payload, including the type prefix if applicable. + fn write_payload(&self, writer: &mut W) -> Result<(), io::Error> { + match Self::TYPE { + Some(_) => self.write_typed(writer), + None => Writeable::write(self, writer), + } + } + + /// Returns the size of the payload, including the type prefix. + fn payload_written_size(&self) -> usize { + match Self::TYPE { + Some(_) => self.written_size() + 1, + None => self.written_size(), + } + } +} diff --git a/crates/io/src/read_write.rs b/crates/io/src/read_write.rs new file mode 100644 index 0000000..84f539c --- /dev/null +++ b/crates/io/src/read_write.rs @@ -0,0 +1,237 @@ +use std::io; + +pub trait Readable { + const SIZE: Option; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read; +} + +pub trait Writeable { + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write; + + fn written_size(&self) -> usize; + + fn to_vec(&self) -> Vec { + let mut buf = Vec::with_capacity(self.written_size()); + self.write(&mut buf).expect("no alloc failure"); + buf + } +} + +impl Readable for u8 { + const SIZE: Option = Some(1); + + fn read(reader: &mut R) -> io::Result + where + R: io::Read, + { + let mut buf = [0u8; 1]; + reader.read_exact(&mut buf)?; + Ok(buf[0]) + } +} + +impl Writeable for u8 { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(&[*self]) + } +} + +impl Readable for u16 { + fn read(reader: &mut R) -> io::Result + where + R: io::Read, + { + let mut buf = [0u8; 2]; + reader.read_exact(&mut buf)?; + Ok(u16::from_be_bytes(buf)) + } + + const SIZE: Option = Some(2); +} + +impl Writeable for u16 { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(&self.to_be_bytes()) + } +} + +impl Readable for u32 { + const SIZE: Option = Some(4); + + fn read(reader: &mut R) -> io::Result + where + R: io::Read, + { + let mut buf = [0u8; 4]; + reader.read_exact(&mut buf)?; + Ok(u32::from_be_bytes(buf)) + } +} + +impl Writeable for u32 { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(&self.to_be_bytes()) + } +} + +impl Readable for u64 { + const SIZE: Option = Some(8); + + fn read(reader: &mut R) -> io::Result + where + R: io::Read, + { + let mut buf = [0u8; 8]; + reader.read_exact(&mut buf)?; + Ok(u64::from_be_bytes(buf)) + } +} + +impl Writeable for u64 { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(&self.to_be_bytes()) + } +} + +impl Readable for [u8; N] { + const SIZE: Option = Some(N); + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let mut buf = [0u8; N]; + reader.read_exact(&mut buf)?; + Ok(buf) + } +} + +impl Writeable for [u8; N] { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(self) + } +} + +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::FixedBytes { + const SIZE: Option = Some(N); + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + <[u8; N]>::read(reader).map(Self) + } +} + +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::FixedBytes { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.0.write(writer) + } +} + +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::Uint { + const SIZE: Option = { Some(BITS * 8) }; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let mut buf = alloy_primitives::Uint::::default().to_be_bytes_vec(); + reader.read_exact(buf.as_mut_slice())?; + + Ok(alloy_primitives::Uint::try_from_be_slice(buf.as_slice()).unwrap()) + } +} + +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::Uint { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + writer.write_all(self.to_be_bytes_vec().as_slice()) + } +} + +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::Address { + const SIZE: Option = Some(20); + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + alloy_primitives::FixedBytes::<20>::read(reader).map(Self) + } +} + +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::Address { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + self.0.write(writer) + } +} From cca72fb8b44954a41fcc78cce1f46a3ae1a0eec2 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Tue, 22 Aug 2023 09:14:53 -0500 Subject: [PATCH 2/2] add wormhole-io as dependency --- Cargo.toml | 1 + crates/vaas/Cargo.toml | 2 + crates/vaas/src/lib.rs | 3 +- crates/vaas/src/read_write.rs | 233 ---------------------------------- 4 files changed, 4 insertions(+), 235 deletions(-) delete mode 100644 crates/vaas/src/read_write.rs diff --git a/Cargo.toml b/Cargo.toml index 18b2a57..f938260 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,5 +22,6 @@ anchor-lang = "0.28.0" serde = "1.0.171" serde_json = "1.0.103" +wormhole-io = { path = "crates/io" } wormhole-vaas = { path = "crates/vaas" } wormhole-explorer-client = { path = "crates/explorer-client" } \ No newline at end of file diff --git a/crates/vaas/Cargo.toml b/crates/vaas/Cargo.toml index 6820c27..8e9883a 100644 --- a/crates/vaas/Cargo.toml +++ b/crates/vaas/Cargo.toml @@ -10,6 +10,8 @@ homepage.workspace = true repository.workspace = true [dependencies] +wormhole-io = { workspace = true, features = ["alloy"] } + alloy-primitives.workspace = true hex-literal.workspace = true diff --git a/crates/vaas/src/lib.rs b/crates/vaas/src/lib.rs index b988ebb..4ae0ebd 100644 --- a/crates/vaas/src/lib.rs +++ b/crates/vaas/src/lib.rs @@ -1,5 +1,4 @@ -mod read_write; -pub use read_write::{Readable, Writeable}; +pub use wormhole_io::{Readable, Writeable}; pub mod utils; pub use utils::{keccak256, quorum}; diff --git a/crates/vaas/src/read_write.rs b/crates/vaas/src/read_write.rs deleted file mode 100644 index cb22c24..0000000 --- a/crates/vaas/src/read_write.rs +++ /dev/null @@ -1,233 +0,0 @@ -use std::io; - -use alloy_primitives::{Address, FixedBytes, Uint}; - -pub trait Readable { - const SIZE: Option; - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read; -} - -pub trait Writeable { - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write; - - fn written_size(&self) -> usize; - - fn to_vec(&self) -> Vec { - let mut buf = Vec::with_capacity(self.written_size()); - self.write(&mut buf).expect("no alloc failure"); - buf - } -} - -impl Readable for u8 { - const SIZE: Option = Some(1); - - fn read(reader: &mut R) -> io::Result - where - R: io::Read, - { - let mut buf = [0u8; 1]; - reader.read_exact(&mut buf)?; - Ok(buf[0]) - } -} - -impl Writeable for u8 { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(&[*self]) - } -} - -impl Readable for u16 { - fn read(reader: &mut R) -> io::Result - where - R: io::Read, - { - let mut buf = [0u8; 2]; - reader.read_exact(&mut buf)?; - Ok(u16::from_be_bytes(buf)) - } - - const SIZE: Option = Some(2); -} - -impl Writeable for u16 { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(&self.to_be_bytes()) - } -} - -impl Readable for u32 { - const SIZE: Option = Some(4); - - fn read(reader: &mut R) -> io::Result - where - R: io::Read, - { - let mut buf = [0u8; 4]; - reader.read_exact(&mut buf)?; - Ok(u32::from_be_bytes(buf)) - } -} - -impl Writeable for u32 { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(&self.to_be_bytes()) - } -} - -impl Readable for u64 { - const SIZE: Option = Some(8); - - fn read(reader: &mut R) -> io::Result - where - R: io::Read, - { - let mut buf = [0u8; 8]; - reader.read_exact(&mut buf)?; - Ok(u64::from_be_bytes(buf)) - } -} - -impl Writeable for u64 { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(&self.to_be_bytes()) - } -} - -impl Readable for [u8; N] { - const SIZE: Option = Some(N); - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - let mut buf = [0u8; N]; - reader.read_exact(&mut buf)?; - Ok(buf) - } -} - -impl Writeable for [u8; N] { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(self) - } -} - -impl Readable for FixedBytes { - const SIZE: Option = Some(N); - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - <[u8; N]>::read(reader).map(Self) - } -} - -impl Writeable for FixedBytes { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - self.0.write(writer) - } -} - -impl Readable for Uint { - const SIZE: Option = { Some(BITS * 8) }; - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - let mut buf = Uint::::default().to_be_bytes_vec(); - reader.read_exact(buf.as_mut_slice())?; - - Ok(Uint::try_from_be_slice(buf.as_slice()).unwrap()) - } -} - -impl Writeable for Uint { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - writer.write_all(self.to_be_bytes_vec().as_slice()) - } -} - -impl Readable for Address { - const SIZE: Option = Some(20); - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - FixedBytes::<20>::read(reader).map(Self) - } -} - -impl Writeable for Address { - fn written_size(&self) -> usize { - ::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - self.0.write(writer) - } -}