Skip to content
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

Multi circuit proof integration #1510

Closed
wants to merge 12 commits into from
Closed

Conversation

vicsn
Copy link
Collaborator

@vicsn vicsn commented May 5, 2023

Motivation

This adds support for batch proving executions and their inclusions.

This is a very rough first draft. I suggest we do the review in two parts: first only important architecture comments on e.g. the callchain, function signatures and objects. There is a lot of repetition in the code, and existing TODOs of mine, so please save yourself time by mentioning your ideas only once.

Some notes on this PR:

  • I removed the generic from verify_execution<const VERIFY_INCLUSION: bool> which was never actually used, because verify_execution would still check whether the execution had an inclusion proof.
  • I separate preparation from execution inside of vm.execute() and vm.execute_fee() to avoid us having to cast_ref! parameters up and down the call chain.
  • Ray asked: "How are we storing the batched function and fee proofs in the Transaction in a way that clearly references which assignments were used and which inputs are required for verification?" I now store a proof in the Execution and Fee objects. I think ordering is straightforward: just adhere to the fixed ordering of the Vector/Array of the Execution/Fee's Assignments/Inputs.
  • I replaced the Execute mode of the Callstack by a Prepare mode - running execute_function(...) in Prepare mode doesn't create a proof so instead the caller can afterwards extract the filled registers.
  • inherent associated types are unstable if we try sth like: type ExecutionAssignments<'a, N> = Vec<&Assignment<N::Field>>;

Test Plan

  • You'll have to resample parameters.
  • It seems the original code never verified inclusion proofs. The likely reason for this is because this requires two input records, which was slightly more effort to program. Instead we had e.g. two test cases:
    • sample_execution_transaction_without_fee calls transfer() but fails as expected before verifying the inclusion
    • sample_execution_transaction_with_fee calls mint() which doesn't require an input record and corresponding
      inclusion proof. I adjusted the test now to call transfer(), there are still other tests which call mint().

Related PRs and design document

https://github.com/AleoHQ/snarkVM/pull/1382
https://docs.google.com/document/d/10f_VfrcL9POyBPdFWVov5vVieVL-YNW6gBCxidEoNq8/edit#heading=h.9e2ahww0jjqr

let mut all_assignments = Vec::with_capacity(1);
let (_response, mut execution, _inclusion, _metrics, function_assignments) =
process.prepare_function::<CurrentAleo, _>(authorization, rng).unwrap();
let function_assignments = Arc::try_unwrap(function_assignments).unwrap_or_default().into_inner(); // TODO: return Err if there is one
Copy link
Collaborator

Choose a reason for hiding this comment

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

IIRC an existence of Arc clones here would indicate a leak/logic error

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes in a next iteration I'm following the same approach we use for e.g. execution/inclusion, just try_unwrap

Comment on lines 36 to 37
// TODO: instead of unwrap, convert the error to an IoError
let batch_len = usize::try_from(u32::read_le(&mut reader)?).unwrap();
Copy link
Collaborator

Choose a reason for hiding this comment

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

is there a plan to support any 16bit architectures? if not, casting u32 to usize should never fail

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I think with that assumption in hand this PR would also be a lot simpler: https://github.com/AleoHQ/snarkVM/pull/1499
But we spent so much time on it already that I think not assuming that is fine for now.

Base automatically changed from staging to testnet3 May 10, 2023 19:02
@vicsn vicsn force-pushed the multi-circuit-proof-integration branch 2 times, most recently from bc49de5 to 24a7dca Compare May 16, 2023 00:21
@vicsn vicsn marked this pull request as ready for review May 17, 2023 18:50
@vicsn vicsn requested a review from ljedrz May 17, 2023 18:50
@vicsn vicsn force-pushed the multi-circuit-proof-integration branch from d9cb92d to df58d23 Compare May 18, 2023 18:48
Comment on lines +440 to +454
impl<N: Network> Ord for ProvingKeyId<N> {
/// Ordering is determined by the program_id first, then the function_name second.
fn cmp(&self, other: &Self) -> Ordering {
match self.program_id == other.program_id {
true => self.function_name.cmp(&other.function_name),
false => self.program_id.cmp(&other.program_id),
}
}
}

impl<N: Network> PartialOrd for ProvingKeyId<N> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
Copy link
Collaborator

@ljedrz ljedrz May 19, 2023

Choose a reason for hiding this comment

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

this should be identical to an automatic #[derive(PartialOrd, Ord)]: the program_id is compared first, and if it's the same, the function_name is compared (source).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Due to the way the derived Ord/PartialOrd works, the compiler also demands the networktype (Testnet3) to have those derivations, and to adjust a large amount of trait bounds to be updated to N: Network+Ord+PartialOrd. I think keep the code as is would be better.

For reference, a non-compiling partial implementation:

diff --git a/console/network/src/testnet3.rs b/console/network/src/testnet3.rs
index b29dcf99e..2ebd3435d 100644
--- a/console/network/src/testnet3.rs
+++ b/console/network/src/testnet3.rs
@@ -75,7 +75,7 @@ lazy_static! {
     };
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Ord, PartialOrd)]
 pub struct Testnet3;
 
 impl Testnet3 {
diff --git a/synthesizer/src/block/transition/mod.rs b/synthesizer/src/block/transition/mod.rs
index 1ac051851..863409eb9 100644
--- a/synthesizer/src/block/transition/mod.rs
+++ b/synthesizer/src/block/transition/mod.rs
@@ -431,24 +431,8 @@ impl<N: Network> Transition<N> {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq)]
-pub struct ProvingKeyId<N: Network> {
+#[derive(Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
+pub struct ProvingKeyId<N: Network + Ord> {
     pub program_id: ProgramID<N>,
     pub function_name: Identifier<N>,
-}
-
-impl<N: Network> Ord for ProvingKeyId<N> {
-    /// Ordering is determined by the program_id first, then the function_name second.
-    fn cmp(&self, other: &Self) -> Ordering {
-        match self.program_id == other.program_id {
-            true => self.function_name.cmp(&other.function_name),
-            false => self.program_id.cmp(&other.program_id),
-        }
-    }
-}
-
-impl<N: Network> PartialOrd for ProvingKeyId<N> {
-    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
-        Some(self.cmp(other))
-    }
-}
+}
\ No newline at end of file
diff --git a/synthesizer/src/process/execute.rs b/synthesizer/src/process/execute.rs
index eebdd5249..d761acc06 100644
--- a/synthesizer/src/process/execute.rs
+++ b/synthesizer/src/process/execute.rs
@@ -18,7 +18,7 @@ use super::*;
 
 use crate::{Key, KeyBatch, KeyMode, ProvingKeyId};
 
-impl<N: Network> Process<N> {
+impl<N: Network + Ord + PartialOrd> Process<N> {

@@ -66,7 +67,6 @@ impl<N: Network> TransitionStorage<N> for TransitionMemory<N> {
input_store: InputStore::open(dev)?,
output_store: OutputStore::open(dev)?,
finalize_map: MemoryMap::default(),
proof_map: MemoryMap::default(),
Copy link
Collaborator

@ljedrz ljedrz May 19, 2023

Choose a reason for hiding this comment

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

should we mark the corresponding DataID as deprecated? if we don't intend to use it anymore, we can remove it before the next network reset

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm good question, implemented it here: 50ab2d3
@raychu86 do we have a process in place for updating database objects? Should I document it in CONTRIBUTING?

Copy link
Collaborator

@ljedrz ljedrz May 19, 2023

Choose a reason for hiding this comment

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

related: https://github.com/AleoHQ/snarkVM/pull/1560; also, only the DataID variant needs to remain, so as to not perturb the order (and values) of the others (unless we explicitly assign values to the DataID variants)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

On advice from Howard, we're merging this PR into staging, allowing us to just remove the DataIDs

Copy link
Collaborator

@ljedrz ljedrz left a comment

Choose a reason for hiding this comment

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

Left a few more comments.

@vicsn vicsn force-pushed the multi-circuit-proof-integration branch from cd0a0b1 to a5fb2b7 Compare May 19, 2023 18:30
@vicsn vicsn requested review from howardwu and raychu86 May 19, 2023 18:47
@vicsn vicsn changed the base branch from testnet3 to ref/syn5 May 19, 2023 19:53
@vicsn vicsn force-pushed the multi-circuit-proof-integration branch from 50ab2d3 to 71d7a63 Compare May 19, 2023 19:56
@vicsn vicsn force-pushed the multi-circuit-proof-integration branch from 71d7a63 to 7f4a4c4 Compare May 19, 2023 20:00
Base automatically changed from ref/syn5 to testnet3 May 19, 2023 21:29
@howardwu howardwu changed the base branch from testnet3 to staging May 25, 2023 21:56
@howardwu howardwu closed this May 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants