-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refactor CallStack::Synthesize to produce consistent dummy outputs for faster nested import deployments #2598
base: staging
Are you sure you want to change the base?
Conversation
NOTE: this PR will also significantly speed up tests using nested deployments, e.g. |
@@ -45,7 +45,7 @@ pub trait CallTrait<N: Network> { | |||
/// Executes the instruction. | |||
fn execute<A: circuit::Aleo<Network = N>, R: CryptoRng + Rng>( | |||
&self, | |||
stack: &(impl StackEvaluate<N> + StackExecute<N> + StackMatches<N> + StackProgram<N>), | |||
stack: &Stack<N>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change the interface? Can we keep it the way it was? Same for the other function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed here: 774efae
synthesizer/process/src/stack/mod.rs
Outdated
@@ -316,6 +316,12 @@ impl<N: Network> StackProgram<N> for Stack<N> { | |||
.ok_or_else(|| anyhow!("Function '{function_name}' does not exist")) | |||
} | |||
|
|||
/// Returns true if the proving key for the given function name already exists in this stack. | |||
#[inline] | |||
fn has_proving_key(&self, function_name: &Identifier<N>) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why add this extra wrapper?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think if we don't want to have this wrapper, I need to revert 774efae.
I guess the cleanest solution is if I go ahead and to that, so we can directly call contains_proving_key
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see. Hmm I don't know the reasoning behind the choice of StackProgram<N>
trait existing. But let's try to keep that unchanged.
One approach which could be somewhat consistent, is to create a new trait StackKeys
. And these particular functions (contains/get/insert proving/verifying keys) could impl<N> StackKeys<N>
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed here: 6ebe642
// Return the request and response. | ||
(request, response) | ||
} | ||
CallStack::Synthesize(_, private_key, ..) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing comment like you added to the other synthesize and authorize cases
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any difference to the contents of CallStack::Synthesize
and CallStack::CheckDeployment
? Perhaps they can be merged into the same case.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed both here: 815a4df
Synthesize
and CheckDeployment
are indeed the same!
// Compute the randomizer. | ||
let randomizer = N::hash_to_scalar_psd2(&[*request.tvk(), index])?; | ||
// Construct the record nonce from that randomizer. | ||
let record_nonce = N::g_scalar_multiply(&randomizer); | ||
// Sample the record with that nonce. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be made a part of sample_record
, so that callers of sample_record
don't have to think about it anymore and all are guaranteed correct usage?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a new function sample_record_using_tvk
here: 0503e5c
@@ -265,22 +267,24 @@ impl<N: Network> CallTrait<N> for Call<N> { | |||
inputs.iter(), | |||
&function.input_types(), | |||
root_tvk, | |||
is_root, | |||
false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed here: d7070d9
@@ -289,38 +293,38 @@ impl<N: Network> CallTrait<N> for Call<N> { | |||
inputs.iter(), | |||
&function.input_types(), | |||
root_tvk, | |||
is_root, | |||
false, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use false
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed here: d7070d9
note: the failing |
Summary
This PR refactors the way
CallStack::Synthesize
is run, decoupling theSynthesize
mode from the oldexecute_function
approach. It produces consistent dummy outputs (inspired byCheckDeployment
) more rapidly and skips sub-circuit construction for nested import calls. The result is significantly faster deployments for deeply nested imports, while still generating cryptographically coherent record nonces.Motivation
Previously,
Authorize
andSynthesize
modes were lumped together. As such, calls in CallStack::Synthesize were forced to run a real sub-circuit viaexecute_function
. This is slow for nested imports and has led to an exponential growth in deployment time w.r.t. the import depth.Thus, this PR refactors the
Synthesize
branch to skip full circuit execution and produce “dummy” outputs with consistent record nonces.Note
This PR changes expected future IDs in 3 of the
execute_and_finalize
tests. The reason is that previously, Synthesize always ran real sub-circuits, consuming RNG draws. With this PR, certain sub-circuits are skipped by producing dummy outputs. As a result, the RNG is executed less times, leading to different transaction commitments and future IDs.Test Plan
Tested the deployment and execution of programs with deep imports in a local devnet.
Related PRs