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:
parent
73522296aa
commit
442010d056
|
@ -49,6 +49,8 @@ pub const SCRIPT_PURPOSE_CONSTRUCTORS: &[&str] = &[
|
||||||
SCRIPT_PURPOSE_PROPOSE,
|
SCRIPT_PURPOSE_PROPOSE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const VALIDATOR_ELSE: &str = "else";
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Types
|
// Types
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>",
|
||||||
|
|
|
@ -69,15 +69,21 @@ impl Validator {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
validators.push(Validator::create_validator_blueprint(
|
// NOTE: Only push the fallback if all other validators have been successfully
|
||||||
generator,
|
// generated. Otherwise, we may fall into scenarios where we cannot generate validators
|
||||||
modules,
|
// (e.g. due to the presence of generics in datum/redeemer), which won't be caught by
|
||||||
module,
|
// the else branch since it lacks arguments.
|
||||||
def,
|
if validators.iter().all(|v| v.is_ok()) {
|
||||||
&def.fallback,
|
validators.push(Validator::create_validator_blueprint(
|
||||||
&mut program,
|
generator,
|
||||||
plutus_version,
|
modules,
|
||||||
));
|
module,
|
||||||
|
def,
|
||||||
|
&def.fallback,
|
||||||
|
&mut program,
|
||||||
|
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,72 +124,83 @@ impl Validator {
|
||||||
})
|
})
|
||||||
.collect::<Result<_, _>>()?;
|
.collect::<Result<_, _>>()?;
|
||||||
|
|
||||||
let datum = datum
|
let (datum, redeemer) = if func.name == well_known::VALIDATOR_ELSE {
|
||||||
.map(|datum| {
|
(None, None)
|
||||||
match datum.tipo.as_ref() {
|
} else {
|
||||||
Type::App { module: module_name, name, args, .. } if module_name.is_empty() && name == well_known::OPTION => {
|
let mut args = func.arguments.iter().rev();
|
||||||
let Some(Annotation::Constructor { arguments, .. }) = datum.annotation.as_ref() else {
|
|
||||||
panic!("Datum isn't an option but should be; this should have been caught by the type-checker!");
|
|
||||||
};
|
|
||||||
|
|
||||||
Annotated::from_type(
|
let (_, _, redeemer, datum) = (
|
||||||
modules.into(),
|
args.next(),
|
||||||
tipo_or_annotation(module, &TypedArg {
|
args.next(),
|
||||||
arg_name: datum.arg_name.clone(),
|
args.next().expect("redeemer is always present"),
|
||||||
|
args.next(),
|
||||||
|
);
|
||||||
|
|
||||||
|
let datum = datum
|
||||||
|
.map(|datum| {
|
||||||
|
match datum.tipo.as_ref() {
|
||||||
|
Type::App { module: module_name, name, args, .. } if module_name.is_empty() && name == well_known::OPTION => {
|
||||||
|
let Some(Annotation::Constructor { arguments, .. }) = datum.annotation.as_ref() else {
|
||||||
|
panic!("Datum isn't an option but should be; this should have been caught by the type-checker!");
|
||||||
|
};
|
||||||
|
|
||||||
|
Annotated::from_type(
|
||||||
|
modules.into(),
|
||||||
|
tipo_or_annotation(module, &TypedArg {
|
||||||
|
arg_name: datum.arg_name.clone(),
|
||||||
|
location: datum.location,
|
||||||
|
annotation: arguments.first().cloned(),
|
||||||
|
doc: datum.doc.clone(),
|
||||||
|
is_validator_param: datum.is_validator_param,
|
||||||
|
tipo: args.first().expect("Option always have a single type argument.").clone()
|
||||||
|
}),
|
||||||
|
&mut definitions,
|
||||||
|
)
|
||||||
|
.map_err(|error| Error::Schema {
|
||||||
|
error,
|
||||||
location: datum.location,
|
location: datum.location,
|
||||||
annotation: arguments.first().cloned(),
|
source_code: NamedSource::new(
|
||||||
doc: datum.doc.clone(),
|
module.input_path.display().to_string(),
|
||||||
is_validator_param: datum.is_validator_param,
|
module.code.clone(),
|
||||||
tipo: args.first().expect("Option always have a single type argument.").clone()
|
),
|
||||||
}),
|
})
|
||||||
&mut definitions,
|
},
|
||||||
)
|
_ => panic!("Datum isn't an option but should be; this should have been caught by the type-checker!"),
|
||||||
.map_err(|error| Error::Schema {
|
}
|
||||||
error,
|
|
||||||
location: datum.location,
|
|
||||||
source_code: NamedSource::new(
|
|
||||||
module.input_path.display().to_string(),
|
|
||||||
module.code.clone(),
|
|
||||||
),
|
|
||||||
})
|
|
||||||
},
|
|
||||||
_ => panic!("Datum isn't an option but should be; this should have been caught by the type-checker!"),
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.transpose()?
|
|
||||||
.map(|schema| Parameter {
|
|
||||||
title: datum.map(|datum| datum.arg_name.get_label()),
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
|
|
||||||
let redeemer = redeemer
|
|
||||||
.map(|redeemer| {
|
|
||||||
Annotated::from_type(
|
|
||||||
modules.into(),
|
|
||||||
tipo_or_annotation(module, redeemer),
|
|
||||||
&mut definitions,
|
|
||||||
)
|
|
||||||
.map_err(|error| Error::Schema {
|
|
||||||
error,
|
|
||||||
location: redeemer.location,
|
|
||||||
source_code: NamedSource::new(
|
|
||||||
module.input_path.display().to_string(),
|
|
||||||
module.code.clone(),
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
|
.transpose()?
|
||||||
|
.map(|schema| Parameter {
|
||||||
|
title: datum.map(|datum| datum.arg_name.get_label()),
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
|
||||||
|
let redeemer = Annotated::from_type(
|
||||||
|
modules.into(),
|
||||||
|
tipo_or_annotation(module, redeemer),
|
||||||
|
&mut definitions,
|
||||||
|
)
|
||||||
|
.map_err(|error| Error::Schema {
|
||||||
|
error,
|
||||||
|
location: redeemer.location,
|
||||||
|
source_code: NamedSource::new(
|
||||||
|
module.input_path.display().to_string(),
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in New Issue