1use fuel_storage::{
4 StorageAsRef,
5 StorageInspect,
6 StorageMutate,
7 StorageRead,
8 StorageSize,
9 StorageWrite,
10};
11use fuel_tx::{
12 ConsensusParameters,
13 Contract,
14 StorageSlot,
15};
16use fuel_types::{
17 AssetId,
18 BlockHeight,
19 Bytes32,
20 ContractId,
21 Word,
22};
23
24use crate::{
25 prelude::{
26 InterpreterError,
27 RuntimeError,
28 },
29 storage::{
30 ContractsAssets,
31 ContractsRawCode,
32 ContractsState,
33 ContractsStateData,
34 UploadedBytecode,
35 UploadedBytecodes,
36 },
37};
38use alloc::borrow::Cow;
39use core::ops::{
40 Deref,
41 DerefMut,
42};
43
44use super::blob_data::BlobData;
45
46pub trait InterpreterStorage:
49 StorageWrite<ContractsRawCode, Error = Self::DataError>
50 + StorageSize<ContractsRawCode, Error = Self::DataError>
51 + StorageRead<ContractsRawCode, Error = Self::DataError>
52 + StorageWrite<ContractsState, Error = Self::DataError>
53 + StorageSize<ContractsState, Error = Self::DataError>
54 + StorageRead<ContractsState, Error = Self::DataError>
55 + StorageMutate<UploadedBytecodes, Error = Self::DataError>
56 + StorageWrite<BlobData, Error = Self::DataError>
57 + StorageSize<BlobData, Error = Self::DataError>
58 + StorageRead<BlobData, Error = Self::DataError>
59 + ContractsAssetsStorage<Error = Self::DataError>
60{
61 type DataError: Into<InterpreterError<Self::DataError>>
63 + Into<RuntimeError<Self::DataError>>
64 + core::fmt::Debug;
65
66 fn block_height(&self) -> Result<BlockHeight, Self::DataError>;
69
70 fn consensus_parameters_version(&self) -> Result<u32, Self::DataError>;
72
73 fn state_transition_version(&self) -> Result<u32, Self::DataError>;
76
77 fn timestamp(&self, height: BlockHeight) -> Result<Word, Self::DataError>;
84
85 fn block_hash(&self, block_height: BlockHeight) -> Result<Bytes32, Self::DataError>;
87
88 fn coinbase(&self) -> Result<ContractId, Self::DataError>;
90
91 fn set_consensus_parameters(
95 &mut self,
96 version: u32,
97 consensus_parameters: &ConsensusParameters,
98 ) -> Result<Option<ConsensusParameters>, Self::DataError>;
99
100 fn contains_state_transition_bytecode_root(
103 &self,
104 root: &Bytes32,
105 ) -> Result<bool, Self::DataError> {
106 let bytecode = self.storage::<UploadedBytecodes>().get(root)?;
107
108 if let Some(cow) = bytecode {
109 if let UploadedBytecode::Completed(_) = cow.as_ref() {
110 Ok(true)
111 } else {
112 Ok(false)
113 }
114 } else {
115 Ok(false)
116 }
117 }
118
119 fn set_state_transition_bytecode(
123 &mut self,
124 version: u32,
125 hash: &Bytes32,
126 ) -> Result<Option<Bytes32>, Self::DataError>;
127
128 fn deploy_contract_with_id(
130 &mut self,
131 slots: &[StorageSlot],
132 contract: &[u8],
133 id: &ContractId,
134 ) -> Result<(), Self::DataError> {
135 self.storage_contract_insert(id, contract)?;
136
137 slots.iter().try_for_each(|s| {
139 self.contract_state_insert(id, s.key(), s.value().as_ref())?;
140 Ok(())
141 })?;
142 Ok(())
143 }
144
145 fn storage_contract(
148 &self,
149 id: &ContractId,
150 ) -> Result<Option<Cow<'_, Contract>>, Self::DataError> {
151 StorageInspect::<ContractsRawCode>::get(self, id)
152 }
153
154 fn storage_contract_size(
157 &self,
158 id: &ContractId,
159 ) -> Result<Option<usize>, Self::DataError> {
160 StorageSize::<ContractsRawCode>::size_of_value(self, id)
161 }
162
163 fn storage_contract_insert(
167 &mut self,
168 id: &ContractId,
169 contract: &[u8],
170 ) -> Result<(), Self::DataError> {
171 StorageMutate::<ContractsRawCode>::insert(self, id, contract)
172 }
173
174 fn storage_contract_exists(&self, id: &ContractId) -> Result<bool, Self::DataError> {
176 self.storage::<ContractsRawCode>().contains_key(id)
177 }
178
179 fn contract_state(
181 &self,
182 id: &ContractId,
183 key: &Bytes32,
184 ) -> Result<Option<Cow<'_, ContractsStateData>>, Self::DataError> {
185 StorageInspect::<ContractsState>::get(self, &(id, key).into())
186 }
187
188 fn contract_state_insert(
190 &mut self,
191 contract: &ContractId,
192 key: &Bytes32,
193 value: &[u8],
194 ) -> Result<(), Self::DataError> {
195 StorageWrite::<ContractsState>::write_bytes(
196 self,
197 &(contract, key).into(),
198 value,
199 )?;
200 Ok(())
201 }
202
203 fn contract_state_remove_range(
205 &mut self,
206 contract: &ContractId,
207 start_key: &Bytes32,
208 range: usize,
209 ) -> Result<(), Self::DataError>;
210}
211
212pub trait ContractsAssetsStorage: StorageMutate<ContractsAssets> {
214 fn contract_asset_id_balance(
216 &self,
217 id: &ContractId,
218 asset_id: &AssetId,
219 ) -> Result<Option<Word>, Self::Error> {
220 let balance = self
221 .storage::<ContractsAssets>()
222 .get(&(id, asset_id).into())?
223 .map(Cow::into_owned);
224
225 Ok(balance)
226 }
227
228 fn contract_asset_id_balance_insert(
230 &mut self,
231 contract: &ContractId,
232 asset_id: &AssetId,
233 value: Word,
234 ) -> Result<(), Self::Error> {
235 StorageMutate::<ContractsAssets>::insert(
236 self,
237 &(contract, asset_id).into(),
238 &value,
239 )
240 }
241
242 fn contract_asset_id_balance_replace(
245 &mut self,
246 contract: &ContractId,
247 asset_id: &AssetId,
248 value: Word,
249 ) -> Result<Option<Word>, Self::Error> {
250 StorageMutate::<ContractsAssets>::replace(
251 self,
252 &(contract, asset_id).into(),
253 &value,
254 )
255 }
256
257 fn contract_asset_id_balance_remove(
259 &mut self,
260 contract: &ContractId,
261 asset_id: &AssetId,
262 ) -> Result<(), Self::Error> {
263 StorageMutate::<ContractsAssets>::remove(self, &(contract, asset_id).into())
264 }
265}
266
267impl<S> ContractsAssetsStorage for &mut S where S: ContractsAssetsStorage {}
268
269impl<S> InterpreterStorage for &mut S
270where
271 S: InterpreterStorage,
272{
273 type DataError = <S as InterpreterStorage>::DataError;
274
275 fn block_height(&self) -> Result<BlockHeight, Self::DataError> {
276 <S as InterpreterStorage>::block_height(self.deref())
277 }
278
279 fn consensus_parameters_version(&self) -> Result<u32, Self::DataError> {
280 <S as InterpreterStorage>::consensus_parameters_version(self.deref())
281 }
282
283 fn state_transition_version(&self) -> Result<u32, Self::DataError> {
284 <S as InterpreterStorage>::state_transition_version(self.deref())
285 }
286
287 fn timestamp(&self, height: BlockHeight) -> Result<Word, Self::DataError> {
288 <S as InterpreterStorage>::timestamp(self.deref(), height)
289 }
290
291 fn block_hash(&self, block_height: BlockHeight) -> Result<Bytes32, Self::DataError> {
292 <S as InterpreterStorage>::block_hash(self.deref(), block_height)
293 }
294
295 fn coinbase(&self) -> Result<ContractId, Self::DataError> {
296 <S as InterpreterStorage>::coinbase(self.deref())
297 }
298
299 fn set_consensus_parameters(
300 &mut self,
301 version: u32,
302 consensus_parameters: &ConsensusParameters,
303 ) -> Result<Option<ConsensusParameters>, Self::DataError> {
304 <S as InterpreterStorage>::set_consensus_parameters(
305 self.deref_mut(),
306 version,
307 consensus_parameters,
308 )
309 }
310
311 fn set_state_transition_bytecode(
312 &mut self,
313 version: u32,
314 hash: &Bytes32,
315 ) -> Result<Option<Bytes32>, Self::DataError> {
316 <S as InterpreterStorage>::set_state_transition_bytecode(
317 self.deref_mut(),
318 version,
319 hash,
320 )
321 }
322
323 fn storage_contract_size(
324 &self,
325 id: &ContractId,
326 ) -> Result<Option<usize>, Self::DataError> {
327 <S as InterpreterStorage>::storage_contract_size(self.deref(), id)
328 }
329
330 fn contract_state_remove_range(
331 &mut self,
332 contract: &ContractId,
333 start_key: &Bytes32,
334 range: usize,
335 ) -> Result<(), Self::DataError> {
336 <S as InterpreterStorage>::contract_state_remove_range(
337 self.deref_mut(),
338 contract,
339 start_key,
340 range,
341 )
342 }
343}