From b236918df4984e53249d7ead22565b3f39bc52da Mon Sep 17 00:00:00 2001 From: d0cd Date: Thu, 29 Jun 2023 00:02:50 -0400 Subject: [PATCH] [Feature] Support `ChaCha::rand_*` (#2433) * Add tests for ChaCha::rand* * Add Chacha::rand* to AST, tyc, and codegen * Add lottery example * Regen expectations * Add check asserting that command is only used in finalize block * Update example and related CI --- .circleci/test-examples.sh | 7 + compiler/ast/src/functions/core_function.rs | 218 ++++++++++++++++++ .../src/code_generation/visit_expressions.rs | 27 +++ .../src/type_checking/check_expressions.rs | 6 + compiler/passes/src/type_checking/checker.rs | 15 ++ compiler/span/src/symbol.rs | 16 ++ .../errors/type_checker/type_checker_error.rs | 7 + examples/lottery/.gitignore | 2 + examples/lottery/README.md | 8 + examples/lottery/inputs/lottery.in | 4 + examples/lottery/program.json | 10 + examples/lottery/src/main.leo | 30 +++ .../mapping_operations_in_inline_fail.out | 2 +- tests/expectations/compiler/finalize/rand.out | 12 + .../finalize/rand_incorrect_num_operands.out | 5 + .../finalize/rand_incorrect_type_fail.out | 5 + .../finalize/rand_not_in_finalize.out | 5 + tests/tests/compiler/finalize/rand.leo | 30 +++ .../finalize/rand_incorrect_num_operands.leo | 19 ++ .../finalize/rand_incorrect_type_fail.leo | 19 ++ .../finalize/rand_not_in_finalize.leo | 19 ++ 21 files changed, 465 insertions(+), 1 deletion(-) create mode 100644 examples/lottery/.gitignore create mode 100644 examples/lottery/README.md create mode 100644 examples/lottery/inputs/lottery.in create mode 100644 examples/lottery/program.json create mode 100644 examples/lottery/src/main.leo create mode 100644 tests/expectations/compiler/finalize/rand.out create mode 100644 tests/expectations/compiler/finalize/rand_incorrect_num_operands.out create mode 100644 tests/expectations/compiler/finalize/rand_incorrect_type_fail.out create mode 100644 tests/expectations/compiler/finalize/rand_not_in_finalize.out create mode 100644 tests/tests/compiler/finalize/rand.leo create mode 100644 tests/tests/compiler/finalize/rand_incorrect_num_operands.leo create mode 100644 tests/tests/compiler/finalize/rand_incorrect_type_fail.leo create mode 100644 tests/tests/compiler/finalize/rand_not_in_finalize.leo diff --git a/.circleci/test-examples.sh b/.circleci/test-examples.sh index 26104a7111..02f801c192 100755 --- a/.circleci/test-examples.sh +++ b/.circleci/test-examples.sh @@ -341,3 +341,10 @@ if [ $EXITCODE -ne 0 ]; then echo "The \`vote\` program failed to run successfully." exit $EXITCODE fi + +# Build the lottery example Leo program. +echo "Building the \`lottery\` program..." +( + cd $EXAMPLES/lottery || exit + $LEO build || exit +) diff --git a/compiler/ast/src/functions/core_function.rs b/compiler/ast/src/functions/core_function.rs index 379271ff0d..09a075c56f 100644 --- a/compiler/ast/src/functions/core_function.rs +++ b/compiler/ast/src/functions/core_function.rs @@ -91,6 +91,22 @@ pub enum CoreFunction { BHP1024HashToU128, BHP1024HashToScalar, + ChaChaRandAddress, + ChaChaRandBool, + ChaChaRandField, + ChaChaRandGroup, + ChaChaRandI8, + ChaChaRandI16, + ChaChaRandI32, + ChaChaRandI64, + ChaChaRandI128, + ChaChaRandU8, + ChaChaRandU16, + ChaChaRandU32, + ChaChaRandU64, + ChaChaRandU128, + ChaChaRandScalar, + Pedersen64CommitToAddress, Pedersen64CommitToField, Pedersen64CommitToGroup, @@ -257,6 +273,22 @@ impl CoreFunction { (sym::BHP1024, sym::hash_to_u128) => Self::BHP1024HashToU128, (sym::BHP1024, sym::hash_to_scalar) => Self::BHP1024HashToScalar, + (sym::ChaCha, sym::rand_address) => Self::ChaChaRandAddress, + (sym::ChaCha, sym::rand_bool) => Self::ChaChaRandBool, + (sym::ChaCha, sym::rand_field) => Self::ChaChaRandField, + (sym::ChaCha, sym::rand_group) => Self::ChaChaRandGroup, + (sym::ChaCha, sym::rand_i8) => Self::ChaChaRandI8, + (sym::ChaCha, sym::rand_i16) => Self::ChaChaRandI16, + (sym::ChaCha, sym::rand_i32) => Self::ChaChaRandI32, + (sym::ChaCha, sym::rand_i64) => Self::ChaChaRandI64, + (sym::ChaCha, sym::rand_i128) => Self::ChaChaRandI128, + (sym::ChaCha, sym::rand_scalar) => Self::ChaChaRandScalar, + (sym::ChaCha, sym::rand_u8) => Self::ChaChaRandU8, + (sym::ChaCha, sym::rand_u16) => Self::ChaChaRandU16, + (sym::ChaCha, sym::rand_u32) => Self::ChaChaRandU32, + (sym::ChaCha, sym::rand_u64) => Self::ChaChaRandU64, + (sym::ChaCha, sym::rand_u128) => Self::ChaChaRandU128, + (sym::Pedersen64, sym::commit_to_address) => Self::Pedersen64CommitToAddress, (sym::Pedersen64, sym::commit_to_field) => Self::Pedersen64CommitToField, (sym::Pedersen64, sym::commit_to_group) => Self::Pedersen64CommitToGroup, @@ -424,6 +456,22 @@ impl CoreFunction { Self::BHP1024HashToU128 => 1, Self::BHP1024HashToScalar => 1, + Self::ChaChaRandAddress => 0, + Self::ChaChaRandBool => 0, + Self::ChaChaRandField => 0, + Self::ChaChaRandGroup => 0, + Self::ChaChaRandI8 => 0, + Self::ChaChaRandI16 => 0, + Self::ChaChaRandI32 => 0, + Self::ChaChaRandI64 => 0, + Self::ChaChaRandI128 => 0, + Self::ChaChaRandU8 => 0, + Self::ChaChaRandU16 => 0, + Self::ChaChaRandU32 => 0, + Self::ChaChaRandU64 => 0, + Self::ChaChaRandU128 => 0, + Self::ChaChaRandScalar => 0, + Self::Pedersen64CommitToAddress => 2, Self::Pedersen64CommitToField => 2, Self::Pedersen64CommitToGroup => 2, @@ -513,4 +561,174 @@ impl CoreFunction { Self::GroupToYCoordinate => 1, } } + + /// Returns whether or not this function is finalize command. + pub fn is_finalize_command(&self) -> bool { + match self { + CoreFunction::ChaChaRandAddress + | CoreFunction::ChaChaRandBool + | CoreFunction::ChaChaRandField + | CoreFunction::ChaChaRandGroup + | CoreFunction::ChaChaRandI8 + | CoreFunction::ChaChaRandI16 + | CoreFunction::ChaChaRandI32 + | CoreFunction::ChaChaRandI64 + | CoreFunction::ChaChaRandI128 + | CoreFunction::ChaChaRandU8 + | CoreFunction::ChaChaRandU16 + | CoreFunction::ChaChaRandU32 + | CoreFunction::ChaChaRandU64 + | CoreFunction::ChaChaRandU128 + | CoreFunction::MappingGet + | CoreFunction::MappingGetOrUse + | CoreFunction::ChaChaRandScalar + | CoreFunction::MappingSet => true, + CoreFunction::BHP256CommitToAddress + | CoreFunction::BHP256CommitToField + | CoreFunction::BHP256CommitToGroup + | CoreFunction::BHP256HashToAddress + | CoreFunction::BHP256HashToField + | CoreFunction::BHP256HashToGroup + | CoreFunction::BHP256HashToI8 + | CoreFunction::BHP256HashToI16 + | CoreFunction::BHP256HashToI32 + | CoreFunction::BHP256HashToI64 + | CoreFunction::BHP256HashToI128 + | CoreFunction::BHP256HashToU8 + | CoreFunction::BHP256HashToU16 + | CoreFunction::BHP256HashToU32 + | CoreFunction::BHP256HashToU64 + | CoreFunction::BHP256HashToU128 + | CoreFunction::BHP256HashToScalar + | CoreFunction::BHP512CommitToAddress + | CoreFunction::BHP512CommitToField + | CoreFunction::BHP512CommitToGroup + | CoreFunction::BHP512HashToAddress + | CoreFunction::BHP512HashToField + | CoreFunction::BHP512HashToGroup + | CoreFunction::BHP512HashToI8 + | CoreFunction::BHP512HashToI16 + | CoreFunction::BHP512HashToI32 + | CoreFunction::BHP512HashToI64 + | CoreFunction::BHP512HashToI128 + | CoreFunction::BHP512HashToU8 + | CoreFunction::BHP512HashToU16 + | CoreFunction::BHP512HashToU32 + | CoreFunction::BHP512HashToU64 + | CoreFunction::BHP512HashToU128 + | CoreFunction::BHP512HashToScalar + | CoreFunction::BHP768CommitToAddress + | CoreFunction::BHP768CommitToField + | CoreFunction::BHP768CommitToGroup + | CoreFunction::BHP768HashToAddress + | CoreFunction::BHP768HashToField + | CoreFunction::BHP768HashToGroup + | CoreFunction::BHP768HashToI8 + | CoreFunction::BHP768HashToI16 + | CoreFunction::BHP768HashToI32 + | CoreFunction::BHP768HashToI64 + | CoreFunction::BHP768HashToI128 + | CoreFunction::BHP768HashToU8 + | CoreFunction::BHP768HashToU16 + | CoreFunction::BHP768HashToU32 + | CoreFunction::BHP768HashToU64 + | CoreFunction::BHP768HashToU128 + | CoreFunction::BHP768HashToScalar + | CoreFunction::BHP1024CommitToAddress + | CoreFunction::BHP1024CommitToField + | CoreFunction::BHP1024CommitToGroup + | CoreFunction::BHP1024HashToAddress + | CoreFunction::BHP1024HashToField + | CoreFunction::BHP1024HashToGroup + | CoreFunction::BHP1024HashToI8 + | CoreFunction::BHP1024HashToI16 + | CoreFunction::BHP1024HashToI32 + | CoreFunction::BHP1024HashToI64 + | CoreFunction::BHP1024HashToI128 + | CoreFunction::BHP1024HashToU8 + | CoreFunction::BHP1024HashToU16 + | CoreFunction::BHP1024HashToU32 + | CoreFunction::BHP1024HashToU64 + | CoreFunction::BHP1024HashToU128 + | CoreFunction::BHP1024HashToScalar + | CoreFunction::Pedersen64CommitToAddress + | CoreFunction::Pedersen64CommitToField + | CoreFunction::Pedersen64CommitToGroup + | CoreFunction::Pedersen64HashToAddress + | CoreFunction::Pedersen64HashToField + | CoreFunction::Pedersen64HashToGroup + | CoreFunction::Pedersen64HashToI8 + | CoreFunction::Pedersen64HashToI16 + | CoreFunction::Pedersen64HashToI32 + | CoreFunction::Pedersen64HashToI64 + | CoreFunction::Pedersen64HashToI128 + | CoreFunction::Pedersen64HashToU8 + | CoreFunction::Pedersen64HashToU16 + | CoreFunction::Pedersen64HashToU32 + | CoreFunction::Pedersen64HashToU64 + | CoreFunction::Pedersen64HashToU128 + | CoreFunction::Pedersen64HashToScalar + | CoreFunction::Pedersen128CommitToAddress + | CoreFunction::Pedersen128CommitToField + | CoreFunction::Pedersen128CommitToGroup + | CoreFunction::Pedersen128HashToAddress + | CoreFunction::Pedersen128HashToField + | CoreFunction::Pedersen128HashToGroup + | CoreFunction::Pedersen128HashToI8 + | CoreFunction::Pedersen128HashToI16 + | CoreFunction::Pedersen128HashToI32 + | CoreFunction::Pedersen128HashToI64 + | CoreFunction::Pedersen128HashToI128 + | CoreFunction::Pedersen128HashToU8 + | CoreFunction::Pedersen128HashToU16 + | CoreFunction::Pedersen128HashToU32 + | CoreFunction::Pedersen128HashToU64 + | CoreFunction::Pedersen128HashToU128 + | CoreFunction::Pedersen128HashToScalar + | CoreFunction::Poseidon2HashToAddress + | CoreFunction::Poseidon2HashToField + | CoreFunction::Poseidon2HashToGroup + | CoreFunction::Poseidon2HashToI8 + | CoreFunction::Poseidon2HashToI16 + | CoreFunction::Poseidon2HashToI32 + | CoreFunction::Poseidon2HashToI64 + | CoreFunction::Poseidon2HashToI128 + | CoreFunction::Poseidon2HashToU8 + | CoreFunction::Poseidon2HashToU16 + | CoreFunction::Poseidon2HashToU32 + | CoreFunction::Poseidon2HashToU64 + | CoreFunction::Poseidon2HashToU128 + | CoreFunction::Poseidon2HashToScalar + | CoreFunction::Poseidon4HashToAddress + | CoreFunction::Poseidon4HashToField + | CoreFunction::Poseidon4HashToGroup + | CoreFunction::Poseidon4HashToI8 + | CoreFunction::Poseidon4HashToI16 + | CoreFunction::Poseidon4HashToI32 + | CoreFunction::Poseidon4HashToI64 + | CoreFunction::Poseidon4HashToI128 + | CoreFunction::Poseidon4HashToU8 + | CoreFunction::Poseidon4HashToU16 + | CoreFunction::Poseidon4HashToU32 + | CoreFunction::Poseidon4HashToU64 + | CoreFunction::Poseidon4HashToU128 + | CoreFunction::Poseidon4HashToScalar + | CoreFunction::Poseidon8HashToAddress + | CoreFunction::Poseidon8HashToField + | CoreFunction::Poseidon8HashToGroup + | CoreFunction::Poseidon8HashToI8 + | CoreFunction::Poseidon8HashToI16 + | CoreFunction::Poseidon8HashToI32 + | CoreFunction::Poseidon8HashToI64 + | CoreFunction::Poseidon8HashToI128 + | CoreFunction::Poseidon8HashToU8 + | CoreFunction::Poseidon8HashToU16 + | CoreFunction::Poseidon8HashToU32 + | CoreFunction::Poseidon8HashToU64 + | CoreFunction::Poseidon8HashToU128 + | CoreFunction::Poseidon8HashToScalar + | CoreFunction::GroupToXCoordinate + | CoreFunction::GroupToYCoordinate => false, + } + } } diff --git a/compiler/passes/src/code_generation/visit_expressions.rs b/compiler/passes/src/code_generation/visit_expressions.rs index 40f38d23ea..ea09bebc30 100644 --- a/compiler/passes/src/code_generation/visit_expressions.rs +++ b/compiler/passes/src/code_generation/visit_expressions.rs @@ -381,6 +381,33 @@ impl<'a> CodeGenerator<'a> { _ => unreachable!("The only associated methods of group are to_x_coordinate and to_y_coordinate"), } } + Type::Identifier(Identifier { name: sym::ChaCha, .. }) => { + // Get the destination register. + let destination_register = get_destination_register(); + // Construct the instruction template. + let mut instruction = format!(" rand.chacha into {destination_register} as "); + // Write the return type. + match input.name { + Identifier { name: sym::rand_address, .. } => writeln!(instruction, "address;"), + Identifier { name: sym::rand_bool, .. } => writeln!(instruction, "boolean;"), + Identifier { name: sym::rand_field, .. } => writeln!(instruction, "field;"), + Identifier { name: sym::rand_group, .. } => writeln!(instruction, "group;"), + Identifier { name: sym::rand_i8, .. } => writeln!(instruction, "i8;"), + Identifier { name: sym::rand_i16, .. } => writeln!(instruction, "i16;"), + Identifier { name: sym::rand_i32, .. } => writeln!(instruction, "i32;"), + Identifier { name: sym::rand_i64, .. } => writeln!(instruction, "i64;"), + Identifier { name: sym::rand_i128, .. } => writeln!(instruction, "i128;"), + Identifier { name: sym::rand_scalar, .. } => writeln!(instruction, "scalar;"), + Identifier { name: sym::rand_u8, .. } => writeln!(instruction, "u8;"), + Identifier { name: sym::rand_u16, .. } => writeln!(instruction, "u16;"), + Identifier { name: sym::rand_u32, .. } => writeln!(instruction, "u32;"), + Identifier { name: sym::rand_u64, .. } => writeln!(instruction, "u64;"), + Identifier { name: sym::rand_u128, .. } => writeln!(instruction, "u128;"), + _ => unreachable!("The only associated methods of ChaCha are `rand_*`"), + } + .expect("failed to write to string"); + (destination_register, instruction) + } _ => unreachable!("All core functions should be known at this phase of compilation"), }; // Add the instruction to the list of instructions. diff --git a/compiler/passes/src/type_checking/check_expressions.rs b/compiler/passes/src/type_checking/check_expressions.rs index 13d1b76169..277d6d6118 100644 --- a/compiler/passes/src/type_checking/check_expressions.rs +++ b/compiler/passes/src/type_checking/check_expressions.rs @@ -45,6 +45,11 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> { AccessExpression::AssociatedFunction(access) => { // Check core struct name and function. if let Some(core_instruction) = self.get_core_function_call(&access.ty, &access.name) { + // Check that operation is not restricted to finalize blocks. + if !self.is_finalize && core_instruction.is_finalize_command() { + self.emit_err(TypeCheckerError::operation_must_be_in_finalize_block(input.span())); + } + // Get the types of the arguments. let argument_types = access .arguments @@ -59,6 +64,7 @@ impl<'a> ExpressionVisitor<'a> for TypeChecker<'a> { if let Some(expected) = expected { self.assert_type(&return_type, expected, input.span()); } + return return_type; } else { self.emit_err(TypeCheckerError::invalid_core_function_call(access, access.span())); diff --git a/compiler/passes/src/type_checking/checker.rs b/compiler/passes/src/type_checking/checker.rs index 2eb3a2c1ea..03e71876a5 100644 --- a/compiler/passes/src/type_checking/checker.rs +++ b/compiler/passes/src/type_checking/checker.rs @@ -866,6 +866,21 @@ impl<'a> TypeChecker<'a> { self.assert_group_type(&arguments[0].0, arguments[0].1); Some(Type::Field) } + CoreFunction::ChaChaRandAddress => Some(Type::Address), + CoreFunction::ChaChaRandBool => Some(Type::Boolean), + CoreFunction::ChaChaRandField => Some(Type::Field), + CoreFunction::ChaChaRandGroup => Some(Type::Group), + CoreFunction::ChaChaRandI8 => Some(Type::Integer(IntegerType::I8)), + CoreFunction::ChaChaRandI16 => Some(Type::Integer(IntegerType::I16)), + CoreFunction::ChaChaRandI32 => Some(Type::Integer(IntegerType::I32)), + CoreFunction::ChaChaRandI64 => Some(Type::Integer(IntegerType::I64)), + CoreFunction::ChaChaRandI128 => Some(Type::Integer(IntegerType::I128)), + CoreFunction::ChaChaRandScalar => Some(Type::Scalar), + CoreFunction::ChaChaRandU8 => Some(Type::Integer(IntegerType::U8)), + CoreFunction::ChaChaRandU16 => Some(Type::Integer(IntegerType::U16)), + CoreFunction::ChaChaRandU32 => Some(Type::Integer(IntegerType::U32)), + CoreFunction::ChaChaRandU64 => Some(Type::Integer(IntegerType::U64)), + CoreFunction::ChaChaRandU128 => Some(Type::Integer(IntegerType::U128)), } } diff --git a/compiler/span/src/symbol.rs b/compiler/span/src/symbol.rs index fd0575b6a5..9d1f3af6c9 100644 --- a/compiler/span/src/symbol.rs +++ b/compiler/span/src/symbol.rs @@ -149,6 +149,7 @@ symbols! { BHP512, BHP768, BHP1024, + ChaCha, commit_to_address, commit_to_field, commit_to_group, @@ -174,6 +175,21 @@ symbols! { Poseidon2, Poseidon4, Poseidon8, + rand_address, + rand_bool, + rand_field, + rand_group, + rand_i8, + rand_i16, + rand_i32, + rand_i64, + rand_i128, + rand_scalar, + rand_u8, + rand_u16, + rand_u32, + rand_u64, + rand_u128, set, to_x_coordinate, to_y_coordinate, diff --git a/errors/src/errors/type_checker/type_checker_error.rs b/errors/src/errors/type_checker/type_checker_error.rs index 3675e23582..8aab4ad49b 100644 --- a/errors/src/errors/type_checker/type_checker_error.rs +++ b/errors/src/errors/type_checker/type_checker_error.rs @@ -635,4 +635,11 @@ create_messages!( msg: format!("`{operation}` is not a valid operand in a finalize context."), help: None, } + + @formatted + operation_must_be_in_finalize_block { + args: (), + msg: format!("This operation can only be used in a `finalize` block."), + help: None, + } ); diff --git a/examples/lottery/.gitignore b/examples/lottery/.gitignore new file mode 100644 index 0000000000..b28696155d --- /dev/null +++ b/examples/lottery/.gitignore @@ -0,0 +1,2 @@ +outputs/ +build/ diff --git a/examples/lottery/README.md b/examples/lottery/README.md new file mode 100644 index 0000000000..897dae6206 --- /dev/null +++ b/examples/lottery/README.md @@ -0,0 +1,8 @@ +# lottery.aleo + +## Build Guide + +To compile this Aleo program, run: +```bash +aleo build +``` diff --git a/examples/lottery/inputs/lottery.in b/examples/lottery/inputs/lottery.in new file mode 100644 index 0000000000..4113519304 --- /dev/null +++ b/examples/lottery/inputs/lottery.in @@ -0,0 +1,4 @@ +// The program input for lottery/src/main.leo +[main] +public a: u32 = 1u32; +b: u32 = 2u32; diff --git a/examples/lottery/program.json b/examples/lottery/program.json new file mode 100644 index 0000000000..b66b29cf1f --- /dev/null +++ b/examples/lottery/program.json @@ -0,0 +1,10 @@ +{ + "program": "lottery.aleo", + "version": "0.0.0", + "description": "", + "development": { + "private_key": "APrivateKey1zkpJrHD9orEuTpL8dDnSBZo6VyKWdbrk3VJfcwEv9SsQBN2", + "address": "aleo1dvx603addv7c2uqj6ksm9hccaypzn0ngus4n2vygvdlhqvkcyyfqvh4zdz" + }, + "license": "MIT" +} diff --git a/examples/lottery/src/main.leo b/examples/lottery/src/main.leo new file mode 100644 index 0000000000..cb450a1dd9 --- /dev/null +++ b/examples/lottery/src/main.leo @@ -0,0 +1,30 @@ +// The 'lottery' program. +program lottery.aleo { + + mapping num_winners: u8 => u8; + + record Ticket { + owner: address, + } + + transition play() -> Ticket { + let ticket: Ticket = Ticket { + owner: self.caller, + }; + return ticket then finalize(); + } + + finalize play() { + // Check that the lottery has not expired. + assert(block.height <= 1000u32); + + // Randomly select whether or not the ticket is a winner. + assert(ChaCha::rand_bool()); + + // Check that the maximum number of winners have not been reached. + let winners: u8 = num_winners.get_or_use(0u8, 0u8); + assert(winners < 5u8); + num_winners.set(0u8, winners + 1u8); + + } +} diff --git a/tests/expectations/compiler/finalize/mapping_operations_in_inline_fail.out b/tests/expectations/compiler/finalize/mapping_operations_in_inline_fail.out index fb04faf830..d15fe5f4a1 100644 --- a/tests/expectations/compiler/finalize/mapping_operations_in_inline_fail.out +++ b/tests/expectations/compiler/finalize/mapping_operations_in_inline_fail.out @@ -2,4 +2,4 @@ namespace: Compile expectation: Fail outputs: - - "Error [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372044]: Function must contain a `finalize` statement on all execution paths.\n --> compiler-test:13:5\n |\n 13 | inline bar() {\n 14 | Mapping::set(values, 0u8, 1u8);\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n 16 | Mapping::get(values, 0u8);\n 17 | }\n | ^\nError [ETYC0372031]: Only transition functions can have a `finalize` block.\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\n |\n = Remove the `finalize` block or use the keyword `transition` instead of `function`.\nError [ETYC0372045]: `finalize` name `bar` does not match function name `finalize_no_params`\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\nError [ETYC0372066]: Cyclic dependency between functions: `bar` --> `bar`\n" + - "Error [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:8:9\n |\n 8 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:9:9\n |\n 9 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:10:9\n |\n 10 | Mapping::get(values, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::set` must be inside a finalize block.\n --> compiler-test:14:9\n |\n 14 | Mapping::set(values, 0u8, 1u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get_or` must be inside a finalize block.\n --> compiler-test:15:9\n |\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372035]: `Mapping::get` must be inside a finalize block.\n --> compiler-test:16:9\n |\n 16 | Mapping::get(values, 0u8);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372044]: Function must contain a `finalize` statement on all execution paths.\n --> compiler-test:13:5\n |\n 13 | inline bar() {\n 14 | Mapping::set(values, 0u8, 1u8);\n 15 | Mapping::get_or_use(account, self.caller, 1u64);\n 16 | Mapping::get(values, 0u8);\n 17 | }\n | ^\nError [ETYC0372031]: Only transition functions can have a `finalize` block.\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\n |\n = Remove the `finalize` block or use the keyword `transition` instead of `function`.\nError [ETYC0372045]: `finalize` name `bar` does not match function name `finalize_no_params`\n --> compiler-test:19:5\n |\n 19 | finalize finalize_no_params() {\n 20 | foo();\n 21 | bar();\n 22 | }\n | ^\nError [ETYC0372066]: Cyclic dependency between functions: `bar` --> `bar`\n" diff --git a/tests/expectations/compiler/finalize/rand.out b/tests/expectations/compiler/finalize/rand.out new file mode 100644 index 0000000000..a450196340 --- /dev/null +++ b/tests/expectations/compiler/finalize/rand.out @@ -0,0 +1,12 @@ +--- +namespace: Compile +expectation: Pass +outputs: + - - initial_ast: 2d7b208912c97c514488786ee171503bfe6d230fb6f0f35725fdcc0d217dad20 + unrolled_ast: 2d7b208912c97c514488786ee171503bfe6d230fb6f0f35725fdcc0d217dad20 + ssa_ast: d31261c1b1ffc59dae4f917070deae35adcb480707a00e4ce900458f962855cc + flattened_ast: 57633e91a7d54fa5f5ec007863b135a0b1bca23f3016c2bc01ab8293ad2f59d4 + inlined_ast: 57633e91a7d54fa5f5ec007863b135a0b1bca23f3016c2bc01ab8293ad2f59d4 + dce_ast: 09659efca22ece8c63c317e0e22e1400871541e2d40a6604e073e64a7fc54153 + bytecode: 268f9afb6b8472b88b0c91f927b0cd4a69c10ad4457714dbb6faddeee5405cc6 + warnings: "" diff --git a/tests/expectations/compiler/finalize/rand_incorrect_num_operands.out b/tests/expectations/compiler/finalize/rand_incorrect_num_operands.out new file mode 100644 index 0000000000..eaf065d538 --- /dev/null +++ b/tests/expectations/compiler/finalize/rand_incorrect_num_operands.out @@ -0,0 +1,5 @@ +--- +namespace: Compile +expectation: Fail +outputs: + - "Error [ETYC0372006]: Call expected `0` args, but got `1`\n --> compiler-test:12:24\n |\n 12 | let a: field = ChaCha::rand_field(1field);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372006]: Call expected `0` args, but got `2`\n --> compiler-test:13:24\n |\n 13 | let b: field = ChaCha::rand_field(1field, 2field);\n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n" diff --git a/tests/expectations/compiler/finalize/rand_incorrect_type_fail.out b/tests/expectations/compiler/finalize/rand_incorrect_type_fail.out new file mode 100644 index 0000000000..b65143c4b8 --- /dev/null +++ b/tests/expectations/compiler/finalize/rand_incorrect_type_fail.out @@ -0,0 +1,5 @@ +--- +namespace: Compile +expectation: Fail +outputs: + - "Error [ETYC0372007]: Expected one type from `scalar`, but got `field`\n --> compiler-test:12:25\n |\n 12 | let a: scalar = ChaCha::rand_field();\n | ^^^^^^^^^^^^^^^^^^^^\nError [ETYC0372007]: Expected one type from `group`, but got `field`\n --> compiler-test:13:24\n |\n 13 | let b: group = ChaCha::rand_field();\n | ^^^^^^^^^^^^^^^^^^^^\n" diff --git a/tests/expectations/compiler/finalize/rand_not_in_finalize.out b/tests/expectations/compiler/finalize/rand_not_in_finalize.out new file mode 100644 index 0000000000..801d6d67fd --- /dev/null +++ b/tests/expectations/compiler/finalize/rand_not_in_finalize.out @@ -0,0 +1,5 @@ +--- +namespace: Compile +expectation: Fail +outputs: + - "Error [ETYC0372077]: This operation can only be used in a `finalize` block.\n --> compiler-test:8:25\n |\n 8 | let a: scalar = ChaCha::rand_scalar();\n | ^^^^^^^^^^^^^^^^^^^^^\n" diff --git a/tests/tests/compiler/finalize/rand.leo b/tests/tests/compiler/finalize/rand.leo new file mode 100644 index 0000000000..1ea0493297 --- /dev/null +++ b/tests/tests/compiler/finalize/rand.leo @@ -0,0 +1,30 @@ +/* +namespace: Compile +expectation: Pass +*/ + +program test.aleo { + + transition foo() { + return then finalize(); + } + + finalize foo() { + let a: address = ChaCha::rand_address(); + let b: bool = ChaCha::rand_bool(); + let c: field = ChaCha::rand_field(); + let d: group = ChaCha::rand_group(); + let e: i8 = ChaCha::rand_i8(); + let f: i16 = ChaCha::rand_i16(); + let g: i32 = ChaCha::rand_i32(); + let h: i64 = ChaCha::rand_i64(); + let i: i128 = ChaCha::rand_i128(); + let j: scalar = ChaCha::rand_scalar(); + let k: u8 = ChaCha::rand_u8(); + let l: u16 = ChaCha::rand_u16(); + let m: u32 = ChaCha::rand_u32(); + let n: u64 = ChaCha::rand_u64(); + let o: u128 = ChaCha::rand_u128(); + assert(b); + } +} diff --git a/tests/tests/compiler/finalize/rand_incorrect_num_operands.leo b/tests/tests/compiler/finalize/rand_incorrect_num_operands.leo new file mode 100644 index 0000000000..d176123747 --- /dev/null +++ b/tests/tests/compiler/finalize/rand_incorrect_num_operands.leo @@ -0,0 +1,19 @@ +/* +namespace: Compile +expectation: Fail +*/ + +program test.aleo { + + mapping values: field => field; + + transition foo() { + return then finalize(); + } + + finalize foo() { + let a: field = ChaCha::rand_field(1field); + let b: field = ChaCha::rand_field(1field, 2field); + values.set(a, b); + } +} diff --git a/tests/tests/compiler/finalize/rand_incorrect_type_fail.leo b/tests/tests/compiler/finalize/rand_incorrect_type_fail.leo new file mode 100644 index 0000000000..deb2e0e9cc --- /dev/null +++ b/tests/tests/compiler/finalize/rand_incorrect_type_fail.leo @@ -0,0 +1,19 @@ +/* +namespace: Compile +expectation: Fail +*/ + +program test.aleo { + + mapping values: scalar => group; + + transition foo() { + return then finalize(); + } + + finalize foo() { + let a: scalar = ChaCha::rand_field(); + let b: group = ChaCha::rand_field(); + values.set(a, b); + } +} diff --git a/tests/tests/compiler/finalize/rand_not_in_finalize.leo b/tests/tests/compiler/finalize/rand_not_in_finalize.leo new file mode 100644 index 0000000000..e7ed6fd1e3 --- /dev/null +++ b/tests/tests/compiler/finalize/rand_not_in_finalize.leo @@ -0,0 +1,19 @@ +/* +namespace: Compile +expectation: Fail +*/ + +program test.aleo { + + mapping values: scalar => group; + + transition foo() { + let a: scalar = ChaCha::rand_scalar(); + return then finalize(a); + } + + finalize foo(a: scalar) { + let b: group = ChaCha::rand_group(); + values.set(a, b); + } +}