mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-24 07:48:04 +03:00
support conditional console functions
This commit is contained in:
parent
b2866951f6
commit
4533915438
@ -1,6 +1,6 @@
|
||||
//! Enforces an assert equals statement in a compiled Leo program.
|
||||
|
||||
use crate::{errors::ConsoleError, evaluate_eq, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use crate::{errors::ConsoleError, program::ConstrainedProgram, value::ConstrainedValue, GroupType};
|
||||
use leo_typed::{Expression, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
@ -14,6 +14,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
indicator: Option<Boolean>,
|
||||
expression: Expression,
|
||||
span: Span,
|
||||
) -> Result<(), ConsoleError> {
|
||||
@ -23,21 +24,27 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
// Evaluate assert expression
|
||||
let assert_expression = self.enforce_expression(cs, file_scope, function_scope, expected_type, expression)?;
|
||||
|
||||
// Expect assert expression to evaluate to true
|
||||
let expect_true = ConstrainedValue::Boolean(Boolean::Constant(true));
|
||||
let result = evaluate_eq(cs, expect_true, assert_expression, span.clone())?;
|
||||
// If the indicator bit is false, do not evaluate the assertion
|
||||
// This is okay since we are not enforcing any constraints
|
||||
let false_boolean = Boolean::Constant(false);
|
||||
|
||||
if let Some(indicator_bool) = indicator {
|
||||
if indicator_bool.eq(&false_boolean) {
|
||||
return Ok(()); // continue execution
|
||||
}
|
||||
}
|
||||
|
||||
// Unwrap assertion value and handle errors
|
||||
let result_option = match result {
|
||||
let result_option = match assert_expression {
|
||||
ConstrainedValue::Boolean(boolean) => boolean.get_value(),
|
||||
_ => unreachable!("evaluate_eq must return boolean"),
|
||||
_ => return Err(ConsoleError::assertion_must_be_boolean(expression_string, span.clone())),
|
||||
};
|
||||
let result_bool = result_option.ok_or(ConsoleError::assertion_depends_on_input(span.clone()))?;
|
||||
|
||||
if !result_bool {
|
||||
Err(ConsoleError::assertion_failed(expression_string, span))
|
||||
} else {
|
||||
return Err(ConsoleError::assertion_failed(expression_string, span));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use leo_typed::{ConsoleFunction, ConsoleFunctionCall};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
|
||||
};
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
@ -14,29 +14,49 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
cs: &mut CS,
|
||||
file_scope: String,
|
||||
function_scope: String,
|
||||
indicator: Option<Boolean>,
|
||||
console: ConsoleFunctionCall,
|
||||
) -> Result<(), ConsoleError> {
|
||||
match console.function {
|
||||
ConsoleFunction::Assert(expression) => {
|
||||
self.evaluate_console_assert(cs, file_scope, function_scope, expression, console.span)?;
|
||||
self.evaluate_console_assert(cs, file_scope, function_scope, indicator, expression, console.span)?;
|
||||
}
|
||||
ConsoleFunction::Debug(string) => {
|
||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
||||
|
||||
if unwrap_indicator_value(indicator) {
|
||||
log::debug!("{}", string);
|
||||
}
|
||||
}
|
||||
ConsoleFunction::Error(string) => {
|
||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
||||
|
||||
if unwrap_indicator_value(indicator) {
|
||||
log::error!("{}", string);
|
||||
}
|
||||
}
|
||||
ConsoleFunction::Log(string) => {
|
||||
let string = self.format(cs, file_scope, function_scope, string)?;
|
||||
|
||||
println!("{}", string);
|
||||
if unwrap_indicator_value(indicator) {
|
||||
log::info!("{}", string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Return the indicator boolean gadget value or true if it is None
|
||||
// This is okay since we are not enforcing any constraints
|
||||
fn unwrap_indicator_value(indicator: Option<Boolean>) -> bool {
|
||||
let false_boolean = Boolean::constant(false);
|
||||
|
||||
if let Some(indicator_bool) = indicator {
|
||||
if indicator_bool.eq(&false_boolean) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -40,7 +40,13 @@ impl ConsoleError {
|
||||
}
|
||||
|
||||
pub fn assertion_failed(expression: String, span: Span) -> Self {
|
||||
let message = format!("Assertion `true == {}` failed", expression);
|
||||
let message = format!("Assertion `{}` failed", expression);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn assertion_must_be_boolean(expression: String, span: Span) -> Self {
|
||||
let message = format!("Assertion expression `{}` must evaluate to a boolean value", expression);
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use leo_typed::{Expression, Function, InputVariable, Span, Type};
|
||||
|
||||
use snarkos_models::{
|
||||
curves::{Field, PrimeField},
|
||||
gadgets::r1cs::ConstraintSystem,
|
||||
gadgets::{r1cs::ConstraintSystem, utilities::boolean::Boolean},
|
||||
};
|
||||
|
||||
pub fn check_arguments_length(expected: usize, actual: usize, span: Span) -> Result<(), FunctionError> {
|
||||
@ -78,6 +78,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
|
||||
// Evaluate every statement in the function and save all potential results
|
||||
let mut results = vec![];
|
||||
let indicator = Some(Boolean::constant(true));
|
||||
|
||||
for statement in function.statements.iter() {
|
||||
let mut result = self.enforce_statement(
|
||||
|
@ -1,5 +0,0 @@
|
||||
pub mod format;
|
||||
pub use self::format::*;
|
||||
|
||||
pub mod macro_;
|
||||
pub use self::macro_::*;
|
@ -78,7 +78,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> ConstrainedProgram<F, G> {
|
||||
results.append(&mut result);
|
||||
}
|
||||
Statement::Console(console) => {
|
||||
self.evaluate_console_function_call(cs, file_scope, function_scope, console)?;
|
||||
self.evaluate_console_function_call(cs, file_scope, function_scope, indicator, console)?;
|
||||
}
|
||||
Statement::Expression(expression, span) => {
|
||||
let expression_string = expression.to_string();
|
||||
|
@ -2,6 +2,7 @@ pub mod address;
|
||||
pub mod array;
|
||||
pub mod boolean;
|
||||
pub mod circuits;
|
||||
pub mod console;
|
||||
pub mod definition;
|
||||
pub mod field;
|
||||
pub mod function;
|
||||
@ -9,7 +10,6 @@ pub mod group;
|
||||
pub mod import;
|
||||
pub mod input_files;
|
||||
pub mod integers;
|
||||
pub mod macros;
|
||||
pub mod mutability;
|
||||
pub mod statements;
|
||||
pub mod syntax;
|
||||
|
Loading…
Reference in New Issue
Block a user