sov_rollup_interface/state_machine/stf.rs
1//! This module is the core of the Sovereign SDK. It defines the traits and types that
2//! allow the SDK to run the "business logic" of any application generically.
3//!
4//! The most important trait in this module is the [`StateTransitionFunction`], which defines the
5//! main event loop of the rollup.
6use borsh::{BorshDeserialize, BorshSerialize};
7use serde::de::DeserializeOwned;
8use serde::{Deserialize, Serialize};
9
10use crate::da::DaSpec;
11use crate::zk::{ValidityCondition, Zkvm};
12
13#[cfg(any(all(test, feature = "sha2"), feature = "fuzzing"))]
14pub mod fuzzing;
15
16/// The configuration of a full node of the rollup which creates zk proofs.
17pub struct ProverConfig;
18/// The configuration used to initialize the "Verifier" of the state transition function
19/// which runs inside of the zkVM.
20pub struct ZkConfig;
21/// The configuration of a standard full node of the rollup which does not create zk proofs
22pub struct StandardConfig;
23
24/// A special marker trait which allows us to define different rollup configurations. There are
25/// only 3 possible instantiations of this trait: [`ProverConfig`], [`ZkConfig`], and [`StandardConfig`].
26pub trait StateTransitionConfig: sealed::Sealed {}
27impl StateTransitionConfig for ProverConfig {}
28impl StateTransitionConfig for ZkConfig {}
29impl StateTransitionConfig for StandardConfig {}
30
31// https://rust-lang.github.io/api-guidelines/future-proofing.html
32mod sealed {
33 use super::{ProverConfig, StandardConfig, ZkConfig};
34
35 pub trait Sealed {}
36 impl Sealed for ProverConfig {}
37 impl Sealed for ZkConfig {}
38 impl Sealed for StandardConfig {}
39}
40
41/// A receipt for a single transaction. These receipts are stored in the rollup's database
42/// and may be queried via RPC. Receipts are generic over a type `R` which the rollup can use to
43/// store additional data, such as the status code of the transaction or the amout of gas used.s
44#[derive(Debug, Clone, Serialize, Deserialize)]
45/// A receipt showing the result of a transaction
46pub struct TransactionReceipt<R> {
47 /// The canonical hash of this transaction
48 pub tx_hash: [u8; 32],
49 /// The canonically serialized body of the transaction, if it should be persisted
50 /// in the database
51 pub body_to_save: Option<Vec<u8>>,
52 /// The events output by this transaction
53 pub events: Vec<Event>,
54 /// Any additional structured data to be saved in the database and served over RPC
55 /// For example, this might contain a status code.
56 pub receipt: R,
57}
58
59/// A receipt for a batch of transactions. These receipts are stored in the rollup's database
60/// and may be queried via RPC. Batch receipts are generic over a type `BatchReceiptContents` which the rollup
61/// can use to store arbitrary typed data, like the gas used by the batch. They are also generic over a type `TxReceiptContents`,
62/// since they contain a vectors of [`TransactionReceipt`]s.
63#[derive(Debug, Clone, Serialize, Deserialize)]
64/// A receipt giving the outcome of a batch of transactions
65pub struct BatchReceipt<BatchReceiptContents, TxReceiptContents> {
66 /// The canonical hash of this batch
67 pub batch_hash: [u8; 32],
68 /// The receipts of all the transactions in this batch.
69 pub tx_receipts: Vec<TransactionReceipt<TxReceiptContents>>,
70 /// Any additional structured data to be saved in the database and served over RPC
71 pub inner: BatchReceiptContents,
72}
73
74/// Result of applying a slot to current state
75/// Where:
76/// - S - generic for state root
77/// - B - generic for batch receipt contents
78/// - T - generic for transaction receipt contents
79/// - W - generic for witness
80pub struct SlotResult<S, B, T, W> {
81 /// Final state root after all blobs were applied
82 pub state_root: S,
83 /// Receipt for each applied batch
84 pub batch_receipts: Vec<BatchReceipt<B, T>>,
85 /// Witness after applying the whole block
86 pub witness: W,
87}
88
89// TODO(@preston-evans98): update spec with simplified API
90/// State transition function defines business logic that responsible for changing state.
91/// Terminology:
92/// - state root: root hash of state merkle tree
93/// - block: DA layer block
94/// - batch: Set of transactions grouped together, or block on L2
95/// - blob: Non serialised batch or anything else that can be posted on DA layer, like attestation or proof.
96pub trait StateTransitionFunction<Vm: Zkvm, Da: DaSpec> {
97 /// Root hash of state merkle tree
98 type StateRoot: Serialize + DeserializeOwned + Clone + AsRef<[u8]>;
99 /// The initial state of the rollup.
100 type InitialState;
101
102 /// The contents of a transaction receipt. This is the data that is persisted in the database
103 type TxReceiptContents: Serialize + DeserializeOwned + Clone;
104
105 /// The contents of a batch receipt. This is the data that is persisted in the database
106 type BatchReceiptContents: Serialize + DeserializeOwned + Clone;
107
108 /// Witness is a data that is produced during actual batch execution
109 /// or validated together with proof during verification
110 type Witness: Default + Serialize + DeserializeOwned;
111
112 /// The validity condition that must be verified outside of the Vm
113 type Condition: ValidityCondition;
114
115 /// Perform one-time initialization for the genesis block and returns the resulting root hash wrapped in a result.
116 /// If the init chain fails we panic.
117 fn init_chain(&mut self, params: Self::InitialState) -> Self::StateRoot;
118
119 /// Called at each **DA-layer block** - whether or not that block contains any
120 /// data relevant to the rollup.
121 /// If slot is started in Full Node mode, default witness should be provided.
122 /// If slot is started in Zero Knowledge mode, witness from execution should be provided.
123 ///
124 /// Applies batches of transactions to the rollup,
125 /// slashing the sequencer who proposed the blob on failure.
126 /// The blobs are contained into a slot whose data is contained within the `slot_data` parameter,
127 /// this parameter is mainly used within the begin_slot hook.
128 /// The concrete blob type is defined by the DA layer implementation,
129 /// which is why we use a generic here instead of an associated type.
130 ///
131 /// Commits state changes to the database
132 fn apply_slot<'a, I>(
133 &mut self,
134 pre_state_root: &Self::StateRoot,
135 witness: Self::Witness,
136 slot_header: &Da::BlockHeader,
137 validity_condition: &Da::ValidityCondition,
138 blobs: I,
139 ) -> SlotResult<
140 Self::StateRoot,
141 Self::BatchReceiptContents,
142 Self::TxReceiptContents,
143 Self::Witness,
144 >
145 where
146 I: IntoIterator<Item = &'a mut Da::BlobTransaction>;
147}
148
149/// A key-value pair representing a change to the rollup state
150#[derive(Debug, Clone, PartialEq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
151#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
152pub struct Event {
153 key: EventKey,
154 value: EventValue,
155}
156
157impl Event {
158 /// Create a new event with the given key and value
159 pub fn new(key: &str, value: &str) -> Self {
160 Self {
161 key: EventKey(key.as_bytes().to_vec()),
162 value: EventValue(value.as_bytes().to_vec()),
163 }
164 }
165
166 /// Get the event key
167 pub fn key(&self) -> &EventKey {
168 &self.key
169 }
170
171 /// Get the event value
172 pub fn value(&self) -> &EventValue {
173 &self.value
174 }
175}
176
177/// The key of an event. This is a wrapper around a `Vec<u8>`.
178#[derive(
179 Debug,
180 Clone,
181 PartialEq,
182 Eq,
183 PartialOrd,
184 Ord,
185 Hash,
186 BorshSerialize,
187 BorshDeserialize,
188 Serialize,
189 Deserialize,
190)]
191#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
192pub struct EventKey(Vec<u8>);
193
194impl EventKey {
195 /// Return the inner bytes of the event key.
196 pub fn inner(&self) -> &Vec<u8> {
197 &self.0
198 }
199}
200
201/// The value of an event. This is a wrapper around a `Vec<u8>`.
202#[derive(Debug, Clone, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize)]
203#[cfg_attr(any(test, feature = "fuzzing"), derive(proptest_derive::Arbitrary))]
204pub struct EventValue(Vec<u8>);
205
206impl EventValue {
207 /// Return the inner bytes of the event value.
208 pub fn inner(&self) -> &Vec<u8> {
209 &self.0
210 }
211}