revm_database/states/
cache.rs1use super::{
2 plain_account::PlainStorage, transition_account::TransitionAccount, CacheAccount, PlainAccount,
3};
4use bytecode::Bytecode;
5use primitives::{Address, HashMap, B256};
6use state::{Account, AccountInfo, EvmState};
7use std::vec::Vec;
8
9#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct CacheState {
19 pub accounts: HashMap<Address, CacheAccount>,
21 pub contracts: HashMap<B256, Bytecode>,
23 pub has_state_clear: bool,
25}
26
27impl Default for CacheState {
28 fn default() -> Self {
29 Self::new(true)
30 }
31}
32
33impl CacheState {
34 pub fn new(has_state_clear: bool) -> Self {
36 Self {
37 accounts: HashMap::default(),
38 contracts: HashMap::default(),
39 has_state_clear,
40 }
41 }
42
43 pub fn set_state_clear_flag(&mut self, has_state_clear: bool) {
45 self.has_state_clear = has_state_clear;
46 }
47
48 pub fn trie_account(&self) -> impl IntoIterator<Item = (Address, &PlainAccount)> {
52 self.accounts.iter().filter_map(|(address, account)| {
53 account
54 .account
55 .as_ref()
56 .map(|plain_acc| (*address, plain_acc))
57 })
58 }
59
60 pub fn insert_not_existing(&mut self, address: Address) {
62 self.accounts
63 .insert(address, CacheAccount::new_loaded_not_existing());
64 }
65
66 pub fn insert_account(&mut self, address: Address, info: AccountInfo) {
68 let account = if !info.is_empty() {
69 CacheAccount::new_loaded(info, HashMap::default())
70 } else {
71 CacheAccount::new_loaded_empty_eip161(HashMap::default())
72 };
73 self.accounts.insert(address, account);
74 }
75
76 pub fn insert_account_with_storage(
78 &mut self,
79 address: Address,
80 info: AccountInfo,
81 storage: PlainStorage,
82 ) {
83 let account = if !info.is_empty() {
84 CacheAccount::new_loaded(info, storage)
85 } else {
86 CacheAccount::new_loaded_empty_eip161(storage)
87 };
88 self.accounts.insert(address, account);
89 }
90
91 pub fn apply_evm_state(&mut self, evm_state: EvmState) -> Vec<(Address, TransitionAccount)> {
93 let mut transitions = Vec::with_capacity(evm_state.len());
94 for (address, account) in evm_state {
95 if let Some(transition) = self.apply_account_state(address, account) {
96 transitions.push((address, transition));
97 }
98 }
99 transitions
100 }
101
102 #[cfg(feature = "std")]
104 pub fn pretty_print(&self) -> String {
105 let mut output = String::new();
106 output.push_str("CacheState:\n");
107 output.push_str(&format!(
108 " (state_clear_enabled: {}, ",
109 self.has_state_clear
110 ));
111 output.push_str(&format!("accounts: {} total)\n", self.accounts.len()));
112
113 let mut accounts: Vec<_> = self.accounts.iter().collect();
115 accounts.sort_by_key(|(addr, _)| *addr);
116
117 let mut contracts = self.contracts.clone();
118
119 for (address, account) in accounts {
120 output.push_str(&format!(" [{address}]:\n"));
121 output.push_str(&format!(" status: {:?}\n", account.status));
122
123 if let Some(plain_account) = &account.account {
124 let code_hash = plain_account.info.code_hash;
125 output.push_str(&format!(" balance: {}\n", plain_account.info.balance));
126 output.push_str(&format!(" nonce: {}\n", plain_account.info.nonce));
127 output.push_str(&format!(" code_hash: {code_hash}\n"));
128
129 if let Some(code) = &plain_account.info.code {
130 if !code.is_empty() {
131 contracts.insert(code_hash, code.clone());
132 }
133 }
134
135 if !plain_account.storage.is_empty() {
136 output.push_str(&format!(
137 " storage: {} slots\n",
138 plain_account.storage.len()
139 ));
140 let mut storage: Vec<_> = plain_account.storage.iter().collect();
142 storage.sort_by_key(|(key, _)| *key);
143
144 for (key, value) in storage.iter() {
145 output.push_str(&format!(" [{key:#x}]: {value:#x}\n"));
146 }
147 }
148 } else {
149 output.push_str(" account: None (destroyed or non-existent)\n");
150 }
151 }
152
153 if !contracts.is_empty() {
154 output.push_str(&format!(" contracts: {} total\n", contracts.len()));
155 for (hash, bytecode) in contracts.iter() {
156 let len = bytecode.len();
157 output.push_str(&format!(" [{hash}]: {len} bytes\n"));
158 }
159 }
160
161 output.push_str("}\n");
162 output
163 }
164
165 fn apply_account_state(
169 &mut self,
170 address: Address,
171 account: Account,
172 ) -> Option<TransitionAccount> {
173 if !account.is_touched() {
175 return None;
176 }
177
178 let this_account = self
179 .accounts
180 .get_mut(&address)
181 .expect("All accounts should be present inside cache");
182
183 if account.is_selfdestructed() {
186 return this_account.selfdestruct();
187 }
188
189 let is_created = account.is_created();
190 let is_empty = account.is_empty();
191
192 let changed_storage = account
194 .storage
195 .into_iter()
196 .filter(|(_, slot)| slot.is_changed())
197 .map(|(key, slot)| (key, slot.into()))
198 .collect();
199
200 if is_created {
209 return Some(this_account.newly_created(account.info, changed_storage));
210 }
211
212 if is_empty {
217 if self.has_state_clear {
218 this_account.touch_empty_eip161()
220 } else {
221 this_account.touch_create_pre_eip161(changed_storage)
224 }
225 } else {
226 Some(this_account.change(account.info, changed_storage))
227 }
228 }
229}