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}