From 6c34c9be19d1837e01ca274798eb33b6fe9168ac Mon Sep 17 00:00:00 2001 From: rvcas Date: Mon, 19 Sep 2022 01:05:33 -0400 Subject: [PATCH] feat: even more errors work --- crates/cli/src/main.rs | 2 +- crates/uplc/src/tx/error.rs | 8 ++++ crates/uplc/src/tx/eval.rs | 76 ++++++++++++++++----------------- crates/uplc/src/tx/phase_one.rs | 19 +++------ 4 files changed, 54 insertions(+), 51 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 58189423..859f2adf 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -54,7 +54,7 @@ fn main() -> anyhow::Result<()> { slot_length, }; - tx::eval(tx_babbage, &resolved_inputs, None, &slot_config)?; + tx::eval_phase_two(tx_babbage, &resolved_inputs, None, &slot_config, true)?; } } }, diff --git a/crates/uplc/src/tx/error.rs b/crates/uplc/src/tx/error.rs index 804405a9..fbdc243b 100644 --- a/crates/uplc/src/tx/error.rs +++ b/crates/uplc/src/tx/error.rs @@ -7,9 +7,13 @@ pub enum Error { #[error("Only shelley reward addresses can be a part of withdrawals")] BadWithdrawalAddress, #[error("{0}")] + FlatDecode(#[from] flat_rs::de::Error), + #[error("{0}")] FragmentDecode(#[from] pallas_primitives::Error), #[error("{0}")] Machine(#[from] machine::Error), + #[error("Native script can't be executed in phase-two")] + NativeScriptPhaseTwo, #[error("Can't eval without redeemers")] NoRedeemers, #[error("Mismatch in required redeemers: {} {}", .missing.join(" "), .extra.join(" "))] @@ -21,6 +25,10 @@ pub enum Error { ResolvedInputNotFound, #[error("A key hash cannot be the hash of a script")] ScriptKeyHash, + #[error("PlutusV1 cost model not found.")] + V1CostModelNotFound, + #[error("PlutusV2 cost model not found.")] + V2CostModelNotFound, #[error("Wrong era, Please use Babbage or Alonzo: {0}")] WrongEra(#[from] pallas_codec::minicbor::decode::Error), } diff --git a/crates/uplc/src/tx/eval.rs b/crates/uplc/src/tx/eval.rs index e3ec011a..7b355e77 100644 --- a/crates/uplc/src/tx/eval.rs +++ b/crates/uplc/src/tx/eval.rs @@ -7,9 +7,9 @@ use pallas_addresses::{Address, ScriptHash, StakePayload}; use pallas_codec::utils::{KeyValuePairs, MaybeIndefArray}; use pallas_crypto::hash::Hash; use pallas_primitives::babbage::{ - Certificate, CostMdls, DatumHash, DatumOption, ExUnits, Language, Mint, MintedTx, + Certificate, CostMdls, DatumHash, DatumOption, ExUnits, Language, Mint, MintedTx, NativeScript, PlutusV1Script, PlutusV2Script, PolicyId, Redeemer, RedeemerTag, RewardAccount, Script, - StakeCredential, TransactionInput, TransactionOutput, Value, Withdrawals, NativeScript, + StakeCredential, TransactionInput, TransactionOutput, Value, Withdrawals, }; use pallas_traverse::{ComputeHash, OriginalHash}; use std::{collections::HashMap, convert::TryInto, ops::Deref, vec}; @@ -606,11 +606,11 @@ pub fn eval_redeemer( .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()); - let result = if let Some(cost_mdls) = cost_mdls_opt { + let (result, budget, _) = if let Some(cost_mdls) = cost_mdls_opt { let costs = if let Some(costs) = &cost_mdls.plutus_v1 { costs } else { - return Err(anyhow::Error::msg("PlutusV1 cost model not found.")); + return Err(Error::V1CostModelNotFound); }; program.eval_as(&Language::PlutusV1, costs) @@ -618,18 +618,18 @@ pub fn eval_redeemer( program.eval_v1() }; - match result.0 { - Ok(_) => {} - Err(_err) => unreachable!("Error in Plutus core."), // TODO: Add the actual error message - } + // TODO: do we want the logs in the error? + result?; + + let initial_budget = ExBudget::default(); let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, data: redeemer.data.clone(), ex_units: ExUnits { - mem: (ExBudget::default().mem - result.1.mem) as u32, - steps: (ExBudget::default().cpu - result.1.cpu) as u64, + mem: (initial_budget.mem - budget.mem) as u32, + steps: (initial_budget.cpu - budget.cpu) as u64, }, }; @@ -652,11 +652,11 @@ pub fn eval_redeemer( .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()); - let result = if let Some(cost_mdls) = cost_mdls_opt { - let costs = if let Some(costs) = &cost_mdls.plutus_v1 { + let (result, budget, _) = if let Some(cost_mdls) = cost_mdls_opt { + let costs = if let Some(costs) = &cost_mdls.plutus_v2 { costs } else { - return Err(anyhow::Error::msg("PlutusV1 cost model not found.")); + return Err(Error::V2CostModelNotFound); }; program.eval_as(&Language::PlutusV2, costs) @@ -664,24 +664,24 @@ pub fn eval_redeemer( program.eval() }; - match result.0 { - Ok(_) => {} - Err(_err) => unreachable!("Error in Plutus core."), // TODO: Add the actual error message - } + // TODO: do we want the logs in the error? + result?; + + let initial_budget = ExBudget::default(); let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, data: redeemer.data.clone(), ex_units: ExUnits { - mem: (ExBudget::default().mem - result.1.mem) as u32, - steps: (ExBudget::default().cpu - result.1.cpu) as u64, + mem: (initial_budget.mem - budget.mem) as u32, + steps: (initial_budget.cpu - budget.cpu) as u64, }, }; Ok(new_redeemer) } - ScriptVersion::Native(_) => unreachable!("Native script can't be executed in phase-two.") + ScriptVersion::Native(_) => Err(Error::NativeScriptPhaseTwo), }, ExecutionPurpose::NoDatum(script_version) => match script_version { ScriptVersion::V1(script) => { @@ -700,11 +700,11 @@ pub fn eval_redeemer( .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()); - let result = if let Some(cost_mdls) = cost_mdls_opt { + let (result, budget, _) = if let Some(cost_mdls) = cost_mdls_opt { let costs = if let Some(costs) = &cost_mdls.plutus_v1 { costs } else { - return Err(anyhow::Error::msg("PlutusV1 cost model not found.")); + return Err(Error::V1CostModelNotFound); }; program.eval_as(&Language::PlutusV1, costs) @@ -712,18 +712,18 @@ pub fn eval_redeemer( program.eval_v1() }; - match result.0 { - Ok(_) => {} - Err(_err) => unreachable!("Error in Plutus core."), // TODO: Add the actual error message - } + // TODO: do we want the logs in the error? + result?; + + let initial_budget = ExBudget::default(); let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, data: redeemer.data.clone(), ex_units: ExUnits { - mem: (ExBudget::default().mem - result.1.mem) as u32, - steps: (ExBudget::default().cpu - result.1.cpu) as u64, + mem: (initial_budget.mem - budget.mem) as u32, + steps: (initial_budget.cpu - budget.cpu) as u64, }, }; @@ -745,11 +745,11 @@ pub fn eval_redeemer( .apply_data(redeemer.data.clone()) .apply_data(script_context.to_plutus_data()); - let result = if let Some(cost_mdls) = cost_mdls_opt { - let costs = if let Some(costs) = &cost_mdls.plutus_v1 { + let (result, budget, _) = if let Some(cost_mdls) = cost_mdls_opt { + let costs = if let Some(costs) = &cost_mdls.plutus_v2 { costs } else { - return Err(anyhow::Error::msg("PlutusV1 cost model not found.")); + return Err(Error::V2CostModelNotFound); }; program.eval_as(&Language::PlutusV2, costs) @@ -757,24 +757,24 @@ pub fn eval_redeemer( program.eval() }; - match result.0 { - Ok(_) => {} - Err(_err) => unreachable!("Error in Plutus core."), // TODO: Add the actual error message - } + // TODO: do we want the logs in the error? + result?; + + let initial_budget = ExBudget::default(); let new_redeemer = Redeemer { tag: redeemer.tag.clone(), index: redeemer.index, data: redeemer.data.clone(), ex_units: ExUnits { - mem: (ExBudget::default().mem - result.1.mem) as u32, - steps: (ExBudget::default().cpu - result.1.cpu) as u64, + mem: (initial_budget.mem - budget.mem) as u32, + steps: (initial_budget.cpu - budget.cpu) as u64, }, }; Ok(new_redeemer) } - ScriptVersion::Native(_) => unreachable!("Native script can't be executed in phase-two.") + ScriptVersion::Native(_) => Err(Error::NativeScriptPhaseTwo), }, } } diff --git a/crates/uplc/src/tx/phase_one.rs b/crates/uplc/src/tx/phase_one.rs index ef2df2e6..8afa7269 100644 --- a/crates/uplc/src/tx/phase_one.rs +++ b/crates/uplc/src/tx/phase_one.rs @@ -40,7 +40,7 @@ pub fn validate_missing_scripts( needed: &AlonzoScriptsNeeded, txscripts: HashMap, ) -> Result<(), Error> { - let received_hashes = txscripts.keys().map(|x| *x).collect::>(); + let received_hashes = txscripts.keys().copied().collect::>(); let needed_hashes = needed.iter().map(|x| x.1).collect::>(); @@ -57,7 +57,7 @@ pub fn validate_missing_scripts( .map(|x| format!("[Extraneous (sh: {:?})]", x)) .collect(); - if missing.len() > 0 || extra.len() > 0 { + if !missing.is_empty() || !extra.is_empty() { let missing_errors = missing.join(" "); let extra_errors = extra.join(" "); @@ -80,8 +80,8 @@ pub fn scripts_needed( let mut spend = Vec::new(); - for input in txb.inputs { - let utxo = match utxos.iter().find(|utxo| utxo.input == input) { + for input in txb.inputs.iter() { + let utxo = match utxos.iter().find(|utxo| utxo.input == *input) { Some(u) => u, None => return Err(Error::ResolvedInputNotFound), }; @@ -164,7 +164,7 @@ pub fn has_exact_set_of_redeemers( for (script_purpose, script_hash) in needed { let redeemer_ptr = build_redeemer_ptr(tx, script_purpose)?; - let script = tx_scripts.get(&script_hash); + let script = tx_scripts.get(script_hash); if let (Some(ptr), Some(script)) = (redeemer_ptr, script) { match script { @@ -200,9 +200,7 @@ pub fn has_exact_set_of_redeemers( .map(|x| { format!( "[Missing (redeemer_ptr: {:?}, script_purpose: {:?}, script_hash: {})]", - x.0, - x.1, - x.2.to_string(), + x.0, x.1, x.2, ) }) .collect(); @@ -213,10 +211,7 @@ pub fn has_exact_set_of_redeemers( .map(|x| format!("[Extraneous (redeemer_ptr: {:?})]", x)) .collect(); - if missing.len() > 0 || extra.len() > 0 { - let missing_errors = missing.join(" "); - let extra_errors = extra.join(" "); - + if !missing.is_empty() || !extra.is_empty() { Err(Error::RequiredRedeemersMismatch { missing, extra }) } else { Ok(())