Merge pull request #422 from aiken-lang/rvcas/json_output_cmds

JSON output for `uplc` cmds
This commit is contained in:
Matthias Benkort 2023-03-08 10:24:05 +01:00 committed by GitHub
commit 95997822dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 171 additions and 134 deletions

1
Cargo.lock generated vendored
View File

@ -2721,6 +2721,7 @@ dependencies = [
"indexmap", "indexmap",
"itertools", "itertools",
"k256", "k256",
"miette",
"num-bigint", "num-bigint",
"num-integer", "num-integer",
"num-traits", "num-traits",

View File

@ -4285,7 +4285,7 @@ impl<'a> CodeGenerator<'a> {
program.try_into().unwrap(); program.try_into().unwrap();
let evaluated_term: Term<NamedDeBruijn> = let evaluated_term: Term<NamedDeBruijn> =
eval_program.eval(ExBudget::default()).0.unwrap(); eval_program.eval(ExBudget::default()).result().unwrap();
arg_stack.push(evaluated_term.try_into().unwrap()); arg_stack.push(evaluated_term.try_into().unwrap());
anon_func = false; anon_func = false;
@ -5416,7 +5416,7 @@ impl<'a> CodeGenerator<'a> {
let eval_program: Program<NamedDeBruijn> = program.try_into().unwrap(); let eval_program: Program<NamedDeBruijn> = program.try_into().unwrap();
let evaluated_term: Term<NamedDeBruijn> = let evaluated_term: Term<NamedDeBruijn> =
eval_program.eval(ExBudget::default()).0.unwrap(); eval_program.eval(ExBudget::default()).result().unwrap();
term = evaluated_term.try_into().unwrap(); term = evaluated_term.try_into().unwrap();
} }

View File

@ -279,13 +279,13 @@ impl Diagnostic for Error {
None => None, None => None,
Some(hint) => { Some(hint) => {
let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, }; let budget = ExBudget { mem: i64::MAX, cpu: i64::MAX, };
let left = pretty::boxed("left", &match hint.left.eval(budget) { let left = pretty::boxed("left", &match hint.left.eval(budget).result() {
(Ok(term), _, _) => format!("{term}"), Ok(term) => format!("{term}"),
(Err(err), _, _) => format!("{err}"), Err(err) => format!("{err}"),
}); });
let right = pretty::boxed("right", &match hint.right.eval(budget) { let right = pretty::boxed("right", &match hint.right.eval(budget).result() {
(Ok(term), _, _) => format!("{term}"), Ok(term) => format!("{term}"),
(Err(err), _, _) => format!("{err}"), Err(err) => format!("{err}"),
}); });
let msg = match hint.bin_op { let msg = match hint.bin_op {
BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")), BinOp::And => Some(format!("{left}\n\nand\n\n{right}\n\nshould both be true.")),

View File

@ -37,7 +37,7 @@ use std::{
}; };
use telemetry::EventListener; use telemetry::EventListener;
use uplc::{ use uplc::{
ast::{Constant, DeBruijn, Term}, ast::{DeBruijn, Term},
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
}; };
@ -726,22 +726,16 @@ where
scripts scripts
.into_par_iter() .into_par_iter()
.map(|script| match script.program.eval(initial_budget) { .map(|script| {
(Ok(result), remaining_budget, logs) => EvalInfo { let mut eval_result = script.program.eval(initial_budget);
success: result != Term::Error
&& result != Term::Constant(Constant::Bool(false).into()), EvalInfo {
success: !eval_result.failed(),
script, script,
spent_budget: initial_budget - remaining_budget, spent_budget: eval_result.cost(),
output: Some(result), logs: eval_result.logs(),
logs, output: eval_result.result().ok(),
}, }
(Err(..), remaining_budget, logs) => EvalInfo {
success: false,
script,
spent_budget: initial_budget - remaining_budget,
output: None,
logs,
},
}) })
.collect() .collect()
} }

View File

@ -144,7 +144,7 @@ pub fn exec(
eprintln!("\n"); eprintln!("\n");
println!( println!(
"{}", "{}",
serde_json::to_string(&total_budget_used) serde_json::to_string_pretty(&total_budget_used)
.map_err(|_| fmt::Error) .map_err(|_| fmt::Error)
.into_diagnostic()? .into_diagnostic()?
); );

View File

@ -1,5 +1,6 @@
use miette::IntoDiagnostic; use miette::IntoDiagnostic;
use std::path::PathBuf; use serde_json::json;
use std::{path::PathBuf, process};
use uplc::{ use uplc::{
ast::{FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term}, ast::{FakeNamedDeBruijn, Name, NamedDeBruijn, Program, Term},
machine::cost_model::ExBudget, machine::cost_model::ExBudget,
@ -63,32 +64,38 @@ pub fn exec(
let budget = ExBudget::default(); let budget = ExBudget::default();
let (term, cost, logs) = program.eval(budget); let mut eval_result = program.eval(budget);
match term { let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() {
Ok(term) => { Ok(term) => {
let term: Term<Name> = term.try_into().into_diagnostic()?; let term: Term<Name> = term.try_into().into_diagnostic()?;
println!("\nResult\n------\n\n{}\n", term.to_pretty()); let output = json!({
"result": term.to_pretty(),
"cpu": cost.cpu,
"mem": cost.mem,
});
println!(
"{}",
serde_json::to_string_pretty(&output).into_diagnostic()?
);
Ok(())
} }
Err(err) => { Err(err) => {
eprintln!("\nError\n-----\n\n{err}\n"); eprintln!("\nError\n-----\n\n{err}\n");
}
}
println!( eprintln!("\nCosts\n-----\ncpu: {}\nmemory: {}", cost.cpu, cost.mem);
"\nCosts\n-----\ncpu: {}\nmemory: {}",
budget.cpu - cost.cpu,
budget.mem - cost.mem
);
println!(
"\nBudget\n------\ncpu: {}\nmemory: {}\n",
cost.cpu, cost.mem
);
if !logs.is_empty() { if !logs.is_empty() {
println!("\nLogs\n----\n{}", logs.join("\n")) eprintln!("\nLogs\n----\n{}", logs.join("\n"))
} }
Ok(()) process::exit(1)
}
}
} }

View File

@ -20,6 +20,7 @@ hex = "0.4.3"
indexmap = "1.9.2" indexmap = "1.9.2"
itertools = "0.10.5" itertools = "0.10.5"
k256 = { version = "0.13.0", optional = true } k256 = { version = "0.13.0", optional = true }
miette = "5.5.0"
num-bigint = "0.4.3" num-bigint = "0.4.3"
num-integer = "0.1.45" num-integer = "0.1.45"
num-traits = "0.2.15" num-traits = "0.2.15"

View File

@ -24,6 +24,7 @@ use crate::{
flat::Binder, flat::Binder,
machine::{ machine::{
cost_model::{initialize_cost_model, CostModel, ExBudget}, cost_model::{initialize_cost_model, CostModel, ExBudget},
eval_result::EvalResult,
Machine, Machine,
}, },
}; };
@ -595,14 +596,7 @@ impl From<Term<FakeNamedDeBruijn>> for Term<NamedDeBruijn> {
} }
impl Program<NamedDeBruijn> { impl Program<NamedDeBruijn> {
pub fn eval( pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
&self,
initial_budget: ExBudget,
) -> (
Result<Term<NamedDeBruijn>, crate::machine::Error>,
ExBudget,
Vec<String>,
) {
let mut machine = Machine::new( let mut machine = Machine::new(
Language::PlutusV2, Language::PlutusV2,
CostModel::default(), CostModel::default(),
@ -612,22 +606,16 @@ impl Program<NamedDeBruijn> {
let term = machine.run(&self.term); let term = machine.run(&self.term);
(term, machine.ex_budget, machine.logs) EvalResult::new(term, machine.ex_budget, initial_budget, machine.logs)
} }
/// Evaluate a Program as PlutusV1 /// Evaluate a Program as PlutusV1
pub fn eval_v1( pub fn eval_v1(&self) -> EvalResult {
&self,
) -> (
Result<Term<NamedDeBruijn>, crate::machine::Error>,
ExBudget,
Vec<String>,
) {
let mut machine = Machine::new(Language::PlutusV1, CostModel::v1(), ExBudget::v1(), 200); let mut machine = Machine::new(Language::PlutusV1, CostModel::v1(), ExBudget::v1(), 200);
let term = machine.run(&self.term); let term = machine.run(&self.term);
(term, machine.ex_budget, machine.logs) EvalResult::new(term, machine.ex_budget, ExBudget::v1(), machine.logs)
} }
pub fn eval_as( pub fn eval_as(
@ -635,11 +623,7 @@ impl Program<NamedDeBruijn> {
version: &Language, version: &Language,
costs: &[i64], costs: &[i64],
initial_budget: Option<&ExBudget>, initial_budget: Option<&ExBudget>,
) -> ( ) -> EvalResult {
Result<Term<NamedDeBruijn>, crate::machine::Error>,
ExBudget,
Vec<String>,
) {
let budget = match initial_budget { let budget = match initial_budget {
Some(b) => *b, Some(b) => *b,
None => ExBudget::default(), None => ExBudget::default(),
@ -654,19 +638,12 @@ impl Program<NamedDeBruijn> {
let term = machine.run(&self.term); let term = machine.run(&self.term);
(term, machine.ex_budget, machine.logs) EvalResult::new(term, machine.ex_budget, budget, machine.logs)
} }
} }
impl Program<DeBruijn> { impl Program<DeBruijn> {
pub fn eval( pub fn eval(&self, initial_budget: ExBudget) -> EvalResult {
&self,
initial_budget: ExBudget,
) -> (
Result<Term<NamedDeBruijn>, crate::machine::Error>,
ExBudget,
Vec<String>,
) {
let program: Program<NamedDeBruijn> = self.clone().into(); let program: Program<NamedDeBruijn> = self.clone().into();
program.eval(initial_budget) program.eval(initial_budget)

View File

@ -8,6 +8,7 @@ use crate::{
pub mod cost_model; pub mod cost_model;
mod error; mod error;
pub mod eval_result;
pub mod runtime; pub mod runtime;
use cost_model::{ExBudget, StepKind}; use cost_model::{ExBudget, StepKind};
@ -785,9 +786,9 @@ mod tests {
}, },
}; };
let (eval_result, _, _) = program.eval(ExBudget::default()); let eval_result = program.eval(ExBudget::default());
let term = eval_result.unwrap(); let term = eval_result.result().unwrap();
assert_eq!( assert_eq!(
term, term,
@ -834,10 +835,10 @@ mod tests {
]; ];
for (fun, n, m, result) in test_data { for (fun, n, m, result) in test_data {
let (eval_result, _, _) = make_program(fun, n, m).eval(ExBudget::default()); let eval_result = make_program(fun, n, m).eval(ExBudget::default());
assert_eq!( assert_eq!(
eval_result.unwrap(), eval_result.result().unwrap(),
Term::Constant(Constant::Integer(result.into()).into()) Term::Constant(Constant::Integer(result.into()).into())
); );
} }

View File

@ -6,13 +6,13 @@ use crate::ast::{NamedDeBruijn, Term, Type};
use super::{ExBudget, Value}; use super::{ExBudget, Value};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug, miette::Diagnostic)]
pub enum Error { pub enum Error {
#[error("Over budget mem: {} & cpu: {}", .0.mem, .0.cpu)] #[error("Over budget mem: {} & cpu: {}", .0.mem, .0.cpu)]
OutOfExError(ExBudget), OutOfExError(ExBudget),
#[error("Invalid Stepkind: {0}")] #[error("Invalid Stepkind: {0}")]
InvalidStepKind(u8), InvalidStepKind(u8),
#[error("Cannot evaluate an open term:\n\n{0}")] #[error("Cannot evaluate an open term:\\n\\n{}", .0.to_pretty())]
OpenTermEvaluated(Term<NamedDeBruijn>), OpenTermEvaluated(Term<NamedDeBruijn>),
#[error("The provided Plutus code called 'error'.")] #[error("The provided Plutus code called 'error'.")]
EvaluationFailure, EvaluationFailure,

View File

@ -0,0 +1,44 @@
use crate::ast::{Constant, NamedDeBruijn, Term};
use super::{cost_model::ExBudget, Error};
pub struct EvalResult {
result: Result<Term<NamedDeBruijn>, Error>,
remaining_budget: ExBudget,
initial_budget: ExBudget,
logs: Vec<String>,
}
impl EvalResult {
pub fn new(
result: Result<Term<NamedDeBruijn>, Error>,
remaining_budget: ExBudget,
initial_budget: ExBudget,
logs: Vec<String>,
) -> EvalResult {
EvalResult {
result,
remaining_budget,
initial_budget,
logs,
}
}
pub fn cost(&self) -> ExBudget {
self.initial_budget - self.remaining_budget
}
pub fn logs(&mut self) -> Vec<String> {
std::mem::take(&mut self.logs)
}
pub fn failed(&self) -> bool {
matches!(self.result, Err(_))
|| matches!(self.result, Ok(Term::Error))
|| matches!(self.result, Ok(Term::Constant(ref con)) if matches!(con.as_ref(), Constant::Bool(false)))
}
pub fn result(self) -> Result<Term<NamedDeBruijn>, Error> {
self.result
}
}

View File

@ -1,6 +1,6 @@
use crate::machine::{self, cost_model::ExBudget}; use crate::machine::{self, cost_model::ExBudget};
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug, miette::Diagnostic)]
pub enum Error { pub enum Error {
#[error("{0}")] #[error("{0}")]
Address(#[from] pallas_addresses::Error), Address(#[from] pallas_addresses::Error),

View File

@ -730,7 +730,7 @@ pub fn eval_redeemer(
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()); .apply_data(script_context.to_plutus_data());
let (result, budget, logs) = if let Some(cost_mdls) = cost_mdls_opt { let mut eval_result = if let Some(cost_mdls) = cost_mdls_opt {
let costs = if let Some(costs) = &cost_mdls.plutus_v1 { let costs = if let Some(costs) = &cost_mdls.plutus_v1 {
costs costs
} else { } else {
@ -742,9 +742,12 @@ pub fn eval_redeemer(
program.eval_v1() program.eval_v1()
}; };
match result { let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(Error::Machine(err, budget, logs)), Err(err) => return Err(Error::Machine(err, cost, logs)),
} }
let new_redeemer = Redeemer { let new_redeemer = Redeemer {
@ -752,8 +755,8 @@ pub fn eval_redeemer(
index: redeemer.index, index: redeemer.index,
data: redeemer.data.clone(), data: redeemer.data.clone(),
ex_units: ExUnits { ex_units: ExUnits {
mem: (initial_budget.mem - budget.mem) as u32, mem: cost.mem as u32,
steps: (initial_budget.cpu - budget.cpu) as u64, steps: cost.cpu as u64,
}, },
}; };
@ -776,7 +779,7 @@ pub fn eval_redeemer(
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()); .apply_data(script_context.to_plutus_data());
let (result, budget, logs) = if let Some(cost_mdls) = cost_mdls_opt { let mut eval_result = if let Some(cost_mdls) = cost_mdls_opt {
let costs = if let Some(costs) = &cost_mdls.plutus_v2 { let costs = if let Some(costs) = &cost_mdls.plutus_v2 {
costs costs
} else { } else {
@ -788,9 +791,12 @@ pub fn eval_redeemer(
program.eval(ExBudget::default()) program.eval(ExBudget::default())
}; };
match result { let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(Error::Machine(err, budget, logs)), Err(err) => return Err(Error::Machine(err, cost, logs)),
} }
let new_redeemer = Redeemer { let new_redeemer = Redeemer {
@ -798,8 +804,8 @@ pub fn eval_redeemer(
index: redeemer.index, index: redeemer.index,
data: redeemer.data.clone(), data: redeemer.data.clone(),
ex_units: ExUnits { ex_units: ExUnits {
mem: (initial_budget.mem - budget.mem) as u32, mem: cost.mem as u32,
steps: (initial_budget.cpu - budget.cpu) as u64, steps: cost.cpu as u64,
}, },
}; };
@ -824,7 +830,7 @@ pub fn eval_redeemer(
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()); .apply_data(script_context.to_plutus_data());
let (result, budget, logs) = if let Some(cost_mdls) = cost_mdls_opt { let mut eval_result = if let Some(cost_mdls) = cost_mdls_opt {
let costs = if let Some(costs) = &cost_mdls.plutus_v1 { let costs = if let Some(costs) = &cost_mdls.plutus_v1 {
costs costs
} else { } else {
@ -836,9 +842,12 @@ pub fn eval_redeemer(
program.eval_v1() program.eval_v1()
}; };
match result { let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(Error::Machine(err, budget, logs)), Err(err) => return Err(Error::Machine(err, cost, logs)),
} }
let new_redeemer = Redeemer { let new_redeemer = Redeemer {
@ -846,8 +855,8 @@ pub fn eval_redeemer(
index: redeemer.index, index: redeemer.index,
data: redeemer.data.clone(), data: redeemer.data.clone(),
ex_units: ExUnits { ex_units: ExUnits {
mem: (initial_budget.mem - budget.mem) as u32, mem: cost.mem as u32,
steps: (initial_budget.cpu - budget.cpu) as u64, steps: cost.cpu as u64,
}, },
}; };
@ -869,7 +878,7 @@ pub fn eval_redeemer(
.apply_data(redeemer.data.clone()) .apply_data(redeemer.data.clone())
.apply_data(script_context.to_plutus_data()); .apply_data(script_context.to_plutus_data());
let (result, budget, logs) = if let Some(cost_mdls) = cost_mdls_opt { let mut eval_result = if let Some(cost_mdls) = cost_mdls_opt {
let costs = if let Some(costs) = &cost_mdls.plutus_v2 { let costs = if let Some(costs) = &cost_mdls.plutus_v2 {
costs costs
} else { } else {
@ -881,9 +890,12 @@ pub fn eval_redeemer(
program.eval(ExBudget::default()) program.eval(ExBudget::default())
}; };
match result { let cost = eval_result.cost();
let logs = eval_result.logs();
match eval_result.result() {
Ok(_) => (), Ok(_) => (),
Err(err) => return Err(Error::Machine(err, budget, logs)), Err(err) => return Err(Error::Machine(err, cost, logs)),
} }
let new_redeemer = Redeemer { let new_redeemer = Redeemer {
@ -891,8 +903,8 @@ pub fn eval_redeemer(
index: redeemer.index, index: redeemer.index,
data: redeemer.data.clone(), data: redeemer.data.clone(),
ex_units: ExUnits { ex_units: ExUnits {
mem: (initial_budget.mem - budget.mem) as u32, mem: cost.mem as u32,
steps: (initial_budget.cpu - budget.cpu) as u64, steps: cost.cpu as u64,
}, },
}; };

View File

@ -5,37 +5,6 @@
"plutusVersion": "v2" "plutusVersion": "v2"
}, },
"validators": [ "validators": [
{
"title": "withdrawals.spend",
"datum": {
"title": "Unit",
"description": "The nullary constructor.",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
}
},
"redeemer": {
"title": "Unit",
"description": "The nullary constructor.",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
}
},
"compiledCode": "59029101000032323232323232323232222533300632323232323001003300100122533300f00114a226464a66601a0042660080080022940c04c008cdc3a4004601a6ea8c044004c8c8c8cc040ccc02cc8c94ccc034cdc3800a40042c2646466e1c0052054375a6028002600e004601c6ea8004cc004dd5998021802998021802803240009006260126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff004c0103d87a80004c0103d87980003301033300b3232533300d3370e00290010b0991919b8700148070dd6980a000980380118071baa00133001375666008600a66008600a00c90002401898126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004c0103d87a80004c0103d87980003301033300b3375e6e9cc8c8c8c008004dd599803180399803180380424000900618008009129998088008a5eb804c8c8c8c8cc058004cc01801800cc04800cdd69809001180a80118098009ba7330104c0126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff00330104c126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004bd7026103d87a80004c0103d87980004bd70111980180100098008009112999807801099ba5480092f5c0264646464a66601e66ebc0140044cdd2a4000660286ea00092f5c0266600e00e00600a60200066eb4c040008c04c00cc04400888c8ccc0040052000003222333300c3370e008004024466600800866e0000d200230140010012300a37540022930b180080091129998040010a4c26600a600260140046660060066016004002ae695cdaab9d5573caae7d5d02ba15745",
"hash": "6917ce2313801b854e38507b68d2c61afd70fca721804235e4760056"
},
{ {
"title": "basic.spend", "title": "basic.spend",
"datum": { "datum": {
@ -77,6 +46,37 @@
"compiledCode": "590488010000323232323232323232323222533300532323232323001003300100122533300f00114a226464a6660180042660080080022940c04c008cdc3a4004601a6ea8c044004cc034ccc01cc8c8c8c8c8c8c94ccc04cc0580084c8c8cdc78018009bae3016001300932533300f3370e900018091baa0011001153301149012a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300830090034800854cc0412401364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375c602800264646464600c00200200264640026644660100040020029110000137566600c600e6600c600e00290002401000e600200244a666020002297ae01323232323301537520026600c00c0066eb8c04400cdd59808801180a0011809000980080091129998078010a5eb7bdb1804c8c8c8c94ccc038cdc7802800880189980a19bb037520026e98008ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d333007323232323322323232323253330123370e00290010b0991919b87001483c850dd6980d0009806801180a1baa001332233008002001001488103666f6f0033223233223253330153370e00290010801099190009bab301d00130100033017375400400297adef6c6033223300b002001002001375666012601400690040009bae30150013008533300d3370e900018081baa0021002153300f49012a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633005300600748008cc014c01801d20003001001222533301100213374a900125eb804c8c8c8c94ccc040cdc7802800899ba548000cc058dd400125eb804ccc01c01c00c014dd718090019bad3012002301500330130023001001222533300f00213374a900125eb804c8c8c8c94ccc038cdc7802800899ba548000cc050dd300125eb804ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d3330073232323233223232533300f3375e006002266e1cc8c018004dd5998049805198049805002240009009240042940c054004c020c94ccc038cdc3a400060226ea8004400454cc0412412a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633223300700200137566600e60106600e60100049000240246600e6010004900100380418008009129998080008a400026466e0120023300300300130130013001001222533300f00213374a900125eb804c8c8c8c94ccc038cdd7802800899ba548000cc0500092f5c0266600e00e00600a6020006602000460260066022004980103d87a80004c0103d87980004bd701119199800800a4000006444666601666e1c0100080488ccc010010cdc0001a40046028002002460146ea8004526163001001222533300900214984cc014c004c02c008ccc00c00cc0300080055cd2b9b5738aae7555cf2ab9f5740ae855d11", "compiledCode": "590488010000323232323232323232323222533300532323232323001003300100122533300f00114a226464a6660180042660080080022940c04c008cdc3a4004601a6ea8c044004cc034ccc01cc8c8c8c8c8c8c94ccc04cc0580084c8c8cdc78018009bae3016001300932533300f3370e900018091baa0011001153301149012a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300830090034800854cc0412401364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375c602800264646464600c00200200264640026644660100040020029110000137566600c600e6600c600e00290002401000e600200244a666020002297ae01323232323301537520026600c00c0066eb8c04400cdd59808801180a0011809000980080091129998078010a5eb7bdb1804c8c8c8c94ccc038cdc7802800880189980a19bb037520026e98008ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d333007323232323322323232323253330123370e00290010b0991919b87001483c850dd6980d0009806801180a1baa001332233008002001001488103666f6f0033223233223253330153370e00290010801099190009bab301d00130100033017375400400297adef6c6033223300b002001002001375666012601400690040009bae30150013008533300d3370e900018081baa0021002153300f49012a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633005300600748008cc014c01801d20003001001222533301100213374a900125eb804c8c8c8c94ccc040cdc7802800899ba548000cc058dd400125eb804ccc01c01c00c014dd718090019bad3012002301500330130023001001222533300f00213374a900125eb804c8c8c8c94ccc038cdc7802800899ba548000cc050dd300125eb804ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d3330073232323233223232533300f3375e006002266e1cc8c018004dd5998049805198049805002240009009240042940c054004c020c94ccc038cdc3a400060226ea8004400454cc0412412a4173736572746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633223300700200137566600e60106600e60100049000240246600e6010004900100380418008009129998080008a400026466e0120023300300300130130013001001222533300f00213374a900125eb804c8c8c8c94ccc038cdd7802800899ba548000cc0500092f5c0266600e00e00600a6020006602000460260066022004980103d87a80004c0103d87980004bd701119199800800a4000006444666601666e1c0100080488ccc010010cdc0001a40046028002002460146ea8004526163001001222533300900214984cc014c004c02c008ccc00c00cc0300080055cd2b9b5738aae7555cf2ab9f5740ae855d11",
"hash": "dbc571e23778572680144ee7065334ab9545cc8111da1ea5dc85ac44" "hash": "dbc571e23778572680144ee7065334ab9545cc8111da1ea5dc85ac44"
}, },
{
"title": "withdrawals.spend",
"datum": {
"title": "Unit",
"description": "The nullary constructor.",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
}
},
"redeemer": {
"title": "Unit",
"description": "The nullary constructor.",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
}
},
"compiledCode": "59029101000032323232323232323232222533300632323232323001003300100122533300f00114a226464a66601a0042660080080022940c04c008cdc3a4004601a6ea8c044004c8c8c8cc040ccc02cc8c94ccc034cdc3800a40042c2646466e1c0052054375a6028002600e004601c6ea8004cc004dd5998021802998021802803240009006260126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff004c0103d87a80004c0103d87980003301033300b3232533300d3370e00290010b0991919b8700148070dd6980a000980380118071baa00133001375666008600a66008600a00c90002401898126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004c0103d87a80004c0103d87980003301033300b3375e6e9cc8c8c8c008004dd599803180399803180380424000900618008009129998088008a5eb804c8c8c8c8cc058004cc01801800cc04800cdd69809001180a80118098009ba7330104c0126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff00330104c126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004bd7026103d87a80004c0103d87980004bd70111980180100098008009112999807801099ba5480092f5c0264646464a66601e66ebc0140044cdd2a4000660286ea00092f5c0266600e00e00600a60200066eb4c040008c04c00cc04400888c8ccc0040052000003222333300c3370e008004024466600800866e0000d200230140010012300a37540022930b180080091129998040010a4c26600a600260140046660060066016004002ae695cdaab9d5573caae7d5d02ba15745",
"hash": "6917ce2313801b854e38507b68d2c61afd70fca721804235e4760056"
},
{ {
"title": "deploy.spend", "title": "deploy.spend",
"datum": { "datum": {