From 7741be64f8bd40c9a348f3794e73089fe8226be7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Tue, 10 Sep 2024 10:47:41 +0200 Subject: [PATCH] Fix validator's fallback handler generation Fixes #1015. --- CHANGELOG.md | 1 + crates/aiken-lang/src/ast.rs | 35 ++++--- .../ctx/simple_else/resolved_inputs.template | 6 ++ .../v3/ctx/simple_else/tx.template | 33 +++++++ .../v3/validators/simple_else.ak | 95 +++++++++++++++++++ 5 files changed, 155 insertions(+), 15 deletions(-) create mode 100644 examples/acceptance_tests/script_context/v3/ctx/simple_else/resolved_inputs.template create mode 100644 examples/acceptance_tests/script_context/v3/ctx/simple_else/tx.template create mode 100644 examples/acceptance_tests/script_context/v3/validators/simple_else.ak diff --git a/CHANGELOG.md b/CHANGELOG.md index 4640505a..a0a99974 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Changed +- **aiken-lang**: Fix validator's else handler generation. See [#1015](https://github.com/aiken-lang/aiken/issues/1015) @KtorZ - **aiken-lang**: Fix underflow in error message reported by the validator arity. See [#1013](https://github.com/aiken-lang/aiken/issues/1013) @KtorZ - **aiken-lang**: Fix list-pattern needlessly formatting over multiple lines. @KtorZ - **aiken-lang**: Fix formatter on long alternative patterns spanning over multiple lines. @KtorZ diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 677dcf17..02675c0e 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -714,25 +714,30 @@ impl TypedValidator { .chain(std::iter::once(&self.fallback).map(|fallback| { let arg = fallback.arguments.first().unwrap(); - let then = &[ - TypedExpr::let_( - TypedExpr::local_var(var_context, arg.tipo.clone(), arg.location), - arg.get_variable_name().map(TypedPattern::var).unwrap_or( - TypedPattern::Discard { - name: var_context.to_string(), - location: arg.location, - }, + let then = match arg.get_variable_name() { + Some(arg_name) => TypedExpr::sequence(&[ + TypedExpr::let_( + TypedExpr::local_var( + var_context, + arg.tipo.clone(), + arg.location, + ), + TypedPattern::var(arg_name), + arg.tipo.clone(), + arg.location, ), - arg.tipo.clone(), - arg.location, - ), - fallback.body.clone(), - ]; + fallback.body.clone(), + ]), + None => fallback.body.clone(), + }; TypedClause { location: Span::empty(), - pattern: TypedPattern::var(var_context), - then: TypedExpr::sequence(then), + pattern: TypedPattern::Discard { + name: "_".to_string(), + location: arg.location, + }, + then, } })) .collect(), diff --git a/examples/acceptance_tests/script_context/v3/ctx/simple_else/resolved_inputs.template b/examples/acceptance_tests/script_context/v3/ctx/simple_else/resolved_inputs.template new file mode 100644 index 00000000..9408beef --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/ctx/simple_else/resolved_inputs.template @@ -0,0 +1,6 @@ +[ + { 0: h'70{{ simple_else.simple_else.else.hash }}' + , 1: 1000000000 + , 2: [1, 24(h'd87980')] + } +] diff --git a/examples/acceptance_tests/script_context/v3/ctx/simple_else/tx.template b/examples/acceptance_tests/script_context/v3/ctx/simple_else/tx.template new file mode 100644 index 00000000..ac9168ff --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/ctx/simple_else/tx.template @@ -0,0 +1,33 @@ +[ + { 0: + [ [h'0000000000000000000000000000000000000000000000000000000000000000', 0] + ] + + , 1: + [] + + , 2: 42 + + , 11: h'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' + + , 13: + [ [h'0000000000000000000000000000000000000000000000000000000000000000', 0] + ] + + , 16: + [ h'6000000000000000000000000000000000000000000000000000000000', 1000000000 + ] + + , 17: 1 + }, + + { 5: [[0, 0, 121([]), [1000000, 100000000]]] + + , 7: [h'{{ simple_else.simple_else.else.cbor }}'] + + }, + + true, + + null +] diff --git a/examples/acceptance_tests/script_context/v3/validators/simple_else.ak b/examples/acceptance_tests/script_context/v3/validators/simple_else.ak new file mode 100644 index 00000000..5183b078 --- /dev/null +++ b/examples/acceptance_tests/script_context/v3/validators/simple_else.ak @@ -0,0 +1,95 @@ +use aiken/collection/dict +use cardano/address.{Address, Script} +use cardano/assets +use cardano/script_context.{ScriptContext, Spending} +use cardano/transaction.{ + InlineDatum, Input, Output, OutputReference, ScriptPurpose, Spend, Transaction, +} + +validator simple_else { + else(ctx: ScriptContext) { + expect Spending(output_ref, _) = ctx.info + + let transaction = ctx.transaction + + assert_transaction_id(transaction.id) + + assert_script_info(output_ref) + + assert_inputs(transaction.inputs) + + expect [] = transaction.outputs + + expect [] = transaction.reference_inputs + + expect [] = transaction.extra_signatories + + expect 42 == transaction.fee + + assert_redeemers(transaction.redeemers) + + expect [] == dict.to_pairs(transaction.datums) + + True + } +} + +fn assert_transaction_id(id: ByteArray) { + expect + #"c6fbd346681a8f8337f6b3e51e6ec973f1509367eabc3a44c849af58a1d8471b" == id + Void +} + +fn assert_script_info(info: OutputReference) { + expect + OutputReference { + transaction_id: #"0000000000000000000000000000000000000000000000000000000000000000", + output_index: 0, + } == info + Void +} + +fn assert_inputs(inputs: List) { + expect [ + Input { + output_reference: OutputReference { transaction_id, output_index: 0 }, + output: Output { + address, + value: resolved_input_value, + datum: InlineDatum(_), + reference_script: None, + }, + }, + ] = inputs + + expect + transaction_id == #"0000000000000000000000000000000000000000000000000000000000000000" + + expect resolved_input_value == assets.from_lovelace(1000000000) + + expect Address { payment_credential: Script(_), stake_credential: None } = + address + + Void +} + +fn assert_redeemers(redeemers: Pairs) { + expect + [ + Pair( + Spend( + OutputReference { + transaction_id: #"0000000000000000000000000000000000000000000000000000000000000000", + output_index: 0, + }, + ), + void(), + ), + ] == redeemers + Void +} + +fn void() -> Data { + let void: Data = Void + void +}