diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index c86ff068..027814aa 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -36,46 +36,10 @@ fn main() -> anyhow::Result<()> { hex::decode(cbor_hex.trim())? }; - let tx = MultiEraTx::decode(Era::Alonzo, &tx_bytes) - .or_else(|_| MultiEraTx::decode(Era::Byron, &tx_bytes))?; + let tx = MultiEraTx::decode(Era::Babbage, &tx_bytes) + .or_else(|_| MultiEraTx::decode(Era::Alonzo, &tx_bytes))?; println!("Simulating: {}", tx.hash()); - - let witnesses = tx.witnesses(); - - if let Some(((datums, redeemers), scripts)) = witnesses - .plutus_data() - .zip(witnesses.redeemer()) - .zip(witnesses.plutus_v1_script()) - { - for ((datum, redeemer), script) in - datums.iter().zip(redeemers.iter()).zip(scripts.iter()) - { - let program: Program = { - let mut buffer = Vec::new(); - - let prog = - Program::::from_cbor(&script.0, &mut buffer)?; - - prog.into() - }; - - program - .apply_data(datum.clone()) - .apply_data(redeemer.data.clone()); - - let file = File::open(&resolved_inputs)?; - let reader = BufReader::new(file); - let resolved_inputs: Vec = - serde_json::from_reader(reader)?; - - let tx_in_info = utils::get_tx_in_info_old(&resolved_inputs)?; - } - } - - println!("\nPlutus V2 Script:"); - - println!("{:#?}", tx.witnesses().plutus_v2_script()); } }, Args::Uplc(uplc_cmd) => match uplc_cmd { diff --git a/crates/cli/src/utils.rs b/crates/cli/src/utils.rs index 7da3b1b4..9227f028 100644 --- a/crates/cli/src/utils.rs +++ b/crates/cli/src/utils.rs @@ -1,102 +1,21 @@ use pallas_addresses::{ Address, ScriptHash, ShelleyDelegationPart, ShelleyPaymentPart, StakePayload, }; -use pallas_codec::{ - minicbor::{bytes::ByteVec}, - utils::{AnyUInt, KeyValuePairs, MaybeIndefArray, Bytes, Int}, -}; -use pallas_crypto::hash::{Hash, Hasher}; -use pallas_primitives::{ - babbage::{ - AddrKeyhash, AssetName, BigInt, Certificate, Coin, Constr, CostModel, DatumHash, - DatumOption, ExUnits, Language, Mint, MintedTx, PlutusV1Script, PlutusV2Script, PolicyId, - Redeemer, RedeemerTag, RewardAccount, Script, ScriptRef, StakeCredential, TransactionInput, - TransactionOutput, Tx, Value, Withdrawals, - }, - Fragment, -}; -use pallas_traverse::{Era, MultiEraTx, OriginalHash, ComputeHash}; -use std::{ - collections::HashMap, - convert::{TryFrom, TryInto}, - ops::Deref, - str::FromStr, - vec, +use pallas_codec::utils::{AnyUInt, Bytes, Int, KeyValuePairs, MaybeIndefArray}; +use pallas_crypto::hash::Hash; +use pallas_primitives::babbage::{ + AddrKeyhash, AssetName, BigInt, Certificate, Coin, Constr, DatumHash, DatumOption, ExUnits, + Mint, MintedTx, PlutusV1Script, PlutusV2Script, PolicyId, Redeemer, RedeemerTag, RewardAccount, + Script, ScriptRef, StakeCredential, TransactionInput, TransactionOutput, Value, Withdrawals, }; +use pallas_traverse::{ComputeHash, OriginalHash}; +use std::{collections::HashMap, convert::TryInto, ops::Deref, vec}; use uplc::{ ast::{FakeNamedDeBruijn, NamedDeBruijn, Program}, machine::cost_model::ExBudget, PlutusData, }; -use crate::args::ResolvedInputOld; - -pub fn get_tx_in_info_old(resolved_inputs: &[ResolvedInputOld]) -> anyhow::Result> { - let mut tx_in_info = Vec::new(); - - for resolved_input in resolved_inputs { - let tx_out_ref = TransactionInput { - transaction_id: Hash::from_str(resolved_input.input.tx_hash.as_str())?, - index: resolved_input.input.index, - } - .to_plutus_data(); - - let address = Address::from_bech32(&resolved_input.output.address)?; - - let lovelace = resolved_input.output.value.0; - - let mut assets = resolved_input.output.value.1.clone(); - - assets.insert( - "".to_string(), - vec![("".to_string(), lovelace)].into_iter().collect(), - ); - - let tx_out = PlutusData::Constr(Constr { - tag: 0, - any_constructor: None, - fields: vec![ - // txOutAddress - address.to_plutus_data(), - // txOutValue - PlutusData::Map(KeyValuePairs::Def( - assets - .iter() - .map(|val| { - let currency_symbol = - PlutusData::BoundedBytes(hex::decode(val.0).unwrap().into()); - let token_map = PlutusData::Map(KeyValuePairs::Def( - val.1 - .iter() - .map(|token| { - ( - PlutusData::BoundedBytes( - token.0.as_bytes().to_vec().into(), - ), - PlutusData::BigInt(BigInt::Int((*token.1 as i64).into())), - ) - }) - .collect(), - )); - (currency_symbol, token_map) - }) - .collect(), - )), - ], - }); - - tx_in_info.push(PlutusData::Constr(Constr { - tag: 0, - any_constructor: None, - fields: vec![tx_out_ref, tx_out], - })); - } - - Ok(tx_in_info) -} - -// --------------- - fn wrap_with_constr(index: u64, data: PlutusData) -> PlutusData { PlutusData::Constr(Constr { tag: constr_index(index), @@ -148,10 +67,10 @@ impl ToPlutusData for Address { let stake_part_plutus_data = match stake_part { ShelleyDelegationPart::Key(stake_keyhash) => { - Some(StakeCredential::AddrKeyhash(stake_keyhash.clone())).to_plutus_data() + Some(StakeCredential::AddrKeyhash(*stake_keyhash)).to_plutus_data() } ShelleyDelegationPart::Script(script_hash) => { - Some(StakeCredential::Scripthash(script_hash.clone())).to_plutus_data() + Some(StakeCredential::Scripthash(*script_hash)).to_plutus_data() } ShelleyDelegationPart::Pointer(pointer) => Some(wrap_multiple_with_constr( 1, @@ -202,15 +121,20 @@ impl ToPlutusData for (K, V) { } } -impl ToPlutusData for Vec where A: ToPlutusData { +impl ToPlutusData for Vec +where + A: ToPlutusData, +{ fn to_plutus_data(&self) -> PlutusData { - PlutusData::Array( - self.iter().map(|p| p.to_plutus_data()).collect(), - ) + PlutusData::Array(self.iter().map(|p| p.to_plutus_data()).collect()) } } -impl ToPlutusData for KeyValuePairs where K: ToPlutusData + Clone, V: ToPlutusData + Clone { +impl ToPlutusData for KeyValuePairs +where + K: ToPlutusData + Clone, + V: ToPlutusData + Clone, +{ fn to_plutus_data(&self) -> PlutusData { let mut data_vec: Vec<(PlutusData, PlutusData)> = vec![]; for (key, value) in self.iter() { @@ -257,7 +181,7 @@ impl ToPlutusData for AnyUInt { impl ToPlutusData for Int { fn to_plutus_data(&self) -> PlutusData { - PlutusData::BigInt(BigInt::Int(self.clone())) + PlutusData::BigInt(BigInt::Int(*self)) } } @@ -679,7 +603,7 @@ pub enum TxOut { V2(TransactionOutput), } -#[derive(Debug, PartialEq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone)] pub enum ScriptPurpose { Minting(PolicyId), Spending(TransactionInput), @@ -748,14 +672,12 @@ fn slot_to_begin_posix_time(slot: u64, sc: &SlotConfig) -> u64 { fn slot_range_to_posix_time_range(slot_range: TimeRange, sc: &SlotConfig) -> TimeRange { TimeRange { - lower_bound: match slot_range.lower_bound { - Some(lower_bound) => Some(slot_to_begin_posix_time(lower_bound, sc)), - None => None, - }, - upper_bound: match slot_range.upper_bound { - Some(upper_bound) => Some(slot_to_begin_posix_time(upper_bound, sc)), - None => None, - }, + lower_bound: slot_range + .lower_bound + .map(|lower_bound| slot_to_begin_posix_time(lower_bound, sc)), + upper_bound: slot_range + .upper_bound + .map(|upper_bound| slot_to_begin_posix_time(upper_bound, sc)), } } @@ -771,12 +693,12 @@ enum ExecutionPurpose { NoDatum(ScriptVersion), // Minting, Wdrl, DCert } -struct DataLookupTable { +pub struct DataLookupTable { datum: HashMap, scripts: HashMap, } -fn get_tx_in_info_v1( +pub fn get_tx_in_info_v1( inputs: &[TransactionInput], utxos: &[ResolvedInput], ) -> anyhow::Result> { @@ -804,12 +726,10 @@ fn get_tx_in_info_v1( match &utxo.output { TransactionOutput::Legacy(_) => {} TransactionOutput::PostAlonzo(output) => { - match output.datum_option { - Some(DatumOption::Data(_)) => { - unreachable!("Inline datum not allowed in PlutusV1.") - } - _ => {} - }; + if let Some(DatumOption::Data(_)) = output.datum_option { + unreachable!("Inline datum not allowed in PlutusV1.") + } + if output.script_ref.is_some() { unreachable!("Reference scripts not allowed in PlutusV1.") } @@ -876,20 +796,17 @@ fn get_script_purpose( .as_ref() .unwrap_or(&KeyValuePairs::Indef(vec![])) .iter() - .map(|(policy_id, _)| policy_id.clone()) + .map(|(policy_id, _)| *policy_id) .collect::>(); policy_ids.sort(); match policy_ids.get(index as usize) { - Some(policy_id) => Ok(ScriptPurpose::Minting(policy_id.clone())), + Some(policy_id) => Ok(ScriptPurpose::Minting(*policy_id)), None => unreachable!("Script purpose not found for redeemer."), } } RedeemerTag::Spend => { // sort lexical by tx_hash and index - let mut inputs = inputs - .iter() - .map(|input| input.clone()) - .collect::>(); + let mut inputs = inputs.to_vec(); // is this correct? Does this sort lexical from low to high? maybe get Ordering into pallas for TransactionInput? inputs.sort_by( |i_a, i_b| match i_a.transaction_id.cmp(&i_b.transaction_id) { @@ -920,7 +837,7 @@ fn get_script_purpose( let credential = match addresss { Address::Stake(stake_address) => match stake_address.payload() { StakePayload::Script(script_hash) => { - StakeCredential::Scripthash(script_hash.clone()) + StakeCredential::Scripthash(*script_hash) } StakePayload::Stake(_) => { unreachable!( @@ -950,7 +867,7 @@ fn get_script_purpose( fn get_tx_info_v1( tx: &MintedTx, - utxos: &MaybeIndefArray, + utxos: &[ResolvedInput], slot_config: &SlotConfig, ) -> anyhow::Result { let body = tx.transaction_body.clone(); @@ -961,45 +878,39 @@ fn get_tx_info_v1( let inputs = get_tx_in_info_v1(&body.inputs, &utxos)?; - let outputs = - body.outputs - .iter() - .map(|output| TxOut::V1(output.clone())) - .collect(); + let outputs = body + .outputs + .iter() + .map(|output| TxOut::V1(output.clone())) + .collect(); let fee = Value::Coin(body.fee); let mint = body.mint.clone().unwrap_or(KeyValuePairs::Indef(vec![])); - let dcert = body - .certificates + let dcert = body.certificates.clone().unwrap_or_default(); + let wdrl = body + .withdrawals .clone() - .unwrap_or(vec![]); - let wdrl = - body.withdrawals - .clone() - .unwrap_or(KeyValuePairs::Indef(vec![])) - .deref() - .clone(); + .unwrap_or(KeyValuePairs::Indef(vec![])) + .deref() + .clone(); let valid_range = slot_range_to_posix_time_range( TimeRange { lower_bound: body.validity_interval_start, upper_bound: body.ttl, }, - &slot_config, + slot_config, ); - let signatories = body - .required_signers - .clone() - .unwrap_or(vec![]); + let signatories = body.required_signers.clone().unwrap_or_default(); - let data = - tx.transaction_witness_set - .plutus_data - .as_ref() - .unwrap_or(&vec![]) - .iter() - .map(|d| (d.original_hash(), d.unwrap())) - .collect(); + let data = tx + .transaction_witness_set + .plutus_data + .as_ref() + .unwrap_or(&vec![]) + .iter() + .map(|d| (d.original_hash(), d.clone().unwrap())) + .collect(); let id = tx.transaction_body.compute_hash(); @@ -1019,30 +930,22 @@ fn get_tx_info_v1( fn get_tx_info_v2( tx: &MintedTx, - utxos: &MaybeIndefArray, + utxos: &[ResolvedInput], slot_config: &SlotConfig, ) -> anyhow::Result { let body = tx.transaction_body.clone(); - let inputs = get_tx_in_info_v2(&body.inputs, &utxos)?; - let reference_inputs = get_tx_in_info_v2( - &body - .reference_inputs - .clone() - .unwrap_or(vec![]), - &utxos, - )?; - let outputs = - body.outputs - .iter() - .map(|output| TxOut::V2(output.clone())) - .collect(); + let inputs = get_tx_in_info_v2(&body.inputs, utxos)?; + let reference_inputs = + get_tx_in_info_v2(&body.reference_inputs.clone().unwrap_or_default(), utxos)?; + let outputs = body + .outputs + .iter() + .map(|output| TxOut::V2(output.clone())) + .collect(); let fee = Value::Coin(body.fee); let mint = body.mint.clone().unwrap_or(KeyValuePairs::Indef(vec![])); - let dcert = body - .certificates - .clone() - .unwrap_or(vec![]); + let dcert = body.certificates.clone().unwrap_or_default(); let wdrl = body .withdrawals .clone() @@ -1052,12 +955,9 @@ fn get_tx_info_v2( lower_bound: body.validity_interval_start, upper_bound: body.ttl, }, - &slot_config, + slot_config, ); - let signatories = body - .required_signers - .clone() - .unwrap_or(vec![]); + let signatories = body.required_signers.clone().unwrap_or_default(); let redeemers = KeyValuePairs::Indef( tx.transaction_witness_set .redeemer @@ -1067,7 +967,7 @@ fn get_tx_info_v2( .map(|r| { ( get_script_purpose( - &r, + r, &tx.transaction_body.inputs, &tx.transaction_body.mint, &tx.transaction_body.certificates, @@ -1085,7 +985,7 @@ fn get_tx_info_v2( .as_ref() .unwrap_or(&vec![]) .iter() - .map(|d| (d.original_hash(), d.unwrap())) + .map(|d| (d.original_hash(), d.clone().unwrap())) .collect(), ); let id = tx.transaction_body.compute_hash(); @@ -1107,7 +1007,7 @@ fn get_tx_info_v2( } fn get_execution_purpose( - utxos: &MaybeIndefArray, + utxos: &[ResolvedInput], script_purpose: &ScriptPurpose, lookup_table: &DataLookupTable, ) -> ExecutionPurpose { @@ -1120,7 +1020,7 @@ fn get_execution_purpose( Some(s) => s.clone(), None => unreachable!("Missing required scripts.") }; - ExecutionPurpose::NoDatum(script.clone()) + ExecutionPurpose::NoDatum(script) } ScriptPurpose::Spending(out_ref) => { let utxo = utxos.iter().find(|utxo| utxo.input == *out_ref).unwrap(); @@ -1129,22 +1029,19 @@ fn get_execution_purpose( let address = Address::from_bytes(&output.address).unwrap(); match address { Address::Shelley(shelley_address) => { - let script = match lookup_table .scripts - .get(&shelley_address.payment().as_hash()) { + .get(shelley_address.payment().as_hash()) { Some(s) => s.clone(), None => unreachable!("Missing required scripts.") }; - - let datum = match lookup_table.datum.get(&output.datum_hash.unwrap_or_else(|| unreachable!("Missing datum hash in input."))) { Some(d) => d.clone(), None => unreachable!("Missing datum in witness set.") }; - ExecutionPurpose::WithDatum(script.clone(), datum.clone()) + ExecutionPurpose::WithDatum(script, datum) } _ => unreachable!( "This is impossible. Only shelley addresses can contain a script hash." @@ -1158,7 +1055,7 @@ fn get_execution_purpose( let script = match lookup_table .scripts - .get(&shelley_address.payment().as_hash()) { + .get(shelley_address.payment().as_hash()) { Some(s) => s.clone(), None => unreachable!("Missing required scripts.") }; @@ -1166,13 +1063,13 @@ fn get_execution_purpose( let datum = match &output.datum_option { Some(DatumOption::Hash(hash)) => { - lookup_table.datum.get(&hash).unwrap().clone() + lookup_table.datum.get(hash).unwrap().clone() } Some(DatumOption::Data(data)) => data.0.clone(), _ => unreachable!( "Missing datum hash or inline datum in input."), }; - ExecutionPurpose::WithDatum(script.clone(), datum) + ExecutionPurpose::WithDatum(script, datum) } _ => unreachable!( "This is impossible. Only shelley addresses can contain a script hash." @@ -1183,7 +1080,7 @@ fn get_execution_purpose( } ScriptPurpose::Rewarding(stake_credential) => { let script_hash = match stake_credential { - StakeCredential::Scripthash(hash) => hash.clone(), + StakeCredential::Scripthash(hash) => *hash, _ => unreachable!("This is impossible. A key hash cannot be the hash of a script."), }; @@ -1198,7 +1095,7 @@ fn get_execution_purpose( // StakeRegistration doesn't require a witness from a stake key/script. So I assume it doesn't need to be handled in Plutus either? Certificate::StakeDeregistration(stake_credential) => { let script_hash = match stake_credential { - StakeCredential::Scripthash(hash) => hash.clone(), + StakeCredential::Scripthash(hash) => *hash, _ => unreachable!( "This is impossible. A key hash cannot be the hash of a script." ), @@ -1213,7 +1110,7 @@ fn get_execution_purpose( } Certificate::StakeDelegation(stake_credential, _) => { let script_hash = match stake_credential { - StakeCredential::Scripthash(hash) => hash.clone(), + StakeCredential::Scripthash(hash) => *hash, _ => unreachable!( "This is impossible. A key hash cannot be the hash of a script." ), @@ -1231,10 +1128,7 @@ fn get_execution_purpose( } } -fn get_script_and_datum_lookup_table( - tx: &MintedTx, - utxos: &MaybeIndefArray, -) -> DataLookupTable { +fn get_script_and_datum_lookup_table(tx: &MintedTx, utxos: &[ResolvedInput]) -> DataLookupTable { let mut datum = HashMap::new(); let mut scripts = HashMap::new(); @@ -1244,30 +1138,32 @@ fn get_script_and_datum_lookup_table( .transaction_witness_set .plutus_data .clone() - .unwrap_or(vec![]); + .unwrap_or_default(); let scripts_v1_witnesses = tx .transaction_witness_set .plutus_v1_script .clone() - .unwrap_or(vec![]); + .unwrap_or_default(); let scripts_v2_witnesses = tx .transaction_witness_set .plutus_v2_script .clone() - .unwrap_or(vec![]); + .unwrap_or_default(); for plutus_data in plutus_data_witnesses.iter() { - datum.insert(plutus_data.original_hash(), plutus_data.clone()); + datum.insert(plutus_data.original_hash(), plutus_data.clone().unwrap()); } for script in scripts_v1_witnesses.iter() { - scripts.insert(script.compute_hash(), ScriptVersion::V1(script.clone())); // TODO: fix hashing bug in pallas + scripts.insert(script.compute_hash(), ScriptVersion::V1(script.clone())); + // TODO: fix hashing bug in pallas } for script in scripts_v2_witnesses.iter() { - scripts.insert(script.compute_hash(), ScriptVersion::V2(script.clone())); // TODO: fix hashing bug in pallas + scripts.insert(script.compute_hash(), ScriptVersion::V2(script.clone())); + // TODO: fix hashing bug in pallas } // discovery in utxos (script ref) @@ -1275,38 +1171,28 @@ fn get_script_and_datum_lookup_table( for utxo in utxos.iter() { match &utxo.output { TransactionOutput::Legacy(_) => {} - TransactionOutput::PostAlonzo(output) => match &output.script_ref { - Some(script) => match &script.0 { - Script::PlutusV1Script(v1) => { - // scripts.insert(v1.to_hash(), ScriptVersion::PlutusV1(v1.clone())); // TODO: fix hashing bug in pallas - let mut prefixed_script: Vec = vec![0x01]; - prefixed_script.extend(v1.0.iter()); - - let hash = Hasher::<224>::hash(&prefixed_script); - scripts.insert(hash, ScriptVersion::V1(v1.clone())); + TransactionOutput::PostAlonzo(output) => { + if let Some(script) = &output.script_ref { + match &script.0 { + Script::PlutusV1Script(v1) => { + scripts.insert(v1.compute_hash(), ScriptVersion::V1(v1.clone())); + } + Script::PlutusV2Script(v2) => { + scripts.insert(v2.compute_hash(), ScriptVersion::V2(v2.clone())); + } + _ => {} } - Script::PlutusV2Script(v2) => { - // scripts.insert(v2.to_hash(), ScriptVersion::PlutusV2(v2.clone())); // TODO: fix hashing bug in pallas - - let mut prefixed_script: Vec = vec![0x02]; - prefixed_script.extend(v2.0.iter()); - - let hash = Hasher::<224>::hash(&prefixed_script); - scripts.insert(hash, ScriptVersion::V2(v2.clone())); - } - _ => {} - }, - _ => {} - }, + } + } } } DataLookupTable { datum, scripts } } -fn eval_redeemer( +pub fn eval_redeemer( tx: &MintedTx, - utxos: &MaybeIndefArray, + utxos: &[ResolvedInput], slot_config: &SlotConfig, redeemer: &Redeemer, lookup_table: &DataLookupTable, @@ -1336,7 +1222,7 @@ fn eval_redeemer( }; let result = program - .apply_data(datum.clone()) + .apply_data(datum) .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()) .eval(); @@ -1371,7 +1257,7 @@ fn eval_redeemer( }; let result = program - .apply_data(datum.clone()) + .apply_data(datum) .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()) .eval(); @@ -1467,12 +1353,12 @@ fn eval_redeemer( } } -fn eval_tx( +pub fn eval_tx( tx: &MintedTx, - utxos: &MaybeIndefArray, + utxos: &[ResolvedInput], //TODO: costMdls slot_config: &SlotConfig, -) -> anyhow::Result> { +) -> anyhow::Result> { let redeemers = tx.transaction_witness_set.redeemer.as_ref(); let lookup_table = get_script_and_datum_lookup_table(tx, utxos); @@ -1489,9 +1375,9 @@ fn eval_tx( &lookup_table, )?) } - Ok(MaybeIndefArray::Indef(collected_redeemers)) + Ok(collected_redeemers) } - None => Ok(MaybeIndefArray::Indef(vec![])), + None => Ok(vec![]), } } @@ -1500,12 +1386,11 @@ mod tests { use pallas_codec::utils::MaybeIndefArray; use pallas_primitives::{ babbage::{TransactionInput, TransactionOutput}, - Fragment, ToHash, + Fragment, }; use pallas_traverse::{Era, MultiEraTx}; - use uplc::PlutusData; - use super::{eval_tx, ResolvedInput, SlotConfig, TxInInfo}; + use super::{eval_tx, ResolvedInput, SlotConfig}; #[test] fn test_eval() { @@ -1526,19 +1411,17 @@ mod tests { let raw_inputs = hex::decode("84825820b16778c9cf065d9efeefe37ec269b4fc5107ecdbd0dd6bf3274b224165c2edd9008258206c732139de33e916342707de2aebef2252c781640326ff37b86ec99d97f1ba8d01825820975c17a4fed0051be622328efa548e206657d2b65a19224bf6ff8132571e6a500282582018f86700660fc88d0370a8f95ea58f75507e6b27a18a17925ad3b1777eb0d77600").unwrap(); let raw_outputs = hex::decode("8482581d60b6c8794e9a7a26599440a4d0fd79cd07644d15917ff13694f1f67235821a000f8548a1581c15be994a64bdb79dde7fe080d8e7ff81b33a9e4860e9ee0d857a8e85a144576177610182581d60b6c8794e9a7a26599440a4d0fd79cd07644d15917ff13694f1f672351b00000001af14b8b482581d60b6c8794e9a7a26599440a4d0fd79cd07644d15917ff13694f1f672351a0098968082581d60b6c8794e9a7a26599440a4d0fd79cd07644d15917ff13694f1f672351a00acd8c6").unwrap(); - let inputs = MaybeIndefArray::::decode_fragment(&raw_inputs).unwrap(); - let outputs = MaybeIndefArray::::decode_fragment(&raw_outputs).unwrap(); + let inputs = Vec::::decode_fragment(&raw_inputs).unwrap(); + let outputs = Vec::::decode_fragment(&raw_outputs).unwrap(); - let utxos: MaybeIndefArray = MaybeIndefArray::Indef( - inputs - .iter() - .zip(outputs.iter()) - .map(|(input, output)| ResolvedInput { - input: input.clone(), - output: output.clone(), - }) - .collect(), - ); + let utxos: Vec = inputs + .iter() + .zip(outputs.iter()) + .map(|(input, output)| ResolvedInput { + input: input.clone(), + output: output.clone(), + }) + .collect(); let slot_config = SlotConfig { zero_time: 1660003200000, // Preview network @@ -1552,7 +1435,7 @@ mod tests { MultiEraTx::Babbage(tx) => { let redeemers = eval_tx(&tx, &utxos, &slot_config).unwrap(); - println!("{:?}", redeemers.len()); + assert_eq!(redeemers.len(), 1) } _ => unreachable!(), };