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 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: TransactionId,
136 db: &'a mut DB,
138}
139
140impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccount<'a, DB, ENTRY> {
141 #[inline]
143 pub const 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: TransactionId,
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 if let Some(account_id) = self.account.info.account_id {
208 self.db
209 .storage_by_account_id(self.address, account_id, key)?
210 } else {
211 self.db.storage(self.address, key)?
212 };
213
214 let slot = vac.insert(EvmStorageSlot::new(value, self.transaction_id));
215 (slot, is_cold)
216 }
217 };
218
219 if is_cold {
220 self.journal_entries
222 .push(ENTRY::storage_warmed(self.address, key));
223 }
224
225 Ok(StateLoad::new(slot, is_cold))
226 }
227
228 #[inline]
234 pub fn sstore_concrete_error(
235 &mut self,
236 key: StorageKey,
237 new: StorageValue,
238 skip_cold_load: bool,
239 ) -> Result<StateLoad<SStoreResult>, JournalLoadError<DB::Error>> {
240 self.touch();
242
243 let slot = self.sload_concrete_error(key, skip_cold_load)?;
245
246 let ret = Ok(StateLoad::new(
247 SStoreResult {
248 original_value: slot.original_value(),
249 present_value: slot.present_value(),
250 new_value: new,
251 },
252 slot.is_cold,
253 ));
254
255 if slot.present_value != new {
257 let previous_value = slot.present_value;
258 slot.data.present_value = new;
260
261 self.journal_entries
263 .push(ENTRY::storage_changed(self.address, key, previous_value));
264 }
265
266 ret
267 }
268
269 #[inline]
273 pub fn load_code_preserve_error(&mut self) -> Result<&Bytecode, JournalLoadError<DB::Error>> {
274 if self.account.info.code.is_none() {
275 let hash = *self.code_hash();
276 let code = if hash == KECCAK_EMPTY {
277 Bytecode::default()
278 } else {
279 self.db.code_by_hash(hash)?
280 };
281 self.account.info.code = Some(code);
282 }
283
284 Ok(self.account.info.code.as_ref().unwrap())
285 }
286
287 #[inline]
289 pub const fn into_account(self) -> &'a Account {
290 self.account
291 }
292}
293
294impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccountTr
295 for JournaledAccount<'a, DB, ENTRY>
296{
297 fn account(&self) -> &Account {
299 self.account
300 }
301
302 #[inline]
304 fn balance(&self) -> &U256 {
305 &self.account.info.balance
306 }
307
308 #[inline]
310 fn nonce(&self) -> u64 {
311 self.account.info.nonce
312 }
313
314 #[inline]
316 fn code_hash(&self) -> &B256 {
317 &self.account.info.code_hash
318 }
319
320 #[inline]
322 fn code(&self) -> Option<&Bytecode> {
323 self.account.info.code.as_ref()
324 }
325
326 #[inline]
328 fn touch(&mut self) {
329 if !self.account.status.is_touched() {
330 self.account.mark_touch();
331 self.journal_entries
332 .push(ENTRY::account_touched(self.address));
333 }
334 }
335
336 #[inline]
343 fn unsafe_mark_cold(&mut self) {
344 self.account.mark_cold();
345 }
346
347 #[inline]
353 fn set_balance(&mut self, balance: U256) {
354 self.touch();
355 if self.account.info.balance != balance {
356 self.journal_entries.push(ENTRY::balance_changed(
357 self.address,
358 self.account.info.balance,
359 ));
360 self.account.info.set_balance(balance);
361 }
362 }
363
364 #[inline]
368 fn incr_balance(&mut self, balance: U256) -> bool {
369 self.touch();
370 let Some(balance) = self.account.info.balance.checked_add(balance) else {
371 return false;
372 };
373 self.set_balance(balance);
374 true
375 }
376
377 #[inline]
381 fn decr_balance(&mut self, balance: U256) -> bool {
382 self.touch();
383 let Some(balance) = self.account.info.balance.checked_sub(balance) else {
384 return false;
385 };
386 self.set_balance(balance);
387 true
388 }
389
390 #[inline]
396 fn bump_nonce(&mut self) -> bool {
397 self.touch();
398 let Some(nonce) = self.account.info.nonce.checked_add(1) else {
399 return false;
400 };
401 self.account.info.set_nonce(nonce);
402 self.journal_entries.push(ENTRY::nonce_bumped(self.address));
403 true
404 }
405
406 #[inline]
410 fn set_nonce(&mut self, nonce: u64) {
411 self.touch();
412 let previous_nonce = self.account.info.nonce;
413 self.account.info.set_nonce(nonce);
414 self.journal_entries
415 .push(ENTRY::nonce_changed(self.address, previous_nonce));
416 }
417
418 #[inline]
423 fn unsafe_set_nonce(&mut self, nonce: u64) {
424 self.account.info.set_nonce(nonce);
425 }
426
427 #[inline]
431 fn set_code(&mut self, code_hash: B256, code: Bytecode) {
432 self.touch();
433 self.account.info.set_code_and_hash(code, code_hash);
434 self.journal_entries.push(ENTRY::code_changed(self.address));
435 }
436
437 #[inline]
441 fn set_code_and_hash_slow(&mut self, code: Bytecode) {
442 let code_hash = code.hash_slow();
443 self.set_code(code_hash, code);
444 }
445
446 #[inline]
451 fn delegate(&mut self, address: Address) {
452 let (bytecode, hash) = if address.is_zero() {
453 (Bytecode::default(), KECCAK_EMPTY)
454 } else {
455 let bytecode = Bytecode::new_eip7702(address);
456 let hash = bytecode.hash_slow();
457 (bytecode, hash)
458 };
459 self.touch();
460 self.set_code(hash, bytecode);
461 self.bump_nonce();
462 }
463
464 #[inline]
466 fn sload(
467 &mut self,
468 key: StorageKey,
469 skip_cold_load: bool,
470 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError> {
471 self.sload_concrete_error(key, skip_cold_load)
472 .map_err(|i| i.map(ErasedError::new))
473 }
474
475 #[inline]
477 fn sstore(
478 &mut self,
479 key: StorageKey,
480 new: StorageValue,
481 skip_cold_load: bool,
482 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError> {
483 self.sstore_concrete_error(key, new, skip_cold_load)
484 .map_err(|i| i.map(ErasedError::new))
485 }
486
487 #[inline]
489 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError> {
490 self.load_code_preserve_error()
491 .map_err(|i| i.map(ErasedError::new))
492 }
493}