revm_context_interface/journaled_state/
account.rs1use crate::{
7 context::{SStoreResult, StateLoad},
8 journaled_state::{entry::JournalEntry, JournalLoadErasedError, JournalLoadError},
9 ErasedError,
10};
11
12use super::entry::JournalEntryTr;
13use auto_impl::auto_impl;
14use database_interface::Database;
15use primitives::{
16 hash_map::Entry, Address, AddressMap, HashSet, StorageKey, StorageValue, B256, KECCAK_EMPTY,
17 U256,
18};
19use state::{Account, Bytecode, EvmStorageSlot};
20use std::vec::Vec;
21
22#[auto_impl(&mut, Box)]
24pub trait JournaledAccountTr {
25 fn account(&self) -> &Account;
27
28 fn sload(
30 &mut self,
31 key: StorageKey,
32 skip_cold_load: bool,
33 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError>;
34
35 fn sstore(
37 &mut self,
38 key: StorageKey,
39 new: StorageValue,
40 skip_cold_load: bool,
41 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError>;
42
43 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError>;
45
46 fn balance(&self) -> &U256;
48
49 fn nonce(&self) -> u64;
51
52 fn code_hash(&self) -> &B256;
54
55 fn code(&self) -> Option<&Bytecode>;
57
58 fn touch(&mut self);
60
61 fn unsafe_mark_cold(&mut self);
68
69 fn set_balance(&mut self, balance: U256);
75
76 fn incr_balance(&mut self, balance: U256) -> bool;
80
81 fn decr_balance(&mut self, balance: U256) -> bool;
85
86 fn bump_nonce(&mut self) -> bool;
92
93 fn set_nonce(&mut self, nonce: u64);
97
98 fn unsafe_set_nonce(&mut self, nonce: u64);
103
104 fn set_code(&mut self, code_hash: B256, code: Bytecode);
108
109 fn set_code_and_hash_slow(&mut self, code: Bytecode);
113
114 fn delegate(&mut self, address: Address);
119}
120
121#[derive(Debug, PartialEq, Eq)]
125pub struct JournaledAccount<'a, DB, ENTRY: JournalEntryTr = JournalEntry> {
126 address: Address,
128 account: &'a mut Account,
130 journal_entries: &'a mut Vec<ENTRY>,
132 access_list: &'a AddressMap<HashSet<StorageKey>>,
134 transaction_id: usize,
136 db: &'a mut DB,
138}
139
140impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccount<'a, DB, ENTRY> {
141 #[inline]
143 pub fn new(
144 address: Address,
145 account: &'a mut Account,
146 journal_entries: &'a mut Vec<ENTRY>,
147 db: &'a mut DB,
148 access_list: &'a AddressMap<HashSet<StorageKey>>,
149 transaction_id: usize,
150 ) -> Self {
151 Self {
152 address,
153 account,
154 journal_entries,
155 access_list,
156 transaction_id,
157 db,
158 }
159 }
160
161 #[inline(never)]
167 pub fn sload_concrete_error(
168 &mut self,
169 key: StorageKey,
170 skip_cold_load: bool,
171 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadError<DB::Error>> {
172 let is_newly_created = self.account.is_created();
173 let (slot, is_cold) = match self.account.storage.entry(key) {
174 Entry::Occupied(occ) => {
175 let slot = occ.into_mut();
176 let mut is_cold = false;
178 if slot.is_cold_transaction_id(self.transaction_id) {
179 is_cold = self
181 .access_list
182 .get(&self.address)
183 .and_then(|v| v.get(&key))
184 .is_none();
185
186 if is_cold && skip_cold_load {
187 return Err(JournalLoadError::ColdLoadSkipped);
188 }
189 }
190 slot.mark_warm_with_transaction_id(self.transaction_id);
191 (slot, is_cold)
192 }
193 Entry::Vacant(vac) => {
194 let is_cold = self
196 .access_list
197 .get(&self.address)
198 .and_then(|v| v.get(&key))
199 .is_none();
200
201 if is_cold && skip_cold_load {
202 return Err(JournalLoadError::ColdLoadSkipped);
203 }
204 let value = if is_newly_created {
206 StorageValue::ZERO
207 } else {
208 self.db.storage(self.address, key)?
209 };
210
211 let slot = vac.insert(EvmStorageSlot::new(value, self.transaction_id));
212 (slot, is_cold)
213 }
214 };
215
216 if is_cold {
217 self.journal_entries
219 .push(ENTRY::storage_warmed(self.address, key));
220 }
221
222 Ok(StateLoad::new(slot, is_cold))
223 }
224
225 #[inline]
231 pub fn sstore_concrete_error(
232 &mut self,
233 key: StorageKey,
234 new: StorageValue,
235 skip_cold_load: bool,
236 ) -> Result<StateLoad<SStoreResult>, JournalLoadError<DB::Error>> {
237 self.touch();
239
240 let slot = self.sload_concrete_error(key, skip_cold_load)?;
242
243 let ret = Ok(StateLoad::new(
244 SStoreResult {
245 original_value: slot.original_value(),
246 present_value: slot.present_value(),
247 new_value: new,
248 },
249 slot.is_cold,
250 ));
251
252 if slot.present_value != new {
254 let previous_value = slot.present_value;
255 slot.data.present_value = new;
257
258 self.journal_entries
260 .push(ENTRY::storage_changed(self.address, key, previous_value));
261 }
262
263 ret
264 }
265
266 #[inline]
270 pub fn load_code_preserve_error(&mut self) -> Result<&Bytecode, JournalLoadError<DB::Error>> {
271 if self.account.info.code.is_none() {
272 let hash = *self.code_hash();
273 let code = if hash == KECCAK_EMPTY {
274 Bytecode::default()
275 } else {
276 self.db.code_by_hash(hash)?
277 };
278 self.account.info.code = Some(code);
279 }
280
281 Ok(self.account.info.code.as_ref().unwrap())
282 }
283
284 #[inline]
286 pub fn into_account(self) -> &'a Account {
287 self.account
288 }
289}
290
291impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccountTr
292 for JournaledAccount<'a, DB, ENTRY>
293{
294 fn account(&self) -> &Account {
296 self.account
297 }
298
299 #[inline]
301 fn balance(&self) -> &U256 {
302 &self.account.info.balance
303 }
304
305 #[inline]
307 fn nonce(&self) -> u64 {
308 self.account.info.nonce
309 }
310
311 #[inline]
313 fn code_hash(&self) -> &B256 {
314 &self.account.info.code_hash
315 }
316
317 #[inline]
319 fn code(&self) -> Option<&Bytecode> {
320 self.account.info.code.as_ref()
321 }
322
323 #[inline]
325 fn touch(&mut self) {
326 if !self.account.status.is_touched() {
327 self.account.mark_touch();
328 self.journal_entries
329 .push(ENTRY::account_touched(self.address));
330 }
331 }
332
333 #[inline]
340 fn unsafe_mark_cold(&mut self) {
341 self.account.mark_cold();
342 }
343
344 #[inline]
350 fn set_balance(&mut self, balance: U256) {
351 self.touch();
352 if self.account.info.balance != balance {
353 self.journal_entries.push(ENTRY::balance_changed(
354 self.address,
355 self.account.info.balance,
356 ));
357 self.account.info.set_balance(balance);
358 }
359 }
360
361 #[inline]
365 fn incr_balance(&mut self, balance: U256) -> bool {
366 self.touch();
367 let Some(balance) = self.account.info.balance.checked_add(balance) else {
368 return false;
369 };
370 self.set_balance(balance);
371 true
372 }
373
374 #[inline]
378 fn decr_balance(&mut self, balance: U256) -> bool {
379 self.touch();
380 let Some(balance) = self.account.info.balance.checked_sub(balance) else {
381 return false;
382 };
383 self.set_balance(balance);
384 true
385 }
386
387 #[inline]
393 fn bump_nonce(&mut self) -> bool {
394 self.touch();
395 let Some(nonce) = self.account.info.nonce.checked_add(1) else {
396 return false;
397 };
398 self.account.info.set_nonce(nonce);
399 self.journal_entries.push(ENTRY::nonce_bumped(self.address));
400 true
401 }
402
403 #[inline]
407 fn set_nonce(&mut self, nonce: u64) {
408 self.touch();
409 let previous_nonce = self.account.info.nonce;
410 self.account.info.set_nonce(nonce);
411 self.journal_entries
412 .push(ENTRY::nonce_changed(self.address, previous_nonce));
413 }
414
415 #[inline]
420 fn unsafe_set_nonce(&mut self, nonce: u64) {
421 self.account.info.set_nonce(nonce);
422 }
423
424 #[inline]
428 fn set_code(&mut self, code_hash: B256, code: Bytecode) {
429 self.touch();
430 self.account.info.set_code_and_hash(code, code_hash);
431 self.journal_entries.push(ENTRY::code_changed(self.address));
432 }
433
434 #[inline]
438 fn set_code_and_hash_slow(&mut self, code: Bytecode) {
439 let code_hash = code.hash_slow();
440 self.set_code(code_hash, code);
441 }
442
443 #[inline]
448 fn delegate(&mut self, address: Address) {
449 let (bytecode, hash) = if address.is_zero() {
450 (Bytecode::default(), KECCAK_EMPTY)
451 } else {
452 let bytecode = Bytecode::new_eip7702(address);
453 let hash = bytecode.hash_slow();
454 (bytecode, hash)
455 };
456 self.touch();
457 self.set_code(hash, bytecode);
458 self.bump_nonce();
459 }
460
461 #[inline]
463 fn sload(
464 &mut self,
465 key: StorageKey,
466 skip_cold_load: bool,
467 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError> {
468 self.sload_concrete_error(key, skip_cold_load)
469 .map_err(|i| i.map(ErasedError::new))
470 }
471
472 #[inline]
474 fn sstore(
475 &mut self,
476 key: StorageKey,
477 new: StorageValue,
478 skip_cold_load: bool,
479 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError> {
480 self.sstore_concrete_error(key, new, skip_cold_load)
481 .map_err(|i| i.map(ErasedError::new))
482 }
483
484 #[inline]
486 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError> {
487 self.load_code_preserve_error()
488 .map_err(|i| i.map(ErasedError::new))
489 }
490}