From 643e43f8aaa501bb5b408c4bb38352b87908cd0a Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 27 Jul 2024 11:31:40 +0200 Subject: [PATCH] Fix zero-arg builtins invokations. There are currently two zero-arg builtins: - mkNilData - mkNilPairData And while they have strictly speaking no arguments, the VM still requires that they are called with an extra unit argument applied. --- crates/aiken-lang/src/gen_uplc.rs | 22 +++-- crates/aiken-project/src/tests/gen_uplc.rs | 38 ++++++++ crates/uplc/src/machine/runtime.rs | 104 ++++++++++++++++++--- 3 files changed, 144 insertions(+), 20 deletions(-) diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index 5d35f0eb..7c133519 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -4066,10 +4066,16 @@ impl<'a> CodeGenerator<'a> { builtin, .. } => { - assert!( - builtin.is_none(), - "found remaining builtin function {func_name:?} ({builtin:?} declared as a module function in {module:?}" - ); + if let Some(func) = builtin { + return self.gen_uplc( + Air::Builtin { + count: 0, + func: *func, + tipo: constructor.tipo, + }, + arg_stack, + ); + } if let Some((names, index, cyclic_name)) = self.cyclic_functions.get(&( FunctionAccessKey { @@ -4490,8 +4496,12 @@ impl<'a> CodeGenerator<'a> { term = builder::apply_builtin_forces(term, func.force_count()); - for arg in arg_vec { - term = term.apply(arg.clone()); + if func.arg_is_unit() { + term = term.apply(Term::unit()) + } else { + for arg in arg_vec { + term = term.apply(arg.clone()); + } } term diff --git a/crates/aiken-project/src/tests/gen_uplc.rs b/crates/aiken-project/src/tests/gen_uplc.rs index 68a47f3e..43957288 100644 --- a/crates/aiken-project/src/tests/gen_uplc.rs +++ b/crates/aiken-project/src/tests/gen_uplc.rs @@ -6562,3 +6562,41 @@ fn mk_cons_direct_invoke_3() { false, ) } + +#[test] +fn mk_nil_pair_data() { + let src = r#" + use aiken/builtin.{mk_nil_pair_data} + + test nil_equals() { + mk_nil_pair_data() == mk_nil_pair_data() + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply(Term::map_data().apply(Term::mk_nil_pair_data().apply(Term::unit()))) + .apply(Term::map_data().apply(Term::mk_nil_pair_data().apply(Term::unit()))), + false, + ) +} + +#[test] +fn mk_nil_list_data() { + let src = r#" + use aiken/builtin.{mk_nil_data} + + test nil_equals() { + mk_nil_data() == mk_nil_data() + } + "#; + + assert_uplc( + src, + Term::equals_data() + .apply(Term::list_data().apply(Term::mk_nil_data().apply(Term::unit()))) + .apply(Term::list_data().apply(Term::mk_nil_data().apply(Term::unit()))), + false, + ) +} diff --git a/crates/uplc/src/machine/runtime.rs b/crates/uplc/src/machine/runtime.rs index 77f6a605..9b935038 100644 --- a/crates/uplc/src/machine/runtime.rs +++ b/crates/uplc/src/machine/runtime.rs @@ -1,23 +1,20 @@ -use std::{mem::size_of, ops::Deref, rc::Rc}; - -use num_bigint::BigInt; -use num_integer::Integer; -use num_traits::{Signed, Zero}; -use once_cell::sync::Lazy; -use pallas_primitives::conway::{Language, PlutusData}; - +use super::{ + cost_model::{BuiltinCosts, ExBudget}, + value::{from_pallas_bigint, to_pallas_bigint}, + Error, Value, +}; use crate::{ ast::{Constant, Data, Type}, builtins::DefaultFunction, machine::value::integer_log2, plutus_data_to_bytes, }; - -use super::{ - cost_model::{BuiltinCosts, ExBudget}, - value::{from_pallas_bigint, to_pallas_bigint}, - Error, Value, -}; +use num_bigint::BigInt; +use num_integer::Integer; +use num_traits::{Signed, Zero}; +use once_cell::sync::Lazy; +use pallas_primitives::conway::{Language, PlutusData}; +use std::{mem::size_of, ops::Deref, rc::Rc}; static SCALAR_PERIOD: Lazy = Lazy::new(|| { BigInt::from_bytes_be( @@ -111,6 +108,85 @@ impl From for BuiltinRuntime { } impl DefaultFunction { + pub fn arg_is_unit(&self) -> bool { + match self { + DefaultFunction::MkNilData | DefaultFunction::MkNilPairData => true, + DefaultFunction::AddInteger + | DefaultFunction::SubtractInteger + | DefaultFunction::MultiplyInteger + | DefaultFunction::DivideInteger + | DefaultFunction::QuotientInteger + | DefaultFunction::RemainderInteger + | DefaultFunction::ModInteger + | DefaultFunction::EqualsInteger + | DefaultFunction::LessThanInteger + | DefaultFunction::LessThanEqualsInteger + | DefaultFunction::AppendByteString + | DefaultFunction::ConsByteString + | DefaultFunction::SliceByteString + | DefaultFunction::LengthOfByteString + | DefaultFunction::IndexByteString + | DefaultFunction::EqualsByteString + | DefaultFunction::LessThanByteString + | DefaultFunction::LessThanEqualsByteString + | DefaultFunction::Sha2_256 + | DefaultFunction::Sha3_256 + | DefaultFunction::Blake2b_224 + | DefaultFunction::Blake2b_256 + | DefaultFunction::Keccak_256 + | DefaultFunction::VerifyEd25519Signature + | DefaultFunction::VerifyEcdsaSecp256k1Signature + | DefaultFunction::VerifySchnorrSecp256k1Signature + | DefaultFunction::AppendString + | DefaultFunction::EqualsString + | DefaultFunction::EncodeUtf8 + | DefaultFunction::DecodeUtf8 + | DefaultFunction::IfThenElse + | DefaultFunction::ChooseUnit + | DefaultFunction::Trace + | DefaultFunction::FstPair + | DefaultFunction::SndPair + | DefaultFunction::ChooseList + | DefaultFunction::MkCons + | DefaultFunction::HeadList + | DefaultFunction::TailList + | DefaultFunction::NullList + | DefaultFunction::ChooseData + | DefaultFunction::ConstrData + | DefaultFunction::MapData + | DefaultFunction::ListData + | DefaultFunction::IData + | DefaultFunction::BData + | DefaultFunction::UnConstrData + | DefaultFunction::UnMapData + | DefaultFunction::UnListData + | DefaultFunction::UnIData + | DefaultFunction::UnBData + | DefaultFunction::EqualsData + | DefaultFunction::SerialiseData + | DefaultFunction::MkPairData + | DefaultFunction::Bls12_381_G1_Add + | DefaultFunction::Bls12_381_G1_Neg + | DefaultFunction::Bls12_381_G1_ScalarMul + | DefaultFunction::Bls12_381_G1_Equal + | DefaultFunction::Bls12_381_G1_Compress + | DefaultFunction::Bls12_381_G1_Uncompress + | DefaultFunction::Bls12_381_G1_HashToGroup + | DefaultFunction::Bls12_381_G2_Add + | DefaultFunction::Bls12_381_G2_Neg + | DefaultFunction::Bls12_381_G2_ScalarMul + | DefaultFunction::Bls12_381_G2_Equal + | DefaultFunction::Bls12_381_G2_Compress + | DefaultFunction::Bls12_381_G2_Uncompress + | DefaultFunction::Bls12_381_G2_HashToGroup + | DefaultFunction::Bls12_381_MillerLoop + | DefaultFunction::Bls12_381_MulMlResult + | DefaultFunction::Bls12_381_FinalVerify + | DefaultFunction::IntegerToByteString + | DefaultFunction::ByteStringToInteger => false, + } + } + pub fn arity(&self) -> usize { match self { DefaultFunction::AddInteger => 2,