-
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
[NCC-ADN] Prevent ignoring proving tasks #2032
Changes from all commits
b898910
6b8012b
ff5d16c
28c7ca2
51434e4
58ee252
3d94ab9
a012dd7
d066cfb
c1a561a
35a8e8a
46b009b
b8a8acd
c40a259
acf3f24
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -19,23 +19,20 @@ mod inclusion; | |||||||||||
pub use inclusion::*; | ||||||||||||
|
||||||||||||
use circuit::Assignment; | ||||||||||||
use console::{ | ||||||||||||
network::prelude::*, | ||||||||||||
program::{InputID, Locator}, | ||||||||||||
}; | ||||||||||||
use console::{network::prelude::*, program::InputID}; | ||||||||||||
use ledger_block::{Execution, Fee, Transition}; | ||||||||||||
use ledger_query::QueryTrait; | ||||||||||||
use synthesizer_snark::{Proof, ProvingKey, VerifyingKey}; | ||||||||||||
|
||||||||||||
use once_cell::sync::OnceCell; | ||||||||||||
use std::collections::HashMap; | ||||||||||||
use std::collections::BTreeMap; | ||||||||||||
|
||||||||||||
#[derive(Clone, Debug, Default)] | ||||||||||||
pub struct Trace<N: Network> { | ||||||||||||
/// The list of transitions. | ||||||||||||
transitions: Vec<Transition<N>>, | ||||||||||||
/// A map of locators to (proving key, assignments) pairs. | ||||||||||||
transition_tasks: HashMap<Locator<N>, (ProvingKey<N>, Vec<Assignment<N::Field>>)>, | ||||||||||||
transition_tasks: BTreeMap<ProvingKey<N>, Vec<Assignment<N::Field>>>, | ||||||||||||
/// A tracker for all inclusion tasks. | ||||||||||||
inclusion_tasks: Inclusion<N>, | ||||||||||||
/// A list of call metrics. | ||||||||||||
|
@@ -52,7 +49,7 @@ impl<N: Network> Trace<N> { | |||||||||||
pub fn new() -> Self { | ||||||||||||
Self { | ||||||||||||
transitions: Vec::new(), | ||||||||||||
transition_tasks: HashMap::new(), | ||||||||||||
transition_tasks: BTreeMap::new(), | ||||||||||||
inclusion_tasks: Inclusion::new(), | ||||||||||||
inclusion_assignments: OnceCell::new(), | ||||||||||||
global_state_root: OnceCell::new(), | ||||||||||||
|
@@ -87,10 +84,8 @@ impl<N: Network> Trace<N> { | |||||||||||
// Insert the transition into the inclusion tasks. | ||||||||||||
self.inclusion_tasks.insert_transition(input_ids, transition)?; | ||||||||||||
|
||||||||||||
// Construct the locator. | ||||||||||||
let locator = Locator::new(*transition.program_id(), *transition.function_name()); | ||||||||||||
// Insert the assignment (and proving key if the entry does not exist), for the specified locator. | ||||||||||||
self.transition_tasks.entry(locator).or_insert((proving_key, vec![])).1.push(assignment); | ||||||||||||
// Insert the assignment (and proving key if the entry does not exist). | ||||||||||||
self.transition_tasks.entry(proving_key).or_default().push(assignment); | ||||||||||||
// Insert the transition into the list. | ||||||||||||
self.transitions.push(transition.clone()); | ||||||||||||
// Insert the call metrics into the list. | ||||||||||||
|
@@ -165,11 +160,9 @@ impl<N: Network> Trace<N> { | |||||||||||
// Retrieve the global state root. | ||||||||||||
let global_state_root = | ||||||||||||
self.global_state_root.get().ok_or_else(|| anyhow!("Global state root has not been set"))?; | ||||||||||||
// Construct the proving tasks. | ||||||||||||
let proving_tasks = self.transition_tasks.values().cloned().collect(); | ||||||||||||
// Compute the proof. | ||||||||||||
let (global_state_root, proof) = | ||||||||||||
Self::prove_batch::<A, R>(locator, proving_tasks, inclusion_assignments, *global_state_root, rng)?; | ||||||||||||
Self::prove_batch::<A, R>(locator, &self.transition_tasks, inclusion_assignments, *global_state_root, rng)?; | ||||||||||||
// Return the execution. | ||||||||||||
Execution::from(self.transitions.iter().cloned(), global_state_root, Some(proof)) | ||||||||||||
} | ||||||||||||
|
@@ -193,12 +186,10 @@ impl<N: Network> Trace<N> { | |||||||||||
self.global_state_root.get().ok_or_else(|| anyhow!("Global state root has not been set"))?; | ||||||||||||
// Retrieve the fee transition. | ||||||||||||
let fee_transition = &self.transitions[0]; | ||||||||||||
// Construct the proving tasks. | ||||||||||||
let proving_tasks = self.transition_tasks.values().cloned().collect(); | ||||||||||||
// Compute the proof. | ||||||||||||
let (global_state_root, proof) = Self::prove_batch::<A, R>( | ||||||||||||
"credits.aleo/fee (private or public)", | ||||||||||||
proving_tasks, | ||||||||||||
&self.transition_tasks, | ||||||||||||
inclusion_assignments, | ||||||||||||
*global_state_root, | ||||||||||||
rng, | ||||||||||||
|
@@ -258,7 +249,7 @@ impl<N: Network> Trace<N> { | |||||||||||
/// Returns the global state root and proof for the given assignments. | ||||||||||||
fn prove_batch<A: circuit::Aleo<Network = N>, R: Rng + CryptoRng>( | ||||||||||||
locator: &str, | ||||||||||||
mut proving_tasks: Vec<(ProvingKey<N>, Vec<Assignment<N::Field>>)>, | ||||||||||||
proving_tasks: &BTreeMap<ProvingKey<N>, Vec<Assignment<N::Field>>>, | ||||||||||||
inclusion_assignments: &[InclusionAssignment<N>], | ||||||||||||
global_state_root: N::StateRoot, | ||||||||||||
rng: &mut R, | ||||||||||||
|
@@ -282,15 +273,27 @@ impl<N: Network> Trace<N> { | |||||||||||
batch_inclusions.push(assignment.to_circuit_assignment::<A>()?); | ||||||||||||
} | ||||||||||||
|
||||||||||||
if !batch_inclusions.is_empty() { | ||||||||||||
// Fetch the inclusion proving key. | ||||||||||||
let proving_key = ProvingKey::<N>::new(N::inclusion_proving_key().clone()); | ||||||||||||
// Insert the inclusion proving key and assignments. | ||||||||||||
proving_tasks.push((proving_key, batch_inclusions)); | ||||||||||||
// Fetch the inclusion proving key. | ||||||||||||
let inclusion_proving_key = ProvingKey::<N>::new(N::inclusion_proving_key().clone()); | ||||||||||||
|
||||||||||||
Comment on lines
+276
to
+278
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
This should be moved back into the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm defining it here to make sure it has the appropriate lifetime:
Before this PR we made copies of the |
||||||||||||
// Proving tasks should not contain inclusion_proving_key if we still have batch_inclusions to add | ||||||||||||
if !batch_inclusions.is_empty() && proving_tasks.contains_key(&inclusion_proving_key) { | ||||||||||||
bail!("The inclusion proving key (and its instances) have already been inserted"); | ||||||||||||
} | ||||||||||||
|
||||||||||||
// Collect optional inclusion iter | ||||||||||||
let inclusion_iter = | ||||||||||||
(!batch_inclusions.is_empty()).then_some((&inclusion_proving_key, batch_inclusions.as_slice())); | ||||||||||||
|
||||||||||||
// Collect references to keys and assignments | ||||||||||||
let proving_tasks = proving_tasks.iter().map(|(p, a)| (p, a.as_slice())); | ||||||||||||
|
||||||||||||
// Optionally insert the inclusion proving key and assignments. | ||||||||||||
let proving_tasks = proving_tasks.chain(inclusion_iter.into_iter()); | ||||||||||||
|
||||||||||||
// Compute the proof. | ||||||||||||
let proof = ProvingKey::prove_batch(locator, &proving_tasks, rng)?; | ||||||||||||
let proof = ProvingKey::prove_batch(locator, proving_tasks, rng)?; | ||||||||||||
|
||||||||||||
// Return the global state root and proof. | ||||||||||||
Ok((global_state_root, proof)) | ||||||||||||
} | ||||||||||||
|
@@ -315,8 +318,9 @@ impl<N: Network> Trace<N> { | |||||||||||
} | ||||||||||||
// Verify the proof. | ||||||||||||
match VerifyingKey::verify_batch(locator, verifier_inputs, proof) { | ||||||||||||
true => Ok(()), | ||||||||||||
false => bail!("Failed to verify proof"), | ||||||||||||
Ok(true) => Ok(()), | ||||||||||||
Ok(false) => bail!("Failed to verify proof"), | ||||||||||||
Err(e) => bail!("Verifier failed - {e}"), | ||||||||||||
} | ||||||||||||
} | ||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,19 +56,20 @@ impl<N: Network> ProvingKey<N> { | |
|
||
/// Returns a proof for the given batch of proving keys and assignments. | ||
#[allow(clippy::type_complexity)] | ||
pub fn prove_batch<R: Rng + CryptoRng>( | ||
pub fn prove_batch<'a, R: Rng + CryptoRng>( | ||
locator: &str, | ||
assignments: &[(ProvingKey<N>, Vec<circuit::Assignment<N::Field>>)], | ||
assignments: impl Iterator<Item = (&'a ProvingKey<N>, &'a [circuit::Assignment<N::Field>])>, | ||
rng: &mut R, | ||
) -> Result<Proof<N>> { | ||
#[cfg(feature = "aleo-cli")] | ||
let timer = std::time::Instant::now(); | ||
|
||
// Prepare the instances. | ||
let instances: BTreeMap<_, _> = assignments | ||
.iter() | ||
.map(|(proving_key, assignments)| (proving_key.deref(), assignments.as_slice())) | ||
.collect(); | ||
let mut instances = BTreeMap::default(); | ||
for (proving_key, assignments) in assignments { | ||
let previous_entry = instances.insert(proving_key.deref(), assignments); | ||
ensure!(previous_entry.is_none(), "prove_batch found duplicate proving keys"); | ||
} | ||
|
||
// Retrieve the proving parameters. | ||
let universal_prover = N::varuna_universal_prover(); | ||
|
@@ -91,3 +92,23 @@ impl<N: Network> Deref for ProvingKey<N> { | |
&self.proving_key | ||
} | ||
} | ||
|
||
impl<N: Network> Eq for ProvingKey<N> {} | ||
|
||
impl<N: Network> PartialEq for ProvingKey<N> { | ||
fn eq(&self, other: &Self) -> bool { | ||
self.deref() == other.deref() | ||
} | ||
} | ||
ljedrz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
impl<N: Network> Ord for ProvingKey<N> { | ||
fn cmp(&self, other: &Self) -> Ordering { | ||
self.deref().cmp(other.deref()) | ||
ljedrz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
} | ||
|
||
impl<N: Network> PartialOrd for ProvingKey<N> { | ||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> { | ||
Some(self.cmp(other)) | ||
} | ||
} | ||
Comment on lines
+98
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why can't these be auto-derived? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. error[E0277]: the trait bound There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's very odd, I'll give it a look tomorrow as well. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this would do the job: https://github.com/AleoHQ/snarkVM/pull/2231 |
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.
Where is the duplicate function call?
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.
The intention was above at
call zero.aleo/b r0 r1 into r2;