Return an EvalResult alongside the redeemer

This refactors things so that eval_phase_two can expose logs even when the script succeeds.

It also enriches traces to be either Logs or Labels, so that we can tell the difference between the two when inspecting the traces.
This commit is contained in:
Pi Lanningham 2025-02-17 15:16:20 -05:00 committed by Lucas
parent e9bacf8f41
commit 17a75d2481
12 changed files with 128 additions and 104 deletions

View File

@ -231,17 +231,17 @@ impl UnitTest {
OnTestFailure::FailImmediately => false, OnTestFailure::FailImmediately => false,
}); });
let mut traces = Vec::new(); let mut logs = Vec::new();
if let Err(err) = eval_result.result() { if let Err(err) = eval_result.result() {
traces.push(format!("{err}")) logs.push(format!("{err}"))
} }
traces.extend(eval_result.logs()); logs.extend(eval_result.logs());
UnitTestResult { UnitTestResult {
success, success,
test: self.to_owned(), test: self.to_owned(),
spent_budget: eval_result.cost(), spent_budget: eval_result.cost(),
traces, logs,
assertion: self.assertion, assertion: self.assertion,
} }
} }
@ -276,7 +276,7 @@ pub struct Fuzzer<T> {
#[derive(Debug, Clone, thiserror::Error, miette::Diagnostic)] #[derive(Debug, Clone, thiserror::Error, miette::Diagnostic)]
#[error("Fuzzer exited unexpectedly: {uplc_error}.")] #[error("Fuzzer exited unexpectedly: {uplc_error}.")]
pub struct FuzzerError { pub struct FuzzerError {
traces: Vec<String>, logs: Vec<String>,
uplc_error: uplc::machine::Error, uplc_error: uplc::machine::Error,
} }
@ -330,7 +330,7 @@ impl PropertyTest {
let mut labels = BTreeMap::new(); let mut labels = BTreeMap::new();
let mut remaining = n; let mut remaining = n;
let (traces, counterexample, iterations) = match self.run_n_times( let (logs, counterexample, iterations) = match self.run_n_times(
&mut remaining, &mut remaining,
Prng::from_seed(seed), Prng::from_seed(seed),
&mut labels, &mut labels,
@ -339,18 +339,12 @@ impl PropertyTest {
Ok(None) => (Vec::new(), Ok(None), n), Ok(None) => (Vec::new(), Ok(None), n),
Ok(Some(counterexample)) => ( Ok(Some(counterexample)) => (
self.eval(&counterexample.value, plutus_version) self.eval(&counterexample.value, plutus_version)
.logs() .logs(),
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
Ok(Some(counterexample.value)), Ok(Some(counterexample.value)),
n - remaining, n - remaining,
), ),
Err(FuzzerError { traces, uplc_error }) => ( Err(FuzzerError { logs, uplc_error }) => (
traces logs,
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
Err(uplc_error), Err(uplc_error),
n - remaining + 1, n - remaining + 1,
), ),
@ -361,7 +355,7 @@ impl PropertyTest {
counterexample, counterexample,
iterations, iterations,
labels, labels,
traces, logs,
} }
} }
@ -397,16 +391,14 @@ impl PropertyTest {
let mut result = self.eval(&value, plutus_version); let mut result = self.eval(&value, plutus_version);
for s in result.logs() { for label in result.labels() {
// NOTE: There may be other log outputs that interefere with labels. So *by // NOTE: There may be other log outputs that interefere with labels. So *by
// convention*, we treat as label strings that starts with a NUL byte, which // convention*, we treat as label strings that starts with a NUL byte, which
// should be a guard sufficient to prevent inadvertent clashes. // should be a guard sufficient to prevent inadvertent clashes.
if let Some(label) = PropertyTest::extract_label(&s) { labels
labels .entry(label)
.entry(label) .and_modify(|count| *count += 1)
.and_modify(|count| *count += 1) .or_insert(1);
.or_insert(1);
}
} }
let is_failure = result.failed(false); let is_failure = result.failed(false);
@ -470,14 +462,6 @@ impl PropertyTest {
.unwrap() .unwrap()
.eval_version(ExBudget::max(), &plutus_version.into()) .eval_version(ExBudget::max(), &plutus_version.into())
} }
fn extract_label(s: &str) -> Option<String> {
if s.starts_with('\0') {
Some(s.split_at(1).1.to_string())
} else {
None
}
}
} }
/// ----- Benchmark ----------------------------------------------------------------- /// ----- Benchmark -----------------------------------------------------------------
@ -498,21 +482,21 @@ pub struct Sampler<T> {
pub enum BenchmarkError { pub enum BenchmarkError {
#[error("Sampler exited unexpectedly: {uplc_error}.")] #[error("Sampler exited unexpectedly: {uplc_error}.")]
SamplerError { SamplerError {
traces: Vec<String>, logs: Vec<String>,
uplc_error: uplc::machine::Error, uplc_error: uplc::machine::Error,
}, },
#[error("Bench exited unexpectedly: {uplc_error}.")] #[error("Bench exited unexpectedly: {uplc_error}.")]
BenchError { BenchError {
traces: Vec<String>, logs: Vec<String>,
uplc_error: uplc::machine::Error, uplc_error: uplc::machine::Error,
}, },
} }
impl BenchmarkError { impl BenchmarkError {
pub fn traces(&self) -> &[String] { pub fn logs(&self) -> &[String] {
match self { match self {
BenchmarkError::SamplerError { traces, .. } BenchmarkError::SamplerError { logs, .. }
| BenchmarkError::BenchError { traces, .. } => traces.as_slice(), | BenchmarkError::BenchError { logs, .. } => logs.as_slice(),
} }
} }
} }
@ -561,19 +545,15 @@ impl Benchmark {
Ok(_) => measures.push((size, result.cost())), Ok(_) => measures.push((size, result.cost())),
Err(uplc_error) => { Err(uplc_error) => {
error = Some(BenchmarkError::BenchError { error = Some(BenchmarkError::BenchError {
traces: result logs: result.logs(),
.logs()
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
uplc_error, uplc_error,
}); });
} }
} }
} }
Err(FuzzerError { traces, uplc_error }) => { Err(FuzzerError { logs, uplc_error }) => {
error = Some(BenchmarkError::SamplerError { traces, uplc_error }); error = Some(BenchmarkError::SamplerError { logs, uplc_error });
} }
} }
@ -692,7 +672,7 @@ impl Prng {
result result
.result() .result()
.map_err(|uplc_error| FuzzerError { .map_err(|uplc_error| FuzzerError {
traces: result.logs(), logs: result.logs(),
uplc_error, uplc_error,
}) })
.map(Prng::from_result) .map(Prng::from_result)
@ -1166,12 +1146,12 @@ impl<U, T> TestResult<U, T> {
} }
} }
pub fn traces(&self) -> &[String] { pub fn logs(&self) -> &[String] {
match self { match self {
TestResult::UnitTestResult(UnitTestResult { traces, .. }) TestResult::UnitTestResult(UnitTestResult { logs, .. })
| TestResult::PropertyTestResult(PropertyTestResult { traces, .. }) => traces, | TestResult::PropertyTestResult(PropertyTestResult { logs, .. }) => logs,
TestResult::BenchmarkResult(BenchmarkResult { error, .. }) => { TestResult::BenchmarkResult(BenchmarkResult { error, .. }) => {
error.as_ref().map(|e| e.traces()).unwrap_or_default() error.as_ref().map(|e| e.logs()).unwrap_or_default()
} }
} }
} }
@ -1181,7 +1161,7 @@ impl<U, T> TestResult<U, T> {
pub struct UnitTestResult<T> { pub struct UnitTestResult<T> {
pub success: bool, pub success: bool,
pub spent_budget: ExBudget, pub spent_budget: ExBudget,
pub traces: Vec<String>, pub logs: Vec<String>,
pub test: UnitTest, pub test: UnitTest,
pub assertion: Option<Assertion<T>>, pub assertion: Option<Assertion<T>>,
} }
@ -1196,7 +1176,7 @@ impl UnitTestResult<(Constant, Rc<Type>)> {
UnitTestResult { UnitTestResult {
success: self.success, success: self.success,
spent_budget: self.spent_budget, spent_budget: self.spent_budget,
traces: self.traces, logs: self.logs,
test: self.test, test: self.test,
assertion: self.assertion.and_then(|assertion| { assertion: self.assertion.and_then(|assertion| {
// No need to spend time/cpu on reifying assertions for successful // No need to spend time/cpu on reifying assertions for successful
@ -1229,7 +1209,7 @@ pub struct PropertyTestResult<T> {
pub counterexample: Result<Option<T>, uplc::machine::Error>, pub counterexample: Result<Option<T>, uplc::machine::Error>,
pub iterations: usize, pub iterations: usize,
pub labels: BTreeMap<String, usize>, pub labels: BTreeMap<String, usize>,
pub traces: Vec<String>, pub logs: Vec<String>,
} }
unsafe impl<T> Send for PropertyTestResult<T> {} unsafe impl<T> Send for PropertyTestResult<T> {}
@ -1249,7 +1229,7 @@ impl PropertyTestResult<PlutusData> {
iterations: self.iterations, iterations: self.iterations,
test: self.test, test: self.test,
labels: self.labels, labels: self.labels,
traces: self.traces, logs: self.logs,
} }
} }
} }

View File

@ -129,8 +129,8 @@ fn fmt_test_json(result: &TestResult<UntypedExpr, UntypedExpr>) -> serde_json::V
TestResult::BenchmarkResult(_) => unreachable!("benchmark returned in JSON output"), TestResult::BenchmarkResult(_) => unreachable!("benchmark returned in JSON output"),
} }
if !result.traces().is_empty() { if !result.logs().is_empty() {
test["traces"] = json!(result.traces()); test["traces"] = json!(result.logs());
} }
test test

View File

@ -584,12 +584,12 @@ fn fmt_test(
} }
// Traces // Traces
if !result.traces().is_empty() { if !result.logs().is_empty() {
test = format!( test = format!(
"{test}\n{title}\n{traces}", "{test}\n{title}\n{traces}",
title = "· with traces".if_supports_color(Stderr, |s| s.bold()), title = "· with traces".if_supports_color(Stderr, |s| s.bold()),
traces = result traces = result
.traces() .logs()
.iter() .iter()
.map(|line| { format!("| {line}",) }) .map(|line| { format!("| {line}",) })
.collect::<Vec<_>>() .collect::<Vec<_>>()

View File

@ -137,7 +137,7 @@ pub fn exec(
// this should allow N scripts to be // this should allow N scripts to be
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })

View File

@ -856,7 +856,7 @@ impl Program<NamedDeBruijn> {
term, term,
machine.ex_budget, machine.ex_budget,
initial_budget, initial_budget,
machine.logs, machine.traces,
machine.spend_counter.map(|i| i.into()), machine.spend_counter.map(|i| i.into()),
) )
} }
@ -871,7 +871,7 @@ impl Program<NamedDeBruijn> {
term, term,
machine.ex_budget, machine.ex_budget,
initial_budget, initial_budget,
machine.logs, machine.traces,
machine.spend_counter.map(|i| i.into()), machine.spend_counter.map(|i| i.into()),
) )
} }
@ -897,7 +897,7 @@ impl Program<NamedDeBruijn> {
term, term,
machine.ex_budget, machine.ex_budget,
budget, budget,
machine.logs, machine.traces,
machine.spend_counter.map(|i| i.into()), machine.spend_counter.map(|i| i.into()),
) )
} }
@ -916,7 +916,7 @@ impl Program<NamedDeBruijn> {
term, term,
machine.ex_budget, machine.ex_budget,
initial_budget, initial_budget,
machine.logs, machine.traces,
machine.spend_counter.map(|i| i.into()), machine.spend_counter.map(|i| i.into()),
) )
} }

View File

@ -45,13 +45,42 @@ enum Context {
pub const TERM_COUNT: usize = 9; pub const TERM_COUNT: usize = 9;
pub const BUILTIN_COUNT: usize = 87; pub const BUILTIN_COUNT: usize = 87;
#[derive(Debug, Clone)]
pub enum Trace {
Log(String),
Label(String),
}
impl Trace {
pub fn to_string(&self) -> String {
match self {
Trace::Log(log) => log.clone(),
Trace::Label(label) => label.clone(),
}
}
pub fn unwrap_log(self) -> Option<String> {
match self {
Trace::Log(log) => Some(log),
_ => None,
}
}
pub fn unwrap_label(self) -> Option<String> {
match self {
Trace::Label(label) => Some(label),
_ => None,
}
}
}
pub struct Machine { pub struct Machine {
costs: CostModel, costs: CostModel,
pub ex_budget: ExBudget, pub ex_budget: ExBudget,
slippage: u32, slippage: u32,
unbudgeted_steps: [u32; 10], unbudgeted_steps: [u32; 10],
pub traces: Vec<Trace>,
pub spend_counter: Option<[i64; (TERM_COUNT + BUILTIN_COUNT) * 2]>, pub spend_counter: Option<[i64; (TERM_COUNT + BUILTIN_COUNT) * 2]>,
pub logs: Vec<String>,
version: Language, version: Language,
} }
@ -67,8 +96,8 @@ impl Machine {
ex_budget: initial_budget, ex_budget: initial_budget,
slippage, slippage,
unbudgeted_steps: [0; 10], unbudgeted_steps: [0; 10],
traces: vec![],
spend_counter: None, spend_counter: None,
logs: vec![],
version, version,
} }
} }
@ -84,8 +113,8 @@ impl Machine {
ex_budget: initial_budget, ex_budget: initial_budget,
slippage, slippage,
unbudgeted_steps: [0; 10], unbudgeted_steps: [0; 10],
traces: vec![],
spend_counter: Some([0; (TERM_COUNT + BUILTIN_COUNT) * 2]), spend_counter: Some([0; (TERM_COUNT + BUILTIN_COUNT) * 2]),
logs: vec![],
version, version,
} }
} }
@ -353,7 +382,7 @@ impl Machine {
counter[i + 1] += cost.cpu; counter[i + 1] += cost.cpu;
} }
runtime.call(&self.version, &mut self.logs) runtime.call(&self.version, &mut self.traces)
} }
fn lookup_var(&mut self, name: &NamedDeBruijn, env: &[Value]) -> Result<Value, Error> { fn lookup_var(&mut self, name: &NamedDeBruijn, env: &[Value]) -> Result<Value, Error> {

View File

@ -1,4 +1,4 @@
use super::{cost_model::ExBudget, Error}; use super::{cost_model::ExBudget, Error, Trace};
use crate::ast::{Constant, NamedDeBruijn, Term}; use crate::ast::{Constant, NamedDeBruijn, Term};
#[derive(Debug)] #[derive(Debug)]
@ -6,7 +6,7 @@ pub struct EvalResult {
result: Result<Term<NamedDeBruijn>, Error>, result: Result<Term<NamedDeBruijn>, Error>,
remaining_budget: ExBudget, remaining_budget: ExBudget,
initial_budget: ExBudget, initial_budget: ExBudget,
logs: Vec<String>, traces: Vec<Trace>,
debug_cost: Option<Vec<i64>>, debug_cost: Option<Vec<i64>>,
} }
@ -15,14 +15,14 @@ impl EvalResult {
result: Result<Term<NamedDeBruijn>, Error>, result: Result<Term<NamedDeBruijn>, Error>,
remaining_budget: ExBudget, remaining_budget: ExBudget,
initial_budget: ExBudget, initial_budget: ExBudget,
logs: Vec<String>, traces: Vec<Trace>,
debug_cost: Option<Vec<i64>>, debug_cost: Option<Vec<i64>>,
) -> EvalResult { ) -> EvalResult {
EvalResult { EvalResult {
result, result,
remaining_budget, remaining_budget,
initial_budget, initial_budget,
logs, traces,
debug_cost, debug_cost,
} }
} }
@ -31,8 +31,22 @@ impl EvalResult {
self.initial_budget - self.remaining_budget self.initial_budget - self.remaining_budget
} }
pub fn traces(&mut self) -> Vec<Trace> {
std::mem::take(&mut self.traces)
}
pub fn logs(&mut self) -> Vec<String> { pub fn logs(&mut self) -> Vec<String> {
std::mem::take(&mut self.logs) std::mem::take(&mut self.traces)
.into_iter()
.filter_map(Trace::unwrap_log)
.collect()
}
pub fn labels(&mut self) -> Vec<String> {
std::mem::take(&mut self.traces)
.into_iter()
.filter_map(Trace::unwrap_label)
.collect()
} }
pub fn failed(&self, can_error: bool) -> bool { pub fn failed(&self, can_error: bool) -> bool {

View File

@ -1,7 +1,5 @@
use super::{ use super::{
cost_model::{BuiltinCosts, ExBudget}, cost_model::{BuiltinCosts, ExBudget}, value::{from_pallas_bigint, to_pallas_bigint}, Error, Trace, Value
value::{from_pallas_bigint, to_pallas_bigint},
Error, Value,
}; };
use crate::{ use crate::{
ast::{Constant, Data, Type}, ast::{Constant, Data, Type},
@ -82,8 +80,8 @@ impl BuiltinRuntime {
self.forces += 1; self.forces += 1;
} }
pub fn call(&self, language: &Language, logs: &mut Vec<String>) -> Result<Value, Error> { pub fn call(&self, language: &Language, traces: &mut Vec<Trace>) -> Result<Value, Error> {
self.fun.call(language.into(), &self.args, logs) self.fun.call(language.into(), &self.args, traces)
} }
pub fn push(&mut self, arg: Value) -> Result<(), Error> { pub fn push(&mut self, arg: Value) -> Result<(), Error> {
@ -388,7 +386,7 @@ impl DefaultFunction {
&self, &self,
semantics: BuiltinSemantics, semantics: BuiltinSemantics,
args: &[Value], args: &[Value],
logs: &mut Vec<String>, traces: &mut Vec<Trace>,
) -> Result<Value, Error> { ) -> Result<Value, Error> {
match self { match self {
DefaultFunction::AddInteger => { DefaultFunction::AddInteger => {
@ -777,7 +775,11 @@ impl DefaultFunction {
DefaultFunction::Trace => { DefaultFunction::Trace => {
let arg1 = args[0].unwrap_string()?; let arg1 = args[0].unwrap_string()?;
logs.push(arg1.clone()); if arg1.starts_with('\0') {
traces.push(Trace::Label(arg1.split_at(1).1.to_string()));
} else {
traces.push(Trace::Log(arg1.clone()));
}
Ok(args[1].clone()) Ok(args[1].clone())
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
ast::{DeBruijn, Program}, ast::{DeBruijn, Program},
machine::cost_model::ExBudget, machine::{cost_model::ExBudget, eval_result::EvalResult},
PlutusData, PlutusData,
}; };
use error::Error; use error::Error;
@ -36,7 +36,7 @@ pub fn eval_phase_two(
slot_config: &SlotConfig, slot_config: &SlotConfig,
run_phase_one: bool, run_phase_one: bool,
with_redeemer: fn(&Redeemer) -> (), with_redeemer: fn(&Redeemer) -> (),
) -> Result<Vec<Redeemer>, Error> { ) -> Result<Vec<(Redeemer, EvalResult)>, Error> {
let redeemers = tx.transaction_witness_set.redeemer.as_ref(); let redeemers = tx.transaction_witness_set.redeemer.as_ref();
let lookup_table = DataLookupTable::from_transaction(tx, utxos); let lookup_table = DataLookupTable::from_transaction(tx, utxos);
@ -48,7 +48,7 @@ pub fn eval_phase_two(
match redeemers { match redeemers {
Some(rs) => { Some(rs) => {
let mut collected_redeemers = vec![]; let mut collected_results = vec![];
let mut remaining_budget = *initial_budget.unwrap_or(&ExBudget::default()); let mut remaining_budget = *initial_budget.unwrap_or(&ExBudget::default());
@ -62,7 +62,7 @@ pub fn eval_phase_two(
with_redeemer(&redeemer); with_redeemer(&redeemer);
let redeemer = eval::eval_redeemer( let (redeemer, eval_result) = eval::eval_redeemer(
tx, tx,
utxos, utxos,
slot_config, slot_config,
@ -77,10 +77,10 @@ pub fn eval_phase_two(
remaining_budget.cpu -= redeemer.ex_units.steps as i64; remaining_budget.cpu -= redeemer.ex_units.steps as i64;
remaining_budget.mem -= redeemer.ex_units.mem as i64; remaining_budget.mem -= redeemer.ex_units.mem as i64;
collected_redeemers.push(redeemer) collected_results.push((redeemer, eval_result));
} }
Ok(collected_redeemers) Ok(collected_results)
} }
None => Ok(vec![]), None => Ok(vec![]),
} }
@ -98,7 +98,7 @@ pub fn eval_phase_two_raw(
slot_config: (u64, u64, u32), slot_config: (u64, u64, u32),
run_phase_one: bool, run_phase_one: bool,
with_redeemer: fn(&Redeemer) -> (), with_redeemer: fn(&Redeemer) -> (),
) -> Result<Vec<Vec<u8>>, Error> { ) -> Result<Vec<(Vec<u8>, EvalResult)>, Error> {
let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, tx_bytes) let multi_era_tx = MultiEraTx::decode_for_era(Era::Conway, tx_bytes)
.or_else(|e| MultiEraTx::decode_for_era(Era::Babbage, tx_bytes).map_err(|_| e)) .or_else(|e| MultiEraTx::decode_for_era(Era::Babbage, tx_bytes).map_err(|_| e))
.or_else(|e| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes).map_err(|_| e))?; .or_else(|e| MultiEraTx::decode_for_era(Era::Alonzo, tx_bytes).map_err(|_| e))?;
@ -139,8 +139,8 @@ pub fn eval_phase_two_raw(
with_redeemer, with_redeemer,
) { ) {
Ok(redeemers) => Ok(redeemers Ok(redeemers) => Ok(redeemers
.iter() .into_iter()
.map(|r| r.encode_fragment().unwrap()) .map(|(r, e)| (r.encode_fragment().unwrap(), e))
.collect()), .collect()),
Err(err) => Err(err), Err(err) => Err(err),
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
machine::{self, cost_model::ExBudget}, machine::{self, cost_model::ExBudget, Trace},
TransactionInput, TransactionInput,
}; };
use pallas_primitives::conway::Language; use pallas_primitives::conway::Language;
@ -15,6 +15,7 @@ pub enum Error {
#[error("{0}")] #[error("{0}")]
FragmentDecode(#[from] pallas_primitives::Error), FragmentDecode(#[from] pallas_primitives::Error),
#[error("{}{}", .0, .2.iter() #[error("{}{}", .0, .2.iter()
.map(|trace| trace.to_string())
.map(|trace| { .map(|trace| {
format!( format!(
"\n{:>13} {}", "\n{:>13} {}",
@ -42,7 +43,7 @@ pub enum Error {
.join("") .join("")
.as_str() .as_str()
)] )]
Machine(machine::Error, ExBudget, Vec<String>), Machine(machine::Error, ExBudget, Vec<Trace>),
#[error("native script can't be executed in phase-two")] #[error("native script can't be executed in phase-two")]
NativeScriptPhaseTwo, NativeScriptPhaseTwo,

View File

@ -5,7 +5,7 @@ use super::{
}; };
use crate::{ use crate::{
ast::{FakeNamedDeBruijn, NamedDeBruijn, Program}, ast::{FakeNamedDeBruijn, NamedDeBruijn, Program},
machine::cost_model::ExBudget, machine::{cost_model::ExBudget, eval_result::EvalResult},
tx::{ tx::{
phase_one::redeemer_tag_to_string, phase_one::redeemer_tag_to_string,
script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2, TxInfoV3}, script_context::{DataLookupTable, ScriptVersion, TxInfoV1, TxInfoV2, TxInfoV3},
@ -23,7 +23,7 @@ pub fn eval_redeemer(
lookup_table: &DataLookupTable, lookup_table: &DataLookupTable,
cost_mdls_opt: Option<&CostModels>, cost_mdls_opt: Option<&CostModels>,
initial_budget: &ExBudget, initial_budget: &ExBudget,
) -> Result<Redeemer, Error> { ) -> Result<(Redeemer, EvalResult), Error> {
fn do_eval_redeemer( fn do_eval_redeemer(
cost_mdl_opt: Option<&CostModel>, cost_mdl_opt: Option<&CostModel>,
initial_budget: &ExBudget, initial_budget: &ExBudget,
@ -32,7 +32,7 @@ pub fn eval_redeemer(
redeemer: &Redeemer, redeemer: &Redeemer,
tx_info: TxInfo, tx_info: TxInfo,
program: Program<NamedDeBruijn>, program: Program<NamedDeBruijn>,
) -> Result<Redeemer, Error> { ) -> Result<(Redeemer, EvalResult), Error> {
let script_context = tx_info let script_context = tx_info
.into_script_context(redeemer, datum.as_ref()) .into_script_context(redeemer, datum.as_ref())
.expect("couldn't create script context from transaction?"); .expect("couldn't create script context from transaction?");
@ -56,11 +56,9 @@ pub fn eval_redeemer(
}; };
let cost = eval_result.cost(); let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() { if let Err(err) = eval_result.result() {
Ok(_) => (), return Err(Error::Machine(err, cost, eval_result.traces()));
Err(err) => return Err(Error::Machine(err, cost, logs)),
} }
let new_redeemer = Redeemer { let new_redeemer = Redeemer {
@ -73,7 +71,7 @@ pub fn eval_redeemer(
}, },
}; };
Ok(new_redeemer) Ok((new_redeemer, eval_result))
} }
let program = |script: Bytes| { let program = |script: Bytes| {

View File

@ -254,7 +254,7 @@ fn test_eval_0() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -527,7 +527,7 @@ fn test_eval_1() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -638,7 +638,7 @@ fn test_eval_2() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -908,7 +908,7 @@ fn test_eval_3() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -1101,7 +1101,7 @@ fn test_eval_5() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -1211,7 +1211,7 @@ fn test_eval_6() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -1321,7 +1321,7 @@ fn test_eval_7() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })
@ -1582,7 +1582,7 @@ fn test_eval_8() {
let total_budget_used: Vec<ExBudget> = redeemers let total_budget_used: Vec<ExBudget> = redeemers
.iter() .iter()
.map(|curr| ExBudget { .map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64, mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64, cpu: curr.ex_units.steps as i64,
}) })