@@ -15,89 +15,28 @@ impl Default for InMemoryDB {
15
15
}
16
16
}
17
17
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.
19
23
#[ derive( Debug , Clone ) ]
20
24
pub struct CacheDB < ExtDB : DatabaseRef > {
21
25
/// Account info where None means it is not existing. Not existing state is needed for Pre TANGERINE forks.
22
26
/// `code` is always `None`, and bytecode can be found in `contracts`.
23
27
pub accounts : HashMap < B160 , DbAccount > ,
28
+ /// Tracks all contracts by their code hash.
24
29
pub contracts : HashMap < B256 , Bytecode > ,
30
+ /// All logs that were committed via [DatabaseCommit::commit].
25
31
pub logs : Vec < Log > ,
32
+ /// All cached block hashes from the [DatabaseRef].
26
33
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.
27
37
pub db : ExtDB ,
28
38
}
29
39
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
-
101
40
impl < ExtDB : DatabaseRef > CacheDB < ExtDB > {
102
41
pub fn new ( db : ExtDB ) -> Self {
103
42
let mut contracts = HashMap :: new ( ) ;
@@ -112,6 +51,11 @@ impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
112
51
}
113
52
}
114
53
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.
115
59
pub fn insert_contract ( & mut self , account : & mut AccountInfo ) {
116
60
if let Some ( code) = & account. code {
117
61
if !code. is_empty ( ) {
@@ -132,6 +76,9 @@ impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
132
76
self . accounts . entry ( address) . or_default ( ) . info = info;
133
77
}
134
78
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.
135
82
pub fn load_account ( & mut self , address : B160 ) -> Result < & mut DbAccount , ExtDB :: Error > {
136
83
let db = & self . db ;
137
84
match self . accounts . entry ( address) {
@@ -210,17 +157,6 @@ impl<ExtDB: DatabaseRef> DatabaseCommit for CacheDB<ExtDB> {
210
157
impl < ExtDB : DatabaseRef > Database for CacheDB < ExtDB > {
211
158
type Error = ExtDB :: Error ;
212
159
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
-
224
160
fn basic ( & mut self , address : B160 ) -> Result < Option < AccountInfo > , Self :: Error > {
225
161
let basic = match self . accounts . entry ( address) {
226
162
Entry :: Occupied ( entry) => entry. into_mut ( ) ,
@@ -237,6 +173,16 @@ impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
237
173
Ok ( basic. info ( ) )
238
174
}
239
175
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
+
240
186
/// Get the value in an account's storage slot.
241
187
///
242
188
/// It is assumed that account is already loaded.
@@ -277,12 +223,13 @@ impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
277
223
}
278
224
}
279
225
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 ( ) ) ,
283
229
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)
286
233
}
287
234
}
288
235
}
@@ -298,6 +245,13 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
298
245
}
299
246
}
300
247
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
+
301
255
fn storage ( & self , address : B160 , index : U256 ) -> Result < U256 , Self :: Error > {
302
256
match self . accounts . get ( & address) {
303
257
Some ( acc_entry) => match acc_entry. storage . get ( & index) {
@@ -317,13 +271,6 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
317
271
}
318
272
}
319
273
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
-
327
274
fn block_hash ( & self , number : U256 ) -> Result < B256 , Self :: Error > {
328
275
match self . block_hashes . get ( & number) {
329
276
Some ( entry) => Ok ( * entry) ,
@@ -332,6 +279,77 @@ impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
332
279
}
333
280
}
334
281
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
+
335
353
/// An empty database that always returns default values when queried.
336
354
#[ derive( Debug , Default , Clone ) ]
337
355
pub struct EmptyDB ( ) ;
0 commit comments