Skip to main content

sp1_core_machine/
executor.rs

1//! Execution utilities for tracing and generating execution records.
2
3use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6use slop_algebra::PrimeField32;
7use sp1_core_executor::Program;
8use sp1_core_executor::{
9    events::MemoryRecord, ExecutionError, ExecutionRecord, SP1CoreOpts, TracingVM,
10};
11use sp1_hypercube::air::PROOF_NONCE_NUM_WORDS;
12use sp1_jit::MinimalTrace;
13use tracing::Level;
14
15/// The output of the machine executor.
16#[derive(Debug, Clone, Serialize, Deserialize)]
17pub struct ExecutionOutput {
18    pub public_value_stream: Vec<u8>,
19    pub cycles: u64,
20}
21
22/// Trace a single [`MinimalTrace`] (corresponding to a shard) and return the execution record.
23///
24/// This is the core tracing function that converts a minimal trace into a full execution record
25/// with all the events needed for proving.
26#[tracing::instrument(
27    level = Level::DEBUG,
28    name = "trace_chunk",
29    skip_all,
30)]
31pub fn trace_chunk<F: PrimeField32>(
32    program: Arc<Program>,
33    opts: SP1CoreOpts,
34    chunk: impl MinimalTrace,
35    proof_nonce: [u32; PROOF_NONCE_NUM_WORDS],
36    mut record: ExecutionRecord,
37) -> Result<(bool, ExecutionRecord, [MemoryRecord; 32]), ExecutionError> {
38    let mut vm = TracingVM::new(&chunk, program, opts, proof_nonce, &mut record);
39    let status = vm.execute()?;
40    tracing::trace!("chunk ended at clk: {}", vm.core.clk());
41    tracing::trace!("chunk ended at pc: {}", vm.core.pc());
42
43    let pv = vm.public_values();
44
45    // Handle the case where `COMMIT` or `COMMIT_DEFERRED_PROOFS` happens across last two shards.
46    //
47    // todo: does this actually work in the new regieme? what if the shard is stopped due to the clk
48    // limit? if so, does that mean this could be wrong? its unclear!
49    if status.is_shard_boundry() && (pv.commit_syscall == 1 || pv.commit_deferred_syscall == 1) {
50        tracing::trace!("commit syscall or commit deferred proofs across last two shards");
51
52        loop {
53            // Execute until we get a done status.
54            if vm.execute()?.is_done() {
55                let pv = *vm.public_values();
56
57                // Update the record.
58                vm.record.public_values.commit_syscall = 1;
59                vm.record.public_values.commit_deferred_syscall = 1;
60                vm.record.public_values.committed_value_digest = pv.committed_value_digest;
61                vm.record.public_values.deferred_proofs_digest = pv.deferred_proofs_digest;
62
63                break;
64            }
65        }
66    }
67
68    // Finalize the public values
69    vm.record.finalize_public_values::<F>(true);
70
71    let registers = *vm.core.registers();
72    drop(vm);
73    Ok((status.is_done(), record, registers))
74}