sp1_sdk/cpu/
execute.rs

1//! # CPU Execution
2//!
3//! This module provides a builder for simulating the execution of a program on the CPU.
4
5use anyhow::Result;
6use sp1_core_executor::{ExecutionReport, HookEnv, IoWriter, SP1ContextBuilder};
7use sp1_core_machine::io::SP1Stdin;
8use sp1_primitives::io::SP1PublicValues;
9use sp1_prover::{components::CpuProverComponents, SP1Prover};
10
11/// A builder for simulating the execution of a program on the CPU.
12///
13/// This builder providers a typed interface for configuring the SP1 RISC-V executor. The builder
14/// is used for all the different variants of the [`crate::ProverClient`].
15pub struct CpuExecuteBuilder<'a> {
16    pub(crate) elf: &'a [u8],
17    pub(crate) stdin: SP1Stdin,
18    pub(crate) prover: &'a SP1Prover<CpuProverComponents>,
19    pub(crate) context_builder: SP1ContextBuilder<'a>,
20}
21
22impl<'a> CpuExecuteBuilder<'a> {
23    /// Add a executor [`sp1_core_executor::Hook`] into the context.
24    ///
25    /// # Arguments
26    /// * `fd` - The file descriptor that triggers this execution hook.
27    /// * `f` - The function to invoke when the hook is triggered.
28    ///
29    /// # Details
30    /// Hooks may be invoked from within SP1 by writing to the specified file descriptor `fd`
31    /// with [`sp1_zkvm::io::write`], returning a list of arbitrary data that may be read
32    /// with successive calls to [`sp1_zkvm::io::read`].
33    ///
34    /// # Example
35    /// ```rust,no_run
36    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
37    ///
38    /// let elf = &[1, 2, 3];
39    /// let stdin = SP1Stdin::new();
40    ///
41    /// let client = ProverClient::builder().cpu().build();
42    /// let builder = client
43    ///     .execute(elf, &stdin)
44    ///     .with_hook(1, |env, data| {
45    ///         println!("Hook triggered with data: {:?}", data);
46    ///         vec![vec![1, 2, 3]]
47    ///     })
48    ///     .run();
49    /// ```
50    #[must_use]
51    pub fn with_hook(
52        mut self,
53        fd: u32,
54        f: impl FnMut(HookEnv, &[u8]) -> Vec<Vec<u8>> + Send + Sync + 'a,
55    ) -> Self {
56        self.context_builder.hook(fd, f);
57        self
58    }
59
60    /// Set the maximum number of cpu cycles to use for execution.
61    ///
62    /// # Arguments
63    /// * `max_cycles` - The maximum number of cycles to use for execution.
64    ///
65    /// # Details
66    /// If the cycle limit is exceeded, execution will fail with the
67    /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`]. This is useful for preventing
68    /// infinite loops in the and limiting the execution time of the program.
69    ///
70    /// # Example
71    /// ```rust,no_run
72    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
73    ///
74    /// let elf = &[1, 2, 3];
75    /// let stdin = SP1Stdin::new();
76    ///
77    /// let client = ProverClient::builder().cpu().build();
78    /// let builder = client.execute(elf, &stdin).cycle_limit(1000000).run();
79    /// ```
80    #[must_use]
81    pub fn cycle_limit(mut self, max_cycles: u64) -> Self {
82        self.context_builder.max_cycles(max_cycles);
83        self
84    }
85
86    /// Whether to enable deferred proof verification in the executor.
87    ///
88    /// # Arguments
89    /// * `value` - Whether to enable deferred proof verification in the executor.
90    ///
91    /// # Details
92    /// Default: `true`. If set to `false`, the executor will skip deferred proof verification.
93    /// This is useful for reducing the execution time of the program and optimistically assuming
94    /// that the deferred proofs are correct. Can also be used for mock proof setups that require
95    /// verifying mock compressed proofs.
96    ///
97    /// # Example
98    /// ```rust,no_run
99    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
100    ///
101    /// let elf = &[1, 2, 3];
102    /// let stdin = SP1Stdin::new();
103    ///
104    /// let client = ProverClient::builder().cpu().build();
105    /// let builder = client.execute(elf, &stdin).deferred_proof_verification(false).run();
106    /// ```
107    #[must_use]
108    pub fn deferred_proof_verification(mut self, value: bool) -> Self {
109        self.context_builder.set_deferred_proof_verification(value);
110        self
111    }
112
113    /// Whether to enable gas calculation in the executor.
114    ///
115    /// # Arguments
116    /// * `value` - Whether to enable gas calculation in the executor.
117    ///
118    /// # Details
119    /// Default: `true`. If set to `false`, the executor will not calculate gas.
120    /// This is useful for reducing the execution time of the program, since gas calculation
121    /// must perform extra work to simulate parts of the proving process.
122    ///
123    /// Gas may be retrieved through the [`ExecutionReport`] available through [`Self::run`].
124    /// It will be `None` if and only if this option is disabled.
125    ///
126    /// # Example
127    /// ```rust,no_run
128    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
129    ///
130    /// let elf = &[1, 2, 3];
131    /// let stdin = SP1Stdin::new();
132    ///
133    /// let client = ProverClient::builder().cpu().build();
134    /// let builder = client.execute(elf, &stdin).calculate_gas(false).run();
135    /// ```
136    #[must_use]
137    pub fn calculate_gas(mut self, value: bool) -> Self {
138        self.context_builder.calculate_gas(value);
139        self
140    }
141
142    /// Override the default stdout of the guest program.
143    ///
144    /// # Example
145    /// ```rust,no_run
146    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
147    ///
148    /// let mut stdout = Vec::new();
149    ///
150    /// let elf = &[1, 2, 3];
151    /// let stdin = SP1Stdin::new();
152    ///
153    /// let client = ProverClient::builder().cpu().build();
154    /// client.execute(elf, &stdin).stdout(&mut stdout).run();
155    /// ```
156    #[must_use]
157    pub fn stdout<W: IoWriter>(mut self, writer: &'a mut W) -> Self {
158        self.context_builder.stdout(writer);
159        self
160    }
161
162    /// Override the default stdout of the guest program.
163    ///
164    /// # Example
165    /// ```rust,no_run
166    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
167    ///
168    /// let mut stderr = Vec::new();
169    ///
170    /// let elf = &[1, 2, 3];
171    /// let stdin = SP1Stdin::new();
172    ///
173    /// let client = ProverClient::builder().cpu().build();
174    /// client.execute(elf, &stdin).stderr(&mut stderr).run();
175    /// ```
176    #[must_use]
177    pub fn stderr<W: IoWriter>(mut self, writer: &'a mut W) -> Self {
178        self.context_builder.stderr(writer);
179        self
180    }
181
182    /// Executes the program on the input with the built arguments.
183    ///
184    /// # Details
185    /// This method will execute the program on the input with the built arguments. If the program
186    /// fails to execute, the method will return an error.
187    ///
188    /// # Example
189    /// ```rust,no_run
190    /// use sp1_sdk::{include_elf, Prover, ProverClient, SP1Stdin};
191    ///
192    /// let elf = &[1, 2, 3];
193    /// let stdin = SP1Stdin::new();
194    ///
195    /// let client = ProverClient::builder().cpu().build();
196    /// let (public_values, execution_report) = client.execute(elf, &stdin).run().unwrap();
197    /// ```
198    pub fn run(self) -> Result<(SP1PublicValues, ExecutionReport)> {
199        let Self { prover, elf, stdin, mut context_builder } = self;
200        let context = context_builder.build();
201        let (pv, _, report) = prover.execute(elf, &stdin, context)?;
202        Ok((pv, report))
203    }
204}