feat: Add mechanism to retain original CBOR (#110)

This commit is contained in:
Santiago Carmuega 2022-06-03 21:43:18 -03:00 committed by GitHub
parent a39682a38d
commit 59a3ac3b49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 29 deletions

View file

@ -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<Self, minicbor::decode::Error> {
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<C, T> minicbor::Encode<C> for KeepRaw<'_, T> {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.writer_mut()
.write_all(self.raw_cbor())
.map_err(minicbor::encode::Error::write)
}
}

View file

@ -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)
impl ToHash<32> for Header {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash_cbor(self)
}
}
pub fn hash_auxiliary_data(data: &AuxiliaryData) -> 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)
}
}
#[deprecated(note = "use TransactionBody::to_hash instead")]
pub fn hash_transaction(data: &TransactionBody) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
#[deprecated(note = "use PlutusData::to_hash instead")]
pub fn hash_plutus_data(data: &PlutusData) -> Hash<32> {
Hasher::<256>::hash_cbor(data)
}
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() {

View file

@ -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<C> minicbor::Encode<C> 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<TransactionBody>,
#[b(1)]
pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>,
#[n(2)]
pub transaction_witness_sets: MaybeIndefArray<TransactionWitnessSet>,
@ -1436,7 +1436,7 @@ 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>);
#[derive(Encode, Decode, Debug)]
pub struct Transaction {
@ -1453,7 +1453,7 @@ pub struct Transaction {
#[cfg(test)]
mod tests {
use super::BlockWrapper;
use crate::Fragment;
use crate::{Fragment, ToHash};
use pallas_codec::minicbor::to_vec;
#[test]
@ -1496,6 +1496,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() {

View file

@ -0,0 +1 @@
820484828f1a002537781a01550c6758200a4bea77c82dc4641df52eb7b48131b5b380b0b8b85cdcc461ce463d582a16fa58209e32d6447bb62e5f13ce769ed0cd1862e2433f3b707cf0240fbd094e60763c6c5820fc2fcf18fa5faaf84f6ecac787e8694e2b2de64ff649bb14b0cc141ec267b298825840e8eb1c57331951d2b3de280b753a6ba5691b8cbcc0d5af7769df37285b70666d304317f44f1b930df097f5147fb7332b8ff7e5699a2206543eacf4a86d35444d5850e1c157310aaee3362bc858bbef4a8e79668df1347c9e316da156400e6f3cf61776c9662b694e14f092625e80eb3f7587310fe9b0a067bd133a4113d435a40828ad3d42921a1c9b89c5b984275fd4070b8258400024acbc27df2d82af0eef2b5d72da906eb3add3531ae595d68800dc2f55688f622459e5b0305c2fd8ea1577d0b8168e37d29a63c0f95c2022e36c6d5edebc8d58503543def2d5f95c37ed7c34915d41ced53f4b41f4e785ab5922bcc4fa23e240d06908c5bc82921c98815be5c1a718167fd76440e7cccd5cf6bd1bc61be2626be5006b25a0c44cf14dc1fd294e0dee690e19016c5820c23a5dae88c44be3926023def87880abde35c6dfd969a5b866ddce1d61044375582043cc179ab51c985bc00d7a346ffb4d2d661221fef106e31cfe17c37555d5bba90118a65840443e5f302bde78e1a6b34175c6be5dd9e037f74893dcf7883c50eca647f7e3d0c5e1dcb7ce347ce57eb7fb5eaf0773d79a8d6c01a3ea00a9b1b4f14e3f24700804005901c039aa67d82106fa79a5a1a99255790aaa93918119d677c39713978bb944fa08df1ff309aa8ee8fa954ee44d3167141ef896c553b1e6e039323c190f6ed23c950e3f9cca8521178fb7891a5c17a1efe8a18c53c92caef5ba5903a1a97e5e3b0c1d3369a22906be1c9ddeef64c7e8013da51132f255803047a4f92c823f67bbcfc6468c645e48992a0c2b9987242f0b470506933afb41d9b789f0edf5ede3b36e237cfd6f30dea7e9232c560f86ae38b0846b878d788e357cd90a332be3684e1d28b7716d8a3fbc6701a5cf7231fb4c23da03bbee3006d685b7b6dc524e1af293526600ddb52fe677b88890689ca824e4ae4a3d9ad942e5bc9c8f33fa6de20080f84a3f23ff094ca63c0c0cf37dc9f44c3e517872d53c6992d3daa9b73b5212215d85bd39fc3bf3bd5b80c38aa726dc0b392bbb37a29ae7339eacfa8cd79f35dc13dc4879958af6b114853e906ccbd2042d2f5e3ee68202a43f1d60c80f515b7e54c557e85aba025e33b1bb277f2d423f5db6bfc5faa96723e3884a7d1ce5a107e2686e66cbba4d4ae850329575a10d0c93ac02ea187285d77a1f0761746042e180174fe8fbdd6b4c052ae9d9b6d2be98c5ba003b4bfa322bbb6e21029305defd0381a500819f58204a8c8c2c5339bd9eca64cb1980ef1b8ecea86b285ddf270217f9acc274e42fb500ff018182583900ee8fb6f212bcd2a2970dc0ae54f02ba15412c89b6c5a6a812003b94bca18550fa36e175ce66ca2b5844691b77c90bb1d538451dea2cb40821a3b793840021a00030d40031a05f5e0ff049f82008200581cca18550fa36e175ce66ca2b5844691b77c90bb1d538451dea2cb4082ff81a10082825820a1d4002d0249d00d50232ddb94c91e5f8ba0a052b6d2d29c5e143ff4259246645840a3d7c4746b4431998a7a3edda41e2815c7fca6d54cdb07c6865350be19641594621b8d8fdba5511afae4e10b40bfa55b308d3522e021d2bf3d3013ab5cd9e00a825820f33bf4dc8b9148aa717392b8f8f7ce47b7fd682efe92e6ce7229367948df3c185840ed43ead57da35edc82b0d214d052da2fafe57e8aa33144b0b52447c709bf1abe9f80a9de3d75352f8b8dabad57f9e074d90035430ba4e61554decc597833060ba0

View file

@ -36,3 +36,7 @@ pub enum Era {
Mary, // multi-assets
Alonzo, // smart-contracts
}
pub trait ToHash<const BYTES: usize> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<BYTES>;
}