Skip to main content

sp1_core_executor/
state.rs

1use std::{
2    collections::VecDeque,
3    fs::File,
4    io::{Seek, Write},
5};
6
7use hashbrown::HashMap;
8use serde::{Deserialize, Serialize};
9use sp1_hypercube::{MachineVerifyingKey, SP1PcsProofInner};
10
11use crate::{
12    events::{MemoryEntry, PageProtRecord},
13    memory::Memory,
14    SP1RecursionProof, SyscallCode,
15};
16
17use sp1_primitives::SP1GlobalContext;
18
19/// Holds data describing the current state of a program's execution.
20#[derive(Debug, Clone, Default, Serialize, Deserialize)]
21#[repr(C)]
22pub struct ExecutionState {
23    /// The program counter.
24    pub pc: u64,
25
26    /// Whether or not the shard is finished.
27    pub shard_finished: bool,
28
29    /// The starting timestamp of the current shard.
30    pub initial_timestamp: u64,
31
32    /// The memory which instructions operate over. Values contain the memory value and last shard
33    /// + timestamp that each memory address was accessed.
34    pub memory: Memory<MemoryEntry>,
35
36    /// The page protection flags for each page in the memory.  The default values should be
37    /// `PROT_READ` | `PROT_WRITE`.
38    pub page_prots: HashMap<u64, PageProtRecord>,
39
40    /// The global clock keeps track of how many instructions have been executed through all
41    /// shards.
42    pub global_clk: u64,
43
44    /// The clock increments by 4 (possibly more in syscalls) for each instruction that has been
45    /// executed in this shard.
46    pub clk: u64,
47
48    /// Uninitialized memory addresses that have a specific value they should be initialized with.
49    /// `SyscallHintRead` uses this to write hint data into uninitialized memory.
50    pub uninitialized_memory: Memory<u64>,
51
52    /// A stream of input values (global to the entire program).
53    pub input_stream: VecDeque<Vec<u8>>,
54
55    /// A stream of proofs (reduce vk, proof, verifying key) inputted to the program.
56    pub proof_stream: Vec<(
57        SP1RecursionProof<SP1GlobalContext, SP1PcsProofInner>,
58        MachineVerifyingKey<SP1GlobalContext>,
59    )>,
60
61    /// A ptr to the current position in the proof stream, incremented after verifying a proof.
62    pub proof_stream_ptr: usize,
63
64    /// A stream of public values from the program (global to entire program).
65    pub public_values_stream: Vec<u8>,
66
67    /// A ptr to the current position in the public values stream, incremented when reading from
68    /// `public_values_stream`.
69    pub public_values_stream_ptr: usize,
70
71    /// Keeps track of how many times a certain syscall has been called.
72    pub syscall_counts: HashMap<SyscallCode, u64>,
73}
74
75impl ExecutionState {
76    #[must_use]
77    /// Create a new [`ExecutionState`].
78    pub fn new(pc_start: u64) -> Self {
79        Self {
80            global_clk: 0,
81            shard_finished: false,
82            initial_timestamp: 1,
83            clk: 0,
84            pc: pc_start,
85            memory: Memory::new_preallocated(),
86            page_prots: HashMap::new(),
87            uninitialized_memory: Memory::new_preallocated(),
88            input_stream: VecDeque::new(),
89            public_values_stream: Vec::new(),
90            public_values_stream_ptr: 0,
91            proof_stream: Vec::new(),
92            proof_stream_ptr: 0,
93            syscall_counts: HashMap::new(),
94        }
95    }
96}
97
98/// Holds data to track changes made to the runtime since a fork point.
99#[derive(Debug, Clone, Default)]
100#[allow(dead_code)]
101pub struct ForkState {
102    /// The `global_clk` value at the fork point.
103    pub global_clk: u64,
104    /// The original `clk` value at the fork point.
105    pub clk: u64,
106    /// The original `pc` value at the fork point.
107    pub pc: u64,
108    /// All memory changes since the fork point.
109    pub memory_diff: Memory<Option<MemoryEntry>>,
110    /// All page protection changes since the fork point.
111    pub page_prots_diff: HashMap<u64, PageProtRecord>,
112}
113
114impl ExecutionState {
115    /// Save the execution state to a file.
116    pub fn save(&self, file: &mut File) -> std::io::Result<()> {
117        let mut writer = std::io::BufWriter::new(file);
118        bincode::serialize_into(&mut writer, self).unwrap();
119        writer.flush()?;
120        writer.seek(std::io::SeekFrom::Start(0))?;
121        Ok(())
122    }
123}