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