Skip to content

Commit

Permalink
Return an EvalResult alongside the redeemer
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Quantumplation committed Feb 17, 2025
1 parent e9bacf8 commit fa88948
Show file tree
Hide file tree
Showing 12 changed files with 128 additions and 104 deletions.
84 changes: 32 additions & 52 deletions crates/aiken-lang/src/test_framework.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,17 @@ impl UnitTest {
OnTestFailure::FailImmediately => false,
});

let mut traces = Vec::new();
let mut logs = Vec::new();
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 {
success,
test: self.to_owned(),
spent_budget: eval_result.cost(),
traces,
logs,
assertion: self.assertion,
}
}
Expand Down Expand Up @@ -276,7 +276,7 @@ pub struct Fuzzer<T> {
#[derive(Debug, Clone, thiserror::Error, miette::Diagnostic)]
#[error("Fuzzer exited unexpectedly: {uplc_error}.")]
pub struct FuzzerError {
traces: Vec<String>,
logs: Vec<String>,
uplc_error: uplc::machine::Error,
}

Expand Down Expand Up @@ -330,7 +330,7 @@ impl PropertyTest {
let mut labels = BTreeMap::new();
let mut remaining = n;

let (traces, counterexample, iterations) = match self.run_n_times(
let (logs, counterexample, iterations) = match self.run_n_times(
&mut remaining,
Prng::from_seed(seed),
&mut labels,
Expand All @@ -339,18 +339,12 @@ impl PropertyTest {
Ok(None) => (Vec::new(), Ok(None), n),
Ok(Some(counterexample)) => (
self.eval(&counterexample.value, plutus_version)
.logs()
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
.logs(),
Ok(Some(counterexample.value)),
n - remaining,
),
Err(FuzzerError { traces, uplc_error }) => (
traces
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
Err(FuzzerError { logs, uplc_error }) => (
logs,
Err(uplc_error),
n - remaining + 1,
),
Expand All @@ -361,7 +355,7 @@ impl PropertyTest {
counterexample,
iterations,
labels,
traces,
logs,
}
}

Expand Down Expand Up @@ -397,16 +391,14 @@ impl PropertyTest {

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
// convention*, we treat as label strings that starts with a NUL byte, which
// should be a guard sufficient to prevent inadvertent clashes.
if let Some(label) = PropertyTest::extract_label(&s) {
labels
.entry(label)
.and_modify(|count| *count += 1)
.or_insert(1);
}
labels
.entry(label)
.and_modify(|count| *count += 1)
.or_insert(1);
}

let is_failure = result.failed(false);
Expand Down Expand Up @@ -470,14 +462,6 @@ impl PropertyTest {
.unwrap()
.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 -----------------------------------------------------------------
Expand All @@ -498,21 +482,21 @@ pub struct Sampler<T> {
pub enum BenchmarkError {
#[error("Sampler exited unexpectedly: {uplc_error}.")]
SamplerError {
traces: Vec<String>,
logs: Vec<String>,
uplc_error: uplc::machine::Error,
},
#[error("Bench exited unexpectedly: {uplc_error}.")]
BenchError {
traces: Vec<String>,
logs: Vec<String>,
uplc_error: uplc::machine::Error,
},
}

impl BenchmarkError {
pub fn traces(&self) -> &[String] {
pub fn logs(&self) -> &[String] {
match self {
BenchmarkError::SamplerError { traces, .. }
| BenchmarkError::BenchError { traces, .. } => traces.as_slice(),
BenchmarkError::SamplerError { logs, .. }
| BenchmarkError::BenchError { logs, .. } => logs.as_slice(),
}
}
}
Expand Down Expand Up @@ -561,19 +545,15 @@ impl Benchmark {
Ok(_) => measures.push((size, result.cost())),
Err(uplc_error) => {
error = Some(BenchmarkError::BenchError {
traces: result
.logs()
.into_iter()
.filter(|s| PropertyTest::extract_label(s).is_none())
.collect(),
logs: result.logs(),
uplc_error,
});
}
}
}

Err(FuzzerError { traces, uplc_error }) => {
error = Some(BenchmarkError::SamplerError { traces, uplc_error });
Err(FuzzerError { logs, uplc_error }) => {
error = Some(BenchmarkError::SamplerError { logs, uplc_error });
}
}

Expand Down Expand Up @@ -692,7 +672,7 @@ impl Prng {
result
.result()
.map_err(|uplc_error| FuzzerError {
traces: result.logs(),
logs: result.logs(),
uplc_error,
})
.map(Prng::from_result)
Expand Down Expand Up @@ -1166,12 +1146,12 @@ impl<U, T> TestResult<U, T> {
}
}

pub fn traces(&self) -> &[String] {
pub fn logs(&self) -> &[String] {
match self {
TestResult::UnitTestResult(UnitTestResult { traces, .. })
| TestResult::PropertyTestResult(PropertyTestResult { traces, .. }) => traces,
TestResult::UnitTestResult(UnitTestResult { logs, .. })
| TestResult::PropertyTestResult(PropertyTestResult { logs, .. }) => logs,
TestResult::BenchmarkResult(BenchmarkResult { error, .. }) => {
error.as_ref().map(|e| e.traces()).unwrap_or_default()
error.as_ref().map(|e| e.logs()).unwrap_or_default()
}
}
}
Expand All @@ -1181,7 +1161,7 @@ impl<U, T> TestResult<U, T> {
pub struct UnitTestResult<T> {
pub success: bool,
pub spent_budget: ExBudget,
pub traces: Vec<String>,
pub logs: Vec<String>,
pub test: UnitTest,
pub assertion: Option<Assertion<T>>,
}
Expand All @@ -1196,7 +1176,7 @@ impl UnitTestResult<(Constant, Rc<Type>)> {
UnitTestResult {
success: self.success,
spent_budget: self.spent_budget,
traces: self.traces,
logs: self.logs,
test: self.test,
assertion: self.assertion.and_then(|assertion| {
// No need to spend time/cpu on reifying assertions for successful
Expand Down Expand Up @@ -1229,7 +1209,7 @@ pub struct PropertyTestResult<T> {
pub counterexample: Result<Option<T>, uplc::machine::Error>,
pub iterations: usize,
pub labels: BTreeMap<String, usize>,
pub traces: Vec<String>,
pub logs: Vec<String>,
}

unsafe impl<T> Send for PropertyTestResult<T> {}
Expand All @@ -1249,7 +1229,7 @@ impl PropertyTestResult<PlutusData> {
iterations: self.iterations,
test: self.test,
labels: self.labels,
traces: self.traces,
logs: self.logs,
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions crates/aiken-project/src/telemetry/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ fn fmt_test_json(result: &TestResult<UntypedExpr, UntypedExpr>) -> serde_json::V
TestResult::BenchmarkResult(_) => unreachable!("benchmark returned in JSON output"),
}

if !result.traces().is_empty() {
test["traces"] = json!(result.traces());
if !result.logs().is_empty() {
test["traces"] = json!(result.logs());
}

test
Expand Down
4 changes: 2 additions & 2 deletions crates/aiken-project/src/telemetry/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -584,12 +584,12 @@ fn fmt_test(
}

// Traces
if !result.traces().is_empty() {
if !result.logs().is_empty() {
test = format!(
"{test}\n{title}\n{traces}",
title = "· with traces".if_supports_color(Stderr, |s| s.bold()),
traces = result
.traces()
.logs()
.iter()
.map(|line| { format!("| {line}",) })
.collect::<Vec<_>>()
Expand Down
2 changes: 1 addition & 1 deletion crates/aiken/src/cmd/tx/simulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ pub fn exec(
// this should allow N scripts to be
let total_budget_used: Vec<ExBudget> = redeemers
.iter()
.map(|curr| ExBudget {
.map(|(curr, _)| ExBudget {
mem: curr.ex_units.mem as i64,
cpu: curr.ex_units.steps as i64,
})
Expand Down
8 changes: 4 additions & 4 deletions crates/uplc/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -856,7 +856,7 @@ impl Program<NamedDeBruijn> {
term,
machine.ex_budget,
initial_budget,
machine.logs,
machine.traces,
machine.spend_counter.map(|i| i.into()),
)
}
Expand All @@ -871,7 +871,7 @@ impl Program<NamedDeBruijn> {
term,
machine.ex_budget,
initial_budget,
machine.logs,
machine.traces,
machine.spend_counter.map(|i| i.into()),
)
}
Expand All @@ -897,7 +897,7 @@ impl Program<NamedDeBruijn> {
term,
machine.ex_budget,
budget,
machine.logs,
machine.traces,
machine.spend_counter.map(|i| i.into()),
)
}
Expand All @@ -916,7 +916,7 @@ impl Program<NamedDeBruijn> {
term,
machine.ex_budget,
initial_budget,
machine.logs,
machine.traces,
machine.spend_counter.map(|i| i.into()),
)
}
Expand Down
37 changes: 33 additions & 4 deletions crates/uplc/src/machine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,42 @@ enum Context {
pub const TERM_COUNT: usize = 9;
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 {
costs: CostModel,
pub ex_budget: ExBudget,
slippage: u32,
unbudgeted_steps: [u32; 10],
pub traces: Vec<Trace>,
pub spend_counter: Option<[i64; (TERM_COUNT + BUILTIN_COUNT) * 2]>,
pub logs: Vec<String>,
version: Language,
}

Expand All @@ -67,8 +96,8 @@ impl Machine {
ex_budget: initial_budget,
slippage,
unbudgeted_steps: [0; 10],
traces: vec![],
spend_counter: None,
logs: vec![],
version,
}
}
Expand All @@ -84,8 +113,8 @@ impl Machine {
ex_budget: initial_budget,
slippage,
unbudgeted_steps: [0; 10],
traces: vec![],
spend_counter: Some([0; (TERM_COUNT + BUILTIN_COUNT) * 2]),
logs: vec![],
version,
}
}
Expand Down Expand Up @@ -353,7 +382,7 @@ impl Machine {
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> {
Expand Down
Loading

0 comments on commit fa88948

Please sign in to comment.