From c2da66e75ceac4ec76dc8b4b9dc7f2e13ef04122 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 11:35:39 -0400 Subject: [PATCH 1/7] Add tests --- .../async_without_finalize_fail.aleo | 17 ++++++++ .../call_after_async_fail.aleo | 37 ++++++++++++++++++ .../future_out_of_order_fail.aleo | 39 +++++++++++++++++++ .../ignore_finalize_fail.aleo | 33 ++++++++++++++++ .../last_reg_is_not_future_fail.aleo | 25 ++++++++++++ .../multiple_async_fail.aleo | 38 ++++++++++++++++++ .../out_of_order_await_fail.aleo | 39 +++++++++++++++++++ .../output_child_without_async_fail.aleo | 32 +++++++++++++++ .../unawaited_future_fail.aleo | 38 ++++++++++++++++++ .../unused_future_fail.aleo | 37 ++++++++++++++++++ 10 files changed, 335 insertions(+) create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/async_without_finalize_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/call_after_async_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/future_out_of_order_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/ignore_finalize_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/last_reg_is_not_future_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/multiple_async_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/out_of_order_await_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/output_child_without_async_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/unawaited_future_fail.aleo create mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/unused_future_fail.aleo diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/async_without_finalize_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/async_without_finalize_fail.aleo new file mode 100644 index 0000000000..caf9ff0c22 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/async_without_finalize_fail.aleo @@ -0,0 +1,17 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +function foo: + input r0 as field.private; + input r1 as field.private; + async foo self.caller into r2; + add r0 r1 into r3; + output r3 as field.private; + + + + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/call_after_async_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/call_after_async_fail.aleo new file mode 100644 index 0000000000..272bc951e0 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/call_after_async_fail.aleo @@ -0,0 +1,37 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + async foo r0 into r1; + call child.aleo/foo into r2; + output r1 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + await r0; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/future_out_of_order_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/future_out_of_order_fail.aleo new file mode 100644 index 0000000000..f2b6225a55 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/future_out_of_order_fail.aleo @@ -0,0 +1,39 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + call child.aleo/foo into r1; + async foo r1 r0 into r2; + output r2 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + input r1 as child.aleo/foo.future; + await r0; + await r1; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/ignore_finalize_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/ignore_finalize_fail.aleo new file mode 100644 index 0000000000..7514c7773c --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/ignore_finalize_fail.aleo @@ -0,0 +1,33 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + input r0 as field.private; + input r1 as field.private; + call child.aleo/foo into r2; + add r0 r1 into r3; + output r3 as field.private; diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/last_reg_is_not_future_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/last_reg_is_not_future_fail.aleo new file mode 100644 index 0000000000..0a0f2ea01b --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/last_reg_is_not_future_fail.aleo @@ -0,0 +1,25 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + input r0 as field.private; + input r1 as field.private; + async foo self.caller into r2; + add r0 r1 into r3; + output r2 as child.aleo/foo.future; + output r3 as field.private; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/multiple_async_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/multiple_async_fail.aleo new file mode 100644 index 0000000000..7a186c0f02 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/multiple_async_fail.aleo @@ -0,0 +1,38 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + call child.aleo/foo into r1; + async foo r0 into r2; + async foo r1 into r3; + output r2 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + await r0; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/out_of_order_await_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/out_of_order_await_fail.aleo new file mode 100644 index 0000000000..b86f29b8b5 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/out_of_order_await_fail.aleo @@ -0,0 +1,39 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + call child.aleo/foo into r1; + async foo r0 r1 into r2; + output r2 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + input r1 as child.aleo/foo.future; + await r1; + await r0; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/output_child_without_async_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/output_child_without_async_fail.aleo new file mode 100644 index 0000000000..7d34f0c060 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/output_child_without_async_fail.aleo @@ -0,0 +1,32 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + output r2 as child.aleo/foo.future; + + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/unawaited_future_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/unawaited_future_fail.aleo new file mode 100644 index 0000000000..26736dca73 --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/unawaited_future_fail.aleo @@ -0,0 +1,38 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + call child.aleo/foo into r1; + async foo r0 r1 into r2; + output r2 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + input r1 as child.aleo/foo.future; + await r0; + diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/unused_future_fail.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/unused_future_fail.aleo new file mode 100644 index 0000000000..9277b9a3dd --- /dev/null +++ b/synthesizer/tests/tests/vm/execute_and_finalize/unused_future_fail.aleo @@ -0,0 +1,37 @@ +/* +randomness: 45791624 +cases: [] +*/ + +program child.aleo; + +mapping count: + key as address.public; + value as field.public; + +function foo: + async foo self.caller into r0; + output r0 as child.aleo/foo.future; + +finalize foo: + input r0 as address.public; + get.or_use count[r0] 0field into r1; + add r1 1field into r2; + set r2 into count[r0]; + +///////////////////////////////////////////////// + +import child.aleo; + +program parent.aleo; + +function foo: + call child.aleo/foo into r0; + call child.aleo/foo into r1; + async foo r0 into r2; + output r2 as parent.aleo/foo.future; + +finalize foo: + input r0 as child.aleo/foo.future; + await r0; + From d18bed2e4ba6d0bb31044f64e07cdff30dfea09a Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 11:36:01 -0400 Subject: [PATCH 2/7] Implement fix --- .../src/stack/finalize_types/initialize.rs | 30 ++++++++++++++++++- .../src/stack/register_types/initialize.rs | 24 +++++++++++---- 2 files changed, 48 insertions(+), 6 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 9a7bc33440..0981ee9fe7 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -39,16 +39,44 @@ impl FinalizeTypes { let mut finalize_types = Self { inputs: IndexMap::new(), destinations: IndexMap::new() }; // Step 1. Check the inputs are well-formed. + let mut input_futures = vec![]; for input in finalize.inputs() { // Check the input register type. - finalize_types.check_input(stack, input.register(), input.finalize_type())?; + let register = input.register().clone(); + let finalize_type = input.finalize_type(); + + // Check the input register. + finalize_types.check_input(stack, ®ister, finalize_type)?; + + // If the input is a future, add it to the list of input futures. + if let FinalizeType::Future(locator) = finalize_type { + input_futures.push((register, *locator)); + } } // Step 2. Check the commands are well-formed. + let mut consumed_futures = vec![]; for command in finalize.commands() { // Check the command opcode, operands, and destinations. finalize_types.check_command(stack, finalize, command)?; + + // If the command is an `await`, add the future to the list of consumed futures. + if let Command::Await(await_) = command { + let register = await_.register().clone(); + // Note that `check_command` ensures that the register is a future. This is an additional check. + let locator = match finalize_types.get_type(stack, ®ister)? { + FinalizeType::Future(locator) => locator, + FinalizeType::Plaintext(..) => bail!("Expected a future"), + }; + consumed_futures.push((register, locator)); + } } + // Check that the input futures are consumed in the order they are passed in. + ensure!( + input_futures == consumed_futures, + "Futures in finalize '{}' are not awaited in the order they are passed in.", + finalize.name() + ); Ok(finalize_types) } diff --git a/synthesizer/process/src/stack/register_types/initialize.rs b/synthesizer/process/src/stack/register_types/initialize.rs index 387f0e0d2e..3f34d5f89d 100644 --- a/synthesizer/process/src/stack/register_types/initialize.rs +++ b/synthesizer/process/src/stack/register_types/initialize.rs @@ -164,8 +164,8 @@ impl RegisterTypes { let mut future_registers = register_types .destinations .iter() - .filter_map(|(_, register_type)| match register_type { - RegisterType::Future(locator) => Some(*locator), + .filter_map(|(index, register_type)| match register_type { + RegisterType::Future(locator) => Some((Register::Locator(*index), *locator)), _ => None, }) .collect::>(); @@ -190,7 +190,7 @@ impl RegisterTypes { .iter() .filter_map(|operand| match operand { Operand::Register(register) => match register_types.get_type(stack, register).ok() { - Some(RegisterType::Future(locator)) => Some(locator), + Some(RegisterType::Future(locator)) => Some((register.clone(), locator)), _ => None, }, _ => None, @@ -461,8 +461,22 @@ impl RegisterTypes { // Retrieve the program. let external = stack.get_external_program(program_id)?; - // Ensure the function or closure exists in the program. - if !external.contains_function(resource) && !external.contains_closure(resource) { + // Check that function exists in the program. + if let Ok(child_function) = external.get_function(resource) { + // If the child function contains a finalize block, then the parent function must also contain a finalize block. + let child_contains_finalize = child_function.finalize_logic().is_some(); + let parent_contains_finalize = + stack.get_function(closure_or_function_name)?.finalize_logic().is_some(); + if child_contains_finalize && !parent_contains_finalize { + bail!( + "Function '{}/{closure_or_function_name}' must contain a finalize block, since it calls '{}/{resource}'.", + stack.program_id(), + program_id + ) + } + } + // Otherwise, ensure the closure exists in the program. + else if !external.contains_closure(resource) { bail!("'{resource}' is not defined in '{}'.", external.id()) } } From d50d161c19dbf24e496cb35911715da715c5ab32 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 11:36:15 -0400 Subject: [PATCH 3/7] Regen expectations --- .../vm/execute_and_finalize/async_without_finalize_fail.out | 3 +++ .../vm/execute_and_finalize/call_after_async_fail.out | 3 +++ .../vm/execute_and_finalize/future_out_of_order_fail.out | 3 +++ .../vm/execute_and_finalize/ignore_finalize_fail.out | 3 +++ .../vm/execute_and_finalize/last_reg_is_not_future_fail.out | 3 +++ .../vm/execute_and_finalize/multiple_async_fail.out | 3 +++ .../vm/execute_and_finalize/out_of_order_await_fail.out | 3 +++ .../execute_and_finalize/output_child_without_async_fail.out | 3 +++ .../vm/execute_and_finalize/unawaited_future_fail.out | 3 +++ .../vm/execute_and_finalize/unused_future_fail.out | 3 +++ 10 files changed, 30 insertions(+) create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/async_without_finalize_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/call_after_async_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/future_out_of_order_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/ignore_finalize_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/last_reg_is_not_future_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/multiple_async_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/out_of_order_await_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/output_child_without_async_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/unawaited_future_fail.out create mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/unused_future_fail.out diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/async_without_finalize_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/async_without_finalize_fail.out new file mode 100644 index 0000000000..e12989bca9 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/async_without_finalize_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program child.aleo: ''child.aleo/foo'' does not have a finalize block' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/call_after_async_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/call_after_async_fail.out new file mode 100644 index 0000000000..cf7e6921fd --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/call_after_async_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: The ''call'' can only be invoked before an ''async'' instruction' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/future_out_of_order_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/future_out_of_order_fail.out new file mode 100644 index 0000000000..0cea7546f1 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/future_out_of_order_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Function ''foo'' contains futures, but the ''async'' instruction does not consume all of them in the order they were produced' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/ignore_finalize_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/ignore_finalize_fail.out new file mode 100644 index 0000000000..1afb6b4e21 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/ignore_finalize_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Function ''parent.aleo/foo'' must contain a finalize block, since it calls ''child.aleo/foo''.' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/last_reg_is_not_future_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/last_reg_is_not_future_fail.out new file mode 100644 index 0000000000..2195cccd79 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/last_reg_is_not_future_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program child.aleo: The last output of function ''foo'' must be a future associated with itself' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/multiple_async_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/multiple_async_fail.out new file mode 100644 index 0000000000..2c841f10f6 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/multiple_async_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Function ''foo'' can contain at most one ''async'' instruction' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/out_of_order_await_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/out_of_order_await_fail.out new file mode 100644 index 0000000000..7d4109cee6 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/out_of_order_await_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Futures in finalize ''foo'' are not awaited in the order they are passed in.' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/output_child_without_async_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/output_child_without_async_fail.out new file mode 100644 index 0000000000..1afb6b4e21 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/output_child_without_async_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Function ''parent.aleo/foo'' must contain a finalize block, since it calls ''child.aleo/foo''.' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/unawaited_future_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/unawaited_future_fail.out new file mode 100644 index 0000000000..7d4109cee6 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/unawaited_future_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Futures in finalize ''foo'' are not awaited in the order they are passed in.' +outputs: [] diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/unused_future_fail.out b/synthesizer/tests/expectations/vm/execute_and_finalize/unused_future_fail.out new file mode 100644 index 0000000000..0cea7546f1 --- /dev/null +++ b/synthesizer/tests/expectations/vm/execute_and_finalize/unused_future_fail.out @@ -0,0 +1,3 @@ +errors: +- 'Failed to run `VM::deploy for program parent.aleo: Function ''foo'' contains futures, but the ''async'' instruction does not consume all of them in the order they were produced' +outputs: [] From 0481d6aad934e06852a86ed60e672630a5a61327 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 11:52:31 -0400 Subject: [PATCH 4/7] Cleanup --- synthesizer/process/src/stack/finalize_types/initialize.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 0981ee9fe7..4d52b7150f 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -44,8 +44,6 @@ impl FinalizeTypes { // Check the input register type. let register = input.register().clone(); let finalize_type = input.finalize_type(); - - // Check the input register. finalize_types.check_input(stack, ®ister, finalize_type)?; // If the input is a future, add it to the list of input futures. From 1b575af7f78ca15d0c73838d53ce98aabfdeff2b Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 18:33:32 -0400 Subject: [PATCH 5/7] Address feedback --- .../src/stack/finalize_types/initialize.rs | 16 ++++++++-------- .../src/stack/register_types/initialize.rs | 19 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 4d52b7150f..243113ef85 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -38,13 +38,13 @@ impl FinalizeTypes { // Initialize a map of registers to their types. let mut finalize_types = Self { inputs: IndexMap::new(), destinations: IndexMap::new() }; - // Step 1. Check the inputs are well-formed. - let mut input_futures = vec![]; + // Step 1. Check the inputs are well-formed. Store the input futures. + let mut input_futures = Vec::new(); for input in finalize.inputs() { // Check the input register type. - let register = input.register().clone(); + let register = input.register(); let finalize_type = input.finalize_type(); - finalize_types.check_input(stack, ®ister, finalize_type)?; + finalize_types.check_input(stack, register, finalize_type)?; // If the input is a future, add it to the list of input futures. if let FinalizeType::Future(locator) = finalize_type { @@ -52,17 +52,17 @@ impl FinalizeTypes { } } - // Step 2. Check the commands are well-formed. - let mut consumed_futures = vec![]; + // Step 2. Check the commands are well-formed. Store the futures consumed by the `await` commands. + let mut consumed_futures = Vec::new(); for command in finalize.commands() { // Check the command opcode, operands, and destinations. finalize_types.check_command(stack, finalize, command)?; // If the command is an `await`, add the future to the list of consumed futures. if let Command::Await(await_) = command { - let register = await_.register().clone(); + let register = await_.register(); // Note that `check_command` ensures that the register is a future. This is an additional check. - let locator = match finalize_types.get_type(stack, ®ister)? { + let locator = match finalize_types.get_type(stack, register)? { FinalizeType::Future(locator) => locator, FinalizeType::Plaintext(..) => bail!("Expected a future"), }; diff --git a/synthesizer/process/src/stack/register_types/initialize.rs b/synthesizer/process/src/stack/register_types/initialize.rs index 3f34d5f89d..075e216b46 100644 --- a/synthesizer/process/src/stack/register_types/initialize.rs +++ b/synthesizer/process/src/stack/register_types/initialize.rs @@ -170,20 +170,19 @@ impl RegisterTypes { }) .collect::>(); - // Remove the last locator, since this is the future created by the `async` call. - future_registers.pop(); - - // Check that all the registers were consumed by the `async` call, in order. match async_ { + // If no `async` instruction exists, then there should not be any future registers. None => { - if !future_registers.is_empty() { - bail!( - "Function '{}' contains futures, but does not contain an 'async' instruction", - function.name() - ) - } + ensure!( + future_registers.is_empty(), + "Function '{}' contains futures, but does not contain an 'async' instruction", + function.name() + ) } + // Otherwise, check that all the registers were consumed by the `async` call, in order. Some(async_) => { + // Remove the last future, since this is the future created by the `async` call. + future_registers.pop(); // Get the register operands that are `future` types. let async_future_operands = async_ .operands() From 7f35b0f074100aec5512976cfb8210b8c89d62a5 Mon Sep 17 00:00:00 2001 From: Pranav Gaddamadugu Date: Wed, 25 Oct 2023 19:23:50 -0400 Subject: [PATCH 6/7] Use get_function_ref --- synthesizer/process/src/stack/register_types/initialize.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/synthesizer/process/src/stack/register_types/initialize.rs b/synthesizer/process/src/stack/register_types/initialize.rs index 075e216b46..173e71d319 100644 --- a/synthesizer/process/src/stack/register_types/initialize.rs +++ b/synthesizer/process/src/stack/register_types/initialize.rs @@ -461,11 +461,11 @@ impl RegisterTypes { // Retrieve the program. let external = stack.get_external_program(program_id)?; // Check that function exists in the program. - if let Ok(child_function) = external.get_function(resource) { + if let Ok(child_function) = external.get_function_ref(resource) { // If the child function contains a finalize block, then the parent function must also contain a finalize block. let child_contains_finalize = child_function.finalize_logic().is_some(); let parent_contains_finalize = - stack.get_function(closure_or_function_name)?.finalize_logic().is_some(); + stack.get_function_ref(closure_or_function_name)?.finalize_logic().is_some(); if child_contains_finalize && !parent_contains_finalize { bail!( "Function '{}/{closure_or_function_name}' must contain a finalize block, since it calls '{}/{resource}'.", From 3034009f41e58636cafbfd3b82f633f7d4389f42 Mon Sep 17 00:00:00 2001 From: Howard Wu <9260812+howardwu@users.noreply.github.com> Date: Wed, 25 Oct 2023 16:25:10 -0700 Subject: [PATCH 7/7] nits --- .../src/stack/finalize_types/initialize.rs | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/synthesizer/process/src/stack/finalize_types/initialize.rs b/synthesizer/process/src/stack/finalize_types/initialize.rs index 243113ef85..77c1ee2893 100644 --- a/synthesizer/process/src/stack/finalize_types/initialize.rs +++ b/synthesizer/process/src/stack/finalize_types/initialize.rs @@ -38,37 +38,39 @@ impl FinalizeTypes { // Initialize a map of registers to their types. let mut finalize_types = Self { inputs: IndexMap::new(), destinations: IndexMap::new() }; - // Step 1. Check the inputs are well-formed. Store the input futures. + // Initialize a list of input futures. let mut input_futures = Vec::new(); + + // Step 1. Check the inputs are well-formed. Store the input futures. for input in finalize.inputs() { // Check the input register type. - let register = input.register(); - let finalize_type = input.finalize_type(); - finalize_types.check_input(stack, register, finalize_type)?; + finalize_types.check_input(stack, input.register(), input.finalize_type())?; // If the input is a future, add it to the list of input futures. - if let FinalizeType::Future(locator) = finalize_type { - input_futures.push((register, *locator)); + if let FinalizeType::Future(locator) = input.finalize_type() { + input_futures.push((input.register(), *locator)); } } - // Step 2. Check the commands are well-formed. Store the futures consumed by the `await` commands. + // Initialize a list of consumed futures. let mut consumed_futures = Vec::new(); + + // Step 2. Check the commands are well-formed. Store the futures consumed by the `await` commands. for command in finalize.commands() { // Check the command opcode, operands, and destinations. finalize_types.check_command(stack, finalize, command)?; // If the command is an `await`, add the future to the list of consumed futures. if let Command::Await(await_) = command { - let register = await_.register(); - // Note that `check_command` ensures that the register is a future. This is an additional check. - let locator = match finalize_types.get_type(stack, register)? { + // Note: `check_command` ensures that the register is a future. This is an additional check. + let locator = match finalize_types.get_type(stack, await_.register())? { FinalizeType::Future(locator) => locator, - FinalizeType::Plaintext(..) => bail!("Expected a future"), + FinalizeType::Plaintext(..) => bail!("Expected a future in '{await_}'"), }; - consumed_futures.push((register, locator)); + consumed_futures.push((await_.register(), locator)); } } + // Check that the input futures are consumed in the order they are passed in. ensure!( input_futures == consumed_futures,