Skip to main content

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    StorageReadError,
24    StorageSize,
25    StorageWrite,
26};
27use fuel_tx::ConsensusParameters;
28use fuel_types::{
29    BlobId,
30    BlockHeight,
31    Bytes32,
32    ContractId,
33};
34
35use super::{
36    BlobData,
37    ContractsAssets,
38    ContractsRawCode,
39    ContractsState,
40    UploadedBytecodes,
41    interpreter::ContractsAssetsStorage,
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_exact(
143        &self,
144        _: &BlobId,
145        _: usize,
146        _: &mut [u8],
147    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
148        Err(Self::Error::UnsupportedStorageOperation)
149    }
150
151    fn read_zerofill(
152        &self,
153        _: &BlobId,
154        _: usize,
155        _: &mut [u8],
156    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
157        Err(Self::Error::UnsupportedStorageOperation)
158    }
159
160    fn read_alloc(&self, _: &BlobId) -> Result<Option<Vec<u8>>, Self::Error> {
161        Err(Self::Error::UnsupportedStorageOperation)
162    }
163}
164
165impl PredicateStorageRequirements for EmptyStorage {
166    fn storage_error_to_string(error: Self::Error) -> String {
167        alloc::format!("{:?}", error)
168    }
169}
170
171impl PredicateStorageProvider for EmptyStorage {
172    type Storage = Self;
173
174    fn storage(&self) -> Self::Storage {
175        *self
176    }
177}
178
179trait NoStorage {}
180
181impl NoStorage for ContractsState {}
182impl NoStorage for ContractsRawCode {}
183impl NoStorage for ContractsAssets {}
184impl NoStorage for UploadedBytecodes {}
185
186impl<Type, D> StorageInspect<Type> for PredicateStorage<D>
187where
188    Type: Mappable + NoStorage,
189{
190    type Error = PredicateStorageError;
191
192    fn get(
193        &self,
194        _key: &Type::Key,
195    ) -> Result<Option<Cow<'_, Type::OwnedValue>>, Self::Error> {
196        Err(Self::Error::UnsupportedStorageOperation)
197    }
198
199    fn contains_key(&self, _key: &Type::Key) -> Result<bool, Self::Error> {
200        Err(Self::Error::UnsupportedStorageOperation)
201    }
202}
203
204impl<D> StorageInspect<BlobData> for PredicateStorage<D>
205where
206    D: PredicateStorageRequirements,
207{
208    type Error = PredicateStorageError;
209
210    fn get(
211        &self,
212        key: &<BlobData as Mappable>::Key,
213    ) -> Result<Option<Cow<'_, <BlobData as Mappable>::OwnedValue>>, Self::Error> {
214        <D as StorageInspect<BlobData>>::get(&self.storage, key)
215            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
216    }
217
218    fn contains_key(
219        &self,
220        key: &<BlobData as Mappable>::Key,
221    ) -> Result<bool, Self::Error> {
222        <D as StorageInspect<BlobData>>::contains_key(&self.storage, key)
223            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
224    }
225}
226
227impl<Type, D> StorageMutate<Type> for PredicateStorage<D>
228where
229    Type: Mappable,
230    Self: StorageInspect<Type, Error = PredicateStorageError>,
231{
232    fn replace(
233        &mut self,
234        _key: &Type::Key,
235        _value: &Type::Value,
236    ) -> Result<Option<Type::OwnedValue>, Self::Error> {
237        Err(Self::Error::UnsupportedStorageOperation)
238    }
239
240    fn take(
241        &mut self,
242        _key: &Type::Key,
243    ) -> Result<Option<Type::OwnedValue>, Self::Error> {
244        Err(Self::Error::UnsupportedStorageOperation)
245    }
246}
247
248impl<D> StorageSize<ContractsRawCode> for PredicateStorage<D> {
249    fn size_of_value(&self, _key: &ContractId) -> Result<Option<usize>, Self::Error> {
250        Err(Self::Error::UnsupportedStorageOperation)
251    }
252}
253
254impl<D> StorageRead<ContractsRawCode> for PredicateStorage<D> {
255    fn read_exact(
256        &self,
257        _key: &<ContractsRawCode as Mappable>::Key,
258        _offset: usize,
259        _buf: &mut [u8],
260    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
261        Err(Self::Error::UnsupportedStorageOperation)
262    }
263
264    fn read_zerofill(
265        &self,
266        _key: &<ContractsRawCode as Mappable>::Key,
267        _offset: usize,
268        _buf: &mut [u8],
269    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
270        Err(Self::Error::UnsupportedStorageOperation)
271    }
272
273    fn read_alloc(
274        &self,
275        _key: &<ContractsRawCode as Mappable>::Key,
276    ) -> Result<Option<Vec<u8>>, Self::Error> {
277        Err(Self::Error::UnsupportedStorageOperation)
278    }
279}
280
281impl<D> StorageWrite<ContractsRawCode> for PredicateStorage<D> {
282    fn write_bytes(
283        &mut self,
284        _key: &<ContractsRawCode as Mappable>::Key,
285        _buf: &[u8],
286    ) -> Result<(), Self::Error> {
287        Err(Self::Error::UnsupportedStorageOperation)
288    }
289
290    fn replace_bytes(
291        &mut self,
292        _key: &<ContractsRawCode as Mappable>::Key,
293        _buf: &[u8],
294    ) -> Result<Option<Vec<u8>>, Self::Error> {
295        Err(Self::Error::UnsupportedStorageOperation)
296    }
297
298    fn take_bytes(
299        &mut self,
300        _key: &<ContractsRawCode as Mappable>::Key,
301    ) -> Result<Option<Vec<u8>>, Self::Error> {
302        Err(Self::Error::UnsupportedStorageOperation)
303    }
304}
305
306impl<D> StorageSize<ContractsState> for PredicateStorage<D> {
307    fn size_of_value(
308        &self,
309        _key: &<ContractsState as Mappable>::Key,
310    ) -> Result<Option<usize>, Self::Error> {
311        Err(Self::Error::UnsupportedStorageOperation)
312    }
313}
314
315impl<D> StorageRead<ContractsState> for PredicateStorage<D> {
316    fn read_exact(
317        &self,
318        _key: &<ContractsState as Mappable>::Key,
319        _offset: usize,
320        _buf: &mut [u8],
321    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
322        Err(Self::Error::UnsupportedStorageOperation)
323    }
324
325    fn read_zerofill(
326        &self,
327        _key: &<ContractsState as Mappable>::Key,
328        _offset: usize,
329        _buf: &mut [u8],
330    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
331        Err(Self::Error::UnsupportedStorageOperation)
332    }
333
334    fn read_alloc(
335        &self,
336        _key: &<ContractsState as Mappable>::Key,
337    ) -> Result<Option<Vec<u8>>, Self::Error> {
338        Err(Self::Error::UnsupportedStorageOperation)
339    }
340}
341
342impl<D> StorageWrite<ContractsState> for PredicateStorage<D> {
343    fn write_bytes(
344        &mut self,
345        _key: &<ContractsState as Mappable>::Key,
346        _buf: &[u8],
347    ) -> Result<(), Self::Error> {
348        Err(Self::Error::UnsupportedStorageOperation)
349    }
350
351    fn replace_bytes(
352        &mut self,
353        _key: &<ContractsState as Mappable>::Key,
354        _buf: &[u8],
355    ) -> Result<Option<Vec<u8>>, Self::Error> {
356        Err(Self::Error::UnsupportedStorageOperation)
357    }
358
359    fn take_bytes(
360        &mut self,
361        _key: &<ContractsState as Mappable>::Key,
362    ) -> Result<Option<Vec<u8>>, Self::Error> {
363        Err(Self::Error::UnsupportedStorageOperation)
364    }
365}
366
367impl<D> StorageSize<BlobData> for PredicateStorage<D>
368where
369    D: PredicateStorageRequirements,
370{
371    fn size_of_value(
372        &self,
373        key: &<BlobData as Mappable>::Key,
374    ) -> Result<Option<usize>, Self::Error> {
375        StorageSize::<BlobData>::size_of_value(&self.storage, key)
376            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
377    }
378}
379
380impl<D> StorageRead<BlobData> for PredicateStorage<D>
381where
382    D: PredicateStorageRequirements,
383{
384    fn read_exact(
385        &self,
386        key: &<BlobData as Mappable>::Key,
387        offset: usize,
388        buf: &mut [u8],
389    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
390        StorageRead::<BlobData>::read_exact(&self.storage, key, offset, buf)
391            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
392    }
393
394    fn read_zerofill(
395        &self,
396        key: &<BlobData as Mappable>::Key,
397        offset: usize,
398        buf: &mut [u8],
399    ) -> Result<Result<usize, StorageReadError>, Self::Error> {
400        StorageRead::<BlobData>::read_zerofill(&self.storage, key, offset, buf)
401            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
402    }
403
404    fn read_alloc(
405        &self,
406        key: &<BlobData as Mappable>::Key,
407    ) -> Result<Option<Vec<u8>>, Self::Error> {
408        StorageRead::<BlobData>::read_alloc(&self.storage, key)
409            .map_err(|e| Self::Error::StorageError(D::storage_error_to_string(e)))
410    }
411}
412
413impl<D> StorageWrite<BlobData> for PredicateStorage<D>
414where
415    D: PredicateStorageRequirements,
416{
417    fn write_bytes(
418        &mut self,
419        _key: &<BlobData as Mappable>::Key,
420        _buf: &[u8],
421    ) -> Result<(), Self::Error> {
422        Err(Self::Error::UnsupportedStorageOperation)
423    }
424
425    fn replace_bytes(
426        &mut self,
427        _key: &<BlobData as Mappable>::Key,
428        _buf: &[u8],
429    ) -> Result<Option<Vec<u8>>, Self::Error> {
430        Err(Self::Error::UnsupportedStorageOperation)
431    }
432
433    fn take_bytes(
434        &mut self,
435        _key: &<BlobData as Mappable>::Key,
436    ) -> Result<Option<Vec<u8>>, Self::Error> {
437        Err(Self::Error::UnsupportedStorageOperation)
438    }
439}
440
441impl<D> ContractsAssetsStorage for PredicateStorage<D> {}
442
443impl<D> InterpreterStorage for PredicateStorage<D>
444where
445    D: PredicateStorageRequirements,
446{
447    type DataError = PredicateStorageError;
448
449    fn block_height(&self) -> Result<BlockHeight, Self::DataError> {
450        Err(Self::DataError::UnsupportedStorageOperation)
451    }
452
453    fn consensus_parameters_version(&self) -> Result<u32, Self::DataError> {
454        Err(Self::DataError::UnsupportedStorageOperation)
455    }
456
457    fn state_transition_version(&self) -> Result<u32, Self::DataError> {
458        Err(Self::DataError::UnsupportedStorageOperation)
459    }
460
461    fn timestamp(&self, _height: BlockHeight) -> Result<Word, Self::DataError> {
462        Err(Self::DataError::UnsupportedStorageOperation)
463    }
464
465    fn block_hash(&self, _block_height: BlockHeight) -> Result<Bytes32, Self::DataError> {
466        Err(Self::DataError::UnsupportedStorageOperation)
467    }
468
469    fn coinbase(&self) -> Result<ContractId, Self::DataError> {
470        Err(Self::DataError::UnsupportedStorageOperation)
471    }
472
473    fn set_consensus_parameters(
474        &mut self,
475        _version: u32,
476        _consensus_parameters: &ConsensusParameters,
477    ) -> Result<Option<ConsensusParameters>, Self::DataError> {
478        Err(Self::DataError::UnsupportedStorageOperation)
479    }
480
481    fn set_state_transition_bytecode(
482        &mut self,
483        _version: u32,
484        _hash: &Bytes32,
485    ) -> Result<Option<Bytes32>, Self::DataError> {
486        Err(Self::DataError::UnsupportedStorageOperation)
487    }
488
489    fn contract_state_remove_range(
490        &mut self,
491        _contract: &ContractId,
492        _start_key: &Bytes32,
493        _range: usize,
494    ) -> Result<(), Self::DataError> {
495        Err(Self::DataError::UnsupportedStorageOperation)
496    }
497}