Skip to content

Commit c3b0312

Browse files
authored
docs: add some CacheDB docs (#484)
1 parent c81acc6 commit c3b0312

File tree

1 file changed

+113
-95
lines changed

1 file changed

+113
-95
lines changed

crates/revm/src/db/in_memory_db.rs

+113-95
Original file line numberDiff line numberDiff line change
@@ -15,89 +15,28 @@ impl Default for InMemoryDB {
1515
}
1616
}
1717

18-
/// Memory backend, storing all state values in a `Map` in memory.
18+
/// A [Database] implementation that stores all state changes in memory.
19+
///
20+
/// This implementation wraps a [DatabaseRef] that is used to load data ([AccountInfo]).
21+
///
22+
/// Accounts and code are stored in two separate maps, the `accounts` map maps addresses to [DbAccount], whereas contracts are identified by their code hash, and are stored in the `contracts` map. The [DbAccount] holds the code hash of the contract, which is used to look up the contract in the `contracts` map.
1923
#[derive(Debug, Clone)]
2024
pub struct CacheDB<ExtDB: DatabaseRef> {
2125
/// Account info where None means it is not existing. Not existing state is needed for Pre TANGERINE forks.
2226
/// `code` is always `None`, and bytecode can be found in `contracts`.
2327
pub accounts: HashMap<B160, DbAccount>,
28+
/// Tracks all contracts by their code hash.
2429
pub contracts: HashMap<B256, Bytecode>,
30+
/// All logs that were committed via [DatabaseCommit::commit].
2531
pub logs: Vec<Log>,
32+
/// All cached block hashes from the [DatabaseRef].
2633
pub block_hashes: HashMap<U256, B256>,
34+
/// The underlying database ([DatabaseRef]) that is used to load data.
35+
///
36+
/// Note: this is read-only, data is never written to this database.
2737
pub db: ExtDB,
2838
}
2939

30-
#[derive(Debug, Clone, Default)]
31-
pub struct DbAccount {
32-
pub info: AccountInfo,
33-
/// If account is selfdestructed or newly created, storage will be cleared.
34-
pub account_state: AccountState,
35-
/// storage slots
36-
pub storage: HashMap<U256, U256>,
37-
}
38-
39-
impl DbAccount {
40-
pub fn new_not_existing() -> Self {
41-
Self {
42-
account_state: AccountState::NotExisting,
43-
..Default::default()
44-
}
45-
}
46-
pub fn info(&self) -> Option<AccountInfo> {
47-
if matches!(self.account_state, AccountState::NotExisting) {
48-
None
49-
} else {
50-
Some(self.info.clone())
51-
}
52-
}
53-
}
54-
55-
impl From<Option<AccountInfo>> for DbAccount {
56-
fn from(from: Option<AccountInfo>) -> Self {
57-
if let Some(info) = from {
58-
Self {
59-
info,
60-
account_state: AccountState::None,
61-
..Default::default()
62-
}
63-
} else {
64-
Self::new_not_existing()
65-
}
66-
}
67-
}
68-
69-
impl From<AccountInfo> for DbAccount {
70-
fn from(info: AccountInfo) -> Self {
71-
Self {
72-
info,
73-
account_state: AccountState::None,
74-
..Default::default()
75-
}
76-
}
77-
}
78-
79-
#[derive(Debug, Clone, Default, Eq, PartialEq)]
80-
pub enum AccountState {
81-
/// Before Spurious Dragon hardfork there was a difference between empty and not existing.
82-
/// And we are flaging it here.
83-
NotExisting,
84-
/// EVM touched this account. For newer hardfork this means it can be clearead/removed from state.
85-
Touched,
86-
/// EVM cleared storage of this account, mostly by selfdestruct, we don't ask database for storage slots
87-
/// and assume they are U256::ZERO
88-
StorageCleared,
89-
/// EVM didn't interacted with this account
90-
#[default]
91-
None,
92-
}
93-
94-
impl AccountState {
95-
/// Returns `true` if EVM cleared storage of this account
96-
pub fn is_storage_cleared(&self) -> bool {
97-
matches!(self, AccountState::StorageCleared)
98-
}
99-
}
100-
10140
impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
10241
pub fn new(db: ExtDB) -> Self {
10342
let mut contracts = HashMap::new();
@@ -112,6 +51,11 @@ impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
11251
}
11352
}
11453

54+
/// Inserts the account's code into the cache.
55+
///
56+
/// Accounts objects and code are stored separately in the cache, this will take the code from the account and instead map it to the code hash.
57+
///
58+
/// Note: This will not insert into the underlying external database.
11559
pub fn insert_contract(&mut self, account: &mut AccountInfo) {
11660
if let Some(code) = &account.code {
11761
if !code.is_empty() {
@@ -132,6 +76,9 @@ impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
13276
self.accounts.entry(address).or_default().info = info;
13377
}
13478

79+
/// Returns the account for the given address.
80+
///
81+
/// If the account was not found in the cache, it will be loaded from the underlying database.
13582
pub fn load_account(&mut self, address: B160) -> Result<&mut DbAccount, ExtDB::Error> {
13683
let db = &self.db;
13784
match self.accounts.entry(address) {
@@ -210,17 +157,6 @@ impl<ExtDB: DatabaseRef> DatabaseCommit for CacheDB<ExtDB> {
210157
impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
211158
type Error = ExtDB::Error;
212159

213-
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
214-
match self.block_hashes.entry(number) {
215-
Entry::Occupied(entry) => Ok(*entry.get()),
216-
Entry::Vacant(entry) => {
217-
let hash = self.db.block_hash(number)?;
218-
entry.insert(hash);
219-
Ok(hash)
220-
}
221-
}
222-
}
223-
224160
fn basic(&mut self, address: B160) -> Result<Option<AccountInfo>, Self::Error> {
225161
let basic = match self.accounts.entry(address) {
226162
Entry::Occupied(entry) => entry.into_mut(),
@@ -237,6 +173,16 @@ impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
237173
Ok(basic.info())
238174
}
239175

176+
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
177+
match self.contracts.entry(code_hash) {
178+
Entry::Occupied(entry) => Ok(entry.get().clone()),
179+
Entry::Vacant(entry) => {
180+
// if you return code bytes when basic fn is called this function is not needed.
181+
Ok(entry.insert(self.db.code_by_hash(code_hash)?).clone())
182+
}
183+
}
184+
}
185+
240186
/// Get the value in an account's storage slot.
241187
///
242188
/// It is assumed that account is already loaded.
@@ -277,12 +223,13 @@ impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
277223
}
278224
}
279225

280-
fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
281-
match self.contracts.entry(code_hash) {
282-
Entry::Occupied(entry) => Ok(entry.get().clone()),
226+
fn block_hash(&mut self, number: U256) -> Result<B256, Self::Error> {
227+
match self.block_hashes.entry(number) {
228+
Entry::Occupied(entry) => Ok(*entry.get()),
283229
Entry::Vacant(entry) => {
284-
// if you return code bytes when basic fn is called this function is not needed.
285-
Ok(entry.insert(self.db.code_by_hash(code_hash)?).clone())
230+
let hash = self.db.block_hash(number)?;
231+
entry.insert(hash);
232+
Ok(hash)
286233
}
287234
}
288235
}
@@ -298,6 +245,13 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
298245
}
299246
}
300247

248+
fn code_by_hash(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
249+
match self.contracts.get(&code_hash) {
250+
Some(entry) => Ok(entry.clone()),
251+
None => self.db.code_by_hash(code_hash),
252+
}
253+
}
254+
301255
fn storage(&self, address: B160, index: U256) -> Result<U256, Self::Error> {
302256
match self.accounts.get(&address) {
303257
Some(acc_entry) => match acc_entry.storage.get(&index) {
@@ -317,13 +271,6 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
317271
}
318272
}
319273

320-
fn code_by_hash(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
321-
match self.contracts.get(&code_hash) {
322-
Some(entry) => Ok(entry.clone()),
323-
None => self.db.code_by_hash(code_hash),
324-
}
325-
}
326-
327274
fn block_hash(&self, number: U256) -> Result<B256, Self::Error> {
328275
match self.block_hashes.get(&number) {
329276
Some(entry) => Ok(*entry),
@@ -332,6 +279,77 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
332279
}
333280
}
334281

282+
#[derive(Debug, Clone, Default)]
283+
pub struct DbAccount {
284+
pub info: AccountInfo,
285+
/// If account is selfdestructed or newly created, storage will be cleared.
286+
pub account_state: AccountState,
287+
/// storage slots
288+
pub storage: HashMap<U256, U256>,
289+
}
290+
291+
impl DbAccount {
292+
pub fn new_not_existing() -> Self {
293+
Self {
294+
account_state: AccountState::NotExisting,
295+
..Default::default()
296+
}
297+
}
298+
pub fn info(&self) -> Option<AccountInfo> {
299+
if matches!(self.account_state, AccountState::NotExisting) {
300+
None
301+
} else {
302+
Some(self.info.clone())
303+
}
304+
}
305+
}
306+
307+
impl From<Option<AccountInfo>> for DbAccount {
308+
fn from(from: Option<AccountInfo>) -> Self {
309+
if let Some(info) = from {
310+
Self {
311+
info,
312+
account_state: AccountState::None,
313+
..Default::default()
314+
}
315+
} else {
316+
Self::new_not_existing()
317+
}
318+
}
319+
}
320+
321+
impl From<AccountInfo> for DbAccount {
322+
fn from(info: AccountInfo) -> Self {
323+
Self {
324+
info,
325+
account_state: AccountState::None,
326+
..Default::default()
327+
}
328+
}
329+
}
330+
331+
#[derive(Debug, Clone, Default, Eq, PartialEq)]
332+
pub enum AccountState {
333+
/// Before Spurious Dragon hardfork there was a difference between empty and not existing.
334+
/// And we are flaging it here.
335+
NotExisting,
336+
/// EVM touched this account. For newer hardfork this means it can be clearead/removed from state.
337+
Touched,
338+
/// EVM cleared storage of this account, mostly by selfdestruct, we don't ask database for storage slots
339+
/// and assume they are U256::ZERO
340+
StorageCleared,
341+
/// EVM didn't interacted with this account
342+
#[default]
343+
None,
344+
}
345+
346+
impl AccountState {
347+
/// Returns `true` if EVM cleared storage of this account
348+
pub fn is_storage_cleared(&self) -> bool {
349+
matches!(self, AccountState::StorageCleared)
350+
}
351+
}
352+
335353
/// An empty database that always returns default values when queried.
336354
#[derive(Debug, Default, Clone)]
337355
pub struct EmptyDB();

0 commit comments

Comments
 (0)