Merge pull request #457 from aiken-lang/double_validators

Two in one validators
This commit is contained in:
Matthias Benkort 2023-03-18 10:59:11 +01:00 committed by GitHub
commit df722d6f0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 977 additions and 518 deletions

View File

@ -322,6 +322,7 @@ pub struct Validator<T, Expr> {
pub doc: Option<String>,
pub end_position: usize,
pub fun: Function<T, Expr>,
pub other_fun: Option<Function<T, Expr>>,
pub location: Span,
pub params: Vec<Arg<T>>,
}

View File

@ -4,7 +4,10 @@ use indexmap::{IndexMap, IndexSet};
use itertools::Itertools;
use uplc::{
ast::{
builder::{apply_wrap, delayed_choose_list, delayed_if_else, if_else},
builder::{
apply_wrap, constr_index_exposer, delayed_choose_list, delayed_if_else, if_else,
CONSTR_FIELDS_EXPOSER,
},
Constant as UplcConstant, Name, Term, Type as UplcType,
},
builtins::DefaultFunction,
@ -193,10 +196,7 @@ pub fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
apply_wrap(DefaultFunction::IData.into(), term)
} else if field_type.is_void() {
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::ChooseUnit).force_wrap(),
term,
),
apply_wrap(Term::Builtin(DefaultFunction::ChooseUnit).force(), term),
Term::Constant(
UplcConstant::Data(PlutusData::Constr(Constr {
tag: convert_constr_to_tag(0).unwrap(),
@ -225,11 +225,9 @@ pub fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
DefaultFunction::ListData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
Term::Var(
Name {
text: "__pair".to_string(),
@ -241,11 +239,9 @@ pub fn convert_type_to_data(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
apply_wrap(
Term::Builtin(DefaultFunction::SndPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::SndPair).force().force(),
Term::Var(
Name {
text: "__pair".to_string(),
@ -303,9 +299,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
Term::Constant(UplcConstant::Integer(0.into()).into()),
),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
apply_wrap(DefaultFunction::UnConstrData.into(), term),
),
),
@ -338,7 +332,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
apply_wrap(
Term::Builtin(DefaultFunction::MkPairData),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "__list_data".to_string(),
@ -349,7 +343,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
),
),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "__tail".to_string(),
@ -362,7 +356,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: "__list_data".to_string(),
@ -385,9 +379,7 @@ pub fn convert_data_to_type(term: Term<Name>, field_type: &Arc<Type>) -> Term<Na
Term::Constant(UplcConstant::Integer(1.into()).into()),
),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
apply_wrap(DefaultFunction::UnConstrData.into(), term),
),
)
@ -576,7 +568,7 @@ pub fn list_access_to_uplc(
&& is_list_accessor
{
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: format!("tail_index_{}_{}", current_index, id_list[current_index]),
@ -588,7 +580,7 @@ pub fn list_access_to_uplc(
} else {
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: format!(
@ -631,7 +623,7 @@ pub fn list_access_to_uplc(
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -690,7 +682,7 @@ pub fn list_access_to_uplc(
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -725,7 +717,7 @@ pub fn list_access_to_uplc(
body: if check_last_item {
delayed_choose_list(
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -740,7 +732,7 @@ pub fn list_access_to_uplc(
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"List/Tuple/Constr contains more items than expected"
@ -751,7 +743,7 @@ pub fn list_access_to_uplc(
),
Term::Delay(Term::Error.into()),
)
.force_wrap(),
.force(),
)
.into()
} else {
@ -775,7 +767,7 @@ pub fn list_access_to_uplc(
body: if check_last_item {
delayed_choose_list(
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -790,7 +782,7 @@ pub fn list_access_to_uplc(
term,
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"List/Tuple/Constr contains more items than it expected"
@ -801,7 +793,7 @@ pub fn list_access_to_uplc(
),
Term::Delay(Term::Error.into()),
)
.force_wrap(),
.force(),
)
.into()
} else {
@ -845,7 +837,7 @@ pub fn list_access_to_uplc(
body: apply_wrap(
list_access_inner,
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -936,7 +928,7 @@ pub fn list_access_to_uplc(
body: apply_wrap(
list_access_inner,
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!(
@ -1358,6 +1350,22 @@ pub fn wrap_validator_args(term: Term<Name>, arguments: &[TypedArg]) -> Term<Nam
term
}
pub fn wrap_as_multi_validator(spend: Term<Name>, mint: Term<Name>) -> Term<Name> {
Term::equals_integer()
.apply(Term::integer(0.into()))
.apply(constr_index_exposer(Term::var("__second_arg")))
.delayed_if_else(
mint.apply(Term::var("__first_arg"))
.apply(Term::var("__second_arg")),
spend.apply(Term::var("__first_arg")).apply(
Term::head_list()
.apply(Term::var(CONSTR_FIELDS_EXPOSER).apply(Term::var("__second_arg"))),
),
)
.lambda("__second_arg")
.lambda("__first_arg")
}
pub fn monomorphize(
ir: Vec<Air>,
mono_types: IndexMap<u64, Arc<Type>>,

View File

@ -23,6 +23,7 @@ pub const RESULT: &str = "Result";
pub const STRING: &str = "String";
pub const OPTION: &str = "Option";
pub const ORDERING: &str = "Ordering";
pub const REDEEMER_WRAPPER: &str = "RedeemerWrapper";
/// Build a prelude that can be injected
/// into a compiler pipeline
@ -1057,3 +1058,12 @@ pub fn unbound_var(id: u64) -> Arc<Type> {
Arc::new(Type::Var { tipo })
}
pub fn wrapped_redeemer(redeemer: Arc<Type>) -> Arc<Type> {
Arc::new(Type::App {
public: true,
module: "".to_string(),
name: REDEEMER_WRAPPER.to_string(),
args: vec![redeemer],
})
}

View File

@ -240,10 +240,11 @@ impl<'comments> Formatter<'comments> {
Definition::Validator(Validator {
end_position,
fun: function,
fun,
other_fun,
params,
..
}) => self.definition_validator(params, function, *end_position),
}) => self.definition_validator(params, fun, other_fun, *end_position),
Definition::Test(Function {
name,
@ -504,55 +505,58 @@ impl<'comments> Formatter<'comments> {
&mut self,
params: &'a [UntypedArg],
fun: &'a UntypedFunction,
other_fun: &'a Option<UntypedFunction>,
end_position: usize,
) -> Document<'a> {
// Fn and args
let head = "fn".to_doc().append(wrap_args(
fun.arguments.iter().map(|e| (self.fn_arg(e), false)),
));
// Add return annotation
let head = match &fun.return_annotation {
Some(anno) => head.append(" -> ").append(self.annotation(anno)),
None => head,
}
.group();
// Format body
let body = self.expr(&fun.body);
// Add any trailing comments
let body = match printed_comments(self.pop_comments(fun.end_position), false) {
Some(comments) => body.append(line()).append(comments),
None => body,
};
// validator name(params)
let v_head = "validator"
.to_doc()
.append(" ")
.append(fun.name.as_str())
.append(if !params.is_empty() {
wrap_args(params.iter().map(|e| (self.fn_arg(e), false)))
} else {
"".to_doc()
});
// Stick it all together
let inner_fn = head
.append(" {")
.append(line().append(body).nest(INDENT).group())
.append(line())
.append("}");
let inner_fn = line()
.append(self.definition_fn(
&false,
"fn",
&fun.name,
&fun.arguments,
&fun.return_annotation,
&fun.body,
fun.end_position,
))
.nest(INDENT)
.group()
.append(if other_fun.is_some() { line() } else { nil() })
.append(
other_fun
.as_ref()
.map(|other| {
line()
.append(self.definition_fn(
&false,
"fn",
&other.name,
&other.arguments,
&other.return_annotation,
&other.body,
other.end_position,
))
.nest(INDENT)
.group()
})
.unwrap_or_else(nil),
);
let inner_fn = match printed_comments(self.pop_comments(end_position), false) {
Some(comments) => inner_fn.append(line()).append(comments),
None => inner_fn,
};
// validator(params)
let v_head = "validator".to_doc().append(if !params.is_empty() {
wrap_args(params.iter().map(|e| (self.fn_arg(e), false)))
} else {
nil()
});
v_head
.append(" {")
.append(line().append(inner_fn).nest(INDENT).group())
.append(inner_fn)
.append(line())
.append("}")
}

View File

@ -242,9 +242,43 @@ pub fn type_alias_parser() -> impl Parser<Token, ast::UntypedDefinition, Error =
}
pub fn validator_parser() -> impl Parser<Token, ast::UntypedDefinition, Error = ParseError> {
just(Token::Validator)
.ignore_then(select! {Token::Name {name} => name}.map_with_span(|name, span| (name, span)))
let func_parser = just(Token::Fn)
.ignore_then(select! {Token::Name {name} => name})
.then(
fn_param_parser()
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.map_with_span(|arguments, span| (arguments, span)),
)
.then(just(Token::RArrow).ignore_then(type_parser()).or_not())
.then(
expr_seq_parser()
.or_not()
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.map_with_span(
|(((name, (arguments, args_span)), return_annotation), body), span| ast::Function {
arguments,
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
doc: None,
location: Span {
start: span.start,
end: return_annotation
.as_ref()
.map(|l| l.location().end)
.unwrap_or_else(|| args_span.end),
},
end_position: span.end - 1,
name,
public: false,
return_annotation,
return_type: (),
},
);
just(Token::Validator)
.ignore_then(
fn_param_parser()
.separated_by(just(Token::Comma))
.allow_trailing()
@ -253,51 +287,31 @@ pub fn validator_parser() -> impl Parser<Token, ast::UntypedDefinition, Error =
.or_not(),
)
.then(
just(Token::Fn)
.ignore_then(
fn_param_parser()
.separated_by(just(Token::Comma))
.allow_trailing()
.delimited_by(just(Token::LeftParen), just(Token::RightParen))
.map_with_span(|arguments, span| (arguments, span)),
)
.then(just(Token::RArrow).ignore_then(type_parser()).or_not())
.then(
expr_seq_parser()
.or_not()
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
)
.map_with_span(
|(((arguments, args_span), return_annotation), body), span| ast::Function {
arguments,
body: body.unwrap_or_else(|| expr::UntypedExpr::todo(span, None)),
doc: None,
location: Span {
start: span.start,
end: return_annotation
.as_ref()
.map(|l| l.location().end)
.unwrap_or_else(|| args_span.end),
},
end_position: span.end - 1,
name: "".to_string(),
public: false,
return_annotation,
return_type: (),
},
)
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace)),
func_parser
.repeated()
.at_least(1)
.at_most(2)
.delimited_by(just(Token::LeftBrace), just(Token::RightBrace))
.map(IntoIterator::into_iter),
)
.map_with_span(|((name, opt_extra_params), mut fun), span| {
fun.name = name.0;
let (params, params_span) = opt_extra_params.unwrap_or((vec![], name.1));
.map_with_span(|(opt_extra_params, mut functions), span| {
let (params, params_span) = opt_extra_params.unwrap_or((
vec![],
Span {
start: 0,
end: span.start + "validator".len(),
},
));
ast::UntypedDefinition::Validator(ast::Validator {
doc: None,
fun,
fun: functions
.next()
.expect("unwrapping safe because there's 'at_least(1)' function"),
other_fun: functions.next(),
location: Span {
start: span.start,
// capture the span from the optional params
end: params_span.end,
},
params,

View File

@ -53,8 +53,8 @@ fn check_validator(
#[test]
fn validator_illegal_return_type() {
let source_code = r#"
validator foo {
fn(d, r, c) {
validator {
fn foo(d, r, c) {
1
}
}
@ -69,8 +69,8 @@ fn validator_illegal_return_type() {
#[test]
fn validator_illegal_arity() {
let source_code = r#"
validator foo {
fn(c) {
validator {
fn foo(c) {
True
}
}
@ -85,8 +85,8 @@ fn validator_illegal_arity() {
#[test]
fn validator_correct_form() {
let source_code = r#"
validator foo {
fn(d, r, c) {
validator {
fn foo(d, r, c) {
True
}
}
@ -98,8 +98,8 @@ fn validator_correct_form() {
#[test]
fn validator_in_lib_warning() {
let source_code = r#"
validator foo {
fn(c) {
validator {
fn foo(c) {
True
}
}

View File

@ -58,16 +58,42 @@ fn test_format_if() {
#[test]
fn test_format_validator() {
let src = indoc! {r#"
validator foo ( ) {
fn(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
validator ( ) {
fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
True
}
}
"#};
let expected = indoc! {r#"
validator foo {
fn(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
validator {
fn foo(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
True
}
}
"#};
assert_fmt(src, expected)
}
#[test]
fn test_format_double_validator() {
let src = indoc! {r#"
validator ( param1 : ByteArray ) {
fn foo (d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
True
}
fn bar(r: Redeemer, ctx : ScriptContext ) -> Bool { True }
}
"#};
let expected = indoc! {r#"
validator(param1: ByteArray) {
fn foo(d: Datum, r: Redeemer, ctx: ScriptContext) -> Bool {
True
}
fn bar(r: Redeemer, ctx: ScriptContext) -> Bool {
True
}
}

View File

@ -41,8 +41,8 @@ fn windows_newline() {
#[test]
fn validator() {
let code = indoc! {r#"
validator foo {
fn(datum, rdmr, ctx) {
validator {
fn foo(datum, rdmr, ctx) {
True
}
}
@ -91,14 +91,120 @@ fn validator() {
name: "True".to_string(),
},
doc: None,
location: Span::new((), 18..38),
location: Span::new((), 14..38),
name: "foo".to_string(),
public: false,
return_annotation: None,
return_type: (),
end_position: 52,
},
location: Span::new((), 0..13),
other_fun: None,
location: Span::new((), 0..9),
params: vec![],
})],
)
}
#[test]
fn double_validator() {
let code = indoc! {r#"
validator {
fn foo(datum, rdmr, ctx) {
True
}
fn bar(rdmr, ctx) {
True
}
}
"#};
assert_definitions(
code,
vec![ast::UntypedDefinition::Validator(ast::Validator {
doc: None,
end_position: 90,
fun: Function {
arguments: vec![
ast::Arg {
arg_name: ast::ArgName::Named {
name: "datum".to_string(),
label: "datum".to_string(),
location: Span::new((), 21..26),
},
location: Span::new((), 21..26),
annotation: None,
tipo: (),
},
ast::Arg {
arg_name: ast::ArgName::Named {
name: "rdmr".to_string(),
label: "rdmr".to_string(),
location: Span::new((), 28..32),
},
location: Span::new((), 28..32),
annotation: None,
tipo: (),
},
ast::Arg {
arg_name: ast::ArgName::Named {
name: "ctx".to_string(),
label: "ctx".to_string(),
location: Span::new((), 34..37),
},
location: Span::new((), 34..37),
annotation: None,
tipo: (),
},
],
body: expr::UntypedExpr::Var {
location: Span::new((), 45..49),
name: "True".to_string(),
},
doc: None,
location: Span::new((), 14..38),
name: "foo".to_string(),
public: false,
return_annotation: None,
return_type: (),
end_position: 52,
},
other_fun: Some(Function {
arguments: vec![
ast::Arg {
arg_name: ast::ArgName::Named {
name: "rdmr".to_string(),
label: "rdmr".to_string(),
location: Span::new((), 64..68),
},
location: Span::new((), 64..68),
annotation: None,
tipo: (),
},
ast::Arg {
arg_name: ast::ArgName::Named {
name: "ctx".to_string(),
label: "ctx".to_string(),
location: Span::new((), 70..73),
},
location: Span::new((), 70..73),
annotation: None,
tipo: (),
},
],
body: expr::UntypedExpr::Var {
location: Span::new((), 81..85),
name: "True".to_string(),
},
doc: None,
location: Span::new((), 57..74),
name: "bar".to_string(),
public: false,
return_annotation: None,
return_type: (),
end_position: 88,
}),
location: Span::new((), 0..9),
params: vec![],
})],
)

View File

@ -10,7 +10,7 @@ use crate::{
ast::{
Annotation, CallArg, DataType, Definition, Function, ModuleConstant, ModuleKind, Pattern,
RecordConstructor, RecordConstructorArg, Span, TypeAlias, TypedDefinition,
UnqualifiedImport, UntypedDefinition, Use, Validator, PIPE_VARIABLE,
UnqualifiedImport, UntypedArg, UntypedDefinition, Use, Validator, PIPE_VARIABLE,
},
builtins::{self, function, generic_var, tuple, unbound_var},
tipo::fields::FieldMap,
@ -1007,6 +1007,66 @@ impl<'a> Environment<'a> {
Ok(())
}
#[allow(clippy::too_many_arguments)]
fn register_function(
&mut self,
name: &'a str,
arguments: &[UntypedArg],
return_annotation: &Option<Annotation>,
module_name: &String,
hydrators: &mut HashMap<String, Hydrator>,
names: &mut HashMap<&'a str, &'a Span>,
location: &'a Span,
) -> Result<(), Error> {
assert_unique_value_name(names, name, location)?;
self.ungeneralised_functions.insert(name.to_string());
// Create the field map so we can reorder labels for usage of this function
let mut field_map = FieldMap::new(arguments.len(), true);
for (i, arg) in arguments.iter().enumerate() {
field_map.insert(arg.arg_name.get_label().clone(), i, &arg.location)?;
}
let field_map = field_map.into_option();
// Construct type from annotations
let mut hydrator = Hydrator::new();
let mut arg_types = Vec::new();
for arg in arguments {
let tipo = hydrator.type_from_option_annotation(&arg.annotation, self)?;
arg_types.push(tipo);
}
let return_type = hydrator.type_from_option_annotation(return_annotation, self)?;
let tipo = function(arg_types, return_type);
// Keep track of which types we create from annotations so we can know
// which generic types not to instantiate later when performing
// inference of the function body.
hydrators.insert(name.to_string(), hydrator);
// Insert the function into the environment
self.insert_variable(
name.to_string(),
ValueConstructorVariant::ModuleFn {
name: name.to_string(),
field_map,
module: module_name.to_owned(),
arity: arguments.len(),
location: *location,
builtin: None,
},
tipo,
);
Ok(())
}
pub fn register_values(
&mut self,
def: &'a UntypedDefinition,
@ -1016,117 +1076,61 @@ impl<'a> Environment<'a> {
kind: ModuleKind,
) -> Result<(), Error> {
match def {
Definition::Fn(Function {
name,
arguments: args,
location,
return_annotation,
public,
..
}) => {
assert_unique_value_name(names, name, location)?;
Definition::Fn(fun) => {
self.register_function(
&fun.name,
&fun.arguments,
&fun.return_annotation,
module_name,
hydrators,
names,
&fun.location,
)?;
self.ungeneralised_functions.insert(name.to_string());
// Create the field map so we can reorder labels for usage of this function
let mut field_map = FieldMap::new(args.len(), true);
for (i, arg) in args.iter().enumerate() {
field_map.insert(arg.arg_name.get_label().clone(), i, &arg.location)?;
}
let field_map = field_map.into_option();
// Construct type from annotations
let mut hydrator = Hydrator::new();
let mut arg_types = Vec::new();
for arg in args {
let tipo = hydrator.type_from_option_annotation(&arg.annotation, self)?;
arg_types.push(tipo);
}
let return_type = hydrator.type_from_option_annotation(return_annotation, self)?;
let tipo = function(arg_types, return_type);
// Keep track of which types we create from annotations so we can know
// which generic types not to instantiate later when performing
// inference of the function body.
hydrators.insert(name.clone(), hydrator);
// Insert the function into the environment
self.insert_variable(
name.clone(),
ValueConstructorVariant::ModuleFn {
name: name.clone(),
field_map,
module: module_name.to_owned(),
arity: args.len(),
location: *location,
builtin: None,
},
tipo,
);
if !public && kind.is_lib() {
self.init_usage(name.clone(), EntityKind::PrivateFunction, *location);
if !fun.public && kind.is_lib() {
self.init_usage(fun.name.clone(), EntityKind::PrivateFunction, fun.location);
}
}
Definition::Validator(Validator {
fun,
location,
other_fun,
params,
..
}) if kind.is_validator() => {
assert_unique_value_name(names, &fun.name, location)?;
let temp_params: Vec<UntypedArg> = params
.iter()
.cloned()
.chain(fun.arguments.clone())
.collect();
// Create the field map so we can reorder labels for usage of this function
let mut field_map = FieldMap::new(fun.arguments.len() + params.len(), true);
self.register_function(
&fun.name,
&temp_params,
&fun.return_annotation,
module_name,
hydrators,
names,
&fun.location,
)?;
// Chain together extra params and function.arguments
for (i, arg) in params.iter().chain(fun.arguments.iter()).enumerate() {
field_map.insert(arg.arg_name.get_label().clone(), i, &arg.location)?;
if let Some(other) = other_fun {
let temp_params: Vec<UntypedArg> = params
.iter()
.cloned()
.chain(other.arguments.clone())
.collect();
self.register_function(
&other.name,
&temp_params,
&other.return_annotation,
module_name,
hydrators,
names,
&other.location,
)?;
}
let field_map = field_map.into_option();
// Construct type from annotations
let mut hydrator = Hydrator::new();
let mut arg_types = Vec::new();
for arg in params.iter().chain(fun.arguments.iter()) {
let tipo = hydrator.type_from_option_annotation(&arg.annotation, self)?;
arg_types.push(tipo);
}
let return_type =
hydrator.type_from_option_annotation(&fun.return_annotation, self)?;
let tipo = function(arg_types, return_type);
// Keep track of which types we create from annotations so we can know
// which generic types not to instantiate later when performing
// inference of the function body.
hydrators.insert(fun.name.clone(), hydrator);
// Insert the function into the environment
self.insert_variable(
fun.name.clone(),
ValueConstructorVariant::ModuleFn {
name: fun.name.clone(),
field_map,
module: module_name.to_owned(),
arity: params.len() + fun.arguments.len(),
location: fun.location,
builtin: None,
},
tipo,
);
}
Definition::Validator(Validator { location, .. }) => {

View File

@ -421,6 +421,17 @@ If you really meant to return that last expression, try to replace it with the f
name: String,
},
#[error("I found a multi-validator where both take the same number of arguments.\n")]
#[diagnostic(code("illegal::multi_validator"))]
#[diagnostic(help("Multi-validators cannot take the same number of arguments. One must take 3 arguments\nand the other must take 2 arguments. Both of these take {} arguments.", count.to_string().purple()))]
MultiValidatorEqualArgs {
#[label("{} here", count)]
location: Span,
#[label("and {} here", count)]
other_location: Span,
count: usize,
},
#[error(
"I stumbled upon an invalid (non-local) clause guard '{}'.\n",
name.if_supports_color(Stdout, |s| s.purple())

View File

@ -3,8 +3,8 @@ use std::collections::HashMap;
use crate::{
ast::{
DataType, Definition, Function, Layer, ModuleConstant, ModuleKind, RecordConstructor,
RecordConstructorArg, Span, Tracing, TypeAlias, TypedDefinition, TypedModule,
UntypedDefinition, UntypedModule, Use, Validator,
RecordConstructorArg, Span, Tracing, TypeAlias, TypedDefinition, TypedFunction,
TypedModule, UntypedDefinition, UntypedModule, Use, Validator,
},
builtins,
builtins::function,
@ -255,46 +255,94 @@ fn infer_definition(
location,
end_position,
mut fun,
mut params,
other_fun,
params,
}) => {
let params_length = params.len();
params.append(&mut fun.arguments);
fun.arguments = params;
let temp_params = params.iter().cloned().chain(fun.arguments);
fun.arguments = temp_params.collect();
if let Definition::Fn(mut typed_fun) = infer_definition(
let Definition::Fn(mut typed_fun) = infer_definition(
Definition::Fn(fun),
module_name,
hydrators,
environment,
tracing,
kind,
)? {
if !typed_fun.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fun.return_type.clone(),
location: typed_fun.location,
});
}
let typed_params = typed_fun.arguments.drain(0..params_length).collect();
if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 {
return Err(Error::IncorrectValidatorArity {
count: typed_fun.arguments.len() as u32,
location: typed_fun.location,
});
}
Ok(Definition::Validator(Validator {
doc,
end_position,
fun: typed_fun,
location,
params: typed_params,
}))
} else {
)? else {
unreachable!("validator definition inferred as something other than a function?")
};
if !typed_fun.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: typed_fun.return_type.clone(),
location: typed_fun.location,
});
}
let typed_params = typed_fun.arguments.drain(0..params_length).collect();
if typed_fun.arguments.len() < 2 || typed_fun.arguments.len() > 3 {
return Err(Error::IncorrectValidatorArity {
count: typed_fun.arguments.len() as u32,
location: typed_fun.location,
});
}
let typed_other_fun = other_fun
.map(|mut other| -> Result<TypedFunction, Error> {
let params = params.into_iter().chain(other.arguments);
other.arguments = params.collect();
let Definition::Fn(mut other_typed_fun) = infer_definition(
Definition::Fn(other),
module_name,
hydrators,
environment,
tracing,
kind,
)? else {
unreachable!(
"validator definition inferred as something other than a function?"
)
};
if !other_typed_fun.return_type.is_bool() {
return Err(Error::ValidatorMustReturnBool {
return_type: other_typed_fun.return_type.clone(),
location: other_typed_fun.location,
});
}
other_typed_fun.arguments.drain(0..params_length);
if other_typed_fun.arguments.len() < 2 || other_typed_fun.arguments.len() > 3 {
return Err(Error::IncorrectValidatorArity {
count: other_typed_fun.arguments.len() as u32,
location: other_typed_fun.location,
});
}
if typed_fun.arguments.len() == other_typed_fun.arguments.len() {
return Err(Error::MultiValidatorEqualArgs {
location: typed_fun.location,
other_location: other_typed_fun.location,
count: other_typed_fun.arguments.len(),
});
}
Ok(other_typed_fun)
})
.transpose();
Ok(Definition::Validator(Validator {
doc,
end_position,
fun: typed_fun,
other_fun: typed_other_fun?,
location,
params: typed_params,
}))
}
Definition::Test(f) => {

View File

@ -20,16 +20,16 @@ use uplc::{
use crate::{
air::Air,
ast::{
ArgName, AssignmentKind, BinOp, Pattern, Span, TypedArg, TypedClause, TypedDataType,
TypedFunction, UnOp,
ArgName, AssignmentKind, BinOp, Pattern, Span, TypedClause, TypedDataType, TypedFunction,
TypedValidator, UnOp,
},
builder::{
check_replaceable_opaque_type, check_when_pattern_needs, constants_ir,
convert_constants_to_data, convert_data_to_type, convert_type_to_data, get_common_ancestor,
get_generic_id_and_type, handle_clause_guard, handle_func_dependencies_ir,
handle_recursion_ir, list_access_to_uplc, lookup_data_type_by_tipo, monomorphize,
rearrange_clauses, replace_opaque_type, wrap_validator_args, AssignmentProperties,
ClauseProperties, DataTypeKey, FuncComponents, FunctionAccessKey,
rearrange_clauses, replace_opaque_type, wrap_as_multi_validator, wrap_validator_args,
AssignmentProperties, ClauseProperties, DataTypeKey, FuncComponents, FunctionAccessKey,
},
builtins::bool,
expr::TypedExpr,
@ -80,14 +80,17 @@ impl<'a> CodeGenerator<'a> {
pub fn generate(
&mut self,
body: &TypedExpr,
arguments: &[TypedArg],
wrap_as_validator: bool,
TypedValidator {
fun,
other_fun,
params,
..
}: &TypedValidator,
) -> Program<Name> {
let mut ir_stack = vec![];
let scope = vec![self.id_gen.next()];
self.build_ir(body, &mut ir_stack, scope);
self.build_ir(&fun.body, &mut ir_stack, scope);
self.define_ir(&mut ir_stack);
@ -102,15 +105,69 @@ impl<'a> CodeGenerator<'a> {
}
// Wrap the validator body if ifThenElse term unit error
term = if wrap_as_validator {
final_wrapper(term)
} else {
term
};
term = final_wrapper(term);
term = wrap_validator_args(term, arguments);
term = wrap_validator_args(term, &fun.arguments);
term = if wrap_as_validator || self.used_data_assert_on_list {
if let Some(other) = other_fun {
self.reset();
let mut other_ir_stack = vec![];
let scope = vec![self.id_gen.next()];
self.build_ir(&other.body, &mut other_ir_stack, scope);
self.define_ir(&mut other_ir_stack);
self.convert_opaque_type_to_inner_ir(&mut other_ir_stack);
let other_term = self.uplc_code_gen(&mut other_ir_stack);
let other_term = final_wrapper(other_term);
let other_term = wrap_validator_args(other_term, &other.arguments);
let (spend, mint) = if other.arguments.len() > fun.arguments.len() {
(other_term, term)
} else {
(term, other_term)
};
term = wrap_as_multi_validator(spend, mint);
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
}
term = wrap_validator_args(term, params);
self.finalize(term, true)
}
pub fn generate_test(&mut self, test_body: &TypedExpr) -> Program<Name> {
let mut ir_stack = vec![];
let scope = vec![self.id_gen.next()];
self.build_ir(test_body, &mut ir_stack, scope);
self.define_ir(&mut ir_stack);
self.convert_opaque_type_to_inner_ir(&mut ir_stack);
let mut term = self.uplc_code_gen(&mut ir_stack);
if self.needs_field_access {
term = builder::constr_get_field(term);
term = builder::constr_fields_exposer(term);
}
self.finalize(term, false)
}
fn finalize(&mut self, term: Term<Name>, wrap_as_validator: bool) -> Program<Name> {
let term = if wrap_as_validator || self.used_data_assert_on_list {
assert_on_list(term)
} else {
term
@ -4029,16 +4086,9 @@ impl<'a> CodeGenerator<'a> {
UplcConstant::ProtoList(UplcType::Data, vec![]).into(),
);
let term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::ConstrData),
Term::Constant(
UplcConstant::Integer(constr_index.try_into().unwrap())
.into(),
),
),
fields,
);
let term = Term::constr_data()
.apply(Term::integer(constr_index.try_into().unwrap()))
.apply(fields);
arg_stack.push(term);
}
@ -4134,10 +4184,7 @@ impl<'a> CodeGenerator<'a> {
convert_type_to_data(arg, &list_type)
};
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
list_item,
),
apply_wrap(Term::Builtin(DefaultFunction::MkCons).force(), list_item),
term,
);
}
@ -4204,7 +4251,7 @@ impl<'a> CodeGenerator<'a> {
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: tail_var,
@ -4231,7 +4278,7 @@ impl<'a> CodeGenerator<'a> {
} else {
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: tail_var,
@ -4340,7 +4387,7 @@ impl<'a> CodeGenerator<'a> {
} => {
let mut term: Term<Name> = Term::Builtin(func);
for _ in 0..func.force_count() {
term = term.force_wrap();
term = term.force();
}
let mut arg_vec = vec![];
@ -4421,8 +4468,8 @@ impl<'a> CodeGenerator<'a> {
Term::Builtin(DefaultFunction::IData),
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
.force()
.force(),
Term::Var(
Name {
text: temp_tuple.clone(),
@ -4436,9 +4483,7 @@ impl<'a> CodeGenerator<'a> {
apply_wrap(
Term::Builtin(DefaultFunction::ListData),
apply_wrap(
Term::Builtin(DefaultFunction::SndPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::SndPair).force().force(),
Term::Var(
Name {
text: temp_tuple,
@ -4504,7 +4549,7 @@ impl<'a> CodeGenerator<'a> {
}
}
term = term.force_wrap();
term = term.force();
if count == 0 {
for temp_var in temp_vars.into_iter().rev() {
@ -4583,7 +4628,7 @@ impl<'a> CodeGenerator<'a> {
DefaultFunction::MapData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
left,
),
Term::Constant(
@ -4603,7 +4648,7 @@ impl<'a> CodeGenerator<'a> {
DefaultFunction::MapData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
right,
),
Term::Constant(
@ -4678,7 +4723,7 @@ impl<'a> CodeGenerator<'a> {
DefaultFunction::MapData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
left,
),
Term::Constant(
@ -4698,7 +4743,7 @@ impl<'a> CodeGenerator<'a> {
DefaultFunction::MapData.into(),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
right,
),
Term::Constant(
@ -4919,7 +4964,7 @@ impl<'a> CodeGenerator<'a> {
let error_term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"Expected on incorrect constructor variant.".to_string(),
@ -4929,7 +4974,7 @@ impl<'a> CodeGenerator<'a> {
),
Term::Delay(Term::Error.into()),
)
.force_wrap();
.force();
term = delayed_if_else(
apply_wrap(
@ -4951,7 +4996,7 @@ impl<'a> CodeGenerator<'a> {
let error_term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::Trace).force_wrap(),
Term::Builtin(DefaultFunction::Trace).force(),
Term::Constant(
UplcConstant::String(
"Expected on incorrect boolean variant.".to_string(),
@ -4961,7 +5006,7 @@ impl<'a> CodeGenerator<'a> {
),
Term::Delay(Term::Error.into()),
)
.force_wrap();
.force();
if is_true {
term = delayed_if_else(value, term, error_term);
@ -5048,7 +5093,7 @@ impl<'a> CodeGenerator<'a> {
.into(),
),
)
.force_wrap();
.force();
} else {
term = if_else(
Term::Var(
@ -5067,7 +5112,7 @@ impl<'a> CodeGenerator<'a> {
),
Term::Delay(body.into()),
)
.force_wrap();
.force();
}
term = apply_wrap(
@ -5175,7 +5220,7 @@ impl<'a> CodeGenerator<'a> {
.into(),
),
)
.force_wrap()
.force()
.into(),
},
Term::Delay(term.into()),
@ -5210,7 +5255,7 @@ impl<'a> CodeGenerator<'a> {
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: tail_name.clone(),
@ -5242,7 +5287,7 @@ impl<'a> CodeGenerator<'a> {
.into(),
),
)
.force_wrap();
.force();
term = apply_wrap(
Term::Lambda {
@ -5318,7 +5363,7 @@ impl<'a> CodeGenerator<'a> {
Term::Delay(then.into()),
term,
)
.force_wrap();
.force();
} else {
term = if_else(
Term::Var(
@ -5331,7 +5376,7 @@ impl<'a> CodeGenerator<'a> {
term,
Term::Delay(then.into()),
)
.force_wrap();
.force();
}
arg_stack.push(term);
} else {
@ -5394,7 +5439,7 @@ impl<'a> CodeGenerator<'a> {
.into(),
),
)
.force_wrap();
.force();
arg_stack.push(term);
}
}
@ -5422,7 +5467,7 @@ impl<'a> CodeGenerator<'a> {
body: term.into(),
},
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: tail_name.clone(),
@ -5454,7 +5499,7 @@ impl<'a> CodeGenerator<'a> {
.into(),
),
)
.force_wrap();
.force();
} else {
term = choose_list(
Term::Var(
@ -5473,7 +5518,7 @@ impl<'a> CodeGenerator<'a> {
),
Term::Delay(term.into()),
)
.force_wrap();
.force();
}
arg_stack.push(term);
@ -5507,7 +5552,7 @@ impl<'a> CodeGenerator<'a> {
for (index, arg) in arg_vec.iter().enumerate().rev() {
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
convert_type_to_data(arg.clone(), &tipo.arg_types().unwrap()[index]),
),
term,
@ -5677,7 +5722,7 @@ impl<'a> CodeGenerator<'a> {
for (arg, tipo) in args.into_iter().zip(tuple_sub_types.into_iter()).rev() {
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
convert_type_to_data(arg, &tipo),
),
term,
@ -5715,7 +5760,7 @@ impl<'a> CodeGenerator<'a> {
unchanged_field_indices.reverse();
let mut term = apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: format!("{tail_name_prefix}_{highest_index}"),
@ -5731,7 +5776,7 @@ impl<'a> CodeGenerator<'a> {
if let Some((tipo, arg)) = args.get(&current_index) {
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
convert_type_to_data(arg.clone(), tipo),
),
term,
@ -5739,9 +5784,9 @@ impl<'a> CodeGenerator<'a> {
} else {
term = apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::MkCons).force_wrap(),
Term::Builtin(DefaultFunction::MkCons).force(),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: tail_name,
@ -5781,7 +5826,7 @@ impl<'a> CodeGenerator<'a> {
if index < prev_index {
for _ in index..prev_index {
tail_list = apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
tail_list,
);
}
@ -5813,10 +5858,8 @@ impl<'a> CodeGenerator<'a> {
);
for _ in 0..prev_index {
tail_list = apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
tail_list,
);
tail_list =
apply_wrap(Term::Builtin(DefaultFunction::TailList).force(), tail_list);
}
if prev_index != 0 {
term = apply_wrap(
@ -5884,9 +5927,7 @@ impl<'a> CodeGenerator<'a> {
if tuple_index == 0 {
term = convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
term,
),
&tipo.get_inner_types()[0],
@ -5894,9 +5935,7 @@ impl<'a> CodeGenerator<'a> {
} else {
term = convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::SndPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::SndPair).force().force(),
term,
),
&tipo.get_inner_types()[1],
@ -5962,8 +6001,8 @@ impl<'a> CodeGenerator<'a> {
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::SndPair)
.force_wrap()
.force_wrap(),
.force()
.force(),
Term::Var(
Name {
text: format!("__tuple_{list_id}"),
@ -5979,9 +6018,7 @@ impl<'a> CodeGenerator<'a> {
},
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
Term::Var(
Name {
text: format!("__tuple_{list_id}"),
@ -6028,10 +6065,10 @@ impl<'a> CodeGenerator<'a> {
let term = arg_stack.pop().unwrap();
let term = apply_wrap(
apply_wrap(Term::Builtin(DefaultFunction::Trace).force_wrap(), text),
apply_wrap(Term::Builtin(DefaultFunction::Trace).force(), text),
Term::Delay(term.into()),
)
.force_wrap();
.force();
arg_stack.push(term);
}
@ -6077,9 +6114,7 @@ impl<'a> CodeGenerator<'a> {
},
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::FstPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::FstPair).force().force(),
Term::Var(
Name {
text: subject_name.clone(),
@ -6103,9 +6138,7 @@ impl<'a> CodeGenerator<'a> {
},
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::SndPair)
.force_wrap()
.force_wrap(),
Term::Builtin(DefaultFunction::SndPair).force().force(),
Term::Var(
Name {
text: subject_name.clone(),
@ -6132,7 +6165,7 @@ impl<'a> CodeGenerator<'a> {
},
convert_data_to_type(
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
repeat_tail_list(
Term::Var(
Name {

View File

@ -60,14 +60,17 @@ impl Blueprint<Reference, Annotated<Schema>> {
let validators: Result<Vec<_>, Error> = modules
.validators()
.map(|(validator, def)| {
Validator::from_checked_module(modules, generator, validator, def).map(
|mut schema| {
definitions.merge(&mut schema.definitions);
schema.definitions = Definitions::new();
schema
},
)
.flat_map(|(validator, def)| {
Validator::from_checked_module(modules, generator, validator, def)
.into_iter()
.map(|result| {
result.map(|mut schema| {
definitions.merge(&mut schema.definitions);
schema.definitions = Definitions::new();
schema
})
})
.collect::<Vec<_>>()
})
.collect();

View File

@ -2,6 +2,7 @@ use crate::blueprint::definitions::{Definitions, Reference};
use crate::CheckedModule;
use aiken_lang::{
ast::{DataType, Definition, TypedDefinition},
builtins::wrapped_redeemer,
tipo::{pretty, Type, TypeVar},
};
use owo_colors::{OwoColorize, Stream::Stdout};
@ -12,6 +13,9 @@ use serde::{
use std::ops::Deref;
use std::{collections::HashMap, sync::Arc};
// NOTE: Can be anything BUT 0
pub const REDEEMER_DISCRIMINANT: usize = 1;
#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)]
pub struct Annotated<T> {
#[serde(skip_serializing_if = "Option::is_none")]
@ -71,6 +75,30 @@ impl<T> From<T> for Annotated<T> {
}
impl Annotated<Schema> {
pub fn as_wrapped_redeemer(
definitions: &mut Definitions<Annotated<Schema>>,
schema: Reference,
type_info: Arc<Type>,
) -> Reference {
definitions
.register(
&wrapped_redeemer(type_info),
&HashMap::new(),
|_| {
Ok::<_, Error>(Annotated {
title: Some("Wrapped Redeemer".to_string()),
description: Some("A redeemer wrapped in an extra constructor to make multi-validator detection possible on-chain.".to_string()),
annotated: Schema::Data(Data::AnyOf(vec![Constructor {
index: REDEEMER_DISCRIMINANT,
fields: vec![schema.into()],
}
.into()])),
})
},
)
.expect("cannot fail because Ok")
}
pub fn from_type(
modules: &HashMap<String, CheckedModule>,
type_info: &Type,

View File

@ -4,7 +4,10 @@ use super::{
schema::{Annotated, Schema},
};
use crate::module::{CheckedModule, CheckedModules};
use aiken_lang::{ast::TypedValidator, uplc::CodeGenerator};
use aiken_lang::{
ast::{TypedArg, TypedFunction, TypedValidator},
uplc::CodeGenerator,
};
use miette::NamedSource;
use serde;
use uplc::ast::{DeBruijn, Program, Term};
@ -47,22 +50,55 @@ impl Validator<Reference, Annotated<Schema>> {
generator: &mut CodeGenerator,
module: &CheckedModule,
def: &TypedValidator,
) -> Vec<Result<Validator<Reference, Annotated<Schema>>, Error>> {
let program = generator.generate(def).try_into().unwrap();
let is_multi_validator = def.other_fun.is_some();
let mut validators = vec![Validator::create_validator_blueprint(
modules,
module,
&program,
&def.params,
&def.fun,
is_multi_validator,
)];
if let Some(ref other_func) = def.other_fun {
validators.push(Validator::create_validator_blueprint(
modules,
module,
&program,
&def.params,
other_func,
is_multi_validator,
));
}
validators
}
fn create_validator_blueprint(
modules: &CheckedModules,
module: &CheckedModule,
program: &Program<DeBruijn>,
params: &[TypedArg],
func: &TypedFunction,
is_multi_validator: bool,
) -> Result<Validator<Reference, Annotated<Schema>>, Error> {
let mut args = def.fun.arguments.iter().rev();
let mut args = func.arguments.iter().rev();
let (_, redeemer, datum) = (args.next(), args.next().unwrap(), args.next());
let mut arguments = Vec::with_capacity(def.params.len() + def.fun.arguments.len());
arguments.extend(def.params.clone());
arguments.extend(def.fun.arguments.clone());
let mut arguments = Vec::with_capacity(params.len() + func.arguments.len());
arguments.extend(params.to_vec());
arguments.extend(func.arguments.clone());
let mut definitions = Definitions::new();
Ok(Validator {
title: format!("{}.{}", &module.name, &def.fun.name),
title: format!("{}.{}", &module.name, &func.name),
description: None,
parameters: def
.params
parameters: params
.iter()
.map(|param| {
Annotated::from_type(modules.into(), &param.tipo, &mut definitions)
@ -109,12 +145,16 @@ impl Validator<Reference, Annotated<Schema>> {
})
.map(|schema| Argument {
title: Some(redeemer.arg_name.get_label()),
schema,
schema: match datum {
Some(..) if is_multi_validator => Annotated::as_wrapped_redeemer(
&mut definitions,
schema,
redeemer.tipo.clone(),
),
_ => schema,
},
})?,
program: generator
.generate(&def.fun.body, &arguments, true)
.try_into()
.unwrap(),
program: program.clone(),
definitions,
})
}
@ -260,20 +300,29 @@ mod test {
.next()
.expect("source code did no yield any validator");
let validator = Validator::from_checked_module(&modules, &mut generator, validator, def)
let validators = Validator::from_checked_module(&modules, &mut generator, validator, def);
if validators.len() > 1 {
panic!("Multi-validator given to test bench. Don't do that.")
}
let validator = validators
.get(0)
.unwrap()
.as_ref()
.expect("Failed to create validator blueprint");
println!("{}", serde_json::to_string_pretty(&validator).unwrap());
println!("{}", serde_json::to_string_pretty(validator).unwrap());
assert_json_eq!(serde_json::to_value(&validator).unwrap(), expected);
assert_json_eq!(serde_json::to_value(validator).unwrap(), expected);
}
#[test]
fn mint_basic() {
assert_validator(
r#"
validator mint {
fn(redeemer: Data, ctx: Data) {
validator {
fn mint(redeemer: Data, ctx: Data) {
True
}
}
@ -302,8 +351,8 @@ mod test {
fn mint_parameterized() {
assert_validator(
r#"
validator mint(utxo_ref: Int) {
fn(redeemer: Data, ctx: Data) {
validator(utxo_ref: Int) {
fn mint(redeemer: Data, ctx: Data) {
True
}
}
@ -373,8 +422,8 @@ mod test {
Abort
}
validator simplified_hydra {
fn(datum: State, redeemer: Input, ctx: Data) {
validator {
fn simplified_hydra(datum: State, redeemer: Input, ctx: Data) {
True
}
}
@ -485,8 +534,8 @@ mod test {
fn tuples() {
assert_validator(
r#"
validator tuples {
fn(datum: (Int, ByteArray), redeemer: (Int, Int, Int), ctx: Void) {
validator {
fn tuples(datum: (Int, ByteArray), redeemer: (Int, Int, Int), ctx: Void) {
True
}
}
@ -560,8 +609,8 @@ mod test {
Infinite
}
validator generics {
fn(redeemer: Either<ByteArray, Interval<Int>>, ctx: Void) {
validator {
fn generics(redeemer: Either<ByteArray, Interval<Int>>, ctx: Void) {
True
}
}
@ -644,8 +693,8 @@ mod test {
type UUID { UUID }
validator list_2_tuples_as_map {
fn(redeemer: Dict<UUID, Int>, ctx: Void) {
validator {
fn list_2_tuples_as_map(redeemer: Dict<UUID, Int>, ctx: Void) {
True
}
}
@ -707,8 +756,8 @@ mod test {
type UUID { UUID }
validator opaque_singleton_variants {
fn(redeemer: Dict<UUID, Int>, ctx: Void) {
validator {
fn opaque_singleton_variants(redeemer: Dict<UUID, Int>, ctx: Void) {
True
}
}
@ -753,8 +802,8 @@ mod test {
foo: Data
}
validator nested_data {
fn(datum: Foo, redeemer: Int, ctx: Void) {
validator {
fn nested_data(datum: Foo, redeemer: Int, ctx: Void) {
True
}
}
@ -814,8 +863,8 @@ mod test {
Mul(Expr, Expr)
}
validator recursive_types {
fn(redeemer: Expr, ctx: Void) {
validator {
fn recursive_types(redeemer: Expr, ctx: Void) {
True
}
}
@ -899,8 +948,8 @@ mod test {
}
}
validator recursive_generic_types {
fn(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {
validator {
fn recursive_generic_types(datum: Foo, redeemer: LinkedList<Int>, ctx: Void) {
True
}
}

View File

@ -675,12 +675,7 @@ where
let mut programs = Vec::new();
for (input_path, module_name, func_def) in scripts {
let Function {
arguments,
name,
body,
..
} = func_def;
let Function { name, body, .. } = func_def;
if verbose {
self.event_listener.handle_event(Event::GeneratingUPLCFor {
@ -695,30 +690,27 @@ where
&self.module_types,
);
let evaluation_hint = if let Some((bin_op, left_src, right_src)) = func_def.test_hint()
{
let evaluation_hint = func_def.test_hint().map(|(bin_op, left_src, right_src)| {
let left = generator
.clone()
.generate(&left_src, &[], false)
.generate_test(&left_src)
.try_into()
.unwrap();
let right = generator
.clone()
.generate(&right_src, &[], false)
.generate_test(&right_src)
.try_into()
.unwrap();
Some(EvalHint {
EvalHint {
bin_op,
left,
right,
})
} else {
None
};
}
});
let program = generator.generate(body, arguments, false);
let program = generator.generate_test(body);
let script = Script::new(
input_path,

View File

@ -206,14 +206,6 @@ impl<T> Term<T> {
pub fn is_unit(&self) -> bool {
matches!(self, Term::Constant(c) if c.as_ref() == &Constant::Unit)
}
pub fn force_wrap(self) -> Self {
Term::Force(self.into())
}
pub fn delay_wrap(self) -> Self {
Term::Delay(self.into())
}
}
impl<'a, T> Display for Term<T>
@ -285,6 +277,15 @@ pub struct Name {
pub unique: Unique,
}
impl Name {
pub fn text(t: impl ToString) -> Name {
Name {
text: t.to_string(),
unique: 0.into(),
}
}
}
impl hash::Hash for Name {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.text.hash(state);

View File

@ -7,6 +7,66 @@ pub const CONSTR_INDEX_EXPOSER: &str = "__constr_index_exposer";
pub const CONSTR_GET_FIELD: &str = "__constr_get_field";
pub const ASSERT_ON_LIST: &str = "__assert_on_list";
impl Term<Name> {
pub fn apply(self, arg: Self) -> Self {
Term::Apply {
function: self.into(),
argument: arg.into(),
}
}
pub fn lambda(self, parameter_name: impl ToString) -> Self {
Term::Lambda {
parameter_name: Name::text(parameter_name).into(),
body: self.into(),
}
}
pub fn force(self) -> Self {
Term::Force(self.into())
}
pub fn delay(self) -> Self {
Term::Delay(self.into())
}
pub fn var(name: impl ToString) -> Self {
Term::Var(Name::text(name).into())
}
pub fn integer(i: num_bigint::BigInt) -> Self {
Term::Constant(Constant::Integer(i).into())
}
pub fn constr_data() -> Self {
Term::Builtin(DefaultFunction::ConstrData)
}
pub fn equals_integer() -> Self {
Term::Builtin(DefaultFunction::EqualsInteger)
}
pub fn head_list() -> Self {
Term::Builtin(DefaultFunction::HeadList).force()
}
pub fn delayed_if_else(self, then_term: Self, else_term: Self) -> Self {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::IfThenElse).force().into(),
argument: self.into(),
}
.into(),
argument: Term::Delay(then_term.into()).into(),
}
.into(),
argument: Term::Delay(else_term.into()).into(),
}
.force()
}
}
pub fn apply_wrap(function: Term<Name>, arg: Term<Name>) -> Term<Name> {
Term::Apply {
function: function.into(),
@ -97,7 +157,7 @@ pub fn assert_on_list(term: Term<Name>) -> Term<Name> {
Term::Constant(Constant::Unit.into()),
apply_wrap(
apply_wrap(
Term::Builtin(DefaultFunction::ChooseUnit).force_wrap(),
Term::Builtin(DefaultFunction::ChooseUnit).force(),
apply_wrap(
Term::Var(
Name {
@ -107,7 +167,7 @@ pub fn assert_on_list(term: Term<Name>) -> Term<Name> {
.into(),
),
apply_wrap(
Term::Builtin(DefaultFunction::HeadList).force_wrap(),
Term::Builtin(DefaultFunction::HeadList).force(),
Term::Var(
Name {
text: "list_to_check".to_string(),
@ -137,7 +197,7 @@ pub fn assert_on_list(term: Term<Name>) -> Term<Name> {
),
),
apply_wrap(
Term::Builtin(DefaultFunction::TailList).force_wrap(),
Term::Builtin(DefaultFunction::TailList).force(),
Term::Var(
Name {
text: "list_to_check".to_string(),
@ -461,9 +521,7 @@ pub fn delayed_if_else(
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::IfThenElse)
.force_wrap()
.into(),
function: Term::Builtin(DefaultFunction::IfThenElse).force().into(),
argument: condition.into(),
}
.into(),
@ -472,16 +530,14 @@ pub fn delayed_if_else(
.into(),
argument: Term::Delay(else_term.into()).into(),
}
.force_wrap()
.force()
}
pub fn if_else(condition: Term<Name>, then_term: Term<Name>, else_term: Term<Name>) -> Term<Name> {
Term::Apply {
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::IfThenElse)
.force_wrap()
.into(),
function: Term::Builtin(DefaultFunction::IfThenElse).force().into(),
argument: condition.into(),
}
.into(),
@ -501,8 +557,8 @@ pub fn delayed_choose_list(
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::ChooseList)
.force_wrap()
.force_wrap()
.force()
.force()
.into(),
argument: list.into(),
}
@ -512,7 +568,7 @@ pub fn delayed_choose_list(
.into(),
argument: Term::Delay(else_term.into()).into(),
}
.force_wrap()
.force()
}
pub fn choose_list(
@ -524,8 +580,8 @@ pub fn choose_list(
function: Term::Apply {
function: Term::Apply {
function: Term::Builtin(DefaultFunction::ChooseList)
.force_wrap()
.force_wrap()
.force()
.force()
.into(),
argument: list.into(),
}
@ -542,7 +598,7 @@ pub fn repeat_tail_list(term: Term<Name>, repeat: usize) -> Term<Name> {
for _ in 0..repeat {
term = Term::Apply {
function: Term::Builtin(DefaultFunction::TailList).force_wrap().into(),
function: Term::Builtin(DefaultFunction::TailList).force().into(),
argument: term.into(),
};
}

View File

@ -43,9 +43,9 @@ impl Program<Name> {
body: term.into(),
},
if default_func.force_count() == 1 {
Term::Builtin(default_func).force_wrap()
Term::Builtin(default_func).force()
} else {
Term::Builtin(default_func).force_wrap().force_wrap()
Term::Builtin(default_func).force().force()
},
);
}

View File

@ -13,15 +13,15 @@ pub fn has_policy_id(self: Output, policy_id: PolicyId) -> Bool {
|> not
}
validator spend {
fn(_datum: Data, _redeemer: Data, ctx: ScriptContext) -> Bool {
validator {
fn spend(_datum: Data, _redeemer: Data, ctx: ScriptContext) -> Bool {
ctx.transaction.outputs
|> list.any(has_policy_id(_, my_policy_id))
}
}
validator mint(output_reference: OutputReference) {
fn(_redeemer: Void, ctx: ScriptContext) -> Bool {
validator (output_reference: OutputReference) {
fn mint(_redeemer: Void, ctx: ScriptContext) -> Bool {
when
list.find(
ctx.transaction.inputs,

View File

@ -1,5 +1,5 @@
validator spend {
fn(_datum: Void, _redeemer: Void, _ctx: Void) -> Bool {
validator {
fn spend(_datum: Void, _redeemer: Void, _ctx: Void) -> Bool {
True
}
}

View File

@ -5,8 +5,8 @@ fn when_tuple(a: (Int, Int)) -> Int {
}
}
validator spend {
fn(a: Data, b: Data, c) -> Bool {
validator {
fn spend(a: Data, b: Data, c) -> Bool {
when_tuple((4, 1)) == 4
}
}

View File

@ -96,8 +96,8 @@ pub fn validate_pool_borrow(
True
}
validator pool_contract {
fn(datum: PoolDatum, redeemer: PoolRedeemer, ctx: ScriptContext) {
validator {
fn pool_contract(datum: PoolDatum, redeemer: PoolRedeemer, ctx: ScriptContext) {
when redeemer.action is {
PoolWithdraw(_) ->
True

View File

@ -2,8 +2,8 @@ use aiken/list.{find, foldr}
use aiken/transaction.{Input, ScriptContext, Spend}
use aiken/transaction/value.{add, zero}
validator staking {
fn(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
validator {
fn staking(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
expect Spend(ref) =
context.purpose

View File

@ -1,8 +1,8 @@
use aiken/list
use aiken/transaction.{Output, ScriptContext}
validator backtrace {
fn(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
validator {
fn backtrace(_datum: Void, _redeemer: Void, context: ScriptContext) -> Bool {
expect Some(_) =
list.find(context.transaction.outputs, fn(_) { True })
let _ =

View File

@ -0,0 +1,5 @@
# This file was generated by Aiken
# You typically do not need to edit this file
requirements = []
packages = []

View File

@ -0,0 +1,2 @@
name = "aiken-lang/acceptance_test_079"
version = "0.0.0"

View File

@ -0,0 +1,57 @@
{
"preamble": {
"title": "aiken-lang/acceptance_test_079",
"version": "0.0.0",
"plutusVersion": "v2"
},
"validators": [
{
"title": "foo.spend",
"datum": {
"title": "datum",
"schema": {
"$ref": "#/definitions/Int"
}
},
"redeemer": {
"title": "redeemer",
"schema": {
"$ref": "#/definitions/RedeemerWrapper$Int"
}
},
"compiledCode": "58a7010000323232323232323232322253330063370e900018041baa0011332253330083370e004902a0a4c2c6eb40080044cc88c894ccc028cdc399b800040024815052616375a0026eb4008c02cc8c028dd50008009119199800800a4000006444666601066e1c0100080348ccc010010cdc0001a4004601e0020026002002444a666010004293099802980098048011998018019805001000ab9a5736aae7555cf2ab9f5742ae89",
"hash": "d5e5d02c9a5b71045eb8a0cfabd036d3a89bc3a403491bbff65a9621"
},
{
"title": "foo.mint",
"redeemer": {
"title": "redeemer",
"schema": {
"$ref": "#/definitions/Int"
}
},
"compiledCode": "58a7010000323232323232323232322253330063370e900018041baa0011332253330083370e004902a0a4c2c6eb40080044cc88c894ccc028cdc399b800040024815052616375a0026eb4008c02cc8c028dd50008009119199800800a4000006444666601066e1c0100080348ccc010010cdc0001a4004601e0020026002002444a666010004293099802980098048011998018019805001000ab9a5736aae7555cf2ab9f5742ae89",
"hash": "d5e5d02c9a5b71045eb8a0cfabd036d3a89bc3a403491bbff65a9621"
}
],
"definitions": {
"Int": {
"dataType": "integer"
},
"RedeemerWrapper$Int": {
"title": "Wrapped Redeemer",
"description": "A redeemer wrapped in an extra constructor to make multi-validator detection possible on-chain.",
"anyOf": [
{
"dataType": "constructor",
"index": 1,
"fields": [
{
"$ref": "#/definitions/Int"
}
]
}
]
}
}
}

View File

@ -0,0 +1,9 @@
validator {
fn spend(datum: Int, redeemer: Int, _context: Data) {
datum + redeemer == 42
}
fn mint(redeemer: Int, _context: Data) {
redeemer == 42
}
}

View File

@ -6,91 +6,83 @@
},
"validators": [
{
"title": "deploy.spend",
"title": "basic.spend",
"datum": {
"title": "Data",
"description": "Any Plutus data.",
"schema": {}
"title": "_datum",
"schema": {
"$ref": "#/definitions/Void"
}
},
"redeemer": {
"title": "Data",
"description": "Any Plutus data.",
"schema": {}
"title": "_redeemer",
"schema": {
"$ref": "#/definitions/Void"
}
},
"compiledCode": "5903e101000032323232323232323232322225333006323232323230020013301033300a32323375e0040026601893260103d87980000074c103d87a80004c0103d87980003301033300a32323232323232330123253330123370e002900009919299980c980e0010a4c2a6602c921364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375a603400260180042a660289212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630143754002a66602266ebd30106d8799f182aff0000113370e64600a00200690020a50301700130093253330103370e900018099baa0011001153301249012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163322330060020010013237280026ecd30106d8799f182aff0037566600e60106600e6010012900024028600200244a6660260022900009919b8048008cc00c00c004c058004c0040048894ccc0480084cdd2a400497ae013232323253330113371e00a002266e952000330170024bd7009998038038018029bae30130033013002301600330140024c0103d87a80004c0103d87980003301033300a32533301000116132533301100116132323232533301032323009001330173330113375e660146016002900226126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff004c0103d87a80004c0103d8798000330173330113375e6601460160029003260122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff004c0103d87a80004c0103d87980004bd700010991918048009980b99980899baf3300a300b3300a300b0014800120024c012ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff004c0103d87a80004c0103d879800033017333011323253330133370e0029002099251300d00216301537540026601460160029002260103d87a80004c0103d87980004bd700008a50301600430150041630140013013001375866006600866006600800a900024008980103d87a80004c0103d87980004bd7018008009129998078008a5113232533300c00213300400400114a0602600466e1d2002300d3754602200244646660020029000001911199980619b870040020132333004004337000069001180a800800918059baa001149858c0040048894ccc0240085261330053001300b002333003003300c0020015734ae6d5ce2ab9d5573caae7d5d02ba15745",
"hash": "3326c651fce284b443e23da9cc6f5864a1e496f2fc7774799fb897f9"
"compiledCode": "5904600100003232323232323232323222253330063232323232300200132323232323233015333010323330113375e660146016002900b26126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff004a0944cc024c02802d20004c0103d87a80004c0103d879800033015333010323253330123370e002900109919299980a19baf3300d300e00148001300126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff0013370e6eb4cc034c038005200248000528180c80098060010b18099baa00133009300a00b48009300103d87a80004c0103d8798000330153330103232533301600116132533301700113232300c001330193330143375e6e98dd5998069807000a40046e98c0152080a8d6b9074c0103d87a80004c0103d8798000330193330143375e6601a601c6601a601c002900024000980122d8799f581c11111111111111111111111111111111111111111111111111111111ff004c0103d87a80004c0103d879800033019333014323253330163370e0029000099250301000214a2602e6ea8004cc034c038cc034c038005200048009300103d87a80004c0103d8798000330193330143375e6601a601c002900219ba5480012f5c098103d87a80004c0103d8798000330193330143375e6601a601c002900319ba5480092f5c098103d87a80004c0103d87980004bd70180c8010b180c8009bac3300a300b00148010cc024c02802d20004c0103d87a80004c0103d879800033015333010323375e6e98dd5998051805800a400c6e98c009205433009300a00b4800130103d87a80004c0103d87980004bd7011999111919000999991111999805002001801000a5eb7bdb180010004020cccc8888cccc03001000c0080052f5bded8c000400200e9101004881000013001001222225333016004133017337606ea400cdd300125eb7bdb1804c8c8c8c94ccc058cdd79980280380099ba5480012f5c026603666ec0dd48039ba6006008153330163371e00e00226603666ec0dd48039ba600600313301b337606ea4004dd3001199998048048018038030029bae30170033756602e004603400a603000844a66601c66e400080044cdd2a400097ae01533300e3371e004002266e9520024bd70099ba5480112f5c0600200244444a66602600826602866ec0dd48019ba80024bd6f7b630099191919299980999baf330050070013374a900025eb804cc060cdd81ba9007375000c0102a66602666e3c01c0044cc060cdd81ba9007375000c00626603066ec0dd48009ba800233333009009003007006005375c60280066eb4c050008c05c014c054010c004004894ccc0380045288991929998060010998020020008a5030120023370e900118061baa301000122323330010014800000c888cccc030cdc3802001009119980200219b8000348008c0500040048c028dd50008a4c2c6002002444a666010004293099802980098050011998018019805801000ab9a5736aae7555cf2ab9f5740ae855d101",
"hash": "42428cc55092a182161081f528491b8ec1fbd908c40eca9069c4d1be"
},
{
"title": "mint.mint",
"redeemer": {
"title": "redeemer",
"schema": {
"$ref": "#/definitions/Data"
}
},
"compiledCode": "590488010000323232323232323232323222533300532323232323001003300100122533300f00114a226464a6660180042660080080022940c04c008cdc3a4004601a6ea8c044004cc034ccc01cc8c8c8c8c8c8c94ccc04cc0580084c8c8cdc78018009bae3016001300932533300f3370e900018091baa0011001153301149012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300830090034800854cc0412401364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375c602800264646464600c00200200264640026644660100040020029110000137566600c600e6600c600e00290002401000e600200244a666020002297ae01323232323301537520026600c00c0066eb8c04400cdd59808801180a0011809000980080091129998078010a5eb7bdb1804c8c8c8c94ccc038cdc7802800880189980a19bb037520026e98008ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d333007323232323322323232323253330123370e00290010b0991919b87001483c850dd6980d0009806801180a1baa001332233008002001001488103666f6f0033223233223253330153370e00290010801099190009bab301d00130100033017375400400297adef6c6033223300b002001002001375666012601400690040009bae30150013008533300d3370e900018081baa0021002153300f49012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633005300600748008cc014c01801d20003001001222533301100213374a900125eb804c8c8c8c94ccc040cdc7802800899ba548000cc058dd400125eb804ccc01c01c00c014dd718090019bad3012002301500330130023001001222533300f00213374a900125eb804c8c8c8c94ccc038cdc7802800899ba548000cc050dd300125eb804ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d3330073232323233223232533300f3375e006002266e1cc8c018004dd5998049805198049805002240009009240042940c054004c020c94ccc038cdc3a400060226ea8004400454cc0412412a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633223300700200137566600e60106600e60100049000240246600e6010004900100380418008009129998080008a400026466e0120023300300300130130013001001222533300f00213374a900125eb804c8c8c8c94ccc038cdd7802800899ba548000cc0500092f5c0266600e00e00600a6020006602000460260066022004980103d87a80004c0103d87980004bd701119199800800a4000006444666601666e1c0100080488ccc010010cdc0001a40046028002002460146ea8004526163001001222533300900214984cc014c004c02c008ccc00c00cc0300080055cd2b9b5738aae7555cf2ab9f5740ae855d11",
"hash": "4621310698e9ee7830df98d79551eb5672cdee04247e28c8e1c1d494"
},
{
"title": "withdrawals.spend",
"datum": {
"title": "Unit",
"description": "The nullary constructor.",
"title": "_datum",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
"$ref": "#/definitions/Void"
}
},
"redeemer": {
"title": "Unit",
"description": "The nullary constructor.",
"title": "_redeemer",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
"$ref": "#/definitions/Void"
}
},
"compiledCode": "59029101000032323232323232323232222533300632323232323001003300100122533300f00114a226464a66601a0042660080080022940c04c008cdc3a4004601a6ea8c044004c8c8c8cc040ccc02cc8c94ccc034cdc3800a40042c2646466e1c0052054375a6028002600e004601c6ea8004cc004dd5998021802998021802803240009006260126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff004c0103d87a80004c0103d87980003301033300b3232533300d3370e00290010b0991919b8700148070dd6980a000980380118071baa00133001375666008600a66008600a00c90002401898126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004c0103d87a80004c0103d87980003301033300b3375e6e9cc8c8c8c008004dd599803180399803180380424000900618008009129998088008a5eb804c8c8c8c8cc058004cc01801800cc04800cdd69809001180a80118098009ba7330104c0126d8799fd8799f581c22222222222222222222222222222222222222222222222222222222ffff00330104c126d8799fd87a9f581cafddc16c18e7d8de379fb9aad39b3d1b5afd27603e5ebac818432a72ffff004bd7026103d87a80004c0103d87980004bd70111980180100098008009112999807801099ba5480092f5c0264646464a66601e66ebc0140044cdd2a4000660286ea00092f5c0266600e00e00600a60200066eb4c040008c04c00cc04400888c8ccc0040052000003222333300c3370e008004024466600800866e0000d200230140010012300a37540022930b180080091129998040010a4c26600a600260140046660060066016004002ae695cdaab9d5573caae7d5d02ba15745",
"hash": "6917ce2313801b854e38507b68d2c61afd70fca721804235e4760056"
},
{
"title": "mint.mint",
"redeemer": {
"title": "Data",
"description": "Any Plutus data.",
"schema": {}
},
"compiledCode": "590488010000323232323232323232323222533300532323232323001003300100122533300f00114a226464a6660180042660080080022940c04c008cdc3a4004601a6ea8c044004cc034ccc01cc8c8c8c8c8c8c94ccc04cc0580084c8c8cdc78018009bae3016001300932533300f3370e900018091baa0011001153301149012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300830090034800854cc0412401364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375c602800264646464600c00200200264640026644660100040020029110000137566600c600e6600c600e00290002401000e600200244a666020002297ae01323232323301537520026600c00c0066eb8c04400cdd59808801180a0011809000980080091129998078010a5eb7bdb1804c8c8c8c94ccc038cdc7802800880189980a19bb037520026e98008ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d333007323232323322323232323253330123370e00290010b0991919b87001483c850dd6980d0009806801180a1baa001332233008002001001488103666f6f0033223233223253330153370e00290010801099190009bab301d00130100033017375400400297adef6c6033223300b002001002001375666012601400690040009bae30150013008533300d3370e900018081baa0021002153300f49012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633005300600748008cc014c01801d20003001001222533301100213374a900125eb804c8c8c8c94ccc040cdc7802800899ba548000cc058dd400125eb804ccc01c01c00c014dd718090019bad3012002301500330130023001001222533300f00213374a900125eb804c8c8c8c94ccc038cdc7802800899ba548000cc050dd300125eb804ccc01c01c00c014dd718080019bab3010002301300330110024c103d87a80004c0103d87980003300d3330073232323233223232533300f3375e006002266e1cc8c018004dd5998049805198049805002240009009240042940c054004c020c94ccc038cdc3a400060226ea8004400454cc0412412a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001633223300700200137566600e60106600e60100049000240246600e6010004900100380418008009129998080008a400026466e0120023300300300130130013001001222533300f00213374a900125eb804c8c8c8c94ccc038cdd7802800899ba548000cc0500092f5c0266600e00e00600a6020006602000460260066022004980103d87a80004c0103d87980004bd701119199800800a4000006444666601666e1c0100080488ccc010010cdc0001a40046028002002460146ea8004526163001001222533300900214984cc014c004c02c008ccc00c00cc0300080055cd2b9b5738aae7555cf2ab9f5740ae855d11",
"hash": "4621310698e9ee7830df98d79551eb5672cdee04247e28c8e1c1d494"
},
{
"title": "basic.spend",
"title": "deploy.spend",
"datum": {
"title": "Unit",
"description": "The nullary constructor.",
"title": "datum",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
"$ref": "#/definitions/Data"
}
},
"redeemer": {
"title": "Unit",
"description": "The nullary constructor.",
"title": "_redeemer",
"schema": {
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
"$ref": "#/definitions/Data"
}
},
"compiledCode": "59046f0100003232323232323232323222253330063232323232300200132323232323233015333010323330113375e660146016002900b26126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff004a0944cc024c02802d20004c0103d87a80004c0103d879800033015333010323253330123370e002900109919299980a19baf3300d300e00148001300126d8799f58200000000000000000000000000000000000000000000000000000000000000000ff0013370e6eb4cc034c038005200248000528180c80098060010b18099baa00133009300a00b48009300103d87a80004c0103d8798000330153330103232533301600116132533301700113232300c001330193330143375e6e98dd5998069807000a40046e98c0152080a8d6b9074c0103d87a80004c0103d8798000330193330143375e6601a601c6601a601c002900024000980122d8799f581c11111111111111111111111111111111111111111111111111111111ff004c0103d87a80004c0103d879800033019333014323253330163370e0029000099250301000214a2602e6ea8004cc034c038cc034c038005200048009300103d87a80004c0103d8798000330193330143375e6601a601c002900219ba5480012f5c098103d87a80004c0103d8798000330193330143375e6601a601c002900319ba5480092f5c098103d87a80004c0103d87980004bd70180c8010b180c8009bac3300a300b00148010cc024c02802d20004c0103d87a80004c0103d879800033015333010323375e6e98dd5998051805800a400c6e98c009205433009300a00b4800130103d87a80004c0103d87980004bd701199911299980999b870014800052f5bded8c02646400266664444666601400800600400297adef6c6000400100833332222333300c0040030020014bd6f7b630001000803a45004881000013001001222225333016004133017337606ea400cdd300125eb7bdb1804c8c8c8c94ccc058cdd79980280380099ba5480012f5c026603666ec0dd48039ba6006008153330163371e00e00226603666ec0dd48039ba600600313301b337606ea4004dd3001199998048048018038030029bae30170033756602e004603400a603000844a66601c66e400080044cdd2a400097ae01533300e3371e004002266e9520024bd70099ba5480112f5c0600200244444a66602600826602866ec0dd48019ba80024bd6f7b630099191919299980999baf330050070013374a900025eb804cc060cdd81ba9007375000c0102a66602666e3c01c0044cc060cdd81ba9007375000c00626603066ec0dd48009ba800233333009009003007006005375c60280066eb4c050008c05c014c054010c004004894ccc0380045288991929998060010998020020008a5030120023370e900118061baa301000122323330010014800000c888cccc030cdc3802001009119980200219b8000348008c0500040048c028dd50008a4c2c6002002444a666010004293099802980098050011998018019805801000ab9a5736aae7555cf2ab9f5740ae855d101",
"hash": "911eb2bc725e7a51670338f2a12102785984d2569fa75b6ba4054c49"
"compiledCode": "5903e101000032323232323232323232322225333006323232323230020013301033300a32323375e0040026601893260103d87980000074c103d87a80004c0103d87980003301033300a32323232323232330123253330123370e002900009919299980c980e0010a4c2a6602c921364c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2069742065787065637465640016375a603400260180042a660289212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630143754002a66602266ebd30106d8799f182aff0000113370e64600a00200690020a50301700130093253330103370e900018099baa0011001153301249012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163322330060020010013237280026ecd30106d8799f182aff0037566600e60106600e6010012900024028600200244a6660260022900009919b8048008cc00c00c004c058004c0040048894ccc0480084cdd2a400497ae013232323253330113371e00a002266e952000330170024bd7009998038038018029bae30130033013002301600330140024c0103d87a80004c0103d87980003301033300a32533301000116132533301100116132323232533301032323009001330173330113375e660146016002900226126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff004c0103d87a80004c0103d8798000330173330113375e6601460160029003260122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff004c0103d87a80004c0103d87980004bd700010991918048009980b99980899baf3300a300b3300a300b0014800120024c012ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff004c0103d87a80004c0103d879800033017333011323253330133370e0029002099251300d00216301537540026601460160029002260103d87a80004c0103d87980004bd700008a50301600430150041630140013013001375866006600866006600800a900024008980103d87a80004c0103d87980004bd7018008009129998078008a5113232533300c00213300400400114a0602600466e1d2002300d3754602200244646660020029000001911199980619b870040020132333004004337000069001180a800800918059baa001149858c0040048894ccc0240085261330053001300b002333003003300c0020015734ae6d5ce2ab9d5573caae7d5d02ba15745",
"hash": "3326c651fce284b443e23da9cc6f5864a1e496f2fc7774799fb897f9"
}
]
],
"definitions": {
"Data": {
"title": "Data",
"description": "Any Plutus data."
},
"Void": {
"title": "Unit",
"description": "The nullary constructor.",
"anyOf": [
{
"dataType": "constructor",
"index": 0,
"fields": []
}
]
}
}
}

View File

@ -4,8 +4,8 @@ use aiken/transaction.{NoDatum, ScriptContext, Spend, TransactionId}
use aiken/transaction/credential.{VerificationKeyCredential}
use aiken/transaction/value
validator spend {
fn(_datum: Void, _redeemer: Void, ctx: ScriptContext) {
validator {
fn spend(_datum: Void, _redeemer: Void, ctx: ScriptContext) {
[
assert_id(ctx.transaction),
assert_purpose(ctx.purpose),

View File

@ -5,8 +5,8 @@ use aiken/list
use aiken/transaction.{DatumHash, InlineDatum, ScriptContext}
use aiken/transaction/credential.{Inline, VerificationKeyCredential}
validator spend {
fn(datum: Data, _redeemer: Data, ctx: ScriptContext) {
validator {
fn spend(datum: Data, _redeemer: Data, ctx: ScriptContext) {
[
assert_datum(datum),
assert_datums(ctx.transaction.datums),

View File

@ -3,8 +3,8 @@ use aiken/list
use aiken/transaction.{Mint, ScriptContext}
use aiken/transaction/value
validator mint {
fn(redeemer: Data, ctx: ScriptContext) {
validator {
fn mint(redeemer: Data, ctx: ScriptContext) {
[
assert_purpose(ctx),
assert_mint(ctx.purpose, ctx.transaction),

View File

@ -5,8 +5,8 @@ use aiken/transaction/credential.{
Inline, ScriptCredential, VerificationKeyCredential,
}
validator spend {
fn(_datum: Void, _redeemer: Void, ctx: ScriptContext) {
validator {
fn spend(_datum: Void, _redeemer: Void, ctx: ScriptContext) {
let alice =
Inline(
VerificationKeyCredential(