Fix generation of fallback validator

This must only happen in case all other validator succeed; otherwise
  we might generate invalid validators.
This commit is contained in:
KtorZ 2024-08-24 11:15:56 +02:00
parent 73522296aa
commit 442010d056
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
4 changed files with 89 additions and 70 deletions

View File

@ -49,6 +49,8 @@ pub const SCRIPT_PURPOSE_CONSTRUCTORS: &[&str] = &[
SCRIPT_PURPOSE_PROPOSE, SCRIPT_PURPOSE_PROPOSE,
]; ];
pub const VALIDATOR_ELSE: &str = "else";
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Types // Types

View File

@ -1575,7 +1575,11 @@ impl<'a> CodeGenerator<'a> {
otherwise: AirTree, otherwise: AirTree,
depth: usize, depth: usize,
) -> AirTree { ) -> AirTree {
assert!(tipo.get_generic().is_none()); assert!(
tipo.get_generic().is_none(),
"left-hand side of expect is generic: {}",
tipo.to_pretty(0)
);
// Shouldn't be needed but still here just in case // Shouldn't be needed but still here just in case
// this function is called from anywhere else besides assignment // this function is called from anywhere else besides assignment
let tipo = &convert_opaque_type(tipo, &self.data_types, true); let tipo = &convert_opaque_type(tipo, &self.data_types, true);

View File

@ -1,6 +1,6 @@
--- ---
source: crates/aiken-project/src/blueprint/validator.rs source: crates/aiken-project/src/blueprint/validator.rs
description: "Code:\n\nvalidator {\n fn generics(redeemer: a, ctx: Void) {\n True\n }\n}\n" description: "Code:\n\nvalidator generics {\n mint(redeemer: a, policy_id: ByteArray, transaction: Data) {\n True\n }\n}\n"
--- ---
Schema { Schema {
error: Error { error: Error {
@ -16,7 +16,7 @@ Schema {
}, },
], ],
}, },
location: 26..37, location: 28..39,
source_code: NamedSource { source_code: NamedSource {
name: "", name: "",
source: "<redacted>", source: "<redacted>",

View File

@ -69,6 +69,11 @@ impl Validator {
)); ));
} }
// NOTE: Only push the fallback if all other validators have been successfully
// generated. Otherwise, we may fall into scenarios where we cannot generate validators
// (e.g. due to the presence of generics in datum/redeemer), which won't be caught by
// the else branch since it lacks arguments.
if validators.iter().all(|v| v.is_ok()) {
validators.push(Validator::create_validator_blueprint( validators.push(Validator::create_validator_blueprint(
generator, generator,
modules, modules,
@ -78,6 +83,7 @@ impl Validator {
&mut program, &mut program,
plutus_version, plutus_version,
)); ));
}
validators validators
} }
@ -92,10 +98,6 @@ impl Validator {
program: &mut MemoProgram, program: &mut MemoProgram,
plutus_version: &PlutusVersion, plutus_version: &PlutusVersion,
) -> Result<Validator, Error> { ) -> Result<Validator, Error> {
let mut args = func.arguments.iter().rev();
let (_, _, redeemer, datum) = (args.next(), args.next(), args.next(), args.next());
let mut definitions = Definitions::new(); let mut definitions = Definitions::new();
let parameters = def let parameters = def
@ -122,6 +124,18 @@ impl Validator {
}) })
.collect::<Result<_, _>>()?; .collect::<Result<_, _>>()?;
let (datum, redeemer) = if func.name == well_known::VALIDATOR_ELSE {
(None, None)
} else {
let mut args = func.arguments.iter().rev();
let (_, _, redeemer, datum) = (
args.next(),
args.next(),
args.next().expect("redeemer is always present"),
args.next(),
);
let datum = datum let datum = datum
.map(|datum| { .map(|datum| {
match datum.tipo.as_ref() { match datum.tipo.as_ref() {
@ -160,9 +174,7 @@ impl Validator {
schema, schema,
}); });
let redeemer = redeemer let redeemer = Annotated::from_type(
.map(|redeemer| {
Annotated::from_type(
modules.into(), modules.into(),
tipo_or_annotation(module, redeemer), tipo_or_annotation(module, redeemer),
&mut definitions, &mut definitions,
@ -175,19 +187,20 @@ impl Validator {
module.code.clone(), module.code.clone(),
), ),
}) })
})
.transpose()?
.map(|schema| Parameter { .map(|schema| Parameter {
title: redeemer.map(|redeemer| redeemer.arg_name.get_label()), title: Some(redeemer.arg_name.get_label()),
schema, schema,
}); })?;
(datum, Some(redeemer))
};
Ok(Validator { Ok(Validator {
title: format!( title: format!(
"{}.{}_{}", "{}.{}_{}",
&module.name, &module.name,
&def.name, &def.name,
if func.name == "else" { if func.name == well_known::VALIDATOR_ELSE {
"__fallback" "__fallback"
} else { } else {
&func.name &func.name