evm_nogas/backend/
memory.rs

1use super::{Apply, ApplyBackend, Backend, Basic, Log};
2use alloc::collections::BTreeMap;
3use alloc::vec::Vec;
4use primitive_types::{H160, H256, U256};
5
6/// Vivinity value of a memory backend.
7#[derive(Clone, Debug, Eq, PartialEq)]
8#[cfg_attr(
9    feature = "with-codec",
10    derive(codec::Encode, codec::Decode, scale_info::TypeInfo)
11)]
12#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct MemoryVicinity {
14    /// Gas price.
15    pub gas_price: U256,
16    /// Origin.
17    pub origin: H160,
18    /// Chain ID.
19    pub chain_id: U256,
20    /// Environmental block hashes.
21    pub block_hashes: Vec<H256>,
22    /// Environmental block number.
23    pub block_number: U256,
24    /// Environmental coinbase.
25    pub block_coinbase: H160,
26    /// Environmental block timestamp.
27    pub block_timestamp: U256,
28    /// Environmental block difficulty.
29    pub block_difficulty: U256,
30    /// Environmental block gas limit.
31    pub block_gas_limit: U256,
32    /// Environmental base fee per gas.
33    pub block_base_fee_per_gas: U256,
34}
35
36/// Account information of a memory backend.
37#[derive(Default, Clone, Debug, Eq, PartialEq)]
38#[cfg_attr(
39    feature = "with-codec",
40    derive(codec::Encode, codec::Decode, scale_info::TypeInfo)
41)]
42#[cfg_attr(feature = "with-serde", derive(serde::Serialize, serde::Deserialize))]
43pub struct MemoryAccount {
44    /// Account nonce.
45    pub nonce: U256,
46    /// Account balance.
47    pub balance: U256,
48    /// Full account storage.
49    pub storage: BTreeMap<H256, H256>,
50    /// Account code.
51    pub code: Vec<u8>,
52}
53
54/// Memory backend, storing all state values in a `BTreeMap` in memory.
55#[derive(Clone, Debug)]
56pub struct MemoryBackend<'vicinity> {
57    vicinity: &'vicinity MemoryVicinity,
58    state: BTreeMap<H160, MemoryAccount>,
59    logs: Vec<Log>,
60}
61
62impl<'vicinity> MemoryBackend<'vicinity> {
63    /// Create a new memory backend.
64    pub fn new(vicinity: &'vicinity MemoryVicinity, state: BTreeMap<H160, MemoryAccount>) -> Self {
65        Self {
66            vicinity,
67            state,
68            logs: Vec::new(),
69        }
70    }
71
72    /// Get the underlying `BTreeMap` storing the state.
73    pub fn state(&self) -> &BTreeMap<H160, MemoryAccount> {
74        &self.state
75    }
76
77    /// Get a mutable reference to the underlying `BTreeMap` storing the state.
78    pub fn state_mut(&mut self) -> &mut BTreeMap<H160, MemoryAccount> {
79        &mut self.state
80    }
81}
82
83impl<'vicinity> Backend for MemoryBackend<'vicinity> {
84    fn gas_price(&self) -> U256 {
85        self.vicinity.gas_price
86    }
87    fn gas_left(&self) -> U256 {
88        U256::zero()
89    }
90    fn origin(&self) -> H160 {
91        self.vicinity.origin
92    }
93    fn block_hash(&self, number: U256) -> H256 {
94        if number >= self.vicinity.block_number
95            || self.vicinity.block_number - number - U256::one()
96                >= U256::from(self.vicinity.block_hashes.len())
97        {
98            H256::default()
99        } else {
100            let index = (self.vicinity.block_number - number - U256::one()).as_usize();
101            self.vicinity.block_hashes[index]
102        }
103    }
104    fn block_number(&self) -> U256 {
105        self.vicinity.block_number
106    }
107    fn block_coinbase(&self) -> H160 {
108        self.vicinity.block_coinbase
109    }
110    fn block_timestamp(&self) -> U256 {
111        self.vicinity.block_timestamp
112    }
113    fn block_difficulty(&self) -> U256 {
114        self.vicinity.block_difficulty
115    }
116    fn block_gas_limit(&self) -> U256 {
117        self.vicinity.block_gas_limit
118    }
119    fn block_base_fee_per_gas(&self) -> U256 {
120        self.vicinity.block_base_fee_per_gas
121    }
122
123    fn chain_id(&self) -> U256 {
124        self.vicinity.chain_id
125    }
126
127    fn exists(&self, address: H160) -> bool {
128        self.state.contains_key(&address)
129    }
130
131    fn basic(&self, address: H160) -> Basic {
132        self.state
133            .get(&address)
134            .map(|a| Basic {
135                balance: a.balance,
136                nonce: a.nonce,
137            })
138            .unwrap_or_default()
139    }
140
141    fn code(&self, address: H160) -> Vec<u8> {
142        self.state
143            .get(&address)
144            .map(|v| v.code.clone())
145            .unwrap_or_default()
146    }
147
148    fn storage(&self, address: H160, index: H256) -> H256 {
149        self.state
150            .get(&address)
151            .map(|v| v.storage.get(&index).cloned().unwrap_or_default())
152            .unwrap_or_default()
153    }
154
155    fn original_storage(&self, address: H160, index: H256) -> Option<H256> {
156        Some(self.storage(address, index))
157    }
158}
159
160impl<'vicinity> ApplyBackend for MemoryBackend<'vicinity> {
161    fn apply<A, I, L>(&mut self, values: A, logs: L, delete_empty: bool)
162    where
163        A: IntoIterator<Item = Apply<I>>,
164        I: IntoIterator<Item = (H256, H256)>,
165        L: IntoIterator<Item = Log>,
166    {
167        for apply in values {
168            match apply {
169                Apply::Modify {
170                    address,
171                    basic,
172                    code,
173                    storage,
174                    reset_storage,
175                } => {
176                    let is_empty = {
177                        let account = self.state.entry(address).or_insert_with(Default::default);
178                        account.balance = basic.balance;
179                        account.nonce = basic.nonce;
180                        if let Some(code) = code {
181                            account.code = code;
182                        }
183
184                        if reset_storage {
185                            account.storage = BTreeMap::new();
186                        }
187
188                        let zeros = account
189                            .storage
190                            .iter()
191                            .filter(|(_, v)| v == &&H256::default())
192                            .map(|(k, _)| *k)
193                            .collect::<Vec<H256>>();
194
195                        for zero in zeros {
196                            account.storage.remove(&zero);
197                        }
198
199                        for (index, value) in storage {
200                            if value == H256::default() {
201                                account.storage.remove(&index);
202                            } else {
203                                account.storage.insert(index, value);
204                            }
205                        }
206
207                        account.balance == U256::zero()
208                            && account.nonce == U256::zero()
209                            && account.code.is_empty()
210                    };
211
212                    if is_empty && delete_empty {
213                        self.state.remove(&address);
214                    }
215                }
216                Apply::Delete { address } => {
217                    self.state.remove(&address);
218                }
219            }
220        }
221
222        for log in logs {
223            self.logs.push(log);
224        }
225    }
226}