feat: Implement Plutus Data hashing / JSON (#100)
This commit is contained in:
parent
0946c8353e
commit
2c41c1756c
4 changed files with 84 additions and 19 deletions
|
|
@ -268,6 +268,12 @@ impl<T> Deref for CborWrap<T> {
|
|||
#[derive(Debug)]
|
||||
pub struct TagWrap<I, const T: u64>(I);
|
||||
|
||||
impl<I, const T: u64> TagWrap<I, T> {
|
||||
pub fn new(inner: I) -> Self {
|
||||
TagWrap(inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'b, I, const T: u64> minicbor::Decode<'b> for TagWrap<I, T>
|
||||
where
|
||||
I: minicbor::Decode<'b>,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use super::{AuxiliaryData, Header, NativeScript, PlutusData, TransactionBody};
|
||||
use super::{AuxiliaryData, Header, NativeScript, PlutusData, PlutusScript, TransactionBody};
|
||||
use pallas_crypto::hash::{Hash, Hasher};
|
||||
|
||||
pub fn hash_block_header(data: &Header) -> Hash<32> {
|
||||
|
|
@ -25,6 +25,12 @@ impl NativeScript {
|
|||
}
|
||||
}
|
||||
|
||||
impl PlutusScript {
|
||||
pub fn to_hash(&self) -> Hash<28> {
|
||||
Hasher::<224>::hash_tagged_cbor(self, 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl PlutusData {
|
||||
pub fn to_hash(&self) -> Hash<32> {
|
||||
Hasher::<256>::hash_cbor(self)
|
||||
|
|
@ -41,10 +47,11 @@ impl TransactionBody {
|
|||
mod tests {
|
||||
use std::str::FromStr;
|
||||
|
||||
use pallas_codec::minicbor::data::Int;
|
||||
use pallas_codec::utils::MaybeIndefArray;
|
||||
use pallas_crypto::hash::Hash;
|
||||
|
||||
use crate::alonzo::{BlockWrapper, NativeScript};
|
||||
use crate::alonzo::{BigInt, BlockWrapper, Constr, NativeScript, PlutusData};
|
||||
use crate::Fragment;
|
||||
|
||||
#[test]
|
||||
|
|
@ -73,7 +80,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn native_script_hashes_cardano_cli() {
|
||||
fn native_script_hashes_as_cardano_cli() {
|
||||
// construct an arbitrary script to use as example
|
||||
let ns = NativeScript::ScriptAll(MaybeIndefArray::Def(vec![
|
||||
NativeScript::ScriptPubkey(
|
||||
|
|
@ -91,4 +98,45 @@ mod tests {
|
|||
Hash::<28>::from_str(cardano_cli_output).unwrap()
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn plutus_data_hashes_as_cardano_cli() {
|
||||
// construct an arbitrary complex datum to use as example
|
||||
let pd = PlutusData::Constr(Constr::<PlutusData> {
|
||||
tag: 1280,
|
||||
any_constructor: None,
|
||||
fields: MaybeIndefArray::Indef(vec![
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(4))),
|
||||
PlutusData::Constr(Constr::<PlutusData> {
|
||||
tag: 124,
|
||||
any_constructor: None,
|
||||
fields: MaybeIndefArray::Indef(vec![
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(-4))),
|
||||
PlutusData::Constr(Constr::<PlutusData> {
|
||||
tag: 102,
|
||||
any_constructor: Some(453),
|
||||
fields: MaybeIndefArray::Indef(vec![
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(2))),
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(3434))),
|
||||
]),
|
||||
}),
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(-11828293))),
|
||||
]),
|
||||
}),
|
||||
PlutusData::BigInt(BigInt::Int(Int::from(11828293))),
|
||||
]),
|
||||
});
|
||||
|
||||
// if you need to try this out in the cardano-cli, uncomment this line to see
|
||||
// the json representation of the above struct:
|
||||
// println!("{}", crate::ToCanonicalJson::to_json(&pd));
|
||||
|
||||
// hash that we assume correct since it was generated through the cardano-cli
|
||||
let cardano_cli_output = "d9bc0eb6ac664286155f70d720cafd2af16277fbd9014a930997431a2ffbe554";
|
||||
|
||||
assert_eq!(
|
||||
pd.to_hash(),
|
||||
Hash::<32>::from_str(cardano_cli_output).unwrap()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,14 +2,24 @@ use serde_json::json;
|
|||
|
||||
use crate::ToCanonicalJson;
|
||||
|
||||
impl<A> super::Constr<A> {
|
||||
pub fn constructor_value(&self) -> Option<u64> {
|
||||
match self.tag {
|
||||
121..=127 => Some(self.tag - 121),
|
||||
1280..=1400 => Some(self.tag - 1280 + 7),
|
||||
102 => self.any_constructor,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// infered from https://github.com/input-output-hk/cardano-node/blob/c1efb2f97134c0607c982246a36e3da7266ac194/cardano-api/src/Cardano/Api/ScriptData.hs#L254
|
||||
impl ToCanonicalJson for super::PlutusData {
|
||||
fn to_json(&self) -> serde_json::Value {
|
||||
match self {
|
||||
super::PlutusData::Constr(x) => {
|
||||
let constructor = x.prefix.map(|x| x as u64).unwrap_or(x.tag);
|
||||
let fields: Vec<_> = x.values.iter().map(|i| i.to_json()).collect();
|
||||
json!({ "constructor": constructor, "fields": fields })
|
||||
let fields: Vec<_> = x.fields.iter().map(|i| i.to_json()).collect();
|
||||
json!({ "constructor": x.constructor_value(), "fields": fields })
|
||||
}
|
||||
super::PlutusData::Map(x) => {
|
||||
let map: Vec<_> = x
|
||||
|
|
|
|||
|
|
@ -908,7 +908,9 @@ impl minicbor::encode::Encode for NativeScript {
|
|||
}
|
||||
}
|
||||
|
||||
pub type PlutusScript = ByteVec;
|
||||
#[derive(Encode, Decode, Debug, PartialEq)]
|
||||
#[cbor(transparent)]
|
||||
pub struct PlutusScript(#[n(0)] ByteVec);
|
||||
|
||||
/*
|
||||
big_int = int / big_uint / big_nint ; New
|
||||
|
|
@ -1058,8 +1060,8 @@ impl minicbor::encode::Encode for PlutusData {
|
|||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Constr<A> {
|
||||
pub tag: u64,
|
||||
pub prefix: Option<u32>,
|
||||
pub values: MaybeIndefArray<A>,
|
||||
pub any_constructor: Option<u64>,
|
||||
pub fields: MaybeIndefArray<A>,
|
||||
}
|
||||
|
||||
impl<'b, A> minicbor::decode::Decode<'b> for Constr<A>
|
||||
|
|
@ -1073,17 +1075,16 @@ where
|
|||
Tag::Unassigned(x) => match x {
|
||||
121..=127 | 1280..=1400 => Ok(Constr {
|
||||
tag: x,
|
||||
values: d.decode()?,
|
||||
prefix: None,
|
||||
fields: d.decode()?,
|
||||
any_constructor: None,
|
||||
}),
|
||||
102 => {
|
||||
d.array()?;
|
||||
let prefix = Some(d.decode()?);
|
||||
let values = d.decode()?;
|
||||
|
||||
Ok(Constr {
|
||||
tag: 102,
|
||||
prefix,
|
||||
values,
|
||||
tag: x,
|
||||
any_constructor: Some(d.decode()?),
|
||||
fields: d.decode()?,
|
||||
})
|
||||
}
|
||||
_ => Err(minicbor::decode::Error::message(
|
||||
|
|
@ -1110,13 +1111,13 @@ where
|
|||
match self.tag {
|
||||
102 => {
|
||||
e.array(2)?;
|
||||
e.encode(self.prefix)?;
|
||||
e.encode(&self.values)?;
|
||||
e.encode(self.any_constructor.unwrap_or_default())?;
|
||||
e.encode(&self.fields)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
_ => {
|
||||
e.encode(&self.values)?;
|
||||
e.encode(&self.fields)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue