feat(traverse): Provide access to original Datum hash (#189)

This commit is contained in:
Santiago Carmuega 2022-09-13 07:52:35 -03:00 committed by GitHub
parent 1850bfe86e
commit 85cf02dec4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 299 additions and 158 deletions

View file

@ -1159,7 +1159,7 @@ pub struct BootstrapWitness {
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)] #[cbor(map)]
pub struct TransactionWitnessSet { pub struct WitnessSet {
#[n(0)] #[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>, pub vkeywitness: Option<Vec<VKeyWitness>>,
@ -1179,6 +1179,43 @@ pub struct TransactionWitnessSet {
pub redeemer: Option<Vec<Redeemer>>, pub redeemer: Option<Vec<Redeemer>>,
} }
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct MintedWitnessSet<'b> {
#[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>,
#[n(1)]
pub native_script: Option<Vec<NativeScript>>,
#[n(2)]
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_script: Option<Vec<PlutusScript>>,
#[b(4)]
pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
fn from(x: MintedWitnessSet<'b>) -> Self {
WitnessSet {
vkeywitness: x.vkeywitness,
native_script: x.native_script,
bootstrap_witness: x.bootstrap_witness,
plutus_script: x.plutus_script,
plutus_data: x
.plutus_data
.map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
redeemer: x.redeemer,
}
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)] #[cbor(map)]
pub struct PostAlonzoAuxiliaryData { pub struct PostAlonzoAuxiliaryData {
@ -1328,7 +1365,7 @@ pub struct Block {
pub transaction_bodies: Vec<TransactionBody>, pub transaction_bodies: Vec<TransactionBody>,
#[n(2)] #[n(2)]
pub transaction_witness_sets: Vec<TransactionWitnessSet>, pub transaction_witness_sets: Vec<WitnessSet>,
#[n(3)] #[n(3)]
pub auxiliary_data_set: BTreeMap<TransactionIndex, AuxiliaryData>, pub auxiliary_data_set: BTreeMap<TransactionIndex, AuxiliaryData>,
@ -1351,7 +1388,7 @@ pub struct MintedBlock<'b> {
pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>, pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>,
#[n(2)] #[n(2)]
pub transaction_witness_sets: MaybeIndefArray<KeepRaw<'b, TransactionWitnessSet>>, pub transaction_witness_sets: MaybeIndefArray<KeepRaw<'b, MintedWitnessSet<'b>>>,
#[n(3)] #[n(3)]
pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>, pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>,
@ -1375,6 +1412,7 @@ impl<'b> From<MintedBlock<'b>> for Block {
.to_vec() .to_vec()
.into_iter() .into_iter()
.map(|x| x.unwrap()) .map(|x| x.unwrap())
.map(|x| WitnessSet::from(x))
.collect(), .collect(),
auxiliary_data_set: x auxiliary_data_set: x
.auxiliary_data_set .auxiliary_data_set
@ -1393,7 +1431,7 @@ pub struct Tx {
pub transaction_body: TransactionBody, pub transaction_body: TransactionBody,
#[n(1)] #[n(1)]
pub transaction_witness_set: TransactionWitnessSet, pub transaction_witness_set: WitnessSet,
#[n(2)] #[n(2)]
pub success: bool, pub success: bool,
@ -1408,7 +1446,7 @@ pub struct MintedTx<'b> {
pub transaction_body: KeepRaw<'b, TransactionBody>, pub transaction_body: KeepRaw<'b, TransactionBody>,
#[n(1)] #[n(1)]
pub transaction_witness_set: KeepRaw<'b, TransactionWitnessSet>, pub transaction_witness_set: KeepRaw<'b, MintedWitnessSet<'b>>,
#[n(2)] #[n(2)]
pub success: bool, pub success: bool,

View file

@ -375,7 +375,7 @@ pub use crate::alonzo::BootstrapWitness;
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)] #[cbor(map)]
pub struct TransactionWitnessSet { pub struct WitnessSet {
#[n(0)] #[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>, pub vkeywitness: Option<Vec<VKeyWitness>>,
@ -398,6 +398,47 @@ pub struct TransactionWitnessSet {
pub plutus_v2_script: Option<Vec<PlutusV2Script>>, pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
} }
#[derive(Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)]
pub struct MintedWitnessSet<'b> {
#[n(0)]
pub vkeywitness: Option<Vec<VKeyWitness>>,
#[n(1)]
pub native_script: Option<Vec<NativeScript>>,
#[n(2)]
pub bootstrap_witness: Option<Vec<BootstrapWitness>>,
#[n(3)]
pub plutus_v1_script: Option<Vec<PlutusV1Script>>,
#[b(4)]
pub plutus_data: Option<Vec<KeepRaw<'b, PlutusData>>>,
#[n(5)]
pub redeemer: Option<Vec<Redeemer>>,
#[n(6)]
pub plutus_v2_script: Option<Vec<PlutusV2Script>>,
}
impl<'b> From<MintedWitnessSet<'b>> for WitnessSet {
fn from(x: MintedWitnessSet<'b>) -> Self {
WitnessSet {
vkeywitness: x.vkeywitness,
native_script: x.native_script,
bootstrap_witness: x.bootstrap_witness,
plutus_v1_script: x.plutus_v1_script,
plutus_data: x
.plutus_data
.map(|x| x.into_iter().map(|x| x.unwrap()).collect()),
redeemer: x.redeemer,
plutus_v2_script: x.plutus_v2_script,
}
}
}
#[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)] #[derive(Serialize, Deserialize, Encode, Decode, Debug, PartialEq, Clone)]
#[cbor(map)] #[cbor(map)]
pub struct PostAlonzoAuxiliaryData { pub struct PostAlonzoAuxiliaryData {
@ -521,7 +562,7 @@ pub struct Block {
pub transaction_bodies: Vec<TransactionBody>, pub transaction_bodies: Vec<TransactionBody>,
#[n(2)] #[n(2)]
pub transaction_witness_sets: Vec<TransactionWitnessSet>, pub transaction_witness_sets: Vec<WitnessSet>,
#[n(3)] #[n(3)]
pub auxiliary_data_set: BTreeMap<TransactionIndex, AuxiliaryData>, pub auxiliary_data_set: BTreeMap<TransactionIndex, AuxiliaryData>,
@ -544,7 +585,7 @@ pub struct MintedBlock<'b> {
pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>, pub transaction_bodies: MaybeIndefArray<KeepRaw<'b, TransactionBody>>,
#[n(2)] #[n(2)]
pub transaction_witness_sets: MaybeIndefArray<KeepRaw<'b, TransactionWitnessSet>>, pub transaction_witness_sets: MaybeIndefArray<KeepRaw<'b, MintedWitnessSet<'b>>>,
#[n(3)] #[n(3)]
pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>, pub auxiliary_data_set: KeyValuePairs<TransactionIndex, KeepRaw<'b, AuxiliaryData>>,
@ -568,6 +609,7 @@ impl<'b> From<MintedBlock<'b>> for Block {
.to_vec() .to_vec()
.into_iter() .into_iter()
.map(|x| x.unwrap()) .map(|x| x.unwrap())
.map(|x| WitnessSet::from(x))
.collect(), .collect(),
auxiliary_data_set: x auxiliary_data_set: x
.auxiliary_data_set .auxiliary_data_set
@ -586,7 +628,7 @@ pub struct Tx {
pub transaction_body: TransactionBody, pub transaction_body: TransactionBody,
#[n(1)] #[n(1)]
pub transaction_witness_set: TransactionWitnessSet, pub transaction_witness_set: WitnessSet,
#[n(2)] #[n(2)]
pub success: bool, pub success: bool,
@ -601,7 +643,7 @@ pub struct MintedTx<'b> {
pub transaction_body: KeepRaw<'b, TransactionBody>, pub transaction_body: KeepRaw<'b, TransactionBody>,
#[n(1)] #[n(1)]
pub transaction_witness_set: KeepRaw<'b, TransactionWitnessSet>, pub transaction_witness_set: KeepRaw<'b, MintedWitnessSet<'b>>,
#[n(2)] #[n(2)]
pub success: bool, pub success: bool,
@ -614,7 +656,7 @@ impl<'b> From<MintedTx<'b>> for Tx {
fn from(x: MintedTx<'b>) -> Self { fn from(x: MintedTx<'b>) -> Self {
Tx { Tx {
transaction_body: x.transaction_body.unwrap(), transaction_body: x.transaction_body.unwrap(),
transaction_witness_set: x.transaction_witness_set.unwrap(), transaction_witness_set: x.transaction_witness_set.unwrap().into(),
success: x.success, success: x.success,
auxiliary_data: x.auxiliary_data.map(|x| x.unwrap()), auxiliary_data: x.auxiliary_data.map(|x| x.unwrap()),
} }

View file

@ -1,137 +1,152 @@
use crate::ToHash; use crate::{ComputeHash, OriginalHash};
use pallas_codec::utils::KeepRaw; use pallas_codec::utils::KeepRaw;
use pallas_crypto::hash::{Hash, Hasher}; use pallas_crypto::hash::{Hash, Hasher};
use pallas_primitives::{alonzo, babbage, byron}; use pallas_primitives::{alonzo, babbage, byron};
impl ToHash<32> for byron::EbbHead { impl ComputeHash<32> for byron::EbbHead {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
// hash expects to have a prefix for the type of block // hash expects to have a prefix for the type of block
Hasher::<256>::hash_cbor(&(0, self)) Hasher::<256>::hash_cbor(&(0, self))
} }
} }
impl ToHash<32> for KeepRaw<'_, byron::EbbHead> { impl OriginalHash<32> for KeepRaw<'_, byron::EbbHead> {
fn to_hash(&self) -> Hash<32> { fn original_hash(&self) -> Hash<32> {
// hash expects to have a prefix for the type of block // hash expects to have a prefix for the type of block
Hasher::<256>::hash_cbor(&(0, self)) Hasher::<256>::hash_cbor(&(0, self))
} }
} }
impl ToHash<32> for byron::BlockHead { impl ComputeHash<32> for byron::BlockHead {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
// hash expects to have a prefix for the type of block // hash expects to have a prefix for the type of block
Hasher::<256>::hash_cbor(&(1, self)) Hasher::<256>::hash_cbor(&(1, self))
} }
} }
impl ToHash<32> for KeepRaw<'_, byron::BlockHead> { impl OriginalHash<32> for KeepRaw<'_, byron::BlockHead> {
fn to_hash(&self) -> Hash<32> { fn original_hash(&self) -> Hash<32> {
// hash expects to have a prefix for the type of block // hash expects to have a prefix for the type of block
Hasher::<256>::hash_cbor(&(1, self)) Hasher::<256>::hash_cbor(&(1, self))
} }
} }
impl ToHash<32> for byron::Tx { impl ComputeHash<32> for byron::Tx {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<32> for KeepRaw<'_, byron::Tx> { impl OriginalHash<32> for KeepRaw<'_, byron::Tx> {
fn to_hash(&self) -> Hash<32> { fn original_hash(&self) -> Hash<32> {
Hasher::<256>::hash(self.raw_cbor()) Hasher::<256>::hash(self.raw_cbor())
} }
} }
impl ToHash<32> for alonzo::Header { impl ComputeHash<32> for alonzo::Header {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { fn compute_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<32> for alonzo::AuxiliaryData { impl OriginalHash<32> for KeepRaw<'_, alonzo::Header> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { fn original_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash(self.raw_cbor())
}
}
impl ComputeHash<32> for alonzo::AuxiliaryData {
fn compute_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<28> for alonzo::NativeScript { impl ComputeHash<28> for alonzo::NativeScript {
fn to_hash(&self) -> Hash<28> { fn compute_hash(&self) -> Hash<28> {
Hasher::<224>::hash_tagged_cbor(self, 0) Hasher::<224>::hash_tagged_cbor(self, 0)
} }
} }
impl ToHash<28> for alonzo::PlutusScript { impl ComputeHash<28> for alonzo::PlutusScript {
fn to_hash(&self) -> Hash<28> { fn compute_hash(&self) -> Hash<28> {
Hasher::<224>::hash_tagged(&self.0, 1) Hasher::<224>::hash_tagged(&self.0, 1)
} }
} }
impl ToHash<32> for alonzo::PlutusData { impl ComputeHash<32> for alonzo::PlutusData {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<32> for alonzo::TransactionBody { impl OriginalHash<32> for KeepRaw<'_, alonzo::PlutusData> {
fn to_hash(&self) -> Hash<32> { fn original_hash(&self) -> Hash<32> {
Hasher::<256>::hash(&self.raw_cbor())
}
}
impl ComputeHash<32> for alonzo::TransactionBody {
fn compute_hash(&self) -> Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<32> for KeepRaw<'_, alonzo::TransactionBody> { impl OriginalHash<32> for KeepRaw<'_, alonzo::TransactionBody> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { fn original_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash(self.raw_cbor()) Hasher::<256>::hash(self.raw_cbor())
} }
} }
impl ToHash<32> for babbage::Header { impl ComputeHash<32> for babbage::Header {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { fn compute_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<28> for babbage::PlutusV2Script { impl OriginalHash<32> for KeepRaw<'_, babbage::Header> {
fn to_hash(&self) -> Hash<28> { fn original_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash(self.raw_cbor())
}
}
impl ComputeHash<28> for babbage::PlutusV2Script {
fn compute_hash(&self) -> Hash<28> {
Hasher::<224>::hash_tagged(&self.0, 2) Hasher::<224>::hash_tagged(&self.0, 2)
} }
} }
impl ToHash<32> for babbage::TransactionBody { impl ComputeHash<32> for babbage::TransactionBody {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
Hasher::<256>::hash_cbor(self) Hasher::<256>::hash_cbor(self)
} }
} }
impl ToHash<32> for KeepRaw<'_, babbage::TransactionBody> { impl OriginalHash<32> for KeepRaw<'_, babbage::TransactionBody> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<32> { fn original_hash(&self) -> pallas_crypto::hash::Hash<32> {
Hasher::<256>::hash(self.raw_cbor()) Hasher::<256>::hash(self.raw_cbor())
} }
} }
impl ToHash<32> for babbage::DatumOption { impl ComputeHash<32> for babbage::DatumOption {
fn to_hash(&self) -> Hash<32> { fn compute_hash(&self) -> Hash<32> {
match self { match self {
babbage::DatumOption::Hash(hash) => *hash, babbage::DatumOption::Hash(hash) => *hash,
babbage::DatumOption::Data(data) => data.to_hash(), babbage::DatumOption::Data(data) => data.compute_hash(),
} }
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{MultiEraTx, Era}; use crate::{Era, MultiEraTx};
use super::ToHash; use super::{ComputeHash, OriginalHash};
use pallas_codec::{minicbor, utils::Bytes};
use pallas_codec::utils::Int; use pallas_codec::utils::Int;
use pallas_codec::{minicbor, utils::Bytes};
use pallas_crypto::hash::Hash; use pallas_crypto::hash::Hash;
use pallas_primitives::{alonzo, babbage, byron}; use pallas_primitives::{alonzo, babbage, byron};
use std::str::FromStr; use std::str::FromStr;
const KNOWN_HASH: &'static str =
"5c196e7394ace0449ba5a51c919369699b13896e97432894b4f0354dce8670b6";
#[test] #[test]
fn byron_transaction_hash_works() { fn byron_transaction_hash_works() {
type BlockWrapper<'b> = (u16, byron::MintedBlock<'b>); type BlockWrapper<'b> = (u16, byron::MintedBlock<'b>);
@ -144,9 +159,12 @@ mod tests {
let (_, block_model): BlockWrapper = minicbor::decode(&block_bytes[..]) let (_, block_model): BlockWrapper = minicbor::decode(&block_bytes[..])
.expect(&format!("error decoding cbor for file {}", block_idx)); .expect(&format!("error decoding cbor for file {}", block_idx));
let computed_hash = block_model.header.to_hash(); let computed_hash = block_model.header.original_hash();
assert_eq!(hex::encode(computed_hash), KNOWN_HASH) assert_eq!(
hex::encode(computed_hash),
"5c196e7394ace0449ba5a51c919369699b13896e97432894b4f0354dce8670b6"
)
} }
#[test] #[test]
@ -170,9 +188,9 @@ mod tests {
]; ];
for (tx_idx, tx) in block_model.transaction_bodies.iter().enumerate() { for (tx_idx, tx) in block_model.transaction_bodies.iter().enumerate() {
let computed_hash = tx.to_hash(); let original_hash = tx.original_hash();
let known_hash = valid_hashes[tx_idx]; let expected_hash = valid_hashes[tx_idx];
assert_eq!(hex::encode(computed_hash), known_hash) assert_eq!(hex::encode(original_hash), expected_hash)
} }
} }
@ -191,9 +209,9 @@ mod tests {
let valid_hashes = vec!["3fad302595665b004971a6b76909854a39a0a7ecdbff3692f37b77ae37dbe882"]; let valid_hashes = vec!["3fad302595665b004971a6b76909854a39a0a7ecdbff3692f37b77ae37dbe882"];
for (tx_idx, tx) in block_model.transaction_bodies.iter().enumerate() { for (tx_idx, tx) in block_model.transaction_bodies.iter().enumerate() {
let computed_hash = tx.to_hash(); let original_hash = tx.original_hash();
let known_hash = valid_hashes[tx_idx]; let expected_hash = valid_hashes[tx_idx];
assert_eq!(hex::encode(computed_hash), known_hash) assert_eq!(hex::encode(original_hash), expected_hash)
} }
} }
@ -212,7 +230,7 @@ mod tests {
let cardano_cli_output = "d6a8ced01ecdfbb26c90850010a06fbc20a7c23632fc92f531667f36"; let cardano_cli_output = "d6a8ced01ecdfbb26c90850010a06fbc20a7c23632fc92f531667f36";
assert_eq!( assert_eq!(
ns.to_hash(), ns.compute_hash(),
Hash::<28>::from_str(cardano_cli_output).unwrap() Hash::<28>::from_str(cardano_cli_output).unwrap()
) )
} }
@ -253,7 +271,7 @@ mod tests {
let cardano_cli_output = "d9bc0eb6ac664286155f70d720cafd2af16277fbd9014a930997431a2ffbe554"; let cardano_cli_output = "d9bc0eb6ac664286155f70d720cafd2af16277fbd9014a930997431a2ffbe554";
assert_eq!( assert_eq!(
pd.to_hash(), pd.compute_hash(),
Hash::<32>::from_str(cardano_cli_output).unwrap() Hash::<32>::from_str(cardano_cli_output).unwrap()
) )
} }
@ -264,7 +282,7 @@ mod tests {
let bytecode = hex::decode(bytecode_hex).unwrap(); let bytecode = hex::decode(bytecode_hex).unwrap();
let script = alonzo::PlutusScript(Bytes::from(bytecode)); let script = alonzo::PlutusScript(Bytes::from(bytecode));
let generated = script.to_hash().to_string(); let generated = script.compute_hash().to_string();
assert_eq!( assert_eq!(
generated, generated,
@ -280,7 +298,7 @@ mod tests {
let bytecode = hex::decode(bytecode_hex).unwrap(); let bytecode = hex::decode(bytecode_hex).unwrap();
let script = babbage::PlutusV2Script(Bytes::from(bytecode)); let script = babbage::PlutusV2Script(Bytes::from(bytecode));
let generated = script.to_hash().to_string(); let generated = script.compute_hash().to_string();
assert_eq!( assert_eq!(
generated, generated,
@ -296,15 +314,37 @@ mod tests {
let bytecode = hex::decode(tx_bytecode_hex).unwrap(); let bytecode = hex::decode(tx_bytecode_hex).unwrap();
let tx = MultiEraTx::decode(Era::Babbage, &bytecode).unwrap(); let tx = MultiEraTx::decode(Era::Babbage, &bytecode).unwrap();
let wits = tx.witnesses(); let generated = tx
.plutus_v1_scripts()
let script = wits.plutus_v1_script().unwrap().get(0).unwrap(); .get(0)
.unwrap()
let generated = script.to_hash().to_string(); .compute_hash()
.to_string();
assert_eq!( assert_eq!(
generated, generated,
"62bdc3d04d04376d516d31664944b25ce3affa76d17f8b5e1279b49d" "62bdc3d04d04376d516d31664944b25ce3affa76d17f8b5e1279b49d"
); );
} }
#[test]
fn test_datum_hash_respects_original_cbor() {
let expected = [
"54ad3c112d58e8946480e21d6a35b2a215d1a9a8f540c13714ded86e4b0b6aea",
"831a557bc2948e1b8c9f5e8e594d62299abff4eb1a11dc19da38bfaf9f2da407",
"923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec",
"b0ea85f16a443da7f60704a427923ae1d89a7dc2d6621d805d9dd441431ed700",
"c695868b4bfbf4c95714e707c69da1823bcf8cfc7c4b14b92c3645d4e1943be3",
"ed33125018c5cbc9ae1b242a3ff8f3db2e108e4a63866d0b5238a34502c723ed",
];
let tx_hex = include_str!("../../test_data/babbage1.tx");
let tx_bytes = hex::decode(tx_hex).unwrap();
let tx = MultiEraTx::decode(Era::Babbage, &tx_bytes).unwrap();
let data = tx.plutus_data();
for (datum, expected_hash) in data.iter().zip(expected) {
assert_eq!(datum.original_hash().to_string(), expected_hash);
}
}
} }

View file

@ -5,8 +5,7 @@ use pallas_codec::minicbor;
use pallas_crypto::hash::{Hash, Hasher}; use pallas_crypto::hash::{Hash, Hasher};
use pallas_primitives::{alonzo, babbage, byron}; use pallas_primitives::{alonzo, babbage, byron};
use crate::time; use crate::{time, Era, Error, MultiEraHeader, OriginalHash};
use crate::{Era, Error, MultiEraHeader, ToHash};
impl<'b> MultiEraHeader<'b> { impl<'b> MultiEraHeader<'b> {
pub fn decode(tag: u8, subtag: Option<u8>, cbor: &'b [u8]) -> Result<Self, Error> { pub fn decode(tag: u8, subtag: Option<u8>, cbor: &'b [u8]) -> Result<Self, Error> {
@ -71,10 +70,10 @@ impl<'b> MultiEraHeader<'b> {
pub fn hash(&self) -> Hash<32> { pub fn hash(&self) -> Hash<32> {
match self { match self {
MultiEraHeader::EpochBoundary(x) => x.to_hash(), MultiEraHeader::EpochBoundary(x) => x.original_hash(),
MultiEraHeader::AlonzoCompatible(x) => x.to_hash(), MultiEraHeader::AlonzoCompatible(x) => x.original_hash(),
MultiEraHeader::Babbage(x) => x.to_hash(), MultiEraHeader::Babbage(x) => x.original_hash(),
MultiEraHeader::Byron(x) => x.to_hash(), MultiEraHeader::Byron(x) => x.original_hash(),
} }
} }

View file

@ -129,14 +129,6 @@ pub enum MultiEraSigners<'b> {
AlonzoCompatible(&'b alonzo::RequiredSigners), AlonzoCompatible(&'b alonzo::RequiredSigners),
} }
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum MultiEraWitnesses<'b> {
Byron(&'b KeepRaw<'b, byron::Witnesses>),
AlonzoCompatible(&'b KeepRaw<'b, alonzo::TransactionWitnessSet>),
Babbage(&'b KeepRaw<'b, babbage::TransactionWitnessSet>),
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct OutputRef(Hash<32>, u64); pub struct OutputRef(Hash<32>, u64);
@ -172,6 +164,10 @@ impl Error {
} }
} }
pub trait ToHash<const BYTES: usize> { pub trait ComputeHash<const BYTES: usize> {
fn to_hash(&self) -> pallas_crypto::hash::Hash<BYTES>; fn compute_hash(&self) -> pallas_crypto::hash::Hash<BYTES>;
}
pub trait OriginalHash<const BYTES: usize> {
fn original_hash(&self) -> pallas_crypto::hash::Hash<BYTES>;
} }

View file

@ -7,7 +7,7 @@ macro_rules! clone_tx_fn {
fn $fn_name<'b>(block: &'b $era::MintedBlock, index: usize) -> Option<$era::MintedTx<'b>> { fn $fn_name<'b>(block: &'b $era::MintedBlock, index: usize) -> Option<$era::MintedTx<'b>> {
let transaction_body = block.transaction_bodies.get(index).cloned()?; let transaction_body = block.transaction_bodies.get(index).cloned()?;
let transaction_witness_set = block.transaction_witness_sets.get(index).cloned()?; let transaction_witness_set = block.transaction_witness_sets.get(index)?.clone();
let success = !block let success = !block
.invalid_transactions .invalid_transactions

View file

@ -6,7 +6,7 @@ use pallas_primitives::{alonzo, babbage, byron};
use crate::{ use crate::{
Era, MultiEraCert, MultiEraInput, MultiEraMeta, MultiEraMint, MultiEraOutput, MultiEraSigners, Era, MultiEraCert, MultiEraInput, MultiEraMeta, MultiEraMint, MultiEraOutput, MultiEraSigners,
MultiEraTx, MultiEraWithdrawals, MultiEraWitnesses, ToHash, MultiEraTx, MultiEraWithdrawals, OriginalHash,
}; };
impl<'b> MultiEraTx<'b> { impl<'b> MultiEraTx<'b> {
@ -61,9 +61,9 @@ impl<'b> MultiEraTx<'b> {
pub fn hash(&self) -> Hash<32> { pub fn hash(&self) -> Hash<32> {
match self { match self {
MultiEraTx::AlonzoCompatible(x, _) => x.transaction_body.to_hash(), MultiEraTx::AlonzoCompatible(x, _) => x.transaction_body.original_hash(),
MultiEraTx::Babbage(x) => x.transaction_body.to_hash(), MultiEraTx::Babbage(x) => x.transaction_body.original_hash(),
MultiEraTx::Byron(x) => x.transaction.to_hash(), MultiEraTx::Byron(x) => x.transaction.original_hash(),
} }
} }
@ -341,16 +341,6 @@ impl<'b> MultiEraTx<'b> {
} }
} }
pub fn witnesses(&self) -> MultiEraWitnesses {
match self {
MultiEraTx::AlonzoCompatible(x, _) => {
MultiEraWitnesses::AlonzoCompatible(&x.transaction_witness_set)
}
MultiEraTx::Babbage(x) => MultiEraWitnesses::Babbage(&x.transaction_witness_set),
MultiEraTx::Byron(x) => MultiEraWitnesses::Byron(&x.witness),
}
}
pub fn is_valid(&self) -> bool { pub fn is_valid(&self) -> bool {
match self { match self {
MultiEraTx::AlonzoCompatible(x, _) => x.success, MultiEraTx::AlonzoCompatible(x, _) => x.success,

View file

@ -1,85 +1,120 @@
use pallas_codec::utils::KeepRaw;
use pallas_primitives::{ use pallas_primitives::{
alonzo::{self, BootstrapWitness, NativeScript, PlutusData, Redeemer, VKeyWitness}, alonzo::{self, BootstrapWitness, NativeScript, PlutusData, Redeemer, VKeyWitness},
babbage::{self, PlutusV2Script}, babbage::PlutusV2Script,
}; };
use crate::MultiEraWitnesses; use crate::MultiEraTx;
impl<'b> MultiEraWitnesses<'b> { impl<'b> MultiEraTx<'b> {
pub fn as_alonzo(&self) -> Option<&alonzo::TransactionWitnessSet> { pub fn vkey_witnesses(&self) -> Option<&[VKeyWitness]> {
match self { match self {
Self::AlonzoCompatible(x) => Some(x), Self::AlonzoCompatible(x, _) => x
.transaction_witness_set
.vkeywitness
.as_ref()
.map(|x| x.as_ref()),
Self::Babbage(x) => x
.transaction_witness_set
.vkeywitness
.as_ref()
.map(|x| x.as_ref()),
_ => None, _ => None,
} }
} }
pub fn as_babbage(&self) -> Option<&babbage::TransactionWitnessSet> { pub fn native_scripts(&self) -> Option<&[NativeScript]> {
match self { match self {
Self::Babbage(x) => Some(x), Self::AlonzoCompatible(x, _) => x
.transaction_witness_set
.native_script
.as_ref()
.map(|x| x.as_ref()),
Self::Babbage(x) => x
.transaction_witness_set
.native_script
.as_ref()
.map(|x| x.as_ref()),
_ => None, _ => None,
} }
} }
pub fn vkeywitness(&self) -> Option<&[VKeyWitness]> { pub fn bootstrap_witnesses(&self) -> Option<&[BootstrapWitness]> {
match self { match self {
Self::AlonzoCompatible(x) => x.vkeywitness.as_ref().map(|x| x.as_ref()), Self::AlonzoCompatible(x, _) => x
Self::Babbage(x) => x.vkeywitness.as_ref().map(|x| x.as_ref()), .transaction_witness_set
.bootstrap_witness
.as_ref()
.map(|x| x.as_ref()),
Self::Babbage(x) => x
.transaction_witness_set
.bootstrap_witness
.as_ref()
.map(|x| x.as_ref()),
_ => None, _ => None,
} }
} }
pub fn native_script(&self) -> Option<&[NativeScript]> { pub fn plutus_v1_scripts(&self) -> Vec<&alonzo::PlutusScript> {
match self { match self {
Self::AlonzoCompatible(x) => x.native_script.as_ref().map(|x| x.as_ref()), Self::AlonzoCompatible(x, _) => x
Self::Babbage(x) => x.native_script.as_ref().map(|x| x.as_ref()), .transaction_witness_set
.plutus_script
.iter()
.flatten()
.collect(),
Self::Babbage(x) => x
.transaction_witness_set
.plutus_v1_script
.iter()
.flatten()
.collect(),
_ => vec![],
}
}
pub fn plutus_data(&self) -> Vec<&KeepRaw<'b, PlutusData>> {
match self {
Self::AlonzoCompatible(x, _) => x
.transaction_witness_set
.plutus_data
.iter()
.flatten()
.collect(),
Self::Babbage(x) => x
.transaction_witness_set
.plutus_data
.iter()
.flatten()
.collect(),
_ => std::iter::empty().collect(),
}
}
pub fn redeemers(&self) -> Option<&[Redeemer]> {
match self {
Self::AlonzoCompatible(x, _) => x
.transaction_witness_set
.redeemer
.as_ref()
.map(|x| x.as_ref()),
Self::Babbage(x) => x
.transaction_witness_set
.redeemer
.as_ref()
.map(|x| x.as_ref()),
_ => None, _ => None,
} }
} }
pub fn bootstrap_witness(&self) -> Option<&[BootstrapWitness]> { pub fn plutus_v2_scripts(&self) -> Option<&[PlutusV2Script]> {
match self { match self {
Self::AlonzoCompatible(x) => x.bootstrap_witness.as_ref().map(|x| x.as_ref()), Self::Babbage(x) => x
Self::Babbage(x) => x.bootstrap_witness.as_ref().map(|x| x.as_ref()), .transaction_witness_set
.plutus_v2_script
.as_ref()
.map(|x| x.as_ref()),
_ => None, _ => None,
} }
} }
pub fn plutus_v1_script(&self) -> Option<&[alonzo::PlutusScript]> {
match self {
Self::AlonzoCompatible(x) => x.plutus_script.as_ref().map(|x| x.as_ref()),
Self::Babbage(x) => x.plutus_v1_script.as_ref().map(|x| x.as_ref()),
_ => None,
}
}
pub fn plutus_data(&self) -> Option<&[PlutusData]> {
match self {
Self::AlonzoCompatible(x) => x.plutus_data.as_ref().map(|x| x.as_ref()),
Self::Babbage(x) => x.plutus_data.as_ref().map(|x| x.as_ref()),
_ => None,
}
}
pub fn redeemer(&self) -> Option<&[Redeemer]> {
match self {
Self::AlonzoCompatible(x) => x.redeemer.as_ref().map(|x| x.as_ref()),
Self::Babbage(x) => x.redeemer.as_ref().map(|x| x.as_ref()),
_ => None,
}
}
pub fn plutus_v2_script(&self) -> Option<&[PlutusV2Script]> {
match self {
Self::Babbage(x) => x.plutus_v2_script.as_ref().map(|x| x.as_ref()),
_ => None,
}
}
pub fn cbor(&self) -> &[u8] {
match self {
MultiEraWitnesses::AlonzoCompatible(x) => x.raw_cbor(),
MultiEraWitnesses::Babbage(x) => x.raw_cbor(),
MultiEraWitnesses::Byron(x) => x.raw_cbor(),
}
}
} }

1
test_data/babbage1.tx Normal file
View file

@ -0,0 +1 @@
84a400828258206c732139de33e916342707de2aebef2252c781640326ff37b86ec99d97f1ba8d0182582018f86700660fc88d0370a8f95ea58f75507e6b27a18a17925ad3b1777eb0d77600018783581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a05820923918e403bf43c34b4ef6b48eb2ee04babed17320d8d1b9ff9ad086e86f44ec83581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a0582054ad3c112d58e8946480e21d6a35b2a215d1a9a8f540c13714ded86e4b0b6aea83581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a05820ed33125018c5cbc9ae1b242a3ff8f3db2e108e4a63866d0b5238a34502c723ed83581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a05820b0ea85f16a443da7f60704a427923ae1d89a7dc2d6621d805d9dd441431ed70083581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a05820831a557bc2948e1b8c9f5e8e594d62299abff4eb1a11dc19da38bfaf9f2da40783581d703a888d65f16790950a72daee1f63aa05add6d268434107cfa5b67712821a000f52c6a05820c695868b4bfbf4c95714e707c69da1823bcf8cfc7c4b14b92c3645d4e1943be382581d60b6c8794e9a7a26599440a4d0fd79cd07644d15917ff13694f1f672351b00000001af62c125021a0002dfb10b58209dc070b08ae8dbd9ced77831308173284a19ab4839ce894fca45b8e3752a8a42a2008182582031ae74f8058527afb305d7495b10a99422d9337fc199e1f28044f2c477a0f94658409d9315424385661b9c17c0c9b96eeb61645d8f18cbefd43aa87677aae8cc2282642650d41004a11d1d0b66146da9fa22c824e6c1b9e0525268e9a43078fb670c049fd8799f413101ffd905039fa101423131d8798043313131ffd87980a10142313141319f0102fffff5f6