Skip to content
2 changes: 1 addition & 1 deletion circuit/program/src/request/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand Down
2 changes: 1 addition & 1 deletion synthesizer/process/benches/check_deployment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ fn prepare_check_deployment<N: Network, A: snarkvm_circuit::Aleo<Network = N>>(
};
// 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(
Expand Down
9 changes: 5 additions & 4 deletions synthesizer/process/src/stack/call/dynamic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<N>,
stack: &'a Stack<N>,
Expand Down
4 changes: 2 additions & 2 deletions synthesizer/process/src/stack/deploy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl<N: Network> Stack<N> {
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.
Expand Down Expand Up @@ -188,7 +188,7 @@ impl<N: Network> Stack<N> {
})
.collect::<Result<Vec<_>>>()?;
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.
Expand Down
2 changes: 1 addition & 1 deletion synthesizer/process/src/stack/helpers/synthesize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl<N: Network> Stack<N> {
_ => self.sample_value(&burner_address, &input_type.into(), rng),
})
.collect::<Result<Vec<_>>>()?;
// 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;
Expand Down
2 changes: 1 addition & 1 deletion synthesizer/process/src/tests/test_credits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
4 changes: 2 additions & 2 deletions synthesizer/src/vm/tests/test_v18/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
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 for block-wide synthesis limits.
Expand Down
83 changes: 83 additions & 0 deletions synthesizer/src/vm/tests/test_v19/closure_dynamic_targets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// 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::*;

// 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-
Comment on lines +18 to +19
#[test]
fn test_conditional_dynamic_call_target_deployment() {
const N_EXPERIMENTS: usize = 10;

let rng = &mut TestRng::default();

// 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::<CurrentNetwork>::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::<CurrentNetwork>::load().unwrap();

// About half of the calls to process.deploy should succeed. Among succeeded ones, about half
// 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::<CurrentAleo, _>(&parse_program(i), rng);

match deployment_attempt {
Ok(deployment) => {
println!(" - Deployment computation {i} succeeded with ID {}", deployment.to_deployment_id().unwrap());

// Ensure that different runs of verify_deployment agree on the result - even if it is a rejection.
let verification_successful =
process.verify_deployment::<CurrentAleo, _>(ConsensusVersion::V19, &deployment, rng).is_ok();
for _ in 1..N_EXPERIMENTS {
assert_eq!(
verification_successful,
process.verify_deployment::<CurrentAleo, _>(ConsensusVersion::V19, &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}");
}
}
}
}
Comment on lines +59 to +83

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description and the documentation of the test makes this very clear. The only guaranteed property being tested is that all verifiers agree on the decision - not that at least one of them accepts (which would in fact defeat the purpose of this PR other verifiers did not).

4 changes: 4 additions & 0 deletions synthesizer/src/vm/tests/test_v19/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
// Tests that the translation-marked variants of Input and Output are checked correctly.
mod translated_type_checks;

// Tests on the resolution of dynamic call targets involving closures. The relevant changes are not
// ConsensusVersion::V19-gated, but they were introduced at that point in time.
mod closure_dynamic_targets;

use super::*;

use super::test_v14::add_and_test_with_costs;
Expand Down