aurora_evm/executor/stack/
memory.rs

1use crate::backend::{Apply, Backend, Basic, Log};
2use crate::core::utils::{U256_ONE, U256_ZERO, U64_MAX};
3use crate::executor::stack::executor::{
4    Accessed, Authorization, StackState, StackSubstateMetadata,
5};
6use crate::prelude::*;
7use crate::{ExitError, Transfer};
8use core::mem;
9use primitive_types::{H160, H256, U256};
10
11#[derive(Clone, Debug)]
12pub struct MemoryStackAccount {
13    pub basic: Basic,
14    pub code: Option<Vec<u8>>,
15    pub reset: bool,
16}
17
18#[derive(Clone, Debug)]
19pub struct MemoryStackSubstate<'config> {
20    metadata: StackSubstateMetadata<'config>,
21    parent: Option<Box<MemoryStackSubstate<'config>>>,
22    logs: Vec<Log>,
23    accounts: BTreeMap<H160, MemoryStackAccount>,
24    storages: BTreeMap<(H160, H256), H256>,
25    tstorages: BTreeMap<(H160, H256), U256>,
26    deletes: BTreeSet<H160>,
27    creates: BTreeSet<H160>,
28}
29
30impl<'config> MemoryStackSubstate<'config> {
31    #[must_use]
32    pub const fn new(metadata: StackSubstateMetadata<'config>) -> Self {
33        Self {
34            metadata,
35            parent: None::<Box<_>>,
36            logs: Vec::new(),
37            accounts: BTreeMap::new(),
38            storages: BTreeMap::new(),
39            tstorages: BTreeMap::new(),
40            deletes: BTreeSet::new(),
41            creates: BTreeSet::new(),
42        }
43    }
44
45    #[must_use]
46    pub fn logs(&self) -> &[Log] {
47        &self.logs
48    }
49
50    pub fn logs_mut(&mut self) -> &mut Vec<Log> {
51        &mut self.logs
52    }
53
54    #[must_use]
55    pub const fn metadata(&self) -> &StackSubstateMetadata<'config> {
56        &self.metadata
57    }
58
59    pub fn metadata_mut(&mut self) -> &mut StackSubstateMetadata<'config> {
60        &mut self.metadata
61    }
62
63    /// Deconstruct the memory stack substate, return state to be applied. Panic if the
64    /// substate is not in the top-level substate.
65    ///
66    /// # Panics
67    /// Panic if parent presents
68    #[must_use]
69    pub fn deconstruct<B: Backend>(
70        mut self,
71        backend: &B,
72    ) -> (
73        impl IntoIterator<Item = Apply<impl IntoIterator<Item = (H256, H256)>>>,
74        impl IntoIterator<Item = Log>,
75    ) {
76        assert!(self.parent.is_none());
77
78        let mut applies = Vec::<Apply<BTreeMap<H256, H256>>>::new();
79
80        let mut addresses = BTreeSet::new();
81
82        for address in self.accounts.keys() {
83            addresses.insert(*address);
84        }
85
86        for (address, _) in self.storages.keys() {
87            addresses.insert(*address);
88        }
89
90        for address in addresses {
91            if self.deletes.contains(&address) {
92                continue;
93            }
94
95            let mut storage = BTreeMap::new();
96            for ((oa, ok), ov) in &self.storages {
97                if *oa == address {
98                    storage.insert(*ok, *ov);
99                }
100            }
101
102            let apply = {
103                let account = if self.is_created(address) {
104                    let account = self
105                        .accounts
106                        .get_mut(&address)
107                        .expect("New account was just inserted");
108                    // Reset storage for CREATE call as initially it's always should be empty.
109                    // NOTE: related to `ethereum-tests`: `stSStoreTest/InitCollisionParis.json`
110                    account.reset = true;
111                    account
112                } else {
113                    self.account_mut(address, backend)
114                };
115
116                Apply::Modify {
117                    address,
118                    basic: account.basic.clone(),
119                    code: account.code.clone(),
120                    storage,
121                    reset_storage: account.reset,
122                }
123            };
124
125            applies.push(apply);
126        }
127
128        for address in self.deletes {
129            applies.push(Apply::Delete { address });
130        }
131
132        (applies, self.logs)
133    }
134
135    pub fn enter(&mut self, gas_limit: u64, is_static: bool) {
136        let mut entering = Self {
137            metadata: self.metadata.spit_child(gas_limit, is_static),
138            parent: None,
139            logs: Vec::new(),
140            accounts: BTreeMap::new(),
141            storages: BTreeMap::new(),
142            tstorages: BTreeMap::new(),
143            deletes: BTreeSet::new(),
144            creates: BTreeSet::new(),
145        };
146        mem::swap(&mut entering, self);
147
148        self.parent = Some(Box::new(entering));
149    }
150
151    /// Exit commit represent successful execution of the `substate`.
152    ///
153    /// It includes:
154    /// - swallow commit
155    ///   - gas recording
156    ///   - warmed accesses merging
157    /// - logs merging
158    /// - for account existed from substate with reset flag, remove storages by keys
159    /// - merge substate data: accounts, storages, tstorages, deletes, creates
160    ///
161    /// # Errors
162    /// Return `ExitError` that is thrown by gasometer gas calculation errors.
163    ///
164    /// # Panics
165    /// Cannot commit on root `substate` i.e. it forces to panic.
166    pub fn exit_commit(&mut self) -> Result<(), ExitError> {
167        let mut exited = *self.parent.take().expect("Cannot commit on root substate");
168        mem::swap(&mut exited, self);
169
170        self.metadata.swallow_commit(exited.metadata)?;
171        self.logs.append(&mut exited.logs);
172
173        let mut resets = BTreeSet::new();
174        for (address, account) in &exited.accounts {
175            if account.reset {
176                resets.insert(*address);
177            }
178        }
179        let mut reset_keys = BTreeSet::new();
180        for (address, key) in self.storages.keys() {
181            if resets.contains(address) {
182                reset_keys.insert((*address, *key));
183            }
184        }
185        for (address, key) in reset_keys {
186            self.storages.remove(&(address, key));
187        }
188
189        self.accounts.append(&mut exited.accounts);
190        self.storages.append(&mut exited.storages);
191        self.tstorages.append(&mut exited.tstorages);
192        self.deletes.append(&mut exited.deletes);
193        self.creates.append(&mut exited.creates);
194        Ok(())
195    }
196
197    /// Exit revert. Represents revert execution of the `substate`.
198    ///
199    /// # Errors
200    /// Return `ExitError`
201    ///
202    /// # Panics
203    /// Cannot discard on root substate
204    pub fn exit_revert(&mut self) -> Result<(), ExitError> {
205        let mut exited = *self.parent.take().expect("Cannot discard on root substate");
206        mem::swap(&mut exited, self);
207        self.metadata.swallow_revert(&exited.metadata)?;
208        Ok(())
209    }
210
211    /// Exit discard. Represents discard execution of the `substate`.
212    ///
213    /// # Errors
214    /// Return `ExitError`. At the momoet it's not throwing any real error.
215    ///
216    /// # Panics
217    /// Cannot discard on root substate
218    pub fn exit_discard(&mut self) -> Result<(), ExitError> {
219        let mut exited = *self.parent.take().expect("Cannot discard on root substate");
220        mem::swap(&mut exited, self);
221        self.metadata.swallow_discard(&exited.metadata);
222        Ok(())
223    }
224
225    pub fn known_account(&self, address: H160) -> Option<&MemoryStackAccount> {
226        self.accounts.get(&address).map_or_else(
227            || {
228                self.parent
229                    .as_ref()
230                    .and_then(|parent| parent.known_account(address))
231            },
232            Some,
233        )
234    }
235
236    #[must_use]
237    pub fn known_basic(&self, address: H160) -> Option<Basic> {
238        self.known_account(address).map(|acc| acc.basic.clone())
239    }
240
241    #[must_use]
242    pub fn known_code(&self, address: H160) -> Option<Vec<u8>> {
243        self.known_account(address).and_then(|acc| acc.code.clone())
244    }
245
246    #[must_use]
247    pub fn known_empty(&self, address: H160) -> Option<bool> {
248        if let Some(account) = self.known_account(address) {
249            if account.basic.balance != U256_ZERO {
250                return Some(false);
251            }
252
253            if account.basic.nonce != U256_ZERO {
254                return Some(false);
255            }
256
257            if let Some(code) = &account.code {
258                return Some(
259                    account.basic.balance == U256_ZERO
260                        && account.basic.nonce == U256_ZERO
261                        && code.is_empty(),
262                );
263            }
264        }
265
266        None
267    }
268
269    #[must_use]
270    pub fn known_storage(&self, address: H160, key: H256) -> Option<H256> {
271        if let Some(value) = self.storages.get(&(address, key)) {
272            return Some(*value);
273        }
274
275        if let Some(account) = self.accounts.get(&address) {
276            if account.reset {
277                return Some(H256::default());
278            }
279        }
280
281        if let Some(parent) = self.parent.as_ref() {
282            return parent.known_storage(address, key);
283        }
284
285        None
286    }
287
288    #[must_use]
289    pub fn known_original_storage(&self, address: H160) -> Option<H256> {
290        if let Some(account) = self.accounts.get(&address) {
291            if account.reset {
292                return Some(H256::default());
293            }
294        }
295
296        if let Some(parent) = self.parent.as_ref() {
297            return parent.known_original_storage(address);
298        }
299
300        None
301    }
302
303    #[must_use]
304    pub fn is_cold(&self, address: H160) -> bool {
305        self.recursive_is_cold(&|a| a.accessed_addresses.contains(&address))
306    }
307
308    #[must_use]
309    pub fn is_storage_cold(&self, address: H160, key: H256) -> bool {
310        self.recursive_is_cold(&|a: &Accessed| a.accessed_storage.contains(&(address, key)))
311    }
312
313    fn recursive_is_cold<F: Fn(&Accessed) -> bool>(&self, f: &F) -> bool {
314        let local_is_accessed = self.metadata.accessed().as_ref().is_some_and(f);
315        if local_is_accessed {
316            false
317        } else {
318            self.parent
319                .as_ref()
320                .map_or(true, |p| p.recursive_is_cold(f))
321        }
322    }
323
324    #[must_use]
325    pub fn deleted(&self, address: H160) -> bool {
326        if self.deletes.contains(&address) {
327            return true;
328        }
329
330        if let Some(parent) = self.parent.as_ref() {
331            return parent.deleted(address);
332        }
333
334        false
335    }
336
337    #[allow(clippy::map_entry)]
338    fn account_mut<B: Backend>(&mut self, address: H160, backend: &B) -> &mut MemoryStackAccount {
339        if !self.accounts.contains_key(&address) {
340            let account = self.known_account(address).cloned().map_or_else(
341                || MemoryStackAccount {
342                    basic: backend.basic(address),
343                    code: None::<Vec<_>>,
344                    reset: false,
345                },
346                |mut v| {
347                    v.reset = false;
348                    v
349                },
350            );
351            self.accounts.insert(address, account);
352        }
353
354        self.accounts
355            .get_mut(&address)
356            .expect("New account was just inserted")
357    }
358
359    /// # Errors
360    /// Return `ExitError`
361    pub fn inc_nonce<B: Backend>(&mut self, address: H160, backend: &B) -> Result<(), ExitError> {
362        let nonce = &mut self.account_mut(address, backend).basic.nonce;
363        if *nonce >= U64_MAX {
364            return Err(ExitError::MaxNonce);
365        }
366        *nonce += U256_ONE;
367        Ok(())
368    }
369
370    pub fn set_storage(&mut self, address: H160, key: H256, value: H256) {
371        #[cfg(feature = "print-debug")]
372        println!("    [SSTORE {address:?}] {key:?}:{value:?}");
373        self.storages.insert((address, key), value);
374    }
375
376    pub fn reset_storage<B: Backend>(&mut self, address: H160, backend: &B) {
377        let mut removing = Vec::new();
378
379        for (oa, ok) in self.storages.keys() {
380            if *oa == address {
381                removing.push(*ok);
382            }
383        }
384
385        for ok in removing {
386            self.storages.remove(&(address, ok));
387        }
388        self.account_mut(address, backend).reset = true;
389    }
390
391    pub fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) {
392        self.logs.push(Log {
393            address,
394            topics,
395            data,
396        });
397    }
398
399    pub fn set_deleted(&mut self, address: H160) {
400        self.deletes.insert(address);
401    }
402
403    pub fn set_created(&mut self, address: H160) {
404        self.creates.insert(address);
405    }
406
407    #[must_use]
408    pub fn is_created(&self, address: H160) -> bool {
409        if self.creates.contains(&address) {
410            return true;
411        }
412
413        if let Some(parent) = self.parent.as_ref() {
414            return parent.is_created(address);
415        }
416
417        false
418    }
419
420    pub fn set_code<B: Backend>(&mut self, address: H160, code: Vec<u8>, backend: &B) {
421        self.account_mut(address, backend).code = Some(code);
422    }
423
424    /// # Errors
425    /// Return `ExitError`
426    pub fn transfer<B: Backend>(
427        &mut self,
428        transfer: &Transfer,
429        backend: &B,
430    ) -> Result<(), ExitError> {
431        {
432            let source = self.account_mut(transfer.source, backend);
433            if source.basic.balance < transfer.value {
434                return Err(ExitError::OutOfFund);
435            }
436            source.basic.balance -= transfer.value;
437        }
438
439        {
440            let target = self.account_mut(transfer.target, backend);
441            target.basic.balance = target.basic.balance.saturating_add(transfer.value);
442        }
443
444        Ok(())
445    }
446
447    /// Only needed for jsontests.
448    /// # Errors
449    /// Return `ExitError`
450    pub fn withdraw<B: Backend>(
451        &mut self,
452        address: H160,
453        value: U256,
454        backend: &B,
455    ) -> Result<(), ExitError> {
456        let source = self.account_mut(address, backend);
457        if source.basic.balance < value {
458            return Err(ExitError::OutOfFund);
459        }
460        source.basic.balance -= value;
461
462        Ok(())
463    }
464
465    // Only needed for jsontests.
466    pub fn deposit<B: Backend>(&mut self, address: H160, value: U256, backend: &B) {
467        let target = self.account_mut(address, backend);
468        target.basic.balance = target.basic.balance.saturating_add(value);
469    }
470
471    pub fn reset_balance<B: Backend>(&mut self, address: H160, backend: &B) {
472        self.account_mut(address, backend).basic.balance = U256_ZERO;
473    }
474
475    pub fn touch<B: Backend>(&mut self, address: H160, backend: &B) {
476        self.account_mut(address, backend);
477    }
478
479    #[must_use]
480    pub fn get_tstorage(&self, address: H160, key: H256) -> U256 {
481        self.known_tstorage(address, key).unwrap_or_default()
482    }
483
484    #[must_use]
485    pub fn known_tstorage(&self, address: H160, key: H256) -> Option<U256> {
486        if let Some(value) = self.tstorages.get(&(address, key)) {
487            return Some(*value);
488        }
489        if let Some(parent) = self.parent.as_ref() {
490            return parent.known_tstorage(address, key);
491        }
492        None
493    }
494
495    pub fn set_tstorage(&mut self, address: H160, key: H256, value: U256) {
496        self.tstorages.insert((address, key), value);
497    }
498
499    /// Get authority target from the current state. If it's `None` just take a look
500    /// recursively in the parent state.
501    fn get_authority_target_recursive(&self, authority: H160) -> Option<H160> {
502        if let Some(target) = self
503            .metadata
504            .accessed()
505            .as_ref()
506            .and_then(|accessed| accessed.get_authority_target(authority))
507        {
508            return Some(target);
509        }
510        self.parent
511            .as_ref()
512            .and_then(|p| p.get_authority_target_recursive(authority))
513    }
514}
515
516#[derive(Clone, Debug)]
517pub struct MemoryStackState<'backend, 'config, B> {
518    backend: &'backend B,
519    substate: MemoryStackSubstate<'config>,
520}
521
522impl<B: Backend> Backend for MemoryStackState<'_, '_, B> {
523    fn gas_price(&self) -> U256 {
524        self.backend.gas_price()
525    }
526    fn origin(&self) -> H160 {
527        self.backend.origin()
528    }
529    fn block_hash(&self, number: U256) -> H256 {
530        self.backend.block_hash(number)
531    }
532    fn block_number(&self) -> U256 {
533        self.backend.block_number()
534    }
535    fn block_coinbase(&self) -> H160 {
536        self.backend.block_coinbase()
537    }
538    fn block_timestamp(&self) -> U256 {
539        self.backend.block_timestamp()
540    }
541    fn block_difficulty(&self) -> U256 {
542        self.backend.block_difficulty()
543    }
544    fn block_randomness(&self) -> Option<H256> {
545        self.backend.block_randomness()
546    }
547    fn block_gas_limit(&self) -> U256 {
548        self.backend.block_gas_limit()
549    }
550    fn block_base_fee_per_gas(&self) -> U256 {
551        self.backend.block_base_fee_per_gas()
552    }
553
554    fn chain_id(&self) -> U256 {
555        self.backend.chain_id()
556    }
557
558    fn exists(&self, address: H160) -> bool {
559        self.substate.known_account(address).is_some() || self.backend.exists(address)
560    }
561
562    fn basic(&self, address: H160) -> Basic {
563        self.substate
564            .known_basic(address)
565            .unwrap_or_else(|| self.backend.basic(address))
566    }
567
568    fn code(&self, address: H160) -> Vec<u8> {
569        self.substate
570            .known_code(address)
571            .unwrap_or_else(|| self.backend.code(address))
572    }
573
574    fn storage(&self, address: H160, key: H256) -> H256 {
575        self.substate
576            .known_storage(address, key)
577            .unwrap_or_else(|| self.backend.storage(address, key))
578    }
579
580    fn is_empty_storage(&self, address: H160) -> bool {
581        self.backend.is_empty_storage(address)
582    }
583
584    fn original_storage(&self, address: H160, key: H256) -> Option<H256> {
585        if let Some(value) = self.substate.known_original_storage(address) {
586            return Some(value);
587        }
588
589        self.backend.original_storage(address, key)
590    }
591    fn blob_gas_price(&self) -> Option<u128> {
592        self.backend.blob_gas_price()
593    }
594    fn get_blob_hash(&self, index: usize) -> Option<U256> {
595        self.backend.get_blob_hash(index)
596    }
597}
598
599impl<'config, B: Backend> StackState<'config> for MemoryStackState<'_, 'config, B> {
600    fn metadata(&self) -> &StackSubstateMetadata<'config> {
601        self.substate.metadata()
602    }
603
604    fn metadata_mut(&mut self) -> &mut StackSubstateMetadata<'config> {
605        self.substate.metadata_mut()
606    }
607
608    fn enter(&mut self, gas_limit: u64, is_static: bool) {
609        self.substate.enter(gas_limit, is_static);
610    }
611
612    fn exit_commit(&mut self) -> Result<(), ExitError> {
613        self.substate.exit_commit()
614    }
615
616    fn exit_revert(&mut self) -> Result<(), ExitError> {
617        self.substate.exit_revert()
618    }
619
620    fn exit_discard(&mut self) -> Result<(), ExitError> {
621        self.substate.exit_discard()
622    }
623
624    fn is_empty(&self, address: H160) -> bool {
625        if let Some(known_empty) = self.substate.known_empty(address) {
626            return known_empty;
627        }
628
629        self.backend.basic(address).balance == U256_ZERO
630            && self.backend.basic(address).nonce == U256_ZERO
631            && self.backend.code(address).is_empty()
632    }
633
634    fn deleted(&self, address: H160) -> bool {
635        self.substate.deleted(address)
636    }
637
638    fn is_cold(&self, address: H160) -> bool {
639        self.substate.is_cold(address)
640    }
641
642    fn is_storage_cold(&self, address: H160, key: H256) -> bool {
643        self.substate.is_storage_cold(address, key)
644    }
645
646    fn inc_nonce(&mut self, address: H160) -> Result<(), ExitError> {
647        self.substate.inc_nonce(address, self.backend)
648    }
649
650    fn set_storage(&mut self, address: H160, key: H256, value: H256) {
651        self.substate.set_storage(address, key, value);
652    }
653
654    fn reset_storage(&mut self, address: H160) {
655        self.substate.reset_storage(address, self.backend);
656    }
657
658    fn log(&mut self, address: H160, topics: Vec<H256>, data: Vec<u8>) {
659        self.substate.log(address, topics, data);
660    }
661
662    fn set_deleted(&mut self, address: H160) {
663        self.substate.set_deleted(address);
664    }
665
666    fn set_created(&mut self, address: H160) {
667        self.substate.set_created(address);
668    }
669
670    fn is_created(&self, address: H160) -> bool {
671        self.substate.is_created(address)
672    }
673
674    fn set_code(&mut self, address: H160, code: Vec<u8>) {
675        self.substate.set_code(address, code, self.backend);
676    }
677
678    fn transfer(&mut self, transfer: Transfer) -> Result<(), ExitError> {
679        self.substate.transfer(&transfer, self.backend)
680    }
681
682    fn reset_balance(&mut self, address: H160) {
683        self.substate.reset_balance(address, self.backend);
684    }
685
686    fn touch(&mut self, address: H160) {
687        self.substate.touch(address, self.backend);
688    }
689
690    fn tload(&mut self, address: H160, index: H256) -> Result<U256, ExitError> {
691        Ok(self.substate.get_tstorage(address, index))
692    }
693
694    fn tstore(&mut self, address: H160, index: H256, value: U256) -> Result<(), ExitError> {
695        self.substate.set_tstorage(address, index, value);
696        Ok(())
697    }
698
699    /// EIP-7702 - check is authority cold.
700    fn is_authority_cold(&mut self, address: H160) -> Option<bool> {
701        self.get_authority_target(address)
702            .map(|target| self.is_cold(target))
703    }
704
705    /// Get authority target (EIP-7702) - delegated address.
706    /// First we're trying to get authority target from the cache recursively with parent state,
707    /// if it's not found we get code for the authority address and check if it's delegation
708    /// designator. If it's true, we add result to cache and return delegated target address.
709    fn get_authority_target(&mut self, authority: H160) -> Option<H160> {
710        // Read from cache
711        if let Some(target_address) = self.substate.get_authority_target_recursive(authority) {
712            Some(target_address)
713        } else {
714            // If not found in the cache
715            // Get code for delegated address
716            let authority_code = self.code(authority);
717            if let Some(target) = Authorization::get_delegated_address(&authority_code) {
718                // Add to cache
719                self.metadata_mut().add_authority(authority, target);
720                return Some(target);
721            }
722            None
723        }
724    }
725}
726
727impl<'backend, 'config, B: Backend> MemoryStackState<'backend, 'config, B> {
728    pub const fn new(metadata: StackSubstateMetadata<'config>, backend: &'backend B) -> Self {
729        Self {
730            backend,
731            substate: MemoryStackSubstate::new(metadata),
732        }
733    }
734
735    /// Returns a mutable reference to an account given its address
736    pub fn account_mut(&mut self, address: H160) -> &mut MemoryStackAccount {
737        self.substate.account_mut(address, self.backend)
738    }
739
740    #[must_use]
741    pub fn deconstruct(
742        self,
743    ) -> (
744        impl IntoIterator<Item = Apply<impl IntoIterator<Item = (H256, H256)>>>,
745        impl IntoIterator<Item = Log>,
746    ) {
747        self.substate.deconstruct(self.backend)
748    }
749
750    /// # Errors
751    /// Return `ExitError`
752    pub fn withdraw(&mut self, address: H160, value: U256) -> Result<(), ExitError> {
753        self.substate.withdraw(address, value, self.backend)
754    }
755
756    pub fn deposit(&mut self, address: H160, value: U256) {
757        self.substate.deposit(address, value, self.backend);
758    }
759}