From 63de76b0873d5a2c7ad5a5cac2c89cd5a1f99cc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Sat, 25 Jul 2026 11:54:03 +0200 Subject: [PATCH 1/9] added test --- .../tests/test_v18/closure_dynamic_targets.rs | 70 +++++++++++++++++++ synthesizer/src/vm/tests/test_v18/mod.rs | 3 + 2 files changed, 73 insertions(+) create mode 100644 synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs diff --git a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs new file mode 100644 index 0000000000..cc48644e9d --- /dev/null +++ b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs @@ -0,0 +1,70 @@ +// Copyright (c) 2019-2026 Provable Inc. +// This file is part of the snarkVM library. + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at: + +// http://www.apache.org/licenses/LICENSE-2.0 + +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use super::*; + +// TODO (Antonio) review documentation + +// Deploys a program whose function selects the target of a `call.dynamic` at runtime, based on the +// last bit of `self.signer`, choosing between the field representation of a closure (`some_closure`) +// and a function (`some_function`). The deployment is then verified repeatedly to ensure the +// verification decision is stable across freshly sampled randomness. +#[test] +fn test_dynamic_call_target_safe() -> Result<()> { + let rng = &mut TestRng::default(); + + // The program declares a closure `some_closure` and a function `some_function`. `some_function` + // reads the last bit of `self.signer`, then uses it to drive a `ternary` that selects between the + // field representation of `some_closure` and `some_function`. The selected field is used as the + // function-name operand of a `call.dynamic` back into the same program. + // Note: `serialize.bits.raw` on an `address` yields `field`-many bits (253 for this network), so + // the last bit is at index 252. `ternary` is applied to the field representations (identifiers + // cannot be used with `ternary` directly), obtained via `cast ... as field`. + let program = Program::::from_str( + r" +program some_dcall.aleo; + +closure some_closure: + input r0 as field; + add r0 r0 into r1; + output r1 as field; + +function some_function: + input r0 as field.public; + serialize.bits.raw self.signer (address) into r1 ([boolean; 253u32]); + cast 'some_closure' into r2 as field; + cast 'some_function' into r3 as field; + ternary r1[0u32] r2 r3 into r4; + call.dynamic 'some_dcall' 'aleo' r4 with r0 (as field.public) into r5 (as field.public); + output r5 as field.public; + +constructor: + assert.eq true true; +", + )?; + + // Initialize a fresh process and construct the deployment once. + let process = Process::::load()?; + let deployment = process.deploy::(&program, rng)?; + + // Verify the deployment 10 times. Each call to `verify_deployment` samples fresh randomness from + // `rng` (which advances between iterations), so the certificates are re-checked against new + // randomness on every iteration. + for _ in 0..10 { + process.verify_deployment::(ConsensusVersion::V14, &deployment, rng)?; + } + + Ok(()) +} diff --git a/synthesizer/src/vm/tests/test_v18/mod.rs b/synthesizer/src/vm/tests/test_v18/mod.rs index 38ca4c50de..806ec6213f 100644 --- a/synthesizer/src/vm/tests/test_v18/mod.rs +++ b/synthesizer/src/vm/tests/test_v18/mod.rs @@ -16,6 +16,9 @@ // Tests for stack fetching relevant to the record-existence check. mod record_existence_stacks; +// Tests on the resolution of dynamic call targets involving closures. +mod closure_dynamic_targets; + use super::*; use super::test_v14::add_and_test_with_costs; From 2c5b7ee9cb04df2c5fbab75a5a7b20691f6447f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Sat, 25 Jul 2026 12:00:43 +0200 Subject: [PATCH 2/9] documented --- .../tests/test_v18/closure_dynamic_targets.rs | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs index cc48644e9d..ace6ee884d 100644 --- a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs +++ b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs @@ -15,23 +15,12 @@ use super::*; -// TODO (Antonio) review documentation - -// Deploys a program whose function selects the target of a `call.dynamic` at runtime, based on the -// last bit of `self.signer`, choosing between the field representation of a closure (`some_closure`) -// and a function (`some_function`). The deployment is then verified repeatedly to ensure the -// verification decision is stable across freshly sampled randomness. +// Deploys a program whose function selects the target of a call.dynamic at runtime, poinring to a +// closure or to a function depending on based on the last bit of self.signer #[test] fn test_dynamic_call_target_safe() -> Result<()> { let rng = &mut TestRng::default(); - // The program declares a closure `some_closure` and a function `some_function`. `some_function` - // reads the last bit of `self.signer`, then uses it to drive a `ternary` that selects between the - // field representation of `some_closure` and `some_function`. The selected field is used as the - // function-name operand of a `call.dynamic` back into the same program. - // Note: `serialize.bits.raw` on an `address` yields `field`-many bits (253 for this network), so - // the last bit is at index 252. `ternary` is applied to the field representations (identifiers - // cannot be used with `ternary` directly), obtained via `cast ... as field`. let program = Program::::from_str( r" program some_dcall.aleo; @@ -55,13 +44,11 @@ constructor: ", )?; - // Initialize a fresh process and construct the deployment once. let process = Process::::load()?; let deployment = process.deploy::(&program, rng)?; - // Verify the deployment 10 times. Each call to `verify_deployment` samples fresh randomness from - // `rng` (which advances between iterations), so the certificates are re-checked against new - // randomness on every iteration. + // Verify the deployment 10 times, each of which has a 50% chance of selecting each of the + // targets. for _ in 0..10 { process.verify_deployment::(ConsensusVersion::V14, &deployment, rng)?; } From b628d1e8901468b2b92e771ed35ad2c465facf8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Sat, 25 Jul 2026 12:09:40 +0200 Subject: [PATCH 3/9] made signer deterministic --- synthesizer/process/src/stack/deploy.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/synthesizer/process/src/stack/deploy.rs b/synthesizer/process/src/stack/deploy.rs index 20d17d8a24..71fd052563 100644 --- a/synthesizer/process/src/stack/deploy.rs +++ b/synthesizer/process/src/stack/deploy.rs @@ -160,7 +160,7 @@ impl Stack { deployment.program().functions().values().zip_eq(deployment.function_verifying_keys()) { // Initialize a burner private key. - let burner_private_key = PrivateKey::new(rng)?; + let burner_private_key = PrivateKey::new(&mut seeded_rng)?; // Compute the burner address. let burner_address = Address::try_from(&burner_private_key)?; // Retrieve the input types. From ccfe407383a6fb4a7d797baad70561bcb771a2e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Sat, 25 Jul 2026 12:17:33 +0200 Subject: [PATCH 4/9] fixed resolve_dynamic_target --- synthesizer/process/src/stack/call/dynamic.rs | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/synthesizer/process/src/stack/call/dynamic.rs b/synthesizer/process/src/stack/call/dynamic.rs index 77e5818715..22bbcb5ee2 100644 --- a/synthesizer/process/src/stack/call/dynamic.rs +++ b/synthesizer/process/src/stack/call/dynamic.rs @@ -971,8 +971,8 @@ impl<'a, N: Network> ResolvedTarget<'a, N> { // A helper function that attempts to resolve the target of a dynamic call. // This function returns: -// - Ok(Some(ResolvedTarget)) if the target is successfully resolved. -// - Ok(None) in `Synthesize` or `CheckDeployment` mode when the target cannot be resolved. +// - Ok(None) in `Synthesize` or `CheckDeployment` +// - Ok(Some(ResolvedTarget)) in other modes if the target is successfully resolved. // - Err(_) in other modes when the target cannot be resolved. fn resolve_dynamic_target<'a, N: Network>( call_stack: &'a CallStack, @@ -981,42 +981,32 @@ fn resolve_dynamic_target<'a, N: Network>( program_network_as_field: &Field, function_name_as_field: &Field, ) -> Result>> { - // Determine whether we are in "dummy" (`Synthesize` or `CheckDeployment`) mode. - let in_dummy_mode = matches!(call_stack, CallStack::Synthesize(..) | CallStack::CheckDeployment(..)); + // If in one of the two dummy modes, return None. + if matches!(call_stack, CallStack::Synthesize(..) | CallStack::CheckDeployment(..)) { + return Ok(None); + } // Decode the program name, exiting gracefully in dummy mode if it fails. let program_name = match Identifier::from_field(program_name_as_field) { Ok(id) => id, - Err(_) if in_dummy_mode => { - return Ok(None); - } Err(e) => return Err(anyhow!("Failed to decode the program name in a dynamic call: {e}")), }; // Decode the program network, exiting gracefully in dummy mode if it fails. let program_network = match Identifier::from_field(program_network_as_field) { Ok(id) => id, - Err(_) if in_dummy_mode => { - return Ok(None); - } Err(e) => return Err(anyhow!("Failed to decode the program network in a dynamic call: {e}")), }; // Decode the function name, exiting gracefully in dummy mode if it fails. let function_name = match Identifier::from_field(function_name_as_field) { Ok(id) => id, - Err(_) if in_dummy_mode => { - return Ok(None); - } Err(e) => return Err(anyhow!("Failed to decode the function name in a dynamic call: {e}")), }; // Construct the program ID. let program_id = match ProgramID::try_from((program_name, program_network)) { Ok(id) => id, - Err(_) if in_dummy_mode => { - return Ok(None); - } Err(e) => return Err(anyhow!("Failed to construct the program ID in a dynamic call: {e}")), }; @@ -1034,9 +1024,6 @@ fn resolve_dynamic_target<'a, N: Network>( let external_stack = match stack.program().id() == &program_id { false => match stack.get_stack_global(&program_id) { Ok(ext_stack) => Some(ext_stack), - Err(_) if in_dummy_mode => { - return Ok(None); - } Err(e) => return Err(anyhow!("Failed to retrieve the external stack in a dynamic call: {e}")), }, true => None, @@ -1053,8 +1040,6 @@ fn resolve_dynamic_target<'a, N: Network>( Err(anyhow!("Cannot dynamically evaluate a closure: {function_name}")) } else if substack.program().contains_function(&function_name) { Ok(Some(ResolvedTarget { program_id, function_name, substack })) - } else if in_dummy_mode { - Ok(None) } else { Err(anyhow!("Dynamic call to '{program_id}/{function_name}' is invalid or unsupported.")) } From b3df9e49442a699e09f7996c50712b13fbcfc184 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 28 Jul 2026 11:26:41 +0200 Subject: [PATCH 5/9] reverted changes to resolve_dynamic_target --- synthesizer/process/src/stack/call/dynamic.rs | 27 ++++++++++++++----- 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/synthesizer/process/src/stack/call/dynamic.rs b/synthesizer/process/src/stack/call/dynamic.rs index 22bbcb5ee2..77e5818715 100644 --- a/synthesizer/process/src/stack/call/dynamic.rs +++ b/synthesizer/process/src/stack/call/dynamic.rs @@ -971,8 +971,8 @@ impl<'a, N: Network> ResolvedTarget<'a, N> { // A helper function that attempts to resolve the target of a dynamic call. // This function returns: -// - Ok(None) in `Synthesize` or `CheckDeployment` -// - Ok(Some(ResolvedTarget)) in other modes if the target is successfully resolved. +// - Ok(Some(ResolvedTarget)) if the target is successfully resolved. +// - Ok(None) in `Synthesize` or `CheckDeployment` mode when the target cannot be resolved. // - Err(_) in other modes when the target cannot be resolved. fn resolve_dynamic_target<'a, N: Network>( call_stack: &'a CallStack, @@ -981,32 +981,42 @@ fn resolve_dynamic_target<'a, N: Network>( program_network_as_field: &Field, function_name_as_field: &Field, ) -> Result>> { - // If in one of the two dummy modes, return None. - if matches!(call_stack, CallStack::Synthesize(..) | CallStack::CheckDeployment(..)) { - return Ok(None); - } + // Determine whether we are in "dummy" (`Synthesize` or `CheckDeployment`) mode. + let in_dummy_mode = matches!(call_stack, CallStack::Synthesize(..) | CallStack::CheckDeployment(..)); // Decode the program name, exiting gracefully in dummy mode if it fails. let program_name = match Identifier::from_field(program_name_as_field) { Ok(id) => id, + Err(_) if in_dummy_mode => { + return Ok(None); + } Err(e) => return Err(anyhow!("Failed to decode the program name in a dynamic call: {e}")), }; // Decode the program network, exiting gracefully in dummy mode if it fails. let program_network = match Identifier::from_field(program_network_as_field) { Ok(id) => id, + Err(_) if in_dummy_mode => { + return Ok(None); + } Err(e) => return Err(anyhow!("Failed to decode the program network in a dynamic call: {e}")), }; // Decode the function name, exiting gracefully in dummy mode if it fails. let function_name = match Identifier::from_field(function_name_as_field) { Ok(id) => id, + Err(_) if in_dummy_mode => { + return Ok(None); + } Err(e) => return Err(anyhow!("Failed to decode the function name in a dynamic call: {e}")), }; // Construct the program ID. let program_id = match ProgramID::try_from((program_name, program_network)) { Ok(id) => id, + Err(_) if in_dummy_mode => { + return Ok(None); + } Err(e) => return Err(anyhow!("Failed to construct the program ID in a dynamic call: {e}")), }; @@ -1024,6 +1034,9 @@ fn resolve_dynamic_target<'a, N: Network>( let external_stack = match stack.program().id() == &program_id { false => match stack.get_stack_global(&program_id) { Ok(ext_stack) => Some(ext_stack), + Err(_) if in_dummy_mode => { + return Ok(None); + } Err(e) => return Err(anyhow!("Failed to retrieve the external stack in a dynamic call: {e}")), }, true => None, @@ -1040,6 +1053,8 @@ fn resolve_dynamic_target<'a, N: Network>( Err(anyhow!("Cannot dynamically evaluate a closure: {function_name}")) } else if substack.program().contains_function(&function_name) { Ok(Some(ResolvedTarget { program_id, function_name, substack })) + } else if in_dummy_mode { + Ok(None) } else { Err(anyhow!("Dynamic call to '{program_id}/{function_name}' is invalid or unsupported.")) } From 9e52ca44f0d43aa46f86d8349b3acc15ecb56170 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 28 Jul 2026 13:40:44 +0200 Subject: [PATCH 6/9] adapted test, polished --- circuit/program/src/request/verify.rs | 2 +- .../process/benches/check_deployment.rs | 2 +- synthesizer/process/src/stack/deploy.rs | 2 +- .../process/src/stack/helpers/synthesize.rs | 2 +- synthesizer/process/src/tests/test_credits.rs | 2 +- .../tests/test_v18/closure_dynamic_targets.rs | 89 +++++++++++------ synthesizer/src/vm/tests/test_v18/mod.rs | 6 +- .../vm/execute_and_finalize/test_rand.out | 47 --------- .../vm/execute_and_finalize/test_rand.aleo | 95 ------------------- 9 files changed, 68 insertions(+), 179 deletions(-) delete mode 100644 synthesizer/tests/expectations/vm/execute_and_finalize/test_rand.out delete mode 100644 synthesizer/tests/tests/vm/execute_and_finalize/test_rand.aleo diff --git a/circuit/program/src/request/verify.rs b/circuit/program/src/request/verify.rs index 5d68906163..3fbbed3732 100644 --- a/circuit/program/src/request/verify.rs +++ b/circuit/program/src/request/verify.rs @@ -463,7 +463,7 @@ mod tests { // Sample 'root_tvk'. let root_tvk = None; - // Sample 'is_root'. + // Set 'is_root' to true. In particular, this guarantees self.caller is set to self.signer. let is_root = true; // Sample 'program_checksum'. let program_checksum = set_program_checksum.then(|| console::Field::from_u64(i as u64)); diff --git a/synthesizer/process/benches/check_deployment.rs b/synthesizer/process/benches/check_deployment.rs index 2394d53c58..457d9538de 100644 --- a/synthesizer/process/benches/check_deployment.rs +++ b/synthesizer/process/benches/check_deployment.rs @@ -53,7 +53,7 @@ fn prepare_check_deployment>( }; // Sample 'root_tvk'. let root_tvk = None; - // Sample 'is_root'. + // Set 'is_root' to true. In particular, this guarantees self.caller is set to self.signer. let is_root = true; // Compute the request. let request = Request::sign( diff --git a/synthesizer/process/src/stack/deploy.rs b/synthesizer/process/src/stack/deploy.rs index 71fd052563..3577e842cc 100644 --- a/synthesizer/process/src/stack/deploy.rs +++ b/synthesizer/process/src/stack/deploy.rs @@ -188,7 +188,7 @@ impl Stack { }) .collect::>>()?; lap!(timer, "Sample the inputs"); - // Sample a dummy 'is_root'. + // Set 'is_root' to true. In particular, this guarantees self.caller is set to self.signer. let is_root = true; // Compute the request, with a burner private key. diff --git a/synthesizer/process/src/stack/helpers/synthesize.rs b/synthesizer/process/src/stack/helpers/synthesize.rs index 80565b30ba..01b64c4213 100644 --- a/synthesizer/process/src/stack/helpers/synthesize.rs +++ b/synthesizer/process/src/stack/helpers/synthesize.rs @@ -59,7 +59,7 @@ impl Stack { _ => self.sample_value(&burner_address, &input_type.into(), rng), }) .collect::>>()?; - // Sample a dummy 'is_root'. + // Set 'is_root' to true. In particular, this guarantees self.caller is set to self.signer. let is_root = true; // Sample a dummy `root_tvk` for circuit synthesis. let root_tvk = None; diff --git a/synthesizer/process/src/tests/test_credits.rs b/synthesizer/process/src/tests/test_credits.rs index f6042392e3..97580b9755 100644 --- a/synthesizer/process/src/tests/test_credits.rs +++ b/synthesizer/process/src/tests/test_credits.rs @@ -2869,7 +2869,7 @@ mod sanity_checks { }; // Sample 'root_tvk'. let root_tvk = None; - // Sample 'is_root'. + // Set 'is_root' to true. let is_root = true; // Compute the request. let request = Request::sign( diff --git a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs index ace6ee884d..a0b3dc5889 100644 --- a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs +++ b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs @@ -15,42 +15,71 @@ use super::*; -// Deploys a program whose function selects the target of a call.dynamic at runtime, poinring to a -// closure or to a function depending on based on the last bit of self.signer +// Deploys a program whose function points the target of a call.dynamic instruction to a closure or a +// function depending on the last bit of self.signer. The test checks several runs of test- #[test] -fn test_dynamic_call_target_safe() -> Result<()> { +fn test_conditional_dynamic_call_target_deployment() -> Result<()> { + const N_EXPERIMENTS: usize = 10; + let rng = &mut TestRng::default(); - let program = Program::::from_str( - r" -program some_dcall.aleo; - -closure some_closure: - input r0 as field; - add r0 r0 into r1; - output r1 as field; - -function some_function: - input r0 as field.public; - serialize.bits.raw self.signer (address) into r1 ([boolean; 253u32]); - cast 'some_closure' into r2 as field; - cast 'some_function' into r3 as field; - ternary r1[0u32] r2 r3 into r4; - call.dynamic 'some_dcall' 'aleo' r4 with r0 (as field.public) into r5 (as field.public); - output r5 as field.public; - -constructor: - assert.eq true true; -", - )?; + // Create a program whose name contains the passed integer. This is so that different executions + // have different deployment IDs and therefore different deployment-check outcomes. + let parse_program = |i| { + Program::::from_str(&format!( + r" + program program_{i}.aleo; + + closure some_closure: + input r0 as field; + add r0 r0 into r1; + output r1 as field; + + function some_function: + input r0 as field.public; + serialize.bits.raw self.signer (address) into r1 ([boolean; 253u32]); + cast 'some_closure' into r2 as field; + cast 'some_function' into r3 as field; + ternary r1[0u32] r2 r3 into r4; + call.dynamic 'program_{i}' 'aleo' r4 with r0 (as field.public) into r5 (as field.public); + output r5 as field.public; + + constructor: + assert.eq true true; + ", + )) + .unwrap() + }; let process = Process::::load()?; - let deployment = process.deploy::(&program, rng)?; - // Verify the deployment 10 times, each of which has a 50% chance of selecting each of the - // targets. - for _ in 0..10 { - process.verify_deployment::(ConsensusVersion::V14, &deployment, rng)?; + // About half of the calls to process.deploy should succeed. About half of those should be + // accepted by process.verify_deployment, but the outcome for each fixed deployment should be + // the same across all calls to verify_deployment. + for i in 0..N_EXPERIMENTS { + let deployment_attempt = process.deploy::(&parse_program(i), rng); + + match deployment_attempt { + Ok(deployment) => { + println!(" - Deployment computation {i} succeeded with ID {}", deployment.to_deployment_id()?); + + // TODO (Antonio) V19 + // Ensure that different runs of verify_deployment agree on the result - even if it is a rejection. + let verification_successful = + process.verify_deployment::(ConsensusVersion::V18, &deployment, rng).is_ok(); + for _ in 1..N_EXPERIMENTS { + assert_eq!( + verification_successful, + process.verify_deployment::(ConsensusVersion::V18, &deployment, rng).is_ok(), + "Verifier disagreement during deployment verification", + ); + } + println!(" All verifiers {}", if verification_successful { "accepted" } else { "rejected" }); + } + Err(error) => { + println!(" - Deployment computation {i} failed: {error}"); + } + } } Ok(()) diff --git a/synthesizer/src/vm/tests/test_v18/mod.rs b/synthesizer/src/vm/tests/test_v18/mod.rs index 6227a019de..bc1b1e5c34 100644 --- a/synthesizer/src/vm/tests/test_v18/mod.rs +++ b/synthesizer/src/vm/tests/test_v18/mod.rs @@ -17,11 +17,13 @@ mod record_existence_stacks; // Tests with Aleo functions which output scalars. -// These changes are not ConsensusVersion::V18-gated, but they were introduced at that point in -// time. +// The relevant changes are not ConsensusVersion::V18-gated, but they were introduced at that point +// in time. mod scalar_outputs; // Tests on the resolution of dynamic call targets involving closures. +// The relevant changes are not ConsensusVersion::V18-gated, but they were introduced at that point +// in time. mod closure_dynamic_targets; use super::*; diff --git a/synthesizer/tests/expectations/vm/execute_and_finalize/test_rand.out b/synthesizer/tests/expectations/vm/execute_and_finalize/test_rand.out deleted file mode 100644 index 17d6a1bef1..0000000000 --- a/synthesizer/tests/expectations/vm/execute_and_finalize/test_rand.out +++ /dev/null @@ -1,47 +0,0 @@ -errors: [] -outputs: -- verified: true - speculate: the execution was accepted - add_next_block: succeeded. -- verified: true - speculate: the execution was accepted - add_next_block: succeeded. -- verified: true - speculate: the execution was accepted - add_next_block: succeeded. -- verified: true - speculate: the execution was accepted - add_next_block: succeeded. -additional: -- execute: - test_rand.aleo/rand_chacha_with_literals: - outputs: - - '{"type":"future","id":"5102038009020533731844782156118375757727610098613388474802700949982136972580field","value":"{\n program_id: test_rand.aleo,\n function_name: rand_chacha_with_literals,\n arguments: [\n 0scalar,\n 0group,\n 0u8,\n 2i16,\n 4u32,\n 7i64,\n 8u128,\n 10field\n ]\n}"}' - child_outputs: - credits.aleo/fee_public: - outputs: - - '{"type":"future","id":"7322057028547022602074287374226793684261978708418540776971106514165554591824field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1vf9njx4j0kf2r24x52a9ftl569v75p0ys3l37avgycyym4xtlvyqgk4kj2,\n 25838u64\n ]\n}"}' -- execute: - test_rand.aleo/rand_chacha_with_struct: - outputs: - - '{"type":"future","id":"482174963780124108786128234836627821724305550501866375697366264773952922026field","value":"{\n program_id: test_rand.aleo,\n function_name: rand_chacha_with_struct,\n arguments: [\n {\n first: 0field,\n second: 0field,\n third: 0field,\n fourth: 0field,\n fifth: 0field\n}\n ]\n}"}' - child_outputs: - credits.aleo/fee_public: - outputs: - - '{"type":"future","id":"4946977589305077180349776064958482383013669820471931787428578911699931647108field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1vf9njx4j0kf2r24x52a9ftl569v75p0ys3l37avgycyym4xtlvyqgk4kj2,\n 2711u64\n ]\n}"}' -- execute: - test_rand.aleo/rand_chacha_check: - outputs: - - '{"type":"future","id":"1570769487878974437081885634900648302244928245971192094848228534413638987183field","value":"{\n program_id: test_rand.aleo,\n function_name: rand_chacha_check,\n arguments: [\n 1field,\n true\n ]\n}"}' - child_outputs: - credits.aleo/fee_public: - outputs: - - '{"type":"future","id":"1452797368278080175662040237480831796947635212130923017288522952418689935524field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1vf9njx4j0kf2r24x52a9ftl569v75p0ys3l37avgycyym4xtlvyqgk4kj2,\n 2396u64\n ]\n}"}' -- execute: - test_rand.aleo/rand_chacha_check: - outputs: - - '{"type":"future","id":"5077734656045242940626023407162461123888003839058071588609845203491859009360field","value":"{\n program_id: test_rand.aleo,\n function_name: rand_chacha_check,\n arguments: [\n 4field,\n false\n ]\n}"}' - child_outputs: - credits.aleo/fee_public: - outputs: - - '{"type":"future","id":"2073924506636794686104397413998990121919856896229428122753202120841830861945field","value":"{\n program_id: credits.aleo,\n function_name: fee_public,\n arguments: [\n aleo1vf9njx4j0kf2r24x52a9ftl569v75p0ys3l37avgycyym4xtlvyqgk4kj2,\n 2396u64\n ]\n}"}' diff --git a/synthesizer/tests/tests/vm/execute_and_finalize/test_rand.aleo b/synthesizer/tests/tests/vm/execute_and_finalize/test_rand.aleo deleted file mode 100644 index 93a4c7de79..0000000000 --- a/synthesizer/tests/tests/vm/execute_and_finalize/test_rand.aleo +++ /dev/null @@ -1,95 +0,0 @@ -/* -randomness: 4792831234 -cases: - - program: test_rand.aleo - function: rand_chacha_with_literals - inputs: [0scalar, 0group, 0u8, 2i16, 4u32, 7i64, 8u128, 10field] - - program: test_rand.aleo - function: rand_chacha_with_struct - inputs: ["{ first: 0field, second: 0field, third: 0field, fourth: 0field, fifth: 0field }"] - - program: test_rand.aleo - function: rand_chacha_check - inputs: [1field, true] - - program: test_rand.aleo - function: rand_chacha_check - inputs: [4field, false] -*/ - -program test_rand.aleo; - -struct bundle: - first as field; - second as field; - third as field; - fourth as field; - fifth as field; - -function rand_chacha_with_struct: - input r0 as bundle.public; - async rand_chacha_with_struct r0 into r1; - output r1 as test_rand.aleo/rand_chacha_with_struct.future; - -finalize rand_chacha_with_struct: - input r0 as bundle.public; - rand.chacha r0 into r1 as field; - -function rand_chacha_check: - input r0 as field.public; - input r1 as boolean.public; - async rand_chacha_check r0 r1 into r2; - output r2 as test_rand.aleo/rand_chacha_check.future; - -finalize rand_chacha_check: - input r0 as field.public; - input r1 as boolean.public; - rand.chacha r0 into r2 as boolean; - assert.eq r1 r2; - -function rand_chacha_with_literals: - input r0 as scalar.public; - input r1 as group.public; - input r2 as u8.public; - input r3 as i16.public; - input r4 as u32.public; - input r5 as i64.public; - input r6 as u128.public; - input r7 as field.public; - async rand_chacha_with_literals r0 r1 r2 r3 r4 r5 r6 r7 into r8; - output r8 as test_rand.aleo/rand_chacha_with_literals.future; - -finalize rand_chacha_with_literals: - input r0 as scalar.public; - input r1 as group.public; - input r2 as u8.public; - input r3 as i16.public; - input r4 as u32.public; - input r5 as i64.public; - input r6 as u128.public; - input r7 as field.public; - rand.chacha into r8 as boolean; - rand.chacha into r9 as scalar; - rand.chacha into r10 as group; - rand.chacha into r11 as u8; - rand.chacha into r12 as i16; - rand.chacha into r13 as u32; - rand.chacha into r14 as i64; - rand.chacha into r15 as u128; - rand.chacha into r16 as field; - rand.chacha r0 into r17 as scalar; - rand.chacha r1 into r18 as group; - rand.chacha r2 into r19 as u8; - rand.chacha r3 into r20 as i16; - rand.chacha r4 into r21 as u32; - rand.chacha r5 into r22 as i64; - rand.chacha r6 into r23 as u128; - rand.chacha r7 into r24 as field; - rand.chacha r0 r1 into r25 as scalar; - rand.chacha r1 r2 into r26 as group; - rand.chacha r2 r3 into r27 as u8; - rand.chacha r3 r4 into r28 as i16; - rand.chacha r4 r5 into r29 as u32; - rand.chacha r5 r6 into r30 as i64; - rand.chacha r6 r7 into r31 as u128; - -constructor: - assert.eq edition 0u16; From d3691764098d5dbd824c4b5c82eb57cbbf595c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Tue, 28 Jul 2026 13:50:26 +0200 Subject: [PATCH 7/9] made test return type void --- .../src/vm/tests/test_v18/closure_dynamic_targets.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs index a0b3dc5889..da23203e63 100644 --- a/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs +++ b/synthesizer/src/vm/tests/test_v18/closure_dynamic_targets.rs @@ -18,7 +18,7 @@ use super::*; // Deploys a program whose function points the target of a call.dynamic instruction to a closure or a // function depending on the last bit of self.signer. The test checks several runs of test- #[test] -fn test_conditional_dynamic_call_target_deployment() -> Result<()> { +fn test_conditional_dynamic_call_target_deployment() { const N_EXPERIMENTS: usize = 10; let rng = &mut TestRng::default(); @@ -51,7 +51,7 @@ fn test_conditional_dynamic_call_target_deployment() -> Result<()> { .unwrap() }; - let process = Process::::load()?; + let process = Process::::load().unwrap(); // About half of the calls to process.deploy should succeed. About half of those should be // accepted by process.verify_deployment, but the outcome for each fixed deployment should be @@ -61,7 +61,7 @@ fn test_conditional_dynamic_call_target_deployment() -> Result<()> { match deployment_attempt { Ok(deployment) => { - println!(" - Deployment computation {i} succeeded with ID {}", deployment.to_deployment_id()?); + println!(" - Deployment computation {i} succeeded with ID {}", deployment.to_deployment_id().unwrap()); // TODO (Antonio) V19 // Ensure that different runs of verify_deployment agree on the result - even if it is a rejection. @@ -81,6 +81,4 @@ fn test_conditional_dynamic_call_target_deployment() -> Result<()> { } } } - - Ok(()) } From e2969569d86a3911424b8f49ff5244ae3922f699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 31 Jul 2026 09:48:41 +0200 Subject: [PATCH 8/9] fixed documentation of --- synthesizer/process/src/stack/call/dynamic.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/synthesizer/process/src/stack/call/dynamic.rs b/synthesizer/process/src/stack/call/dynamic.rs index c1c37406a4..4b69349daa 100644 --- a/synthesizer/process/src/stack/call/dynamic.rs +++ b/synthesizer/process/src/stack/call/dynamic.rs @@ -978,11 +978,12 @@ impl<'a, N: Network> ResolvedTarget<'a, N> { } } -// A helper function that attempts to resolve the target of a dynamic call. -// This function returns: -// - Ok(Some(ResolvedTarget)) if the target is successfully resolved. +// A helper function that attempts to resolve the target of a dynamic call. This function returns: +// - Ok(Some(ResolvedTarget)) if the target is successfully resolved to a non-closure. // - Ok(None) in `Synthesize` or `CheckDeployment` mode when the target cannot be resolved. -// - Err(_) in other modes when the target cannot be resolved. +// - Err(_) in +// - `Synthesize` or `CheckDeployment` mode when the target is resolved to a closure. +// - other modes when the target cannot be resolved or it is resolved to a closure. fn resolve_dynamic_target<'a, N: Network>( call_stack: &'a CallStack, stack: &'a Stack, From 13db1fd48e7f36e13112869200d2d723c0c33624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Antonio=20Mej=C3=ADas=20Gil?= Date: Fri, 31 Jul 2026 09:51:51 +0200 Subject: [PATCH 9/9] removed TODOs --- synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs b/synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs index ce9af1876d..f084031c4b 100644 --- a/synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs +++ b/synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs @@ -61,10 +61,8 @@ fn test_conditional_dynamic_call_target_deployment() { match deployment_attempt { Ok(deployment) => { - // TODO (Antonio) remove println!(" - Deployment computation {i} succeeded with ID {}", deployment.to_deployment_id().unwrap()); - // TODO (Antonio) V19 // Ensure that different runs of verify_deployment agree on the result - even if it is a rejection. let verification_successful = process.verify_deployment::(ConsensusVersion::V19, &deployment, rng).is_ok();