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, TransactionId};
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 #[cfg(feature = "account-ext")]
78 fn set_extension(&mut self, extension: state::AccountExtension);
79
80 fn incr_balance(&mut self, balance: U256) -> bool;
84
85 fn decr_balance(&mut self, balance: U256) -> bool;
89
90 fn bump_nonce(&mut self) -> bool;
96
97 fn set_nonce(&mut self, nonce: u64);
101
102 fn unsafe_set_nonce(&mut self, nonce: u64);
107
108 fn set_code(&mut self, code_hash: B256, code: Bytecode);
112
113 fn set_code_and_hash_slow(&mut self, code: Bytecode);
117
118 fn delegate(&mut self, address: Address);
123}
124
125#[derive(Debug, PartialEq, Eq)]
129pub struct JournaledAccount<'a, DB, ENTRY: JournalEntryTr = JournalEntry> {
130 address: Address,
132 account: &'a mut Account,
134 journal_entries: &'a mut Vec<ENTRY>,
136 access_list: &'a AddressMap<HashSet<StorageKey>>,
138 transaction_id: TransactionId,
140 db: &'a mut DB,
142}
143
144impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccount<'a, DB, ENTRY> {
145 #[inline]
147 pub const fn new(
148 address: Address,
149 account: &'a mut Account,
150 journal_entries: &'a mut Vec<ENTRY>,
151 db: &'a mut DB,
152 access_list: &'a AddressMap<HashSet<StorageKey>>,
153 transaction_id: TransactionId,
154 ) -> Self {
155 Self {
156 address,
157 account,
158 journal_entries,
159 access_list,
160 transaction_id,
161 db,
162 }
163 }
164
165 #[inline(never)]
171 pub fn sload_concrete_error(
172 &mut self,
173 key: StorageKey,
174 skip_cold_load: bool,
175 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadError<DB::Error>> {
176 let is_newly_created = self.account.is_created();
177 let (slot, is_cold) = match self.account.storage.entry(key) {
178 Entry::Occupied(occ) => {
179 let slot = occ.into_mut();
180 let mut is_cold = false;
182 if slot.is_cold_transaction_id(self.transaction_id) {
183 is_cold = self
185 .access_list
186 .get(&self.address)
187 .and_then(|v| v.get(&key))
188 .is_none();
189
190 if is_cold && skip_cold_load {
191 return Err(JournalLoadError::ColdLoadSkipped);
192 }
193 }
194 slot.mark_warm_with_transaction_id(self.transaction_id);
195 (slot, is_cold)
196 }
197 Entry::Vacant(vac) => {
198 let is_cold = self
200 .access_list
201 .get(&self.address)
202 .and_then(|v| v.get(&key))
203 .is_none();
204
205 if is_cold && skip_cold_load {
206 return Err(JournalLoadError::ColdLoadSkipped);
207 }
208 let value = if is_newly_created {
210 StorageValue::ZERO
211 } else if let Some(account_id) = self.account.info.account_id {
212 self.db
213 .storage_by_account_id(self.address, account_id, key)?
214 } else {
215 self.db.storage(self.address, key)?
216 };
217
218 let slot = vac.insert(EvmStorageSlot::new(value, self.transaction_id));
219 (slot, is_cold)
220 }
221 };
222
223 if is_cold {
224 self.journal_entries
226 .push(ENTRY::storage_warmed(self.address, key));
227 }
228
229 Ok(StateLoad::new(slot, is_cold))
230 }
231
232 #[inline]
238 pub fn sstore_concrete_error(
239 &mut self,
240 key: StorageKey,
241 new: StorageValue,
242 skip_cold_load: bool,
243 ) -> Result<StateLoad<SStoreResult>, JournalLoadError<DB::Error>> {
244 self.touch();
246
247 let slot = self.sload_concrete_error(key, skip_cold_load)?;
249
250 let ret = Ok(StateLoad::new(
251 SStoreResult {
252 original_value: slot.original_value(),
253 present_value: slot.present_value(),
254 new_value: new,
255 },
256 slot.is_cold,
257 ));
258
259 if slot.present_value != new {
261 let previous_value = slot.present_value;
262 slot.data.present_value = new;
264
265 self.journal_entries
267 .push(ENTRY::storage_changed(self.address, key, previous_value));
268 }
269
270 ret
271 }
272
273 #[inline]
277 pub fn load_code_preserve_error(&mut self) -> Result<&Bytecode, JournalLoadError<DB::Error>> {
278 if self.account.info.code.is_none() {
279 let hash = *self.code_hash();
280 let code = if hash == KECCAK_EMPTY {
281 Bytecode::default()
282 } else {
283 self.db.code_by_hash(hash)?
284 };
285 self.account.info.code = Some(code);
286 }
287
288 Ok(self.account.info.code.as_ref().unwrap())
289 }
290
291 #[inline]
293 pub const fn into_account(self) -> &'a Account {
294 self.account
295 }
296}
297
298impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccountTr
299 for JournaledAccount<'a, DB, ENTRY>
300{
301 fn account(&self) -> &Account {
303 self.account
304 }
305
306 #[inline]
308 fn balance(&self) -> &U256 {
309 &self.account.info.balance
310 }
311
312 #[inline]
314 fn nonce(&self) -> u64 {
315 self.account.info.nonce
316 }
317
318 #[inline]
320 fn code_hash(&self) -> &B256 {
321 &self.account.info.code_hash
322 }
323
324 #[inline]
326 fn code(&self) -> Option<&Bytecode> {
327 self.account.info.code.as_ref()
328 }
329
330 #[inline]
332 fn touch(&mut self) {
333 if !self.account.status.is_touched() {
334 self.account.mark_touch();
335 self.journal_entries
336 .push(ENTRY::account_touched(self.address));
337 }
338 }
339
340 #[inline]
347 fn unsafe_mark_cold(&mut self) {
348 self.account.mark_cold();
349 }
350
351 #[inline]
357 fn set_balance(&mut self, balance: U256) {
358 self.touch();
359 if self.account.info.balance != balance {
360 self.journal_entries.push(ENTRY::balance_changed(
361 self.address,
362 self.account.info.balance,
363 ));
364 self.account.info.set_balance(balance);
365 }
366 }
367
368 #[cfg(feature = "account-ext")]
369 fn set_extension(&mut self, extension: state::AccountExtension) {
370 self.touch();
371 if self.account.info.extension != extension {
372 let old_extension = self.account.info.set_extension(extension);
373 self.journal_entries
374 .push(ENTRY::extension_changed(self.address, old_extension));
375 }
376 }
377
378 #[inline]
382 fn incr_balance(&mut self, balance: U256) -> bool {
383 self.touch();
384 let Some(balance) = self.account.info.balance.checked_add(balance) else {
385 return false;
386 };
387 self.set_balance(balance);
388 true
389 }
390
391 #[inline]
395 fn decr_balance(&mut self, balance: U256) -> bool {
396 self.touch();
397 let Some(balance) = self.account.info.balance.checked_sub(balance) else {
398 return false;
399 };
400 self.set_balance(balance);
401 true
402 }
403
404 #[inline]
410 fn bump_nonce(&mut self) -> bool {
411 self.touch();
412 let Some(nonce) = self.account.info.nonce.checked_add(1) else {
413 return false;
414 };
415 self.account.info.set_nonce(nonce);
416 self.journal_entries.push(ENTRY::nonce_bumped(self.address));
417 true
418 }
419
420 #[inline]
424 fn set_nonce(&mut self, nonce: u64) {
425 self.touch();
426 let previous_nonce = self.account.info.nonce;
427 self.account.info.set_nonce(nonce);
428 self.journal_entries
429 .push(ENTRY::nonce_changed(self.address, previous_nonce));
430 }
431
432 #[inline]
437 fn unsafe_set_nonce(&mut self, nonce: u64) {
438 self.account.info.set_nonce(nonce);
439 }
440
441 #[inline]
445 fn set_code(&mut self, code_hash: B256, code: Bytecode) {
446 self.touch();
447 let (had_code_hash, had_code) = self.account.info.set_code_and_hash(code, code_hash);
448 self.journal_entries
449 .push(ENTRY::code_changed(self.address, had_code_hash, had_code));
450 }
451
452 #[inline]
456 fn set_code_and_hash_slow(&mut self, code: Bytecode) {
457 let code_hash = code.hash_slow();
458 self.set_code(code_hash, code);
459 }
460
461 #[inline]
466 fn delegate(&mut self, address: Address) {
467 let (bytecode, hash) = if address.is_zero() {
468 (Bytecode::default(), KECCAK_EMPTY)
469 } else {
470 let bytecode = Bytecode::new_eip7702(address);
471 let hash = bytecode.hash_slow();
472 (bytecode, hash)
473 };
474 self.touch();
475 self.set_code(hash, bytecode);
476 self.bump_nonce();
477 }
478
479 #[inline]
481 fn sload(
482 &mut self,
483 key: StorageKey,
484 skip_cold_load: bool,
485 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError> {
486 self.sload_concrete_error(key, skip_cold_load)
487 .map_err(|i| i.map(ErasedError::new))
488 }
489
490 #[inline]
492 fn sstore(
493 &mut self,
494 key: StorageKey,
495 new: StorageValue,
496 skip_cold_load: bool,
497 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError> {
498 self.sstore_concrete_error(key, new, skip_cold_load)
499 .map_err(|i| i.map(ErasedError::new))
500 }
501
502 #[inline]
504 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError> {
505 self.load_code_preserve_error()
506 .map_err(|i| i.map(ErasedError::new))
507 }
508}