evm_nogas/backend/
memory.rs1use super::{Apply, ApplyBackend, Backend, Basic, Log};
2use alloc::collections::BTreeMap;
3use alloc::vec::Vec;
4use primitive_types::{H160, H256, U256};
5
6#[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 pub gas_price: U256,
16 pub origin: H160,
18 pub chain_id: U256,
20 pub block_hashes: Vec<H256>,
22 pub block_number: U256,
24 pub block_coinbase: H160,
26 pub block_timestamp: U256,
28 pub block_difficulty: U256,
30 pub block_gas_limit: U256,
32 pub block_base_fee_per_gas: U256,
34}
35
36#[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 pub nonce: U256,
46 pub balance: U256,
48 pub storage: BTreeMap<H256, H256>,
50 pub code: Vec<u8>,
52}
53
54#[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 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 pub fn state(&self) -> &BTreeMap<H160, MemoryAccount> {
74 &self.state
75 }
76
77 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}