feat: Implement Plutus Data hashing / JSON (#100)
This commit is contained in:
parent
e0f153a5b1
commit
1c214ac72f
4 changed files with 84 additions and 19 deletions
|
|
@ -268,6 +268,12 @@ impl<T> Deref for CborWrap<T> {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct TagWrap<I, const T: u64>(I);
|
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>
|
impl<'b, I, const T: u64> minicbor::Decode<'b> for TagWrap<I, T>
|
||||||
where
|
where
|
||||||
I: minicbor::Decode<'b>,
|
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};
|
use pallas_crypto::hash::{Hash, Hasher};
|
||||||
|
|
||||||
pub fn hash_block_header(data: &Header) -> Hash<32> {
|
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 {
|
impl PlutusData {
|
||||||
pub fn to_hash(&self) -> Hash<32> {
|
pub fn to_hash(&self) -> Hash<32> {
|
||||||
Hasher::<256>::hash_cbor(self)
|
Hasher::<256>::hash_cbor(self)
|
||||||
|
|
@ -41,10 +47,11 @@ impl TransactionBody {
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
use pallas_codec::minicbor::data::Int;
|
||||||
use pallas_codec::utils::MaybeIndefArray;
|
use pallas_codec::utils::MaybeIndefArray;
|
||||||
use pallas_crypto::hash::Hash;
|
use pallas_crypto::hash::Hash;
|
||||||
|
|
||||||
use crate::alonzo::{BlockWrapper, NativeScript};
|
use crate::alonzo::{BigInt, BlockWrapper, Constr, NativeScript, PlutusData};
|
||||||
use crate::Fragment;
|
use crate::Fragment;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -73,7 +80,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn native_script_hashes_cardano_cli() {
|
fn native_script_hashes_as_cardano_cli() {
|
||||||
// construct an arbitrary script to use as example
|
// construct an arbitrary script to use as example
|
||||||
let ns = NativeScript::ScriptAll(MaybeIndefArray::Def(vec![
|
let ns = NativeScript::ScriptAll(MaybeIndefArray::Def(vec![
|
||||||
NativeScript::ScriptPubkey(
|
NativeScript::ScriptPubkey(
|
||||||
|
|
@ -91,4 +98,45 @@ mod tests {
|
||||||
Hash::<28>::from_str(cardano_cli_output).unwrap()
|
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;
|
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
|
// 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 {
|
impl ToCanonicalJson for super::PlutusData {
|
||||||
fn to_json(&self) -> serde_json::Value {
|
fn to_json(&self) -> serde_json::Value {
|
||||||
match self {
|
match self {
|
||||||
super::PlutusData::Constr(x) => {
|
super::PlutusData::Constr(x) => {
|
||||||
let constructor = x.prefix.map(|x| x as u64).unwrap_or(x.tag);
|
let fields: Vec<_> = x.fields.iter().map(|i| i.to_json()).collect();
|
||||||
let fields: Vec<_> = x.values.iter().map(|i| i.to_json()).collect();
|
json!({ "constructor": x.constructor_value(), "fields": fields })
|
||||||
json!({ "constructor": constructor, "fields": fields })
|
|
||||||
}
|
}
|
||||||
super::PlutusData::Map(x) => {
|
super::PlutusData::Map(x) => {
|
||||||
let map: Vec<_> = 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
|
big_int = int / big_uint / big_nint ; New
|
||||||
|
|
@ -1058,8 +1060,8 @@ impl minicbor::encode::Encode for PlutusData {
|
||||||
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct Constr<A> {
|
pub struct Constr<A> {
|
||||||
pub tag: u64,
|
pub tag: u64,
|
||||||
pub prefix: Option<u32>,
|
pub any_constructor: Option<u64>,
|
||||||
pub values: MaybeIndefArray<A>,
|
pub fields: MaybeIndefArray<A>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b, A> minicbor::decode::Decode<'b> for Constr<A>
|
impl<'b, A> minicbor::decode::Decode<'b> for Constr<A>
|
||||||
|
|
@ -1073,17 +1075,16 @@ where
|
||||||
Tag::Unassigned(x) => match x {
|
Tag::Unassigned(x) => match x {
|
||||||
121..=127 | 1280..=1400 => Ok(Constr {
|
121..=127 | 1280..=1400 => Ok(Constr {
|
||||||
tag: x,
|
tag: x,
|
||||||
values: d.decode()?,
|
fields: d.decode()?,
|
||||||
prefix: None,
|
any_constructor: None,
|
||||||
}),
|
}),
|
||||||
102 => {
|
102 => {
|
||||||
d.array()?;
|
d.array()?;
|
||||||
let prefix = Some(d.decode()?);
|
|
||||||
let values = d.decode()?;
|
|
||||||
Ok(Constr {
|
Ok(Constr {
|
||||||
tag: 102,
|
tag: x,
|
||||||
prefix,
|
any_constructor: Some(d.decode()?),
|
||||||
values,
|
fields: d.decode()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
_ => Err(minicbor::decode::Error::message(
|
_ => Err(minicbor::decode::Error::message(
|
||||||
|
|
@ -1110,13 +1111,13 @@ where
|
||||||
match self.tag {
|
match self.tag {
|
||||||
102 => {
|
102 => {
|
||||||
e.array(2)?;
|
e.array(2)?;
|
||||||
e.encode(self.prefix)?;
|
e.encode(self.any_constructor.unwrap_or_default())?;
|
||||||
e.encode(&self.values)?;
|
e.encode(&self.fields)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
e.encode(&self.values)?;
|
e.encode(&self.fields)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue