mirror of
https://github.com/ProvableHQ/leo.git
synced 2024-11-28 01:01:53 +03:00
add parsing for .in and .state files and update errors
This commit is contained in:
parent
3d3e8f5e72
commit
ac8c940169
@ -32,10 +32,10 @@ pub struct Compiler<F: Field + PrimeField, G: GroupType<F>> {
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
pub fn new(package_name: String) -> Self {
|
||||
pub fn new(package_name: String, main_file_path: PathBuf) -> Self {
|
||||
Self {
|
||||
package_name: package_name.clone(),
|
||||
main_file_path: PathBuf::new(),
|
||||
main_file_path,
|
||||
program: Program::new(package_name),
|
||||
program_inputs: Inputs::new(),
|
||||
imported_programs: ImportParser::new(),
|
||||
@ -44,37 +44,48 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_from_path(
|
||||
package_name: String,
|
||||
main_file_path: PathBuf,
|
||||
inputs_string: &str,
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut compiler = Self::new(package_name);
|
||||
compiler.set_path(main_file_path);
|
||||
/// Parses program files.
|
||||
/// Returns a compiler struct that stores the typed program abstract syntax trees (ast).
|
||||
pub fn parse_program_without_inputs(package_name: String, main_file_path: PathBuf) -> Result<Self, CompilerError> {
|
||||
let mut compiler = Self::new(package_name, main_file_path);
|
||||
|
||||
// Generate the inputs file abstract syntax tree and store definitions
|
||||
compiler.parse_inputs(inputs_string)?;
|
||||
|
||||
// Generate the program abstract syntax tree and assemble the program
|
||||
let program_string = compiler.load_program()?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
|
||||
pub fn set_path(&mut self, main_file_path: PathBuf) {
|
||||
self.main_file_path = main_file_path
|
||||
/// Parses input, state, and program files.
|
||||
/// Returns a compiler struct that stores the typed inputs and typed program abstract syntax trees (ast).
|
||||
pub fn parse_program_with_inputs(
|
||||
package_name: String,
|
||||
main_file_path: PathBuf,
|
||||
inputs_string: &str,
|
||||
state_string: &str,
|
||||
) -> Result<Self, CompilerError> {
|
||||
let mut compiler = Self::new(package_name, main_file_path);
|
||||
|
||||
compiler.parse_inputs(inputs_string, state_string)?;
|
||||
|
||||
let program_string = compiler.load_program()?;
|
||||
compiler.parse_program(&program_string)?;
|
||||
|
||||
Ok(compiler)
|
||||
}
|
||||
|
||||
pub fn set_inputs(&mut self, program_inputs: MainInputs) {
|
||||
self.program_inputs.set_main_inputs(program_inputs);
|
||||
}
|
||||
|
||||
fn load_program(&mut self) -> Result<String, CompilerError> {
|
||||
// Load the program syntax tree from the file path
|
||||
Ok(LeoParser::load_file(&self.main_file_path)?)
|
||||
/// Parse the input and state files.
|
||||
/// Stores a typed ast of all inputs to the program.
|
||||
pub fn parse_inputs(&mut self, inputs_string: &str, state_string: &str) -> Result<(), CompilerError> {
|
||||
let inputs_syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
|
||||
let state_syntax_tree = LeoInputsParser::parse_file(&state_string)?;
|
||||
|
||||
self.program_inputs.parse_inputs(inputs_syntax_tree)?;
|
||||
self.program_inputs.parse_state(state_syntax_tree)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse the program file and all associated import files.
|
||||
pub fn parse_program(&mut self, program_string: &str) -> Result<(), CompilerError> {
|
||||
// Parse the program syntax tree
|
||||
let syntax_tree = LeoParser::parse_file(&self.main_file_path, program_string)?;
|
||||
@ -90,12 +101,14 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_inputs(&mut self, inputs_string: &str) -> Result<(), CompilerError> {
|
||||
let syntax_tree = LeoInputsParser::parse_file(&inputs_string)?;
|
||||
/// Loads the program file at `main_file_path`.
|
||||
fn load_program(&mut self) -> Result<String, CompilerError> {
|
||||
Ok(LeoParser::load_file(&self.main_file_path)?)
|
||||
}
|
||||
|
||||
self.program_inputs.parse(syntax_tree)?;
|
||||
|
||||
Ok(())
|
||||
/// Manually set the inputs to the `main` program function.
|
||||
pub fn set_main_inputs(&mut self, program_inputs: MainInputs) {
|
||||
self.program_inputs.set_main_inputs(program_inputs);
|
||||
}
|
||||
|
||||
pub fn checksum(&self) -> Result<String, CompilerError> {
|
||||
@ -111,6 +124,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
Ok(hex::encode(hash))
|
||||
}
|
||||
|
||||
/// Synthesizes the circuit without program inputs to verify correctness.
|
||||
pub fn compile_constraints<CS: ConstraintSystem<F>>(
|
||||
self,
|
||||
cs: &mut CS,
|
||||
@ -125,6 +139,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Synthesizes the circuit for test functions with program inputs.
|
||||
pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem<F>) -> Result<(), CompilerError> {
|
||||
generate_test_constraints::<F, G>(cs, self.program, self.program_inputs, &self.imported_programs)
|
||||
}
|
||||
@ -150,6 +165,7 @@ impl<F: Field + PrimeField, G: GroupType<F>> Compiler<F, G> {
|
||||
}
|
||||
|
||||
impl<F: Field + PrimeField, G: GroupType<F>> ConstraintSynthesizer<F> for Compiler<F, G> {
|
||||
/// Synthesizes the circuit with program inputs.
|
||||
fn generate_constraints<CS: ConstraintSystem<F>>(self, cs: &mut CS) -> Result<(), SynthesisError> {
|
||||
let result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs, &self.imported_programs)
|
||||
.map_err(|e| {
|
||||
|
@ -80,7 +80,7 @@ fn test_input_pass() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Address(TEST_ADDRESS_1.to_string()))]);
|
||||
|
||||
let _output = get_output(program);
|
||||
}
|
||||
@ -90,7 +90,7 @@ fn test_input_fail_bool() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
|
||||
let _err = get_error(program);
|
||||
}
|
||||
@ -101,11 +101,11 @@ fn test_ternary() {
|
||||
let mut program_1 = parse_program(bytes).unwrap();
|
||||
let mut program_2 = program_1.clone();
|
||||
|
||||
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
|
||||
output_test_address(program_1, TEST_ADDRESS_1);
|
||||
|
||||
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_2.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
|
||||
output_test_address(program_2, TEST_ADDRESS_2);
|
||||
}
|
||||
@ -116,14 +116,14 @@ fn test_equal() {
|
||||
let mut program_1 = parse_program(bytes).unwrap();
|
||||
let mut program_2 = program_1.clone();
|
||||
|
||||
program_1.set_inputs(vec![
|
||||
program_1.set_main_inputs(vec![
|
||||
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
|
||||
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
|
||||
]);
|
||||
|
||||
output_true(program_1);
|
||||
|
||||
program_2.set_inputs(vec![
|
||||
program_2.set_main_inputs(vec![
|
||||
Some(InputValue::Address(TEST_ADDRESS_1.to_string())),
|
||||
Some(InputValue::Address(TEST_ADDRESS_2.to_string())),
|
||||
]);
|
||||
|
@ -107,7 +107,7 @@ fn test_input_array() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Array(vec![input_value_u32_one(); 3]))]);
|
||||
|
||||
output_ones(program)
|
||||
}
|
||||
@ -117,7 +117,7 @@ fn test_input_array_fail() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(input_value_u32_one())]);
|
||||
program.set_main_inputs(vec![Some(input_value_u32_one())]);
|
||||
|
||||
fail_array(program);
|
||||
}
|
||||
@ -127,7 +127,7 @@ fn test_input_field_none() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![None]);
|
||||
program.set_main_inputs(vec![None]);
|
||||
|
||||
fail_integer(program)
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ fn test_input_bool_field() {
|
||||
let bytes = include_bytes!("input_bool.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Field("1field".to_string()))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Field("1field".to_string()))]);
|
||||
|
||||
fail_boolean(program);
|
||||
}
|
||||
@ -70,7 +70,7 @@ fn test_input_bool_none() {
|
||||
let bytes = include_bytes!("input_bool.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![None]);
|
||||
program.set_main_inputs(vec![None]);
|
||||
|
||||
fail_boolean(program);
|
||||
}
|
||||
|
@ -83,7 +83,7 @@ fn test_input_pass() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Field("1".into()))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Field("1".into()))]);
|
||||
|
||||
let cs = TestConstraintSystem::<Fq>::new();
|
||||
let expected = FqGadget::one(cs).unwrap();
|
||||
@ -96,7 +96,7 @@ fn test_input_fail_bool() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
fail_field(program);
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ fn test_input_fail_none() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![None]);
|
||||
program.set_main_inputs(vec![None]);
|
||||
fail_field(program);
|
||||
}
|
||||
|
||||
@ -136,7 +136,7 @@ fn test_add() {
|
||||
let bytes = include_bytes!("add.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -172,7 +172,7 @@ fn test_sub() {
|
||||
let bytes = include_bytes!("sub.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -208,7 +208,7 @@ fn test_mul() {
|
||||
let bytes = include_bytes!("mul.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -244,7 +244,7 @@ fn test_div() {
|
||||
let bytes = include_bytes!("div.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -275,7 +275,7 @@ fn test_eq() {
|
||||
let bytes = include_bytes!("eq.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -288,7 +288,7 @@ fn test_eq() {
|
||||
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -310,7 +310,7 @@ fn test_assert_eq_pass() {
|
||||
let bytes = include_bytes!("assert_eq.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -341,7 +341,7 @@ fn test_assert_eq_fail() {
|
||||
let bytes = include_bytes!("assert_eq.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![
|
||||
program.set_main_inputs(vec![
|
||||
Some(InputValue::Field(r1_bigint.to_str_radix(10))),
|
||||
Some(InputValue::Field(r2_bigint.to_str_radix(10))),
|
||||
]);
|
||||
@ -372,7 +372,7 @@ fn test_ternary() {
|
||||
let mut program_2 = program_1.clone();
|
||||
|
||||
// true -> field 1
|
||||
program_1.set_inputs(vec![
|
||||
program_1.set_main_inputs(vec![
|
||||
Some(InputValue::Boolean(true)),
|
||||
Some(InputValue::Field(r1.to_string())),
|
||||
Some(InputValue::Field(r2.to_string())),
|
||||
@ -381,7 +381,7 @@ fn test_ternary() {
|
||||
output_expected_allocated(program_1, g1);
|
||||
|
||||
// false -> field 2
|
||||
program_2.set_inputs(vec![
|
||||
program_2.set_main_inputs(vec![
|
||||
Some(InputValue::Boolean(false)),
|
||||
Some(InputValue::Field(r1.to_string())),
|
||||
Some(InputValue::Field(r2.to_string())),
|
||||
|
@ -84,7 +84,7 @@ fn test_input() {
|
||||
let bytes = include_bytes!("input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Group(TEST_POINT_1.into()))]);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
let constant_point = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
||||
@ -163,7 +163,7 @@ fn test_ternary() {
|
||||
let mut program_2 = program_1.clone();
|
||||
|
||||
// true -> point_1
|
||||
program_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
let point_1 = EdwardsAffine::from_str(TEST_POINT_1).unwrap();
|
||||
@ -172,7 +172,7 @@ fn test_ternary() {
|
||||
output_expected_allocated(program_1, expected_point_1);
|
||||
|
||||
// false -> point_2
|
||||
program_2.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_2.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
|
||||
let mut cs = TestConstraintSystem::<Fq>::new();
|
||||
let point_2 = EdwardsAffine::from_str(TEST_POINT_2).unwrap();
|
||||
|
@ -61,7 +61,7 @@ fn test_print_input() {
|
||||
let bytes = include_bytes!("print_input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
|
||||
let _output = get_output(program);
|
||||
}
|
||||
|
@ -49,8 +49,7 @@ pub(crate) fn fail_enforce(program: EdwardsTestCompiler) {
|
||||
fn new_compiler() -> EdwardsTestCompiler {
|
||||
let program_name = "test".to_string();
|
||||
let path = PathBuf::from("/test/src/main.leo");
|
||||
let mut compiler = EdwardsTestCompiler::new(program_name);
|
||||
compiler.set_path(path);
|
||||
let mut compiler = EdwardsTestCompiler::new(program_name, path);
|
||||
|
||||
compiler
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ fn test_function_input() {
|
||||
let bytes = include_bytes!("function_input.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(input_value_u32_one())]);
|
||||
program.set_main_inputs(vec![Some(input_value_u32_one())]);
|
||||
mut_fail(program);
|
||||
}
|
||||
|
||||
@ -109,6 +109,6 @@ fn test_function_input_mut() {
|
||||
let bytes = include_bytes!("function_input_mut.leo");
|
||||
let mut program = parse_program(bytes).unwrap();
|
||||
|
||||
program.set_inputs(vec![Some(input_value_u32_one())]);
|
||||
program.set_main_inputs(vec![Some(input_value_u32_one())]);
|
||||
mut_success(program);
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ fn test_assert() {
|
||||
|
||||
// Check that an input value of 1 satisfies the constraint system
|
||||
|
||||
program_1_pass.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_1_pass.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
1.to_string(),
|
||||
))]);
|
||||
@ -43,7 +43,7 @@ fn test_assert() {
|
||||
|
||||
// Check that an input value of 0 satisfies the constraint system
|
||||
|
||||
program_0_pass.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_0_pass.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
0.to_string(),
|
||||
))]);
|
||||
@ -51,7 +51,7 @@ fn test_assert() {
|
||||
|
||||
// Check that an input value of 2 does not satisfy the constraint system
|
||||
|
||||
program_2_fail.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_2_fail.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
2.to_string(),
|
||||
))]);
|
||||
@ -68,7 +68,7 @@ fn test_mutate() {
|
||||
|
||||
// Check that an input value of 1 satisfies the constraint system
|
||||
|
||||
program_1_true.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_1_true.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
1.to_string(),
|
||||
))]);
|
||||
@ -76,7 +76,7 @@ fn test_mutate() {
|
||||
|
||||
// Check that an input value of 0 satisfies the constraint system
|
||||
|
||||
program_0_pass.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_0_pass.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
0.to_string(),
|
||||
))]);
|
||||
@ -91,12 +91,12 @@ fn test_for_loop() {
|
||||
|
||||
// Check that an input value of true satisfies the constraint system
|
||||
|
||||
program_true_6.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_true_6.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
output_number(program_true_6, 6u32);
|
||||
|
||||
// Check that an input value of false satisfies the constraint system
|
||||
|
||||
program_false_0.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
output_zero(program_false_0);
|
||||
}
|
||||
|
||||
@ -108,21 +108,21 @@ fn test_chain() {
|
||||
let mut program_2_3 = program_1_1.clone();
|
||||
|
||||
// Check that an input of 1 outputs true
|
||||
program_1_1.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_1_1.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
1.to_string(),
|
||||
))]);
|
||||
output_number(program_1_1, 1u32);
|
||||
|
||||
// Check that an input of 0 outputs true
|
||||
program_2_2.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_2_2.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
2.to_string(),
|
||||
))]);
|
||||
output_number(program_2_2, 2u32);
|
||||
|
||||
// Check that an input of 0 outputs true
|
||||
program_2_3.set_inputs(vec![Some(InputValue::Integer(
|
||||
program_2_3.set_main_inputs(vec![Some(InputValue::Integer(
|
||||
IntegerType::U32Type(U32Type {}),
|
||||
5.to_string(),
|
||||
))]);
|
||||
@ -138,17 +138,17 @@ fn test_nested() {
|
||||
|
||||
// Check that an input value of true true satisfies the constraint system
|
||||
|
||||
program_true_true_3.set_inputs(vec![Some(InputValue::Boolean(true)); 2]);
|
||||
program_true_true_3.set_main_inputs(vec![Some(InputValue::Boolean(true)); 2]);
|
||||
output_number(program_true_true_3, 3u32);
|
||||
|
||||
// Check that an input value of true false satisfies the constraint system
|
||||
|
||||
program_true_false_1.set_inputs(vec![Some(InputValue::Boolean(true)), Some(InputValue::Boolean(false))]);
|
||||
program_true_false_1.set_main_inputs(vec![Some(InputValue::Boolean(true)), Some(InputValue::Boolean(false))]);
|
||||
output_number(program_true_false_1, 1u32);
|
||||
|
||||
// Check that an input value of false false satisfies the constraint system
|
||||
|
||||
program_false_false_0.set_inputs(vec![Some(InputValue::Boolean(false)), Some(InputValue::Boolean(false))]);
|
||||
program_false_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false)), Some(InputValue::Boolean(false))]);
|
||||
output_number(program_false_false_0, 0u32);
|
||||
}
|
||||
|
||||
@ -160,11 +160,11 @@ fn test_multiple_returns() {
|
||||
|
||||
// Check that an input value of true returns 1 and satisfies the constraint system
|
||||
|
||||
program_true_1.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_true_1.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
output_number(program_true_1, 1u32);
|
||||
|
||||
// Check that an input value of false returns 0 and satisfies the constraint system
|
||||
|
||||
program_false_0.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_false_0.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
output_number(program_false_0, 0u32);
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ fn test_ternary_basic() {
|
||||
|
||||
let mut program_input_false = program_input_true.clone();
|
||||
|
||||
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_input_true.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
output_one(program_input_true);
|
||||
|
||||
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_input_false.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
output_zero(program_input_false);
|
||||
}
|
||||
|
||||
@ -46,7 +46,7 @@ fn test_assertion_basic() {
|
||||
let mut program_input_true = program.clone();
|
||||
let mut cs_satisfied = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
program_input_true.set_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
program_input_true.set_main_inputs(vec![Some(InputValue::Boolean(true))]);
|
||||
let _output = program_input_true.compile_constraints(&mut cs_satisfied).unwrap();
|
||||
|
||||
assert!(cs_satisfied.is_satisfied());
|
||||
@ -54,7 +54,7 @@ fn test_assertion_basic() {
|
||||
let mut program_input_false = program.clone();
|
||||
let mut cs_unsatisfied = TestConstraintSystem::<Fq>::new();
|
||||
|
||||
program_input_false.set_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
program_input_false.set_main_inputs(vec![Some(InputValue::Boolean(false))]);
|
||||
let _output = program_input_false.compile_constraints(&mut cs_unsatisfied).unwrap();
|
||||
|
||||
assert!(!cs_unsatisfied.is_satisfied());
|
||||
|
@ -2,11 +2,12 @@ use crate::{
|
||||
ast::Rule,
|
||||
errors::SyntaxError as InputSyntaxError,
|
||||
expressions::{ArrayInitializerExpression, ArrayInlineExpression, Expression},
|
||||
sections::Header,
|
||||
tables::Table,
|
||||
types::{DataType, Type},
|
||||
values::{NumberImplicitValue, NumberValue, Value},
|
||||
};
|
||||
|
||||
use crate::sections::Header;
|
||||
use pest::{
|
||||
error::{Error, ErrorVariant},
|
||||
Span,
|
||||
@ -84,21 +85,40 @@ impl InputParserError {
|
||||
}
|
||||
|
||||
pub fn input_section_header(header: Header) -> Self {
|
||||
let message = format!("the section header {} does not belong in an input `.in` file", header);
|
||||
let message = format!("the section header `{}` is not valid in an input `.in` file", header);
|
||||
let span = header.span();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn public_section(header: Header) -> Self {
|
||||
let message = format!("the section header {} is not a public section", header);
|
||||
let message = format!("the section header `{}` is not a public section", header);
|
||||
let span = header.span();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn private_section(header: Header) -> Self {
|
||||
let message = format!("the section header {} is not a private section", header);
|
||||
let message = format!("the section header `{}` is not a private section", header);
|
||||
let span = header.span();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
}
|
||||
|
||||
pub fn table(table: Table) -> Self {
|
||||
let message = format!(
|
||||
"the double bracket section `{}` is not valid in an input `.in` file",
|
||||
table
|
||||
);
|
||||
|
||||
Self::new_from_span(message, table.span)
|
||||
}
|
||||
|
||||
pub fn section(header: Header) -> Self {
|
||||
let message = format!(
|
||||
"the section header `{}` must have a double bracket visibility in a state `.state` file",
|
||||
header
|
||||
);
|
||||
let span = header.span();
|
||||
|
||||
Self::new_from_span(message, span)
|
||||
|
@ -18,6 +18,7 @@ impl From<Error<Rule>> for SyntaxError {
|
||||
Rule::file => "a table or section".to_owned(),
|
||||
Rule::identifier => "a variable name".to_owned(),
|
||||
Rule::type_ => "a type".to_owned(),
|
||||
Rule::header => "[[public]] or [[private]]".to_owned(),
|
||||
|
||||
rule => format!("{:?}", rule),
|
||||
});
|
||||
|
@ -30,8 +30,6 @@ protected_name = {
|
||||
|
||||
// Declared in common/line_end.rs
|
||||
LINE_END = { ";" ~ NEWLINE* }
|
||||
|
||||
|
||||
/// Types
|
||||
|
||||
// Declared in types/type_.rs
|
||||
|
@ -2,6 +2,7 @@ use crate::ast::Rule;
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::private))]
|
||||
@ -9,3 +10,9 @@ pub struct Private<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Private<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.span.as_str().to_string())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use crate::ast::Rule;
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::public))]
|
||||
@ -9,3 +10,9 @@ pub struct Public<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Public<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.span.as_str().to_string())
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ use crate::{ast::Rule, sections::Section, tables::Visibility};
|
||||
|
||||
use pest::Span;
|
||||
use pest_ast::FromPest;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::table))]
|
||||
@ -11,3 +12,9 @@ pub struct Table<'ast> {
|
||||
#[pest_ast(outer())]
|
||||
pub span: Span<'ast>,
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Table<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "[[{}]]", self.visibility)
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use pest_ast::FromPest;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Clone, Debug, FromPest, PartialEq)]
|
||||
#[pest_ast(rule(Rule::visibility))]
|
||||
@ -11,3 +12,12 @@ pub enum Visibility<'ast> {
|
||||
Private(Private<'ast>),
|
||||
Public(Public<'ast>),
|
||||
}
|
||||
|
||||
impl<'ast> fmt::Display for Visibility<'ast> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Visibility::Private(private) => write!(f, "{}", private),
|
||||
Visibility::Public(public) => write!(f, "{}", public),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use snarkos_algorithms::snark::KeypairAssembly;
|
||||
use snarkos_curves::{bls12_377::Bls12_377, edwards_bls12::Fq};
|
||||
use snarkos_models::gadgets::r1cs::ConstraintSystem;
|
||||
|
||||
use crate::files::StateFile;
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
@ -41,9 +42,6 @@ impl CLI for BuildCommand {
|
||||
let manifest = Manifest::try_from(&path)?;
|
||||
let package_name = manifest.get_package_name();
|
||||
|
||||
// Load the inputs file at `package_name`
|
||||
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Sanitize the package path to the root directory
|
||||
let mut package_path = path.clone();
|
||||
if package_path.is_file() {
|
||||
@ -58,10 +56,9 @@ impl CLI for BuildCommand {
|
||||
lib_file_path.push(LIB_FILE_NAME);
|
||||
|
||||
// Compile the library file but do not output
|
||||
let _program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
|
||||
let _program = Compiler::<Fq, EdwardsGroupType>::parse_program_without_inputs(
|
||||
package_name.clone(),
|
||||
lib_file_path.clone(),
|
||||
&inputs_string,
|
||||
)?;
|
||||
|
||||
log::info!("Compiled library file {:?}", lib_file_path);
|
||||
@ -77,11 +74,18 @@ impl CLI for BuildCommand {
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
// Load the inputs file at `package_name.in`
|
||||
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Load the state file at `package_name.in`
|
||||
let state_string = StateFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Load the program at `main_file_path`
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_inputs(
|
||||
package_name.clone(),
|
||||
main_file_path.clone(),
|
||||
&inputs_string,
|
||||
&state_string,
|
||||
)?;
|
||||
|
||||
// Compute the current program checksum
|
||||
|
@ -3,14 +3,13 @@ use crate::{
|
||||
cli_types::*,
|
||||
directories::source::SOURCE_DIRECTORY_NAME,
|
||||
errors::{CLIError, TestError},
|
||||
files::{MainFile, Manifest, MAIN_FILE_NAME},
|
||||
files::{InputsFile, MainFile, Manifest, StateFile, MAIN_FILE_NAME},
|
||||
};
|
||||
use leo_compiler::{compiler::Compiler, group::targets::edwards_bls12::EdwardsGroupType};
|
||||
|
||||
use snarkos_curves::edwards_bls12::Fq;
|
||||
use snarkos_models::gadgets::r1cs::TestConstraintSystem;
|
||||
|
||||
use crate::files::InputsFile;
|
||||
use clap::ArgMatches;
|
||||
use std::{convert::TryFrom, env::current_dir};
|
||||
|
||||
@ -41,9 +40,6 @@ impl CLI for TestCommand {
|
||||
let manifest = Manifest::try_from(&path)?;
|
||||
let package_name = manifest.get_package_name();
|
||||
|
||||
// Load the inputs file at `package_name`
|
||||
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Sanitize the package path to the root directory
|
||||
let mut package_path = path.clone();
|
||||
if package_path.is_file() {
|
||||
@ -60,11 +56,18 @@ impl CLI for TestCommand {
|
||||
main_file_path.push(SOURCE_DIRECTORY_NAME);
|
||||
main_file_path.push(MAIN_FILE_NAME);
|
||||
|
||||
// Load the inputs file at `package_name`
|
||||
let inputs_string = InputsFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Load the state file at `package_name.in`
|
||||
let state_string = StateFile::new(&package_name).read_from(&path)?;
|
||||
|
||||
// Compute the current program checksum
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::new_from_path(
|
||||
let program = Compiler::<Fq, EdwardsGroupType>::parse_program_with_inputs(
|
||||
package_name.clone(),
|
||||
main_file_path.clone(),
|
||||
&inputs_string,
|
||||
&state_string,
|
||||
)?;
|
||||
|
||||
// Generate the program on the constraint system and verify correctness
|
||||
|
@ -53,6 +53,9 @@ pub enum CLIError {
|
||||
#[error("{}", _0)]
|
||||
SourceDirectoryError(SourceDirectoryError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
StateFileError(StateFileError),
|
||||
|
||||
#[error("{}", _0)]
|
||||
TestError(TestError),
|
||||
|
||||
@ -172,6 +175,13 @@ impl From<SourceDirectoryError> for CLIError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StateFileError> for CLIError {
|
||||
fn from(error: StateFileError) -> Self {
|
||||
log::error!("{}\n", error);
|
||||
CLIError::StateFileError(error)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<TestError> for CLIError {
|
||||
fn from(error: TestError) -> Self {
|
||||
log::error!("{}\n", error);
|
||||
|
@ -25,5 +25,8 @@ pub use self::proof::*;
|
||||
pub mod proving_key;
|
||||
pub use self::proving_key::*;
|
||||
|
||||
pub mod state;
|
||||
pub use self::state::*;
|
||||
|
||||
pub mod verification_key;
|
||||
pub use self::verification_key::*;
|
||||
|
22
leo/errors/files/state.rs
Normal file
22
leo/errors/files/state.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use std::{io, path::PathBuf};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum StateFileError {
|
||||
#[error("{}: {}", _0, _1)]
|
||||
Crate(&'static str, String),
|
||||
|
||||
#[error("creating: {}", _0)]
|
||||
Creating(io::Error),
|
||||
|
||||
#[error("Cannot read from the provided file path - {:?}", _0)]
|
||||
FileReadError(PathBuf),
|
||||
|
||||
#[error("writing: {}", _0)]
|
||||
Writing(io::Error),
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for StateFileError {
|
||||
fn from(error: std::io::Error) -> Self {
|
||||
StateFileError::Crate("std::io", format!("{}", error))
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
//! The `inputs.leo` file.
|
||||
//! The `program.in` file.
|
||||
|
||||
use crate::{directories::inputs::INPUTS_DIRECTORY_NAME, errors::InputsFileError};
|
||||
|
||||
@ -28,7 +28,7 @@ impl InputsFile {
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Reads the proof from the given file path if it exists.
|
||||
/// Reads the inputs from the given file path if it exists.
|
||||
pub fn read_from(&self, path: &PathBuf) -> Result<String, InputsFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
|
@ -25,5 +25,8 @@ pub use self::proof::*;
|
||||
pub mod proving_key;
|
||||
pub use self::proving_key::*;
|
||||
|
||||
pub mod state;
|
||||
pub use self::state::*;
|
||||
|
||||
pub mod verification_key;
|
||||
pub use self::verification_key::*;
|
||||
|
89
leo/files/state.rs
Normal file
89
leo/files/state.rs
Normal file
@ -0,0 +1,89 @@
|
||||
//! The `program.state` file.
|
||||
|
||||
use crate::{directories::inputs::INPUTS_DIRECTORY_NAME, errors::StateFileError};
|
||||
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
fs::{self, File},
|
||||
io::Write,
|
||||
path::PathBuf,
|
||||
};
|
||||
|
||||
pub static STATE_FILE_EXTENSION: &str = ".state";
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct StateFile {
|
||||
pub package_name: String,
|
||||
}
|
||||
|
||||
impl StateFile {
|
||||
pub fn new(package_name: &str) -> Self {
|
||||
Self {
|
||||
package_name: package_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn exists_at(&self, path: &PathBuf) -> bool {
|
||||
let path = self.setup_file_path(path);
|
||||
path.exists()
|
||||
}
|
||||
|
||||
/// Reads the state inputs from the given file path if it exists.
|
||||
pub fn read_from(&self, path: &PathBuf) -> Result<String, StateFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
let inputs = fs::read_to_string(&path).map_err(|_| StateFileError::FileReadError(path.clone()))?;
|
||||
Ok(inputs)
|
||||
}
|
||||
|
||||
/// Writes the standard input format to a file.
|
||||
pub fn write_to(self, path: &PathBuf) -> Result<(), StateFileError> {
|
||||
let path = self.setup_file_path(path);
|
||||
|
||||
let mut file = File::create(&path)?;
|
||||
Ok(file.write_all(self.template().as_bytes())?)
|
||||
}
|
||||
|
||||
fn template(&self) -> String {
|
||||
format!(
|
||||
r#"// The program state for {}/src/main.leo
|
||||
[[public]]
|
||||
|
||||
[state]
|
||||
leaf_index: u32 = 0;
|
||||
root: u8[32] = [0u8; 32];
|
||||
|
||||
[[private]]
|
||||
|
||||
[record]
|
||||
serial_number: u8[32] = [0u8; 32];
|
||||
commitment: u8[32] = [0u8; 32];
|
||||
owner: address = aleo1...;
|
||||
value: u64 = 5;
|
||||
payload: u8[32] = [0u8; 32]; // TBD
|
||||
birth_program_id: u8[32] = [0u8; 32];
|
||||
death_program_id: u8[32] = [0u8; 32];
|
||||
serial_number_nonce: u8[32] = [0u8; 32];
|
||||
commitment_randomness: u8[32] = [0u8; 32];
|
||||
|
||||
[state_leaf]
|
||||
path: u8[32][2] = [ [0u8; 32], [0u8; 32] ];
|
||||
memo: u8[32] = [0u8; 32];
|
||||
network_id: u8 = 0;
|
||||
leaf_randomness: u8[32] = [0u8; 32];
|
||||
"#,
|
||||
self.package_name
|
||||
)
|
||||
}
|
||||
|
||||
fn setup_file_path(&self, path: &PathBuf) -> PathBuf {
|
||||
let mut path = path.to_owned();
|
||||
if path.is_dir() {
|
||||
if !path.ends_with(INPUTS_DIRECTORY_NAME) {
|
||||
path.push(PathBuf::from(INPUTS_DIRECTORY_NAME));
|
||||
}
|
||||
path.push(PathBuf::from(format!("{}{}", self.package_name, STATE_FILE_EXTENSION)));
|
||||
}
|
||||
path
|
||||
}
|
||||
}
|
@ -39,13 +39,24 @@ impl Inputs {
|
||||
}
|
||||
|
||||
/// Parse all inputs included in a file and store them in `self`.
|
||||
/// Currently parser does not care if file is `.in` or `.state`
|
||||
pub fn parse(&mut self, file: File) -> Result<(), InputParserError> {
|
||||
pub fn parse_inputs(&mut self, file: File) -> Result<(), InputParserError> {
|
||||
for entry in file.entries.into_iter() {
|
||||
match entry {
|
||||
TableOrSection::Section(section) => {
|
||||
self.inputs.parse(section)?;
|
||||
}
|
||||
TableOrSection::Table(table) => return Err(InputParserError::table(table)),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Parse all inputs included in a file and store them in `self`.
|
||||
pub fn parse_state(&mut self, file: File) -> Result<(), InputParserError> {
|
||||
for entry in file.entries.into_iter() {
|
||||
match entry {
|
||||
TableOrSection::Section(section) => return Err(InputParserError::section(section.header)),
|
||||
TableOrSection::Table(table) => {
|
||||
self.state.parse(table)?;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user