From d8c92f6d147bb6198eab8c485f55d9f8314319a2 Mon Sep 17 00:00:00 2001 From: Santiago Carmuega Date: Thu, 2 Jun 2022 14:20:14 -0300 Subject: [PATCH] feat: Add mechanism to retain original CBOR --- pallas-codec/src/utils.rs | 63 +++++++++++++++++++ pallas-primitives/src/alonzo/crypto.rs | 49 ++++++++------- pallas-primitives/src/alonzo/model.rs | 14 +++-- .../src/alonzo/test_data/test22.block | 1 + pallas-primitives/src/framework.rs | 4 ++ 5 files changed, 102 insertions(+), 29 deletions(-) create mode 100644 pallas-primitives/src/alonzo/test_data/test22.block diff --git a/pallas-codec/src/utils.rs b/pallas-codec/src/utils.rs index 9ba35429..089c3f52 100644 --- a/pallas-codec/src/utils.rs +++ b/pallas-codec/src/utils.rs @@ -503,3 +503,66 @@ impl From<&AnyUInt> for u64 { u64::from(*x) } } + +/// Decodes a struct while preserving original CBOR +/// +/// # Examples +/// +/// ``` +/// use pallas_codec::utils::KeepRaw; +/// +/// let a = (123u16, (456u16, 789u16), 123u16); +/// let data = minicbor::to_vec(a).unwrap(); +/// +/// let (_, keeper, _): (u16, KeepRaw<(u16, u16)>, u16) = minicbor::decode(&data).unwrap(); +/// let confirm: (u16, u16) = minicbor::decode(keeper.raw_cbor()).unwrap(); +/// assert_eq!(confirm, (456u16, 789u16)); +/// ``` +#[derive(Debug, PartialEq, PartialOrd)] +pub struct KeepRaw<'b, T> { + raw: &'b [u8], + inner: T, +} + +impl<'b, T> KeepRaw<'b, T> { + pub fn raw_cbor(&self) -> &'b [u8] { + self.raw + } +} + +impl<'b, T> Deref for KeepRaw<'b, T> { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl<'b, T, C> minicbor::Decode<'b, C> for KeepRaw<'b, T> +where + T: minicbor::Decode<'b, C>, +{ + fn decode(d: &mut minicbor::Decoder<'b>, ctx: &mut C) -> Result { + let all = d.input(); + let start = d.position(); + let inner: T = d.decode_with(ctx)?; + let end = d.position(); + + Ok(Self { + inner, + raw: &all[start..end], + }) + } +} + +impl minicbor::Encode for KeepRaw<'_, T> { + fn encode( + &self, + e: &mut minicbor::Encoder, + _ctx: &mut C, + ) -> Result<(), minicbor::encode::Error> { + e.writer_mut() + .write_all(self.raw_cbor()) + .map_err(minicbor::encode::Error::write) + } +} diff --git a/pallas-primitives/src/alonzo/crypto.rs b/pallas-primitives/src/alonzo/crypto.rs index d023d176..5ba1785a 100644 --- a/pallas-primitives/src/alonzo/crypto.rs +++ b/pallas-primitives/src/alonzo/crypto.rs @@ -1,48 +1,51 @@ +use crate::ToHash; + use super::{AuxiliaryData, Header, NativeScript, PlutusData, PlutusScript, TransactionBody}; +use pallas_codec::utils::KeepRaw; use pallas_crypto::hash::{Hash, Hasher}; -pub fn hash_block_header(data: &Header) -> Hash<32> { - Hasher::<256>::hash_cbor(data) -} - -pub fn hash_auxiliary_data(data: &AuxiliaryData) -> Hash<32> { - Hasher::<256>::hash_cbor(data) -} - -#[deprecated(note = "use TransactionBody::to_hash instead")] -pub fn hash_transaction(data: &TransactionBody) -> Hash<32> { - Hasher::<256>::hash_cbor(data) +impl ToHash<32> for Header { + fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { + Hasher::<256>::hash_cbor(self) + } } -#[deprecated(note = "use PlutusData::to_hash instead")] -pub fn hash_plutus_data(data: &PlutusData) -> Hash<32> { - Hasher::<256>::hash_cbor(data) +impl ToHash<32> for AuxiliaryData { + fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { + Hasher::<256>::hash_cbor(self) + } } -impl NativeScript { - pub fn to_hash(&self) -> Hash<28> { +impl ToHash<28> for NativeScript { + fn to_hash(&self) -> Hash<28> { Hasher::<224>::hash_tagged_cbor(self, 0) } } -impl PlutusScript { - pub fn to_hash(&self) -> Hash<28> { +impl ToHash<28> for PlutusScript { + fn to_hash(&self) -> Hash<28> { Hasher::<224>::hash_tagged_cbor(self, 1) } } -impl PlutusData { - pub fn to_hash(&self) -> Hash<32> { +impl ToHash<32> for PlutusData { + fn to_hash(&self) -> Hash<32> { Hasher::<256>::hash_cbor(self) } } -impl TransactionBody { - pub fn to_hash(&self) -> Hash<32> { +impl ToHash<32> for TransactionBody { + fn to_hash(&self) -> Hash<32> { Hasher::<256>::hash_cbor(self) } } +impl ToHash<32> for KeepRaw<'_, TransactionBody> { + fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { + Hasher::<256>::hash(self.raw_cbor()) + } +} + #[cfg(test)] mod tests { use std::str::FromStr; @@ -52,7 +55,7 @@ mod tests { use pallas_crypto::hash::Hash; use crate::alonzo::{BigInt, BlockWrapper, Constr, NativeScript, PlutusData}; - use crate::Fragment; + use crate::{Fragment, ToHash}; #[test] fn transaction_hash_works() { diff --git a/pallas-primitives/src/alonzo/model.rs b/pallas-primitives/src/alonzo/model.rs index 118aab95..81eac4ec 100644 --- a/pallas-primitives/src/alonzo/model.rs +++ b/pallas-primitives/src/alonzo/model.rs @@ -6,7 +6,7 @@ use pallas_codec::minicbor::{bytes::ByteVec, data::Int, data::Tag, Decode, Encod use pallas_crypto::hash::Hash; use std::ops::Deref; -use pallas_codec::utils::{AnyUInt, KeyValuePairs, MaybeIndefArray}; +use pallas_codec::utils::{AnyUInt, KeepRaw, KeyValuePairs, MaybeIndefArray}; // required for derive attrs to work use pallas_codec::minicbor; @@ -1418,12 +1418,12 @@ impl minicbor::Encode for AuxiliaryData { pub type TransactionIndex = u32; #[derive(Encode, Decode, Debug, PartialEq)] -pub struct Block { +pub struct Block<'b> { #[n(0)] pub header: Header, - #[n(1)] - pub transaction_bodies: MaybeIndefArray, + #[b(1)] + pub transaction_bodies: MaybeIndefArray>, #[n(2)] pub transaction_witness_sets: MaybeIndefArray, @@ -1436,12 +1436,12 @@ pub struct Block { } #[derive(Encode, Decode, Debug)] -pub struct BlockWrapper(#[n(0)] pub u16, #[n(1)] pub Block); +pub struct BlockWrapper<'b>(#[n(0)] pub u16, #[b(1)] pub Block<'b>); #[cfg(test)] mod tests { use super::BlockWrapper; - use crate::Fragment; + use crate::{Fragment, ToHash}; use pallas_codec::minicbor::to_vec; #[test] @@ -1484,6 +1484,8 @@ mod tests { include_str!("test_data/test20.block"), // peculiar block with bad tx hash include_str!("test_data/test21.block"), + // peculiar block with bad tx hash + include_str!("test_data/test22.block"), ]; for (idx, block_str) in test_blocks.iter().enumerate() { diff --git a/pallas-primitives/src/alonzo/test_data/test22.block b/pallas-primitives/src/alonzo/test_data/test22.block new file mode 100644 index 00000000..8f4e95df --- /dev/null +++ b/pallas-primitives/src/alonzo/test_data/test22.block @@ -0,0 +1 @@ +820484828f1a002537781a01550c6758200a4bea77c82dc4641df52eb7b48131b5b380b0b8b85cdcc461ce463d582a16fa58209e32d6447bb62e5f13ce769ed0cd1862e2433f3b707cf0240fbd094e60763c6c5820fc2fcf18fa5faaf84f6ecac787e8694e2b2de64ff649bb14b0cc141ec267b298825840e8eb1c57331951d2b3de280b753a6ba5691b8cbcc0d5af7769df37285b70666d304317f44f1b930df097f5147fb7332b8ff7e5699a2206543eacf4a86d35444d5850e1c157310aaee3362bc858bbef4a8e79668df1347c9e316da156400e6f3cf61776c9662b694e14f092625e80eb3f7587310fe9b0a067bd133a4113d435a40828ad3d42921a1c9b89c5b984275fd4070b8258400024acbc27df2d82af0eef2b5d72da906eb3add3531ae595d68800dc2f55688f622459e5b0305c2fd8ea1577d0b8168e37d29a63c0f95c2022e36c6d5edebc8d58503543def2d5f95c37ed7c34915d41ced53f4b41f4e785ab5922bcc4fa23e240d06908c5bc82921c98815be5c1a718167fd76440e7cccd5cf6bd1bc61be2626be5006b25a0c44cf14dc1fd294e0dee690e19016c5820c23a5dae88c44be3926023def87880abde35c6dfd969a5b866ddce1d61044375582043cc179ab51c985bc00d7a346ffb4d2d661221fef106e31cfe17c37555d5bba90118a65840443e5f302bde78e1a6b34175c6be5dd9e037f74893dcf7883c50eca647f7e3d0c5e1dcb7ce347ce57eb7fb5eaf0773d79a8d6c01a3ea00a9b1b4f14e3f24700804005901c039aa67d82106fa79a5a1a99255790aaa93918119d677c39713978bb944fa08df1ff309aa8ee8fa954ee44d3167141ef896c553b1e6e039323c190f6ed23c950e3f9cca8521178fb7891a5c17a1efe8a18c53c92caef5ba5903a1a97e5e3b0c1d3369a22906be1c9ddeef64c7e8013da51132f255803047a4f92c823f67bbcfc6468c645e48992a0c2b9987242f0b470506933afb41d9b789f0edf5ede3b36e237cfd6f30dea7e9232c560f86ae38b0846b878d788e357cd90a332be3684e1d28b7716d8a3fbc6701a5cf7231fb4c23da03bbee3006d685b7b6dc524e1af293526600ddb52fe677b88890689ca824e4ae4a3d9ad942e5bc9c8f33fa6de20080f84a3f23ff094ca63c0c0cf37dc9f44c3e517872d53c6992d3daa9b73b5212215d85bd39fc3bf3bd5b80c38aa726dc0b392bbb37a29ae7339eacfa8cd79f35dc13dc4879958af6b114853e906ccbd2042d2f5e3ee68202a43f1d60c80f515b7e54c557e85aba025e33b1bb277f2d423f5db6bfc5faa96723e3884a7d1ce5a107e2686e66cbba4d4ae850329575a10d0c93ac02ea187285d77a1f0761746042e180174fe8fbdd6b4c052ae9d9b6d2be98c5ba003b4bfa322bbb6e21029305defd0381a500819f58204a8c8c2c5339bd9eca64cb1980ef1b8ecea86b285ddf270217f9acc274e42fb500ff018182583900ee8fb6f212bcd2a2970dc0ae54f02ba15412c89b6c5a6a812003b94bca18550fa36e175ce66ca2b5844691b77c90bb1d538451dea2cb40821a3b793840021a00030d40031a05f5e0ff049f82008200581cca18550fa36e175ce66ca2b5844691b77c90bb1d538451dea2cb4082ff81a10082825820a1d4002d0249d00d50232ddb94c91e5f8ba0a052b6d2d29c5e143ff4259246645840a3d7c4746b4431998a7a3edda41e2815c7fca6d54cdb07c6865350be19641594621b8d8fdba5511afae4e10b40bfa55b308d3522e021d2bf3d3013ab5cd9e00a825820f33bf4dc8b9148aa717392b8f8f7ce47b7fd682efe92e6ce7229367948df3c185840ed43ead57da35edc82b0d214d052da2fafe57e8aa33144b0b52447c709bf1abe9f80a9de3d75352f8b8dabad57f9e074d90035430ba4e61554decc597833060ba0 \ No newline at end of file diff --git a/pallas-primitives/src/framework.rs b/pallas-primitives/src/framework.rs index 22a088ee..50379624 100644 --- a/pallas-primitives/src/framework.rs +++ b/pallas-primitives/src/framework.rs @@ -36,3 +36,7 @@ pub enum Era { Mary, // multi-assets Alonzo, // smart-contracts } + +pub trait ToHash { + fn to_hash(&self) -> pallas_crypto::hash::Hash; +}