From ac8c94016918dfd9960eb02af5544d0308384ba6 Mon Sep 17 00:00:00 2001 From: collin Date: Wed, 29 Jul 2020 13:20:44 -0700 Subject: [PATCH] add parsing for .in and .state files and update errors --- compiler/src/compiler.rs | 70 +++++++++------ compiler/tests/address/mod.rs | 12 +-- compiler/tests/array/mod.rs | 6 +- compiler/tests/boolean/mod.rs | 4 +- compiler/tests/field/mod.rs | 26 +++--- compiler/tests/group/mod.rs | 6 +- compiler/tests/macros/mod.rs | 2 +- compiler/tests/mod.rs | 3 +- compiler/tests/mutability/mod.rs | 4 +- compiler/tests/statements/conditional/mod.rs | 30 +++---- compiler/tests/statements/mod.rs | 8 +- leo-inputs/src/errors/parser.rs | 28 +++++- leo-inputs/src/errors/syntax.rs | 1 + leo-inputs/src/leo-inputs.pest | 2 - leo-inputs/src/tables/private.rs | 7 ++ leo-inputs/src/tables/public.rs | 7 ++ leo-inputs/src/tables/table.rs | 7 ++ leo-inputs/src/tables/visibility.rs | 10 +++ leo/commands/build.rs | 16 ++-- leo/commands/test.rs | 15 ++-- leo/errors/cli.rs | 10 +++ leo/errors/files/mod.rs | 3 + leo/errors/files/state.rs | 22 +++++ leo/files/inputs.rs | 4 +- leo/files/mod.rs | 3 + leo/files/state.rs | 89 ++++++++++++++++++++ types/src/inputs/inputs.rs | 15 +++- 27 files changed, 310 insertions(+), 100 deletions(-) create mode 100644 leo/errors/files/state.rs create mode 100644 leo/files/state.rs diff --git a/compiler/src/compiler.rs b/compiler/src/compiler.rs index 7bbedc0479..b58bcd9611 100644 --- a/compiler/src/compiler.rs +++ b/compiler/src/compiler.rs @@ -32,10 +32,10 @@ pub struct Compiler> { } impl> Compiler { - 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> Compiler { } } - pub fn new_from_path( - package_name: String, - main_file_path: PathBuf, - inputs_string: &str, - ) -> Result { - 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 { + 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 { + 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 { - // 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> Compiler { 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 { + 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 { @@ -111,6 +124,7 @@ impl> Compiler { Ok(hex::encode(hash)) } + /// Synthesizes the circuit without program inputs to verify correctness. pub fn compile_constraints>( self, cs: &mut CS, @@ -125,6 +139,7 @@ impl> Compiler { }) } + /// Synthesizes the circuit for test functions with program inputs. pub fn compile_test_constraints(self, cs: &mut TestConstraintSystem) -> Result<(), CompilerError> { generate_test_constraints::(cs, self.program, self.program_inputs, &self.imported_programs) } @@ -150,6 +165,7 @@ impl> Compiler { } impl> ConstraintSynthesizer for Compiler { + /// Synthesizes the circuit with program inputs. fn generate_constraints>(self, cs: &mut CS) -> Result<(), SynthesisError> { let result = generate_constraints::<_, G, _>(cs, self.program, self.program_inputs, &self.imported_programs) .map_err(|e| { diff --git a/compiler/tests/address/mod.rs b/compiler/tests/address/mod.rs index de951e220c..b2e3f1ed2f 100644 --- a/compiler/tests/address/mod.rs +++ b/compiler/tests/address/mod.rs @@ -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())), ]); diff --git a/compiler/tests/array/mod.rs b/compiler/tests/array/mod.rs index 94886b1527..06dd2f95cc 100644 --- a/compiler/tests/array/mod.rs +++ b/compiler/tests/array/mod.rs @@ -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) } diff --git a/compiler/tests/boolean/mod.rs b/compiler/tests/boolean/mod.rs index fc849e6008..4a2fa0f3e9 100644 --- a/compiler/tests/boolean/mod.rs +++ b/compiler/tests/boolean/mod.rs @@ -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); } diff --git a/compiler/tests/field/mod.rs b/compiler/tests/field/mod.rs index 48aa04b1d6..e5da123b09 100644 --- a/compiler/tests/field/mod.rs +++ b/compiler/tests/field/mod.rs @@ -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::::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())), diff --git a/compiler/tests/group/mod.rs b/compiler/tests/group/mod.rs index ea056fed13..d66f0708c9 100644 --- a/compiler/tests/group/mod.rs +++ b/compiler/tests/group/mod.rs @@ -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::::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::::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::::new(); let point_2 = EdwardsAffine::from_str(TEST_POINT_2).unwrap(); diff --git a/compiler/tests/macros/mod.rs b/compiler/tests/macros/mod.rs index 7d14bfebdf..ce581af148 100644 --- a/compiler/tests/macros/mod.rs +++ b/compiler/tests/macros/mod.rs @@ -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); } diff --git a/compiler/tests/mod.rs b/compiler/tests/mod.rs index ee1770e40c..7820c7372b 100644 --- a/compiler/tests/mod.rs +++ b/compiler/tests/mod.rs @@ -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 } diff --git a/compiler/tests/mutability/mod.rs b/compiler/tests/mutability/mod.rs index cc8dcdb2dd..ca656cfd18 100644 --- a/compiler/tests/mutability/mod.rs +++ b/compiler/tests/mutability/mod.rs @@ -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); } diff --git a/compiler/tests/statements/conditional/mod.rs b/compiler/tests/statements/conditional/mod.rs index b9e8f959ae..3d8beae280 100644 --- a/compiler/tests/statements/conditional/mod.rs +++ b/compiler/tests/statements/conditional/mod.rs @@ -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); } diff --git a/compiler/tests/statements/mod.rs b/compiler/tests/statements/mod.rs index 2d59beaa39..84e1febd74 100644 --- a/compiler/tests/statements/mod.rs +++ b/compiler/tests/statements/mod.rs @@ -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::::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::::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()); diff --git a/leo-inputs/src/errors/parser.rs b/leo-inputs/src/errors/parser.rs index b0345e3963..0b9c81cb4d 100644 --- a/leo-inputs/src/errors/parser.rs +++ b/leo-inputs/src/errors/parser.rs @@ -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) diff --git a/leo-inputs/src/errors/syntax.rs b/leo-inputs/src/errors/syntax.rs index 8e73accb69..4bca70f5f6 100644 --- a/leo-inputs/src/errors/syntax.rs +++ b/leo-inputs/src/errors/syntax.rs @@ -18,6 +18,7 @@ impl From> 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), }); diff --git a/leo-inputs/src/leo-inputs.pest b/leo-inputs/src/leo-inputs.pest index d9fdc3c801..589271f33f 100644 --- a/leo-inputs/src/leo-inputs.pest +++ b/leo-inputs/src/leo-inputs.pest @@ -30,8 +30,6 @@ protected_name = { // Declared in common/line_end.rs LINE_END = { ";" ~ NEWLINE* } - - /// Types // Declared in types/type_.rs diff --git a/leo-inputs/src/tables/private.rs b/leo-inputs/src/tables/private.rs index af3ac5fdca..1c1c86d44b 100644 --- a/leo-inputs/src/tables/private.rs +++ b/leo-inputs/src/tables/private.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()) + } +} diff --git a/leo-inputs/src/tables/public.rs b/leo-inputs/src/tables/public.rs index fa448c70fe..a16e567914 100644 --- a/leo-inputs/src/tables/public.rs +++ b/leo-inputs/src/tables/public.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::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()) + } +} diff --git a/leo-inputs/src/tables/table.rs b/leo-inputs/src/tables/table.rs index b97877569a..e115c237ea 100644 --- a/leo-inputs/src/tables/table.rs +++ b/leo-inputs/src/tables/table.rs @@ -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) + } +} diff --git a/leo-inputs/src/tables/visibility.rs b/leo-inputs/src/tables/visibility.rs index e6ee92c032..af2c93e2e4 100644 --- a/leo-inputs/src/tables/visibility.rs +++ b/leo-inputs/src/tables/visibility.rs @@ -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), + } + } +} diff --git a/leo/commands/build.rs b/leo/commands/build.rs index 6fc7fcdcab..7c6638b45a 100644 --- a/leo/commands/build.rs +++ b/leo/commands/build.rs @@ -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::::new_from_path( + let _program = Compiler::::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::::new_from_path( + let program = Compiler::::parse_program_with_inputs( package_name.clone(), main_file_path.clone(), &inputs_string, + &state_string, )?; // Compute the current program checksum diff --git a/leo/commands/test.rs b/leo/commands/test.rs index 59d8ac480d..a8d4526b35 100644 --- a/leo/commands/test.rs +++ b/leo/commands/test.rs @@ -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::::new_from_path( + let program = Compiler::::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 diff --git a/leo/errors/cli.rs b/leo/errors/cli.rs index 1beb8fc84c..54aa0a9d6a 100644 --- a/leo/errors/cli.rs +++ b/leo/errors/cli.rs @@ -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 for CLIError { } } +impl From for CLIError { + fn from(error: StateFileError) -> Self { + log::error!("{}\n", error); + CLIError::StateFileError(error) + } +} + impl From for CLIError { fn from(error: TestError) -> Self { log::error!("{}\n", error); diff --git a/leo/errors/files/mod.rs b/leo/errors/files/mod.rs index 97bcc19e30..22638df0eb 100644 --- a/leo/errors/files/mod.rs +++ b/leo/errors/files/mod.rs @@ -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::*; diff --git a/leo/errors/files/state.rs b/leo/errors/files/state.rs new file mode 100644 index 0000000000..a0cd41d28a --- /dev/null +++ b/leo/errors/files/state.rs @@ -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 for StateFileError { + fn from(error: std::io::Error) -> Self { + StateFileError::Crate("std::io", format!("{}", error)) + } +} diff --git a/leo/files/inputs.rs b/leo/files/inputs.rs index 10bb9a185e..538f9adc13 100644 --- a/leo/files/inputs.rs +++ b/leo/files/inputs.rs @@ -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 { let path = self.setup_file_path(path); diff --git a/leo/files/mod.rs b/leo/files/mod.rs index 0e4f02c8dc..8c273c1146 100644 --- a/leo/files/mod.rs +++ b/leo/files/mod.rs @@ -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::*; diff --git a/leo/files/state.rs b/leo/files/state.rs new file mode 100644 index 0000000000..0dfab788dc --- /dev/null +++ b/leo/files/state.rs @@ -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 { + 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 + } +} diff --git a/types/src/inputs/inputs.rs b/types/src/inputs/inputs.rs index 8d31add380..b1d319a627 100644 --- a/types/src/inputs/inputs.rs +++ b/types/src/inputs/inputs.rs @@ -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)?; }