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}