fuel_vm/storage/
predicate.rs

1//! The module contains storage requirements for the predicate execution.
2
3use crate::{
4    prelude::{
5        InterpreterError,
6        RuntimeError,
7    },
8    storage::InterpreterStorage,
9};
10use alloc::{
11    borrow::Cow,
12    string::String,
13    vec::Vec,
14};
15use core::fmt::Debug;
16
17use fuel_asm::Word;
18use fuel_storage::{
19    Mappable,
20    StorageInspect,
21    StorageMutate,
22    StorageRead,
23    StorageSize,
24    StorageWrite,
25};
26use fuel_tx::ConsensusParameters;
27use fuel_types::{
28    BlobId,
29    BlockHeight,
30    Bytes32,
31    ContractId,
32};
33
34use super::{
35    interpreter::ContractsAssetsStorage,
36    BlobData,
37    ContractsAssets,
38    ContractsRawCode,
39    ContractsState,
40    ContractsStateData,
41    UploadedBytecodes,
42};
43
44/// Create an empty predicate storage.
45pub fn empty_predicate_storage() -> PredicateStorage<EmptyStorage> {
46    PredicateStorage::new(EmptyStorage)
47}
48
49/// No-op storage used for predicate operations.
50///
51/// The storage implementations are expected to provide KV-like operations for contract
52/// operations. However, predicates, as defined in the protocol, cannot execute contract
53/// opcodes. This means its storage backend for predicate execution shouldn't provide any
54/// functionality. Unless the storage access is limited to immutable data and read-only.
55#[derive(Debug, Default)]
56pub struct PredicateStorage<D> {
57    storage: D,
58}
59
60impl<D> PredicateStorage<D> {
61    /// instantiate predicate storage with access to Blobs
62    pub fn new(storage: D) -> Self {
63        Self { storage }
64    }
65}
66
67/// Errors that happen when using predicate storage
68#[derive(Debug, Clone)]
69pub enum PredicateStorageError {
70    /// Storage operation is unavailable in predicate context.
71    UnsupportedStorageOperation,
72    /// An storage error occurred
73    StorageError(String),
74}
75
76impl From<PredicateStorageError> for InterpreterError<PredicateStorageError> {
77    fn from(val: PredicateStorageError) -> Self {
78        let rt: RuntimeError<PredicateStorageError> = val.into();
79        rt.into()
80    }
81}
82
83impl From<PredicateStorageError> for RuntimeError<PredicateStorageError> {
84    fn from(val: PredicateStorageError) -> Self {
85        RuntimeError::Storage(val)
86    }
87}
88
89/// Storage requirements for predicates.
90pub trait PredicateStorageRequirements
91where
92    Self: StorageRead<BlobData>,
93{
94    /// Converts the storage error to a string.
95    fn storage_error_to_string(error: Self::Error) -> String;
96}
97
98impl<D> PredicateStorageRequirements for &D
99where
100    D: PredicateStorageRequirements,
101{
102    fn storage_error_to_string(error: Self::Error) -> String {
103        D::storage_error_to_string(error)
104    }
105}
106
107/// The type that returns the predicate storage instance.
108pub trait PredicateStorageProvider: Sync {
109    /// The storage type.
110    type Storage: PredicateStorageRequirements + Send + Sync + 'static;
111
112    /// Returns the storage instance.
113    fn storage(&self) -> Self::Storage;
114}
115
116/// Empty storage.
117#[derive(Default, Debug, Clone, Copy)]
118pub struct EmptyStorage;
119
120impl StorageInspect<BlobData> for EmptyStorage {
121    type Error = PredicateStorageError;
122
123    fn get(
124        &self,
125        _: &BlobId,
126    ) -> Result<Option<Cow<<BlobData as Mappable>::OwnedValue>>, Self::Error> {
127        Err(Self::Error::UnsupportedStorageOperation)
128    }
129
130    fn contains_key(&self, _: &BlobId) -> Result<bool, Self::Error> {
131        Err(Self::Error::UnsupportedStorageOperation)
132    }
133}
134
135impl StorageSize<BlobData> for EmptyStorage {
136    fn size_of_value(&self, _: &BlobId) -> Result<Option<usize>, Self::Error> {
137        Err(Self::Error::UnsupportedStorageOperation)
138    }
139}
140
141impl StorageRead<BlobData> for EmptyStorage {
142    fn read(
143        &self,
144        _: &BlobId,
145        _: usize,
146        _: &mut [u8],
147    ) -> Result<Option<usize>, Self::Error> {
148        Err(Self::Error::UnsupportedStorageOperation)
149    }
150
151    fn read_alloc(&self, _: &BlobId) -> Result<Option<Vec<u8>>, Self::Error> {
152        Err(Self::Error::UnsupportedStorageOperation)
153    }
154}
155
156impl PredicateStorageRequirements for EmptyStorage {
157    fn storage_error_to_string(error: Self::Error) -> String {
158        alloc::format!("{:?}", error)
159    }
160}
161
162impl PredicateStorageProvider for EmptyStorage {
163    type Storage = Self;
164
165    fn storage(&self) -> Self::Storage {
166        *self
167    }
168}
169
170trait NoStorage {}
171
172impl NoStorage for ContractsState {}
173impl NoStorage for ContractsRawCode {}
174impl NoStorage for ContractsAssets {}
175impl NoStorage for UploadedBytecodes {}
176
177impl<Type, D> StorageInspect<Type> for PredicateStorage<D>
178where
179    Type: Mappable + NoStorage,
180{
181    type Error = PredicateStorageError;
182
183    fn get(
184        &self,
185        _key: &Type::Key,
186    ) -> Result<Option<Cow<'_, Type::OwnedValue>>, Self::Error> {
187        Err(Self::Error::UnsupportedStorageOperation)
188    }
189
190    fn contains_key(&self, _key: &Type::Key) -> Result<bool, Self::Error> {
191        Err(Self::Error::UnsupportedStorageOperation)
192    }
193}
194
195impl<D> StorageInspect<BlobData> for PredicateStorage<D>
196where
197    D: PredicateStorageRequirements,
198{
199    type Error = PredicateStorageError;
200
201    fn get(
202        &self,
203        key: &<BlobData as Mappable>::Key,
204    ) -> Result<Option<Cow<'_, <BlobData as Mappable>::OwnedValue>>, Self::Error> {
205        <D as StorageInspect<BlobData>>::get(&self.storage, key)
206            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
207    }
208
209    fn contains_key(
210        &self,
211        key: &<BlobData as Mappable>::Key,
212    ) -> Result<bool, Self::Error> {
213        <D as StorageInspect<BlobData>>::contains_key(&self.storage, key)
214            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
215    }
216}
217
218impl<Type, D> StorageMutate<Type> for PredicateStorage<D>
219where
220    Type: Mappable,
221    Self: StorageInspect<Type, Error = PredicateStorageError>,
222{
223    fn replace(
224        &mut self,
225        _key: &Type::Key,
226        _value: &Type::Value,
227    ) -> Result<Option<Type::OwnedValue>, Self::Error> {
228        Err(Self::Error::UnsupportedStorageOperation)
229    }
230
231    fn take(
232        &mut self,
233        _key: &Type::Key,
234    ) -> Result<Option<Type::OwnedValue>, Self::Error> {
235        Err(Self::Error::UnsupportedStorageOperation)
236    }
237}
238
239impl<D> StorageSize<ContractsRawCode> for PredicateStorage<D> {
240    fn size_of_value(&self, _key: &ContractId) -> Result<Option<usize>, Self::Error> {
241        Err(Self::Error::UnsupportedStorageOperation)
242    }
243}
244
245impl<D> StorageRead<ContractsRawCode> for PredicateStorage<D> {
246    fn read(
247        &self,
248        _key: &<ContractsRawCode as Mappable>::Key,
249        _offset: usize,
250        _buf: &mut [u8],
251    ) -> Result<Option<usize>, Self::Error> {
252        Err(Self::Error::UnsupportedStorageOperation)
253    }
254
255    fn read_alloc(
256        &self,
257        _key: &<ContractsRawCode as Mappable>::Key,
258    ) -> Result<Option<Vec<u8>>, Self::Error> {
259        Err(Self::Error::UnsupportedStorageOperation)
260    }
261}
262
263impl<D> StorageWrite<ContractsRawCode> for PredicateStorage<D> {
264    fn write_bytes(
265        &mut self,
266        _key: &<ContractsRawCode as Mappable>::Key,
267        _buf: &[u8],
268    ) -> Result<usize, Self::Error> {
269        Err(Self::Error::UnsupportedStorageOperation)
270    }
271
272    fn replace_bytes(
273        &mut self,
274        _key: &<ContractsRawCode as Mappable>::Key,
275        _buf: &[u8],
276    ) -> Result<(usize, Option<Vec<u8>>), Self::Error> {
277        Err(Self::Error::UnsupportedStorageOperation)
278    }
279
280    fn take_bytes(
281        &mut self,
282        _key: &<ContractsRawCode as Mappable>::Key,
283    ) -> Result<Option<Vec<u8>>, Self::Error> {
284        Err(Self::Error::UnsupportedStorageOperation)
285    }
286}
287
288impl<D> StorageSize<ContractsState> for PredicateStorage<D> {
289    fn size_of_value(
290        &self,
291        _key: &<ContractsState as Mappable>::Key,
292    ) -> Result<Option<usize>, Self::Error> {
293        Err(Self::Error::UnsupportedStorageOperation)
294    }
295}
296
297impl<D> StorageRead<ContractsState> for PredicateStorage<D> {
298    fn read(
299        &self,
300        _key: &<ContractsState as Mappable>::Key,
301        _offset: usize,
302        _buf: &mut [u8],
303    ) -> Result<Option<usize>, Self::Error> {
304        Err(Self::Error::UnsupportedStorageOperation)
305    }
306
307    fn read_alloc(
308        &self,
309        _key: &<ContractsState as Mappable>::Key,
310    ) -> Result<Option<Vec<u8>>, Self::Error> {
311        Err(Self::Error::UnsupportedStorageOperation)
312    }
313}
314
315impl<D> StorageWrite<ContractsState> for PredicateStorage<D> {
316    fn write_bytes(
317        &mut self,
318        _key: &<ContractsState as Mappable>::Key,
319        _buf: &[u8],
320    ) -> Result<usize, Self::Error> {
321        Err(Self::Error::UnsupportedStorageOperation)
322    }
323
324    fn replace_bytes(
325        &mut self,
326        _key: &<ContractsState as Mappable>::Key,
327        _buf: &[u8],
328    ) -> Result<(usize, Option<Vec<u8>>), Self::Error> {
329        Err(Self::Error::UnsupportedStorageOperation)
330    }
331
332    fn take_bytes(
333        &mut self,
334        _key: &<ContractsState as Mappable>::Key,
335    ) -> Result<Option<Vec<u8>>, Self::Error> {
336        Err(Self::Error::UnsupportedStorageOperation)
337    }
338}
339
340impl<D> StorageSize<BlobData> for PredicateStorage<D>
341where
342    D: PredicateStorageRequirements,
343{
344    fn size_of_value(
345        &self,
346        key: &<BlobData as Mappable>::Key,
347    ) -> Result<Option<usize>, Self::Error> {
348        StorageSize::<BlobData>::size_of_value(&self.storage, key)
349            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
350    }
351}
352
353impl<D> StorageRead<BlobData> for PredicateStorage<D>
354where
355    D: PredicateStorageRequirements,
356{
357    fn read(
358        &self,
359        key: &<BlobData as Mappable>::Key,
360        offset: usize,
361        buf: &mut [u8],
362    ) -> Result<Option<usize>, Self::Error> {
363        StorageRead::<BlobData>::read(&self.storage, key, offset, buf)
364            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
365    }
366
367    fn read_alloc(
368        &self,
369        key: &<BlobData as Mappable>::Key,
370    ) -> Result<Option<Vec<u8>>, Self::Error> {
371        StorageRead::<BlobData>::read_alloc(&self.storage, key)
372            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
373    }
374}
375
376impl<D> StorageWrite<BlobData> for PredicateStorage<D>
377where
378    D: PredicateStorageRequirements,
379{
380    fn write_bytes(
381        &mut self,
382        _key: &<BlobData as Mappable>::Key,
383        _buf: &[u8],
384    ) -> Result<usize, Self::Error> {
385        Err(Self::Error::UnsupportedStorageOperation)
386    }
387
388    fn replace_bytes(
389        &mut self,
390        _key: &<BlobData as Mappable>::Key,
391        _buf: &[u8],
392    ) -> Result<(usize, Option<Vec<u8>>), Self::Error> {
393        Err(Self::Error::UnsupportedStorageOperation)
394    }
395
396    fn take_bytes(
397        &mut self,
398        _key: &<BlobData as Mappable>::Key,
399    ) -> Result<Option<Vec<u8>>, Self::Error> {
400        Err(Self::Error::UnsupportedStorageOperation)
401    }
402}
403
404impl<D> ContractsAssetsStorage for PredicateStorage<D> {}
405
406impl<D> InterpreterStorage for PredicateStorage<D>
407where
408    D: PredicateStorageRequirements,
409{
410    type DataError = PredicateStorageError;
411
412    fn block_height(&self) -> Result<BlockHeight, Self::DataError> {
413        Err(Self::DataError::UnsupportedStorageOperation)
414    }
415
416    fn consensus_parameters_version(&self) -> Result<u32, Self::DataError> {
417        Err(Self::DataError::UnsupportedStorageOperation)
418    }
419
420    fn state_transition_version(&self) -> Result<u32, Self::DataError> {
421        Err(Self::DataError::UnsupportedStorageOperation)
422    }
423
424    fn timestamp(&self, _height: BlockHeight) -> Result<Word, Self::DataError> {
425        Err(Self::DataError::UnsupportedStorageOperation)
426    }
427
428    fn block_hash(&self, _block_height: BlockHeight) -> Result<Bytes32, Self::DataError> {
429        Err(Self::DataError::UnsupportedStorageOperation)
430    }
431
432    fn coinbase(&self) -> Result<ContractId, Self::DataError> {
433        Err(Self::DataError::UnsupportedStorageOperation)
434    }
435
436    fn set_consensus_parameters(
437        &mut self,
438        _version: u32,
439        _consensus_parameters: &ConsensusParameters,
440    ) -> Result<Option<ConsensusParameters>, Self::DataError> {
441        Err(Self::DataError::UnsupportedStorageOperation)
442    }
443
444    fn set_state_transition_bytecode(
445        &mut self,
446        _version: u32,
447        _hash: &Bytes32,
448    ) -> Result<Option<Bytes32>, Self::DataError> {
449        Err(Self::DataError::UnsupportedStorageOperation)
450    }
451
452    fn contract_state_range(
453        &self,
454        _id: &ContractId,
455        _start_key: &Bytes32,
456        _range: usize,
457    ) -> Result<Vec<Option<Cow<ContractsStateData>>>, Self::DataError> {
458        Err(Self::DataError::UnsupportedStorageOperation)
459    }
460
461    fn contract_state_insert_range<'a, I>(
462        &mut self,
463        _: &ContractId,
464        _: &Bytes32,
465        _: I,
466    ) -> Result<usize, Self::DataError>
467    where
468        I: Iterator<Item = &'a [u8]>,
469    {
470        Err(Self::DataError::UnsupportedStorageOperation)
471    }
472
473    fn contract_state_remove_range(
474        &mut self,
475        _contract: &ContractId,
476        _start_key: &Bytes32,
477        _range: usize,
478    ) -> Result<Option<()>, Self::DataError> {
479        Err(Self::DataError::UnsupportedStorageOperation)
480    }
481}