Skip to content

Commit

Permalink
fix: deferred checkpoints optimization (#1973)
Browse files Browse the repository at this point in the history
Co-authored-by: N <[email protected]>
  • Loading branch information
2 people authored and tamirhemo committed Jan 28, 2025
1 parent e98bbe6 commit 1dda2c0
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 38 deletions.
6 changes: 4 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ jobs:
pull_token: ${{ secrets.PULL_TOKEN }}

# If it's a nightly release, tag with the release time. If the tag is `main`, we want to use
# `latest` as the tag name. Else, use the tag name as is.
# `latest` as the tag name. else, use the tag name as is.
- name: Compute release name and tag
id: release_info
run: |
Expand Down Expand Up @@ -220,6 +220,8 @@ jobs:
fi
# Creates the release for this specific version
# If this is for latest, this will override the files there, but not change the commit to the current main.
# todo(n): change this to override the commit as well somehow.
- name: Create release
uses: softprops/action-gh-release@v2
with:
Expand Down Expand Up @@ -272,7 +274,7 @@ jobs:

- name: "Install SP1"
env:
SP1UP_VERSION: ${{ github.ref_name }}
SP1UP_VERSION: ${{ github.ref_name == 'main' && 'latest' || github.ref_name }}
run: |
cd sp1up
chmod +x sp1up
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/toolchain-ec2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ jobs:
- name: "Install SP1"
env:
SP1UP_VERSION: ${{ github.ref_name }}
SP1UP_VERSION: ${{ github.ref_name == 'main' && 'latest' || github.ref_name }}
run: |
cd sp1up
chmod +x sp1up
Expand Down
10 changes: 8 additions & 2 deletions crates/core/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,8 @@ pub struct Executor<'a> {
/// The costs of the program.
pub costs: HashMap<RiscvAirId, u64>,

/// Skip deferred proof verification.
/// Skip deferred proof verification. This check is informational only, not related to circuit
/// correctness.
pub deferred_proof_verification: DeferredProofVerification,

/// The frequency to check the stopping condition.
Expand Down Expand Up @@ -378,6 +379,9 @@ impl<'a> Executor<'a> {
pub fn recover(program: Program, state: ExecutionState, opts: SP1CoreOpts) -> Self {
let mut runtime = Self::new(program, opts);
runtime.state = state;
// Disable deferred proof verification since we're recovering from a checkpoint, and the
// checkpoint creator already had a chance to check the proofs.
runtime.deferred_proof_verification = DeferredProofVerification::Disabled;
runtime
}

Expand Down Expand Up @@ -1800,12 +1804,14 @@ impl<'a> Executor<'a> {
self.executor_mode = ExecutorMode::Checkpoint;
self.emit_global_memory_events = emit_global_memory_events;

// Clone self.state without memory and uninitialized_memory in it so it's faster.
// Clone self.state without memory, uninitialized_memory, proof_stream in it so it's faster.
let memory = std::mem::take(&mut self.state.memory);
let uninitialized_memory = std::mem::take(&mut self.state.uninitialized_memory);
let proof_stream = std::mem::take(&mut self.state.proof_stream);
let mut checkpoint = tracing::debug_span!("clone").in_scope(|| self.state.clone());
self.state.memory = memory;
self.state.uninitialized_memory = uninitialized_memory;
self.state.proof_stream = proof_stream;

let done = tracing::debug_span!("execute").in_scope(|| self.execute())?;
// Create a checkpoint using `memory_checkpoint`. Just include all memory if `done` since we
Expand Down
62 changes: 29 additions & 33 deletions crates/core/executor/src/syscalls/verify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,43 +15,39 @@ impl Syscall for VerifySyscall {
) -> Option<u32> {
let rt = &mut ctx.rt;

// vkey_ptr is a pointer to [u32; 8] which contains the verification key.
assert_eq!(vkey_ptr % 4, 0, "vkey_ptr must be word-aligned");
// pv_digest_ptr is a pointer to [u32; 8] which contains the public values digest.
assert_eq!(pv_digest_ptr % 4, 0, "pv_digest_ptr must be word-aligned");

let vkey = (0..8).map(|i| rt.word(vkey_ptr + i * 4)).collect::<Vec<u32>>();
// Skip deferred proof verification if the corresponding runtime flag is set.
if rt.deferred_proof_verification == DeferredProofVerification::Enabled {
// vkey_ptr is a pointer to [u32; 8] which contains the verification key.
assert_eq!(vkey_ptr % 4, 0, "vkey_ptr must be word-aligned");
// pv_digest_ptr is a pointer to [u32; 8] which contains the public values digest.
assert_eq!(pv_digest_ptr % 4, 0, "pv_digest_ptr must be word-aligned");

let pv_digest = (0..8).map(|i| rt.word(pv_digest_ptr + i * 4)).collect::<Vec<u32>>();
let vkey = (0..8).map(|i| rt.word(vkey_ptr + i * 4)).collect::<Vec<u32>>();

let proof_index = rt.state.proof_stream_ptr;
if proof_index >= rt.state.proof_stream.len() {
panic!("Not enough proofs were written to the runtime.");
}
let (proof, proof_vk) = &rt.state.proof_stream[proof_index].clone();
rt.state.proof_stream_ptr += 1;
let pv_digest = (0..8).map(|i| rt.word(pv_digest_ptr + i * 4)).collect::<Vec<u32>>();

let vkey_bytes: [u32; 8] = vkey.try_into().unwrap();
let pv_digest_bytes: [u32; 8] = pv_digest.try_into().unwrap();

// Skip deferred proof verification if the corresponding runtime flag is set.
match rt.deferred_proof_verification {
DeferredProofVerification::Enabled => {
if let Some(verifier) = rt.subproof_verifier {
verifier
.verify_deferred_proof(proof, proof_vk, vkey_bytes, pv_digest_bytes)
.unwrap_or_else(|e| {
panic!(
"Failed to verify proof {proof_index} with digest {}: {}",
hex::encode(bytemuck::cast_slice(&pv_digest_bytes)),
e
)
});
} else if rt.state.proof_stream_ptr == 1 {
tracing::info!("Not verifying sub proof during runtime");
};
let proof_index = rt.state.proof_stream_ptr;
if proof_index >= rt.state.proof_stream.len() {
panic!("Not enough proofs were written to the runtime.");
}
DeferredProofVerification::Disabled => {}
let (proof, proof_vk) = &rt.state.proof_stream[proof_index].clone();
rt.state.proof_stream_ptr += 1;

let vkey_bytes: [u32; 8] = vkey.try_into().unwrap();
let pv_digest_bytes: [u32; 8] = pv_digest.try_into().unwrap();
if let Some(verifier) = rt.subproof_verifier {
verifier
.verify_deferred_proof(proof, proof_vk, vkey_bytes, pv_digest_bytes)
.unwrap_or_else(|e| {
panic!(
"Failed to verify proof {proof_index} with digest {}: {}",
hex::encode(bytemuck::cast_slice(&pv_digest_bytes)),
e
)
});
} else if rt.state.proof_stream_ptr == 1 {
tracing::info!("Not verifying sub proof during runtime");
};
}

None
Expand Down

0 comments on commit 1dda2c0

Please sign in to comment.