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, HashMap, HashSet, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256,
17};
18use state::{Account, Bytecode, EvmStorageSlot};
19use std::vec::Vec;
20
21#[auto_impl(&mut, Box)]
23pub trait JournaledAccountTr {
24 fn account(&self) -> &Account;
26
27 fn sload(
29 &mut self,
30 key: StorageKey,
31 skip_cold_load: bool,
32 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError>;
33
34 fn sstore(
36 &mut self,
37 key: StorageKey,
38 new: StorageValue,
39 skip_cold_load: bool,
40 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError>;
41
42 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError>;
44
45 fn balance(&self) -> &U256;
47
48 fn nonce(&self) -> u64;
50
51 fn code_hash(&self) -> &B256;
53
54 fn code(&self) -> Option<&Bytecode>;
56
57 fn touch(&mut self);
59
60 fn unsafe_mark_cold(&mut self);
67
68 fn set_balance(&mut self, balance: U256);
74
75 fn incr_balance(&mut self, balance: U256) -> bool;
79
80 fn decr_balance(&mut self, balance: U256) -> bool;
84
85 fn bump_nonce(&mut self) -> bool;
91
92 fn set_nonce(&mut self, nonce: u64);
96
97 fn unsafe_set_nonce(&mut self, nonce: u64);
102
103 fn set_code(&mut self, code_hash: B256, code: Bytecode);
107
108 fn set_code_and_hash_slow(&mut self, code: Bytecode);
112
113 fn delegate(&mut self, address: Address);
118}
119
120#[derive(Debug, PartialEq, Eq)]
124pub struct JournaledAccount<'a, DB, ENTRY: JournalEntryTr = JournalEntry> {
125 address: Address,
127 account: &'a mut Account,
129 journal_entries: &'a mut Vec<ENTRY>,
131 access_list: &'a HashMap<Address, HashSet<StorageKey>>,
133 transaction_id: usize,
135 db: &'a mut DB,
137}
138
139impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccount<'a, DB, ENTRY> {
140 #[inline]
142 pub fn new(
143 address: Address,
144 account: &'a mut Account,
145 journal_entries: &'a mut Vec<ENTRY>,
146 db: &'a mut DB,
147 access_list: &'a HashMap<Address, HashSet<StorageKey>>,
148 transaction_id: usize,
149 ) -> Self {
150 Self {
151 address,
152 account,
153 journal_entries,
154 access_list,
155 transaction_id,
156 db,
157 }
158 }
159
160 #[inline(never)]
166 pub fn sload_concrete_error(
167 &mut self,
168 key: StorageKey,
169 skip_cold_load: bool,
170 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadError<DB::Error>> {
171 let is_newly_created = self.account.is_created();
172 let (slot, is_cold) = match self.account.storage.entry(key) {
173 Entry::Occupied(occ) => {
174 let slot = occ.into_mut();
175 let is_cold = slot.is_cold_transaction_id(self.transaction_id);
177 if is_cold && skip_cold_load {
178 return Err(JournalLoadError::ColdLoadSkipped);
179 }
180 slot.mark_warm_with_transaction_id(self.transaction_id);
181 (slot, is_cold)
182 }
183 Entry::Vacant(vac) => {
184 let is_cold = self
186 .access_list
187 .get(&self.address)
188 .and_then(|v| v.get(&key))
189 .is_none();
190
191 if is_cold && skip_cold_load {
192 return Err(JournalLoadError::ColdLoadSkipped);
193 }
194 let value = if is_newly_created {
196 StorageValue::ZERO
197 } else {
198 self.db.storage(self.address, key)?
199 };
200
201 let slot = vac.insert(EvmStorageSlot::new(value, self.transaction_id));
202 (slot, is_cold)
203 }
204 };
205
206 if is_cold {
207 self.journal_entries
209 .push(ENTRY::storage_warmed(self.address, key));
210 }
211
212 Ok(StateLoad::new(slot, is_cold))
213 }
214
215 #[inline]
221 pub fn sstore_concrete_error(
222 &mut self,
223 key: StorageKey,
224 new: StorageValue,
225 skip_cold_load: bool,
226 ) -> Result<StateLoad<SStoreResult>, JournalLoadError<DB::Error>> {
227 self.touch();
229
230 let slot = self.sload_concrete_error(key, skip_cold_load)?;
232
233 let ret = Ok(StateLoad::new(
234 SStoreResult {
235 original_value: slot.original_value(),
236 present_value: slot.present_value(),
237 new_value: new,
238 },
239 slot.is_cold,
240 ));
241
242 if slot.present_value != new {
244 let previous_value = slot.present_value;
245 slot.data.present_value = new;
247
248 self.journal_entries
250 .push(ENTRY::storage_changed(self.address, key, previous_value));
251 }
252
253 ret
254 }
255
256 #[inline]
260 pub fn load_code_preserve_error(&mut self) -> Result<&Bytecode, JournalLoadError<DB::Error>> {
261 if self.account.info.code.is_none() {
262 let hash = *self.code_hash();
263 let code = if hash == KECCAK_EMPTY {
264 Bytecode::default()
265 } else {
266 self.db.code_by_hash(hash)?
267 };
268 self.account.info.code = Some(code);
269 }
270
271 Ok(self.account.info.code.as_ref().unwrap())
272 }
273
274 #[inline]
276 pub fn into_account(self) -> &'a Account {
277 self.account
278 }
279}
280
281impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccountTr
282 for JournaledAccount<'a, DB, ENTRY>
283{
284 fn account(&self) -> &Account {
286 self.account
287 }
288
289 #[inline]
291 fn balance(&self) -> &U256 {
292 &self.account.info.balance
293 }
294
295 #[inline]
297 fn nonce(&self) -> u64 {
298 self.account.info.nonce
299 }
300
301 #[inline]
303 fn code_hash(&self) -> &B256 {
304 &self.account.info.code_hash
305 }
306
307 #[inline]
309 fn code(&self) -> Option<&Bytecode> {
310 self.account.info.code.as_ref()
311 }
312
313 #[inline]
315 fn touch(&mut self) {
316 if !self.account.status.is_touched() {
317 self.account.mark_touch();
318 self.journal_entries
319 .push(ENTRY::account_touched(self.address));
320 }
321 }
322
323 #[inline]
330 fn unsafe_mark_cold(&mut self) {
331 self.account.mark_cold();
332 }
333
334 #[inline]
340 fn set_balance(&mut self, balance: U256) {
341 self.touch();
342 if self.account.info.balance != balance {
343 self.journal_entries.push(ENTRY::balance_changed(
344 self.address,
345 self.account.info.balance,
346 ));
347 self.account.info.set_balance(balance);
348 }
349 }
350
351 #[inline]
355 fn incr_balance(&mut self, balance: U256) -> bool {
356 self.touch();
357 let Some(balance) = self.account.info.balance.checked_add(balance) else {
358 return false;
359 };
360 self.set_balance(balance);
361 true
362 }
363
364 #[inline]
368 fn decr_balance(&mut self, balance: U256) -> bool {
369 self.touch();
370 let Some(balance) = self.account.info.balance.checked_sub(balance) else {
371 return false;
372 };
373 self.set_balance(balance);
374 true
375 }
376
377 #[inline]
383 fn bump_nonce(&mut self) -> bool {
384 self.touch();
385 let Some(nonce) = self.account.info.nonce.checked_add(1) else {
386 return false;
387 };
388 self.account.info.set_nonce(nonce);
389 self.journal_entries.push(ENTRY::nonce_bumped(self.address));
390 true
391 }
392
393 #[inline]
397 fn set_nonce(&mut self, nonce: u64) {
398 self.touch();
399 let previous_nonce = self.account.info.nonce;
400 self.account.info.set_nonce(nonce);
401 self.journal_entries
402 .push(ENTRY::nonce_changed(self.address, previous_nonce));
403 }
404
405 #[inline]
410 fn unsafe_set_nonce(&mut self, nonce: u64) {
411 self.account.info.set_nonce(nonce);
412 }
413
414 #[inline]
418 fn set_code(&mut self, code_hash: B256, code: Bytecode) {
419 self.touch();
420 self.account.info.set_code_hash(code_hash);
421 self.account.info.set_code(code);
422 self.journal_entries.push(ENTRY::code_changed(self.address));
423 }
424
425 #[inline]
429 fn set_code_and_hash_slow(&mut self, code: Bytecode) {
430 let code_hash = code.hash_slow();
431 self.set_code(code_hash, code);
432 }
433
434 #[inline]
439 fn delegate(&mut self, address: Address) {
440 let (bytecode, hash) = if address.is_zero() {
441 (Bytecode::default(), KECCAK_EMPTY)
442 } else {
443 let bytecode = Bytecode::new_eip7702(address);
444 let hash = bytecode.hash_slow();
445 (bytecode, hash)
446 };
447 self.touch();
448 self.set_code(hash, bytecode);
449 self.bump_nonce();
450 }
451
452 #[inline]
454 fn sload(
455 &mut self,
456 key: StorageKey,
457 skip_cold_load: bool,
458 ) -> Result<StateLoad<&mut EvmStorageSlot>, JournalLoadErasedError> {
459 self.sload_concrete_error(key, skip_cold_load)
460 .map_err(|i| i.map(ErasedError::new))
461 }
462
463 #[inline]
465 fn sstore(
466 &mut self,
467 key: StorageKey,
468 new: StorageValue,
469 skip_cold_load: bool,
470 ) -> Result<StateLoad<SStoreResult>, JournalLoadErasedError> {
471 self.sstore_concrete_error(key, new, skip_cold_load)
472 .map_err(|i| i.map(ErasedError::new))
473 }
474
475 #[inline]
477 fn load_code(&mut self) -> Result<&Bytecode, JournalLoadErasedError> {
478 self.load_code_preserve_error()
479 .map_err(|i| i.map(ErasedError::new))
480 }
481}