1use core::fmt::Debug;
2use hashbrown::HashMap;
3
4use fuel_storage::{
5 StorageRead,
6 StorageSize,
7 StorageWrite,
8};
9use fuel_tx::ConsensusParameters;
10use fuel_types::{
11 BlobId,
12 BlockHeight,
13 Bytes32,
14 ContractId,
15};
16
17use crate::storage::{
18 BlobBytes,
19 BlobData,
20 ContractsAssetKey,
21 ContractsAssetsStorage,
22 ContractsStateData,
23 ContractsStateKey,
24 InterpreterStorage,
25 UploadedBytecode,
26 UploadedBytecodes,
27};
28
29use super::{
30 ExecutableTransaction,
31 Interpreter,
32 *,
33};
34
35#[derive(Debug)]
36pub(super) enum StorageDelta {
38 State(MappableDelta<ContractsStateKey, ContractsStateData>),
39 Assets(MappableDelta<ContractsAssetKey, u64>),
40 RawCode(MappableDelta<ContractId, Contract>),
41 UploadedBytecode(MappableDelta<Bytes32, UploadedBytecode>),
42 BlobData(MappableDelta<BlobId, BlobBytes>),
43}
44
45#[derive(Debug, Clone)]
47pub(super) enum StorageState {
48 State(MappableState<ContractsStateKey, ContractsStateData>),
49 Assets(MappableState<ContractsAssetKey, u64>),
50 RawCode(MappableState<ContractId, Contract>),
51 UploadedBytecode(MappableState<Bytes32, UploadedBytecode>),
52 BlobData(MappableState<BlobId, BlobBytes>),
53}
54
55#[derive(Debug)]
56pub(super) enum MappableDelta<Key, Value> {
58 Replace(Key, Value, Option<Value>),
59 Take(Key, Value),
60}
61
62#[derive(Debug, Clone)]
64pub(super) struct MappableState<Key, Value> {
65 pub key: Key,
66 pub value: Option<Value>,
67}
68
69pub(super) trait StorageType: Mappable {
71 fn record_replace(
73 key: &Self::Key,
74 value: &Self::Value,
75 existing: Option<Self::OwnedValue>,
76 ) -> StorageDelta;
77
78 fn record_take(key: &Self::Key, value: Self::OwnedValue) -> StorageDelta;
80}
81
82#[derive(Debug)]
83pub struct Record<S>(pub(super) S, pub(super) Vec<StorageDelta>)
84where
85 S: InterpreterStorage;
86
87impl<M, S, Tx, Ecal> Interpreter<M, Record<S>, Tx, Ecal>
88where
89 S: InterpreterStorage,
90 Tx: ExecutableTransaction,
91{
92 pub fn remove_recording(self) -> Interpreter<M, S, Tx, Ecal> {
96 Interpreter {
97 registers: self.registers,
98 memory: self.memory,
99 frames: self.frames,
100 receipts: self.receipts,
101 tx: self.tx,
102 initial_balances: self.initial_balances,
103 input_contracts: self.input_contracts,
104 input_contracts_index_to_output_index: self
105 .input_contracts_index_to_output_index,
106 storage: self.storage.0,
107 debugger: self.debugger,
108 context: self.context,
109 balances: self.balances,
110 panic_context: self.panic_context,
111 interpreter_params: self.interpreter_params,
112 ecal_state: self.ecal_state,
113 verifier: self.verifier,
114 owner_ptr: self.owner_ptr,
115 }
116 }
117
118 pub fn storage_diff(&self) -> Diff<Deltas> {
120 let mut diff = Diff {
121 changes: Vec::new(),
122 };
123 let mut contracts_state = Delta {
124 from: HashMap::new(),
125 to: HashMap::new(),
126 };
127 let mut contracts_assets = Delta {
128 from: HashMap::new(),
129 to: HashMap::new(),
130 };
131 let mut contracts_raw_code = Delta {
132 from: HashMap::new(),
133 to: HashMap::new(),
134 };
135 let mut uploaded_bytecode: Delta<HashMap<Bytes32, &UploadedBytecode>> = Delta {
136 from: HashMap::new(),
137 to: HashMap::new(),
138 };
139 let mut blob_data = Delta {
140 from: HashMap::new(),
141 to: HashMap::new(),
142 };
143
144 for delta in self.storage.1.iter() {
145 match delta {
146 StorageDelta::State(delta) => {
147 mappable_delta_to_hashmap(&mut contracts_state, delta)
148 }
149 StorageDelta::Assets(delta) => {
150 mappable_delta_to_hashmap(&mut contracts_assets, delta)
151 }
152 StorageDelta::RawCode(delta) => {
153 mappable_delta_to_hashmap(&mut contracts_raw_code, delta)
154 }
155 StorageDelta::UploadedBytecode(delta) => {
156 mappable_delta_to_hashmap(&mut uploaded_bytecode, delta)
157 }
158 StorageDelta::BlobData(delta) => {
159 mappable_delta_to_hashmap(&mut blob_data, delta)
160 }
161 }
162 }
163 storage_state_to_changes(&mut diff, contracts_state, StorageState::State);
164 storage_state_to_changes(&mut diff, contracts_assets, StorageState::Assets);
165 storage_state_to_changes(&mut diff, contracts_raw_code, StorageState::RawCode);
166 storage_state_to_changes(
167 &mut diff,
168 uploaded_bytecode,
169 StorageState::UploadedBytecode,
170 );
171 storage_state_to_changes(&mut diff, blob_data, StorageState::BlobData);
172 diff
173 }
174}
175
176impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V>
177where
178 M: Memory,
179 S: InterpreterStorage,
180 Tx: ExecutableTransaction,
181{
182 pub fn add_recording(self) -> Interpreter<M, Record<S>, Tx, Ecal, V> {
187 Interpreter {
188 registers: self.registers,
189 memory: self.memory,
190 frames: self.frames,
191 receipts: self.receipts,
192 tx: self.tx,
193 initial_balances: self.initial_balances,
194 input_contracts: self.input_contracts,
195 input_contracts_index_to_output_index: self
196 .input_contracts_index_to_output_index,
197 storage: Record::new(self.storage),
198 debugger: self.debugger,
199 context: self.context,
200 balances: self.balances,
201 panic_context: self.panic_context,
202 interpreter_params: self.interpreter_params,
203 ecal_state: self.ecal_state,
204 verifier: self.verifier,
205 owner_ptr: self.owner_ptr,
206 }
207 }
208
209 pub fn reset_vm_state(&mut self, diff: &Diff<InitialVmState>)
211 where
212 Tx: Clone + 'static,
213 {
214 for change in &diff.changes {
215 self.inverse_inner(change);
216 if let Change::Storage(Previous(from)) = change {
217 match from {
218 StorageState::State(MappableState { key, value }) => {
219 if let Some(value) = value {
220 StorageMutate::<ContractsState>::insert(
221 &mut self.storage,
222 key,
223 value.as_ref(),
224 )
225 .unwrap();
226 }
227 }
228 StorageState::Assets(MappableState { key, value }) => {
229 if let Some(value) = value {
230 StorageMutate::<ContractsAssets>::insert(
231 &mut self.storage,
232 key,
233 value,
234 )
235 .unwrap();
236 }
237 }
238 StorageState::RawCode(MappableState { key, value }) => {
239 if let Some(value) = value {
240 StorageMutate::<ContractsRawCode>::insert(
241 &mut self.storage,
242 key,
243 value.as_ref(),
244 )
245 .unwrap();
246 }
247 }
248 StorageState::UploadedBytecode(MappableState { key, value }) => {
249 if let Some(value) = value {
250 StorageMutate::<UploadedBytecodes>::insert(
251 &mut self.storage,
252 key,
253 value,
254 )
255 .unwrap();
256 }
257 }
258 StorageState::BlobData(MappableState { key, value }) => {
259 if let Some(value) = value {
260 StorageMutate::<BlobData>::insert(
261 &mut self.storage,
262 key,
263 value.as_ref(),
264 )
265 .unwrap();
266 }
267 }
268 }
269 }
270 }
271 }
272}
273
274fn mappable_delta_to_hashmap<'value, K, V>(
275 state: &mut Delta<HashMap<K, &'value V>>,
276 delta: &'value MappableDelta<K, V>,
277) where
278 K: Copy + PartialEq + Eq + core::hash::Hash + 'static,
279 V: Clone + 'static,
280{
281 match delta {
282 MappableDelta::Replace(key, value, Some(existing)) => {
283 state.from.entry(*key).or_insert(existing);
284 state.to.insert(*key, value);
285 }
286 MappableDelta::Replace(key, value, None) => {
287 state.to.insert(*key, value);
288 }
289 MappableDelta::Take(key, existing) => {
290 state.from.entry(*key).or_insert(existing);
291 state.to.remove(key);
292 }
293 }
294}
295
296fn storage_state_to_changes<K, V>(
297 diff: &mut Diff<Deltas>,
298 state: Delta<HashMap<K, &V>>,
299 f: fn(MappableState<K, V>) -> StorageState,
300) where
301 K: Copy + PartialEq + Eq + Hash + 'static,
302 V: Clone + 'static,
303{
304 let Delta { mut from, to } = state;
305 let iter = to.into_iter().map(|(k, v)| {
306 Change::Storage(Delta {
307 from: f(MappableState {
308 key: k,
309 value: from.remove(&k).cloned(),
310 }),
311 to: f(MappableState {
312 key: k,
313 value: Some(v.clone()),
314 }),
315 })
316 });
317 diff.changes.extend(iter);
318 let iter = from.into_iter().map(|(k, v)| {
319 Change::Storage(Delta {
320 from: f(MappableState {
321 key: k,
322 value: Some(v.clone()),
323 }),
324 to: f(MappableState {
325 key: k,
326 value: None,
327 }),
328 })
329 });
330 diff.changes.extend(iter);
331}
332
333impl<Type: Mappable, S> StorageInspect<Type> for Record<S>
334where
335 S: StorageInspect<Type>,
336 S: InterpreterStorage,
337{
338 type Error = <S as StorageInspect<Type>>::Error;
339
340 fn get(
341 &self,
342 key: &<Type as Mappable>::Key,
343 ) -> Result<Option<alloc::borrow::Cow<<Type as Mappable>::OwnedValue>>, Self::Error>
344 {
345 <S as StorageInspect<Type>>::get(&self.0, key)
346 }
347
348 fn contains_key(&self, key: &<Type as Mappable>::Key) -> Result<bool, Self::Error> {
349 <S as StorageInspect<Type>>::contains_key(&self.0, key)
350 }
351}
352
353impl<Type: Mappable, S> StorageSize<Type> for Record<S>
354where
355 S: StorageSize<Type>,
356 S: InterpreterStorage,
357{
358 fn size_of_value(
359 &self,
360 key: &<Type as Mappable>::Key,
361 ) -> Result<Option<usize>, Self::Error> {
362 <S as StorageSize<Type>>::size_of_value(&self.0, key)
363 }
364}
365
366impl<Type: Mappable, S> StorageRead<Type> for Record<S>
367where
368 S: StorageRead<Type>,
369 S: InterpreterStorage,
370{
371 fn read(
372 &self,
373 key: &<Type as Mappable>::Key,
374 offset: usize,
375 buf: &mut [u8],
376 ) -> Result<bool, Self::Error> {
377 <S as StorageRead<Type>>::read(&self.0, key, offset, buf)
378 }
379
380 fn read_alloc(
381 &self,
382 key: &<Type as Mappable>::Key,
383 ) -> Result<Option<Vec<u8>>, Self::Error> {
384 <S as StorageRead<Type>>::read_alloc(&self.0, key)
385 }
386}
387
388impl<Type: StorageType, S> StorageMutate<Type> for Record<S>
389where
390 S: StorageInspect<Type>,
391 S: StorageMutate<Type>,
392 S: InterpreterStorage,
393{
394 fn replace(
395 &mut self,
396 key: &Type::Key,
397 value: &Type::Value,
398 ) -> Result<Option<Type::OwnedValue>, Self::Error> {
399 let existing = <S as StorageMutate<Type>>::replace(&mut self.0, key, value)?;
400 self.1.push(<Type as StorageType>::record_replace(
401 key,
402 value,
403 existing.clone(),
404 ));
405 Ok(existing)
406 }
407
408 fn take(&mut self, key: &Type::Key) -> Result<Option<Type::OwnedValue>, Self::Error> {
409 let existing = <S as StorageMutate<Type>>::take(&mut self.0, key)?;
410 if let Some(existing) = &existing {
411 self.1
412 .push(<Type as StorageType>::record_take(key, existing.clone()));
413 }
414 Ok(existing)
415 }
416}
417
418impl<Type: StorageType, S> StorageWrite<Type> for Record<S>
419where
420 S: StorageWrite<Type>,
421 S: InterpreterStorage,
422{
423 fn write_bytes(&mut self, key: &Type::Key, buf: &[u8]) -> Result<(), Self::Error> {
424 <S as StorageWrite<Type>>::write_bytes(&mut self.0, key, buf)
425 }
426
427 fn replace_bytes(
428 &mut self,
429 key: &Type::Key,
430 buf: &[u8],
431 ) -> Result<Option<Vec<u8>>, Self::Error> {
432 <S as StorageWrite<Type>>::replace_bytes(&mut self.0, key, buf)
433 }
434
435 fn take_bytes(&mut self, key: &Type::Key) -> Result<Option<Vec<u8>>, Self::Error> {
436 <S as StorageWrite<Type>>::take_bytes(&mut self.0, key)
437 }
438}
439
440impl<S: ContractsAssetsStorage + InterpreterStorage> ContractsAssetsStorage
441 for Record<S>
442{
443}
444
445impl<S> InterpreterStorage for Record<S>
446where
447 S: InterpreterStorage,
448{
449 type DataError = <S as InterpreterStorage>::DataError;
450
451 fn block_height(&self) -> Result<BlockHeight, Self::DataError> {
452 self.0.block_height()
453 }
454
455 fn consensus_parameters_version(&self) -> Result<u32, Self::DataError> {
456 self.0.consensus_parameters_version()
457 }
458
459 fn state_transition_version(&self) -> Result<u32, Self::DataError> {
460 self.0.state_transition_version()
461 }
462
463 fn timestamp(&self, height: BlockHeight) -> Result<Word, Self::DataError> {
464 self.0.timestamp(height)
465 }
466
467 fn block_hash(&self, block_height: BlockHeight) -> Result<Bytes32, Self::DataError> {
468 self.0.block_hash(block_height)
469 }
470
471 fn coinbase(&self) -> Result<fuel_types::ContractId, Self::DataError> {
472 self.0.coinbase()
473 }
474
475 fn set_consensus_parameters(
476 &mut self,
477 version: u32,
478 consensus_parameters: &ConsensusParameters,
479 ) -> Result<Option<ConsensusParameters>, Self::DataError> {
480 self.0
481 .set_consensus_parameters(version, consensus_parameters)
482 }
483
484 fn set_state_transition_bytecode(
485 &mut self,
486 version: u32,
487 hash: &Bytes32,
488 ) -> Result<Option<Bytes32>, Self::DataError> {
489 self.0.set_state_transition_bytecode(version, hash)
490 }
491
492 fn contract_state_range(
493 &self,
494 id: &ContractId,
495 start_key: &Bytes32,
496 range: usize,
497 ) -> Result<Vec<Option<alloc::borrow::Cow<ContractsStateData>>>, Self::DataError>
498 {
499 self.0.contract_state_range(id, start_key, range)
500 }
501
502 fn contract_state_insert_range<'a, I>(
503 &mut self,
504 contract: &ContractId,
505 start_key: &Bytes32,
506 values: I,
507 ) -> Result<usize, Self::DataError>
508 where
509 I: Iterator<Item = &'a [u8]>,
510 {
511 self.0
512 .contract_state_insert_range(contract, start_key, values)
513 }
514
515 fn contract_state_remove_range(
516 &mut self,
517 contract: &ContractId,
518 start_key: &Bytes32,
519 range: usize,
520 ) -> Result<Option<()>, S::DataError> {
521 self.0
522 .contract_state_remove_range(contract, start_key, range)
523 }
524}
525
526impl StorageType for ContractsState {
527 fn record_replace(
528 key: &Self::Key,
529 value: &[u8],
530 existing: Option<ContractsStateData>,
531 ) -> StorageDelta {
532 StorageDelta::State(MappableDelta::Replace(
533 *key,
534 value.to_vec().into(),
535 existing,
536 ))
537 }
538
539 fn record_take(key: &Self::Key, value: ContractsStateData) -> StorageDelta {
540 StorageDelta::State(MappableDelta::Take(*key, value))
541 }
542}
543
544impl StorageType for ContractsAssets {
545 fn record_replace(
546 key: &Self::Key,
547 value: &u64,
548 existing: Option<u64>,
549 ) -> StorageDelta {
550 StorageDelta::Assets(MappableDelta::Replace(*key, *value, existing))
551 }
552
553 fn record_take(key: &Self::Key, value: u64) -> StorageDelta {
554 StorageDelta::Assets(MappableDelta::Take(*key, value))
555 }
556}
557
558impl StorageType for ContractsRawCode {
559 fn record_replace(
560 key: &ContractId,
561 value: &[u8],
562 existing: Option<Contract>,
563 ) -> StorageDelta {
564 StorageDelta::RawCode(MappableDelta::Replace(
565 *key,
566 value.to_vec().into(),
567 existing,
568 ))
569 }
570
571 fn record_take(key: &ContractId, value: Contract) -> StorageDelta {
572 StorageDelta::RawCode(MappableDelta::Take(*key, value))
573 }
574}
575
576impl StorageType for UploadedBytecodes {
577 fn record_replace(
578 key: &Bytes32,
579 value: &UploadedBytecode,
580 existing: Option<UploadedBytecode>,
581 ) -> StorageDelta {
582 StorageDelta::UploadedBytecode(MappableDelta::Replace(
583 *key,
584 value.clone(),
585 existing,
586 ))
587 }
588
589 fn record_take(key: &Bytes32, value: UploadedBytecode) -> StorageDelta {
590 StorageDelta::UploadedBytecode(MappableDelta::Take(*key, value))
591 }
592}
593
594impl StorageType for BlobData {
595 fn record_replace(
596 key: &BlobId,
597 value: &[u8],
598 existing: Option<BlobBytes>,
599 ) -> StorageDelta {
600 StorageDelta::BlobData(MappableDelta::Replace(
601 *key,
602 value.to_vec().into(),
603 existing,
604 ))
605 }
606
607 fn record_take(key: &BlobId, value: BlobBytes) -> StorageDelta {
608 StorageDelta::BlobData(MappableDelta::Take(*key, value))
609 }
610}
611impl<S> Record<S>
612where
613 S: InterpreterStorage,
614{
615 pub fn new(s: S) -> Self {
616 Self(s, Vec::new())
617 }
618}