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/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/vaas/src/read_write.rs b/crates/io/src/read_write.rs similarity index 84% rename from crates/vaas/src/read_write.rs rename to crates/io/src/read_write.rs index cb22c24..84f539c 100644 --- a/crates/vaas/src/read_write.rs +++ b/crates/io/src/read_write.rs @@ -1,7 +1,5 @@ use std::io; -use alloy_primitives::{Address, FixedBytes, Uint}; - pub trait Readable { const SIZE: Option; @@ -154,7 +152,8 @@ impl Writeable for [u8; N] { } } -impl Readable for FixedBytes { +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::FixedBytes { const SIZE: Option = Some(N); fn read(reader: &mut R) -> io::Result @@ -166,7 +165,8 @@ impl Readable for FixedBytes { } } -impl Writeable for FixedBytes { +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::FixedBytes { fn written_size(&self) -> usize { ::SIZE.unwrap() } @@ -179,7 +179,8 @@ impl Writeable for FixedBytes { } } -impl Readable for Uint { +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::Uint { const SIZE: Option = { Some(BITS * 8) }; fn read(reader: &mut R) -> io::Result @@ -187,14 +188,15 @@ impl Readable for Uint { Self: Sized, R: io::Read, { - let mut buf = Uint::::default().to_be_bytes_vec(); + let mut buf = alloy_primitives::Uint::::default().to_be_bytes_vec(); reader.read_exact(buf.as_mut_slice())?; - Ok(Uint::try_from_be_slice(buf.as_slice()).unwrap()) + Ok(alloy_primitives::Uint::try_from_be_slice(buf.as_slice()).unwrap()) } } -impl Writeable for Uint { +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::Uint { fn written_size(&self) -> usize { ::SIZE.unwrap() } @@ -207,7 +209,8 @@ impl Writeable for Uint { } } -impl Readable for Address { +#[cfg(feature = "alloy")] +impl Readable for alloy_primitives::Address { const SIZE: Option = Some(20); fn read(reader: &mut R) -> io::Result @@ -215,11 +218,12 @@ impl Readable for Address { Self: Sized, R: io::Read, { - FixedBytes::<20>::read(reader).map(Self) + alloy_primitives::FixedBytes::<20>::read(reader).map(Self) } } -impl Writeable for Address { +#[cfg(feature = "alloy")] +impl Writeable for alloy_primitives::Address { fn written_size(&self) -> usize { ::SIZE.unwrap() } 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};