sov_state/
storage.rs

1use std::fmt::Display;
2use std::sync::Arc;
3
4use borsh::{BorshDeserialize, BorshSerialize};
5use hex;
6use jmt::Version;
7use serde::de::DeserializeOwned;
8use serde::{Deserialize, Serialize};
9use sov_first_read_last_write_cache::{CacheKey, CacheValue};
10
11use crate::codec::{EncodeKeyLike, StateValueCodec};
12use crate::internal_cache::OrderedReadsAndWrites;
13use crate::utils::AlignedVec;
14use crate::witness::Witness;
15use crate::Prefix;
16
17/// The key type suitable for use in [`Storage::get`] and other getter methods of
18/// [`Storage`]. Cheaply-clonable.
19#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize, BorshDeserialize, BorshSerialize)]
20pub struct StorageKey {
21    key: Arc<Vec<u8>>,
22}
23
24impl From<CacheKey> for StorageKey {
25    fn from(cache_key: CacheKey) -> Self {
26        Self { key: cache_key.key }
27    }
28}
29
30impl StorageKey {
31    /// Returns a new [`Arc`] reference to the bytes of this key.
32    pub fn key(&self) -> Arc<Vec<u8>> {
33        self.key.clone()
34    }
35
36    /// Converts this key into a [`CacheKey`] via cloning.
37    pub fn to_cache_key(&self) -> CacheKey {
38        CacheKey {
39            key: self.key.clone(),
40        }
41    }
42
43    /// Converts this key into a [`CacheKey`].
44    pub fn into_cache_key(self) -> CacheKey {
45        CacheKey { key: self.key }
46    }
47}
48
49impl AsRef<Vec<u8>> for StorageKey {
50    fn as_ref(&self) -> &Vec<u8> {
51        &self.key
52    }
53}
54
55impl Display for StorageKey {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        write!(f, "{:x?}", hex::encode(self.key().as_ref()))
58    }
59}
60
61impl StorageKey {
62    /// Creates a new [`StorageKey`] that combines a prefix and a key.
63    pub fn new<K, Q, KC>(prefix: &Prefix, key: &Q, codec: &KC) -> Self
64    where
65        KC: EncodeKeyLike<Q, K>,
66        Q: ?Sized,
67    {
68        let encoded_key = codec.encode_key_like(key);
69        let encoded_key = AlignedVec::new(encoded_key);
70
71        let full_key = Vec::<u8>::with_capacity(prefix.len() + encoded_key.len());
72        let mut full_key = AlignedVec::new(full_key);
73        full_key.extend(prefix.as_aligned_vec());
74        full_key.extend(&encoded_key);
75
76        Self {
77            key: Arc::new(full_key.into_inner()),
78        }
79    }
80
81    /// Creates a new [`StorageKey`] that combines a prefix and a key.
82    pub fn singleton(prefix: &Prefix) -> Self {
83        Self {
84            key: Arc::new(prefix.as_aligned_vec().clone().into_inner()),
85        }
86    }
87}
88
89/// A serialized value suitable for storing. Internally uses an [`Arc<Vec<u8>>`]
90/// for cheap cloning.
91#[derive(
92    Clone, Debug, PartialEq, Eq, BorshSerialize, BorshDeserialize, Serialize, Deserialize, Default,
93)]
94pub struct StorageValue {
95    value: Arc<Vec<u8>>,
96}
97
98impl From<CacheValue> for StorageValue {
99    fn from(cache_value: CacheValue) -> Self {
100        Self {
101            value: cache_value.value,
102        }
103    }
104}
105
106impl From<Vec<u8>> for StorageValue {
107    fn from(value: Vec<u8>) -> Self {
108        Self {
109            value: Arc::new(value),
110        }
111    }
112}
113
114impl StorageValue {
115    /// Create a new storage value by serializing the input with the given codec.
116    pub fn new<V, VC>(value: &V, codec: &VC) -> Self
117    where
118        VC: StateValueCodec<V>,
119    {
120        let encoded_value = codec.encode_value(value);
121        Self {
122            value: Arc::new(encoded_value),
123        }
124    }
125
126    /// Get the bytes of this value.
127    pub fn value(&self) -> &[u8] {
128        &self.value
129    }
130
131    /// Convert this value into a [`CacheValue`].
132    pub fn into_cache_value(self) -> CacheValue {
133        CacheValue { value: self.value }
134    }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize, BorshDeserialize, BorshSerialize)]
138/// A proof that a particular storage key has a particular value, or is absent.
139pub struct StorageProof<P> {
140    /// The key which is proven
141    pub key: StorageKey,
142    /// The value, if any, which is proven
143    pub value: Option<StorageValue>,
144    /// The cryptographic proof
145    pub proof: P,
146}
147
148/// An interface for storing and retrieving values in the storage.
149pub trait Storage: Clone {
150    /// The witness type for this storage instance.
151    type Witness: Witness + Send + Sync;
152
153    /// The runtime config for this storage instance.
154    type RuntimeConfig;
155
156    /// A cryptographic proof that a particular key has a particular value, or is absent.
157    type Proof: Serialize
158        + DeserializeOwned
159        + core::fmt::Debug
160        + Clone
161        + BorshSerialize
162        + BorshDeserialize;
163
164    /// A cryptographic commitment to the contents of this storage
165    type Root: Serialize
166        + DeserializeOwned
167        + core::fmt::Debug
168        + Clone
169        + BorshSerialize
170        + BorshDeserialize
171        + Eq
172        + AsRef<[u8]>
173        + Into<[u8; 32]>; // Require a one-way conversion from the state root to a 32-byte array. This can always be
174                          // implemented by hashing the state root even if the root itself is not 32 bytes.
175
176    /// State update that will be committed to the database.
177    type StateUpdate;
178
179    /// Creates a new instance of this [`Storage`] type, with some configuration
180    /// options.
181    fn with_config(config: Self::RuntimeConfig) -> Result<Self, anyhow::Error>;
182
183    /// Returns the value corresponding to the key or None if key is absent.
184    fn get(&self, key: &StorageKey, witness: &Self::Witness) -> Option<StorageValue>;
185
186    /// Returns the value corresponding to the key or None if key is absent.
187    ///
188    /// # About accessory state
189    /// This method is blanket-implemented to return [`None`]. **Only native
190    /// execution environments** (i.e. outside of the zmVM) **SHOULD** override
191    /// this method to return a value. This is because accessory state **MUST
192    /// NOT** be readable from within the zmVM.
193    fn get_accessory(&self, _key: &StorageKey) -> Option<StorageValue> {
194        None
195    }
196
197    /// Calculates new state root but does not commit any changes to the database.
198    fn compute_state_update(
199        &self,
200        state_accesses: OrderedReadsAndWrites,
201        witness: &Self::Witness,
202    ) -> Result<(Self::Root, Self::StateUpdate), anyhow::Error>;
203
204    /// Commits state changes to the database.
205    fn commit(&self, node_batch: &Self::StateUpdate, accessory_update: &OrderedReadsAndWrites);
206
207    /// Validate all of the storage accesses in a particular cache log,
208    /// returning the new state root after applying all writes.
209    /// This function is equivalent to calling:
210    /// `self.compute_state_update & self.commit`
211    fn validate_and_commit(
212        &self,
213        state_accesses: OrderedReadsAndWrites,
214        witness: &Self::Witness,
215    ) -> Result<Self::Root, anyhow::Error> {
216        Self::validate_and_commit_with_accessory_update(
217            self,
218            state_accesses,
219            witness,
220            &Default::default(),
221        )
222    }
223
224    /// A version of [`Storage::validate_and_commit`] that allows for
225    /// "accessory" non-JMT updates. See `sov_db::NativeDB` for more information
226    /// about accessory state.
227    fn validate_and_commit_with_accessory_update(
228        &self,
229        state_accesses: OrderedReadsAndWrites,
230        witness: &Self::Witness,
231        accessory_update: &OrderedReadsAndWrites,
232    ) -> Result<Self::Root, anyhow::Error> {
233        let (root_hash, node_batch) = self.compute_state_update(state_accesses, witness)?;
234        self.commit(&node_batch, accessory_update);
235
236        Ok(root_hash)
237    }
238
239    /// Opens a storage access proof and validates it against a state root.
240    /// It returns a result with the opened leaf (key, value) pair in case of success.
241    fn open_proof(
242        state_root: Self::Root,
243        proof: StorageProof<Self::Proof>,
244    ) -> Result<(StorageKey, Option<StorageValue>), anyhow::Error>;
245
246    /// Indicates if storage is empty or not.
247    /// Useful during initialization.
248    fn is_empty(&self) -> bool;
249}
250
251// Used only in tests.
252impl From<&str> for StorageKey {
253    fn from(key: &str) -> Self {
254        Self {
255            key: Arc::new(key.as_bytes().to_vec()),
256        }
257    }
258}
259
260// Used only in tests.
261impl From<&str> for StorageValue {
262    fn from(value: &str) -> Self {
263        Self {
264            value: Arc::new(value.as_bytes().to_vec()),
265        }
266    }
267}
268
269/// A [`Storage`] that is suitable for use in native execution environments
270/// (outside of the zkVM).
271pub trait NativeStorage: Storage {
272    /// Returns the value corresponding to the key or None if key is absent and a proof to
273    /// get the value.
274    fn get_with_proof(&self, key: StorageKey) -> StorageProof<Self::Proof>;
275
276    /// Get the root hash of the tree at the requested version
277    fn get_root_hash(&self, version: Version) -> Result<Self::Root, anyhow::Error>;
278}