use serde::{Serialize, de::DeserializeOwned}; #[derive(Debug, thiserror::Error)] pub enum CodecError { #[error("canonical encoding failed: {0}")] Encode(#[from] postcard::Error), } pub fn encode_canonical(value: &T) -> Result, CodecError> { postcard::to_allocvec(value).map_err(CodecError::from) } pub fn decode_canonical(bytes: &[u8]) -> Result { postcard::from_bytes(bytes).map_err(CodecError::from) } pub fn hash_canonical( value: &T, ) -> Result { let bytes = encode_canonical(value)?; Ok(blake3_hash_bytes(&bytes)) } #[must_use] pub fn blake3_hash_bytes(bytes: &[u8]) -> geth_types::BlobHash { geth_types::BlobHash::new(blake3::hash(bytes).to_hex().to_string()) } #[cfg(test)] mod tests { use super::*; use serde::{Deserialize, Serialize}; #[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] struct Sample { version: u8, name: String, values: Vec, } #[test] fn canonical_encoding_is_deterministic() { let sample = Sample { version: 1, name: "geth".to_owned(), values: vec![1, 2, 3], }; assert_eq!( encode_canonical(&sample).expect("encode"), encode_canonical(&sample).expect("encode again") ); assert_eq!( hash_canonical(&sample).expect("hash"), hash_canonical(&sample).expect("hash again") ); assert_eq!( decode_canonical::(&encode_canonical(&sample).expect("encode")) .expect("decode"), sample ); } }