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 mut is_cold = false;
177 if slot.is_cold_transaction_id(self.transaction_id) {
178 is_cold = self
180 .access_list
181 .get(&self.address)
182 .and_then(|v| v.get(&key))
183 .is_none();
184
185 if is_cold && skip_cold_load {
186 return Err(JournalLoadError::ColdLoadSkipped);
187 }
188 }
189 slot.mark_warm_with_transaction_id(self.transaction_id);
190 (slot, is_cold)
191 }
192 Entry::Vacant(vac) => {
193 let is_cold = self
195 .access_list
196 .get(&self.address)
197 .and_then(|v| v.get(&key))
198 .is_none();
199
200 if is_cold && skip_cold_load {
201 return Err(JournalLoadError::ColdLoadSkipped);
202 }
203 let value = if is_newly_created {
205 StorageValue::ZERO
206 } else {
207 self.db.storage(self.address, key)?
208 };
209
210 let slot = vac.insert(EvmStorageSlot::new(value, self.transaction_id));
211 (slot, is_cold)
212 }
213 };
214
215 if is_cold {
216 self.journal_entries
218 .push(ENTRY::storage_warmed(self.address, key));
219 }
220
221 Ok(StateLoad::new(slot, is_cold))
222 }
223
224 #[inline]
230 pub fn sstore_concrete_error(
231 &mut self,
232 key: StorageKey,
233 new: StorageValue,
234 skip_cold_load: bool,
235 ) -> Result<StateLoad<SStoreResult>, JournalLoadError<DB::Error>> {
236 self.touch();
238
239 let slot = self.sload_concrete_error(key, skip_cold_load)?;
241
242 let ret = Ok(StateLoad::new(
243 SStoreResult {
244 original_value: slot.original_value(),
245 present_value: slot.present_value(),
246 new_value: new,
247 },
248 slot.is_cold,
249 ));
250
251 if slot.present_value != new {
253 let previous_value = slot.present_value;
254 slot.data.present_value = new;
256
257 self.journal_entries
259 .push(ENTRY::storage_changed(self.address, key, previous_value));
260 }
261
262 ret
263 }
264
265 #[inline]
269 pub fn load_code_preserve_error(&mut self) -> Result<&Bytecode, JournalLoadError<DB::Error>> {
270 if self.account.info.code.is_none() {
271 let hash = *self.code_hash();
272 let code = if hash == KECCAK_EMPTY {
273 Bytecode::default()
274 } else {
275 self.db.code_by_hash(hash)?
276 };
277 self.account.info.code = Some(code);
278 }
279
280 Ok(self.account.info.code.as_ref().unwrap())
281 }
282
283 #[inline]
285 pub fn into_account(self) -> &'a Account {
286 self.account
287 }
288}
289
290impl<'a, DB: Database, ENTRY: JournalEntryTr> JournaledAccountTr
291 for JournaledAccount<'a, DB, ENTRY>
292{
293 fn account(&self) -> &Account {
295 self.account
296 }
297
298 #[inline]
300 fn balance(&self) -> &U256 {
301 &self.account.info.balance
302 }
303
304 #[inline]
306 fn nonce(&self) -> u64 {
307 self.account.info.nonce
308 }
309
310 #[inline]
312 fn code_hash(&self) -> &B256 {
313 &self.account.info.code_hash
314 }
315
316 #[inline]
318 fn code(&self) -> Option<&Bytecode> {
319 self.account.info.code.as_ref()
320 }
321
322 #[inline]
324 fn touch(&mut self) {
325 if !self.account.status.is_touched() {
326 self.account.mark_touch();
327 self.journal_entries
328 .push(ENTRY::account_touched(self.address));
329 }
330 }
331
332 #[inline]
339 fn unsafe_mark_cold(&mut self) {
340 self.account.mark_cold();
341 }
342
343 #[inline]
349 fn set_balance(&mut self, balance: U256) {
350 self.touch();
351 if self.account.info.balance != balance {
352 self.journal_entries.push(ENTRY::balance_changed(
353 self.address,
354 self.account.info.balance,
355 ));
356 self.account.info.set_balance(balance);
357 }
358 }
359
360 #[inline]
364 fn incr_balance(&mut self, balance: U256) -> bool {
365 self.touch();
366 let Some(balance) = self.account.info.balance.checked_add(balance) else {
367 return false;
368 };
369 self.set_balance(balance);
370 true
371 }
372
373 #[inline]
377 fn decr_balance(&mut self, balance: U256) -> bool {
378 self.touch();
379 let Some(balance) = self.account.info.balance.checked_sub(balance) else {
380 return false;
381 };
382 self.set_balance(balance);
383 true
384 }
385
386 #[inline]
392 fn bump_nonce(&mut self) -> bool {
393 self.touch();
394 let Some(nonce) = self.account.info.nonce.checked_add(1) else {
395 return false;
396 };
397 self.account.info.set_nonce(nonce);
398 self.journal_entries.push(ENTRY::nonce_bumped(self.address));
399 true
400 }
401
402 #[inline]
406 fn set_nonce(&mut self, nonce: u64) {
407 self.touch();
408 let previous_nonce = self.account.info.nonce;
409 self.account.info.set_nonce(nonce);
410 self.journal_entries
411 .push(ENTRY::nonce_changed(self.address, previous_nonce));
412 }
413
414 #[inline]
419 fn unsafe_set_nonce(&mut self, nonce: u64) {
420 self.account.info.set_nonce(nonce);
421 }
422
423 #[inline]
427 fn set_code(&mut self, code_hash: B256, code: Bytecode) {
428 self.touch();
429 self.account.info.set_code_hash(code_hash);
430 self.account.info.set_code(code);
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}