1use crate::DatabaseKabuExt;
2use crate::alloydb::AlloyDB;
3use crate::error::KabuDBError;
4use crate::fast_cache_db::FastDbAccount;
5use crate::fast_hasher::SimpleBuildHasher;
6use crate::kabu_db_helper::KabuDBHelper;
7use alloy::consensus::constants::KECCAK_EMPTY;
8use alloy::eips::BlockNumberOrTag;
9use alloy::primitives::map::HashMap;
10use alloy::primitives::{Address, B256, BlockNumber, Log, U256};
11use alloy::providers::{Network, Provider, ProviderBuilder};
12use alloy::rpc::client::ClientBuilder;
13use alloy::rpc::types::trace::geth::AccountState as GethAccountState;
14use alloy::transports::Transport;
15use eyre::{OptionExt, Result};
16use revm::database::AccountState as DBAccountState;
17use revm::database::EmptyDBTyped;
18use revm::state::{Account, AccountInfo, Bytecode};
19use revm::{Database, DatabaseCommit, DatabaseRef};
20use std::collections::BTreeMap;
21use std::collections::hash_map::Entry;
22use std::fmt::{Debug, Formatter};
23use std::sync::Arc;
24use tracing::{error, trace};
25
26#[derive(Clone)]
27pub struct KabuDB
28where
29 Self: Sized + Send + Sync,
30{
31 pub accounts: HashMap<Address, FastDbAccount>,
32 pub contracts: HashMap<B256, Bytecode, SimpleBuildHasher>,
33 pub logs: Vec<Log>,
34 pub block_hashes: HashMap<BlockNumber, B256>,
35 pub read_only_db: Option<Arc<KabuDB>>,
36 pub ext_db: Option<Arc<dyn DatabaseRef<Error = KabuDBError> + Send + Sync>>,
37}
38
39impl Debug for KabuDB {
40 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("KabuDB").field("accounts", &self.accounts).finish()
42 }
43}
44
45impl Default for KabuDB {
46 fn default() -> Self {
47 KabuDB::new().with_ext_db(EmptyDBTyped::<KabuDBError>::new())
48 }
49}
50
51#[allow(dead_code)]
52impl KabuDB {
53 pub fn empty() -> Self {
54 Self::default()
55 }
56 pub fn new() -> Self {
57 let mut contracts = HashMap::with_hasher(SimpleBuildHasher::default());
58 contracts.insert(KECCAK_EMPTY, Bytecode::default());
59 contracts.insert(B256::ZERO, Bytecode::default());
60
61 Self {
62 read_only_db: None,
63 ext_db: None,
64 accounts: Default::default(),
65 contracts,
66 logs: Default::default(),
67 block_hashes: Default::default(),
68 }
69 }
70
71 pub fn is_rw_ro_account(&self, address: &Address) -> bool {
72 self.accounts.contains_key(address) || if let Some(db) = &self.read_only_db { db.accounts.contains_key(address) } else { false }
73 }
74
75 pub fn is_rw_ro_slot(&self, address: &Address, slot: &U256) -> bool {
76 let is_rw_slot = if let Some(account) = self.accounts.get(address) { account.storage.contains_key(slot) } else { false };
77
78 if is_rw_slot {
79 true
80 } else if let Some(read_only_db) = &self.read_only_db {
81 if let Some(account) = read_only_db.accounts.get(address) { account.storage.contains_key(slot) } else { false }
82 } else {
83 false
84 }
85 }
86
87 pub fn read_only_db(&self) -> Self {
88 self.read_only_db.clone().map_or(KabuDB::empty(), |a| a.as_ref().clone())
89 }
90 pub fn rw_contracts_len(&self) -> usize {
91 self.contracts.len()
92 }
93 pub fn rw_accounts_len(&self) -> usize {
94 self.accounts.len()
95 }
96
97 pub fn ro_contracts_len(&self) -> usize {
98 self.read_only_db.as_ref().map_or(0, |db| db.contracts_len())
99 }
100
101 pub fn ro_accounts_len(&self) -> usize {
102 self.read_only_db.as_ref().map_or(0, |db| db.accounts_len())
103 }
104
105 pub fn rw_storage_len(&self) -> usize {
106 self.accounts.values().map(|a| a.storage.len()).sum()
107 }
108 pub fn ro_storage_len(&self) -> usize {
109 self.read_only_db.as_ref().map_or(0, |db| db.accounts.values().map(|a| a.storage.len()).sum())
110 }
111
112 pub fn with_ext_db<ExtDB>(self, ext_db: ExtDB) -> Self
113 where
114 ExtDB: DatabaseRef<Error = KabuDBError> + Send + Sync + 'static,
115 Self: Sized,
116 {
117 let ext_db = Arc::new(ext_db) as Arc<dyn DatabaseRef<Error = KabuDBError> + Send + Sync>;
118 Self { ext_db: Some(ext_db), ..self }
119 }
120
121 pub fn without_ext_db(self) -> Self
122 where
123 Self: Sized,
124 {
125 Self { ext_db: None, ..self }
126 }
127
128 pub fn with_ro_db(self, db: Option<KabuDB>) -> Self {
129 Self { read_only_db: db.map(Arc::new), ..self }
130 }
131
132 pub fn new_with_ext_db<ExtDB>(db: KabuDB, ext_db: ExtDB) -> Self
133 where
134 ExtDB: DatabaseRef<Error = KabuDBError> + Send + Sync + 'static,
135 Self: Sized,
136 {
137 Self::new().with_ro_db(Some(db)).with_ext_db(ext_db)
138 }
139
140 pub fn load_ro_rw_ext_account(&mut self, address: Address) -> Result<&mut FastDbAccount> {
144 match self.accounts.entry(address) {
145 Entry::Occupied(entry) => Ok(entry.into_mut()),
146 Entry::Vacant(entry) => Ok(entry.insert(
147 KabuDBHelper::get_or_fetch_basic(&self.read_only_db, &self.ext_db, address)
148 .unwrap_or_default()
149 .map(|info| FastDbAccount { info, ..Default::default() })
150 .unwrap_or_else(FastDbAccount::new_not_existing),
151 )),
152 }
153 }
154
155 pub fn load_ro_rw_account(&mut self, address: Address) -> Result<&mut FastDbAccount> {
159 match self.accounts.entry(address) {
160 Entry::Occupied(entry) => Ok(entry.into_mut()),
161 Entry::Vacant(entry) => Ok(entry.insert(
162 KabuDBHelper::get_basic(&self.read_only_db, address)
163 .unwrap_or_default()
164 .map(|info| FastDbAccount { info, ..Default::default() })
165 .unwrap_or_else(FastDbAccount::new_not_existing),
166 )),
167 }
168 }
169
170 pub fn new_with_ro_db_and_provider<P, N>(read_only_db: Option<KabuDB>, client: P) -> Result<Self>
171 where
172 N: Network,
173 P: Provider<N> + 'static,
174 Self: Sized,
175 {
176 let box_transport = client.client().transport().clone().boxed();
177
178 let rpc_client = ClientBuilder::default().transport(box_transport, true);
179
180 let provider = ProviderBuilder::new().disable_recommended_fillers().connect_client(rpc_client);
181
182 let ext_db = AlloyDB::new(provider, BlockNumberOrTag::Latest.into());
183
184 let ext_db = ext_db.ok_or_eyre("EXT_DB_NOT_CREATED")?;
185
186 Ok(Self::new().with_ro_db(read_only_db).with_ext_db(ext_db))
187 }
188
189 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
190 if let Some(code) = &account.code
191 && !code.is_empty()
192 {
193 if account.code_hash == KECCAK_EMPTY {
194 account.code_hash = code.hash_slow();
195 }
196 self.contracts.entry(account.code_hash).or_insert_with(|| code.clone());
197 }
198 if account.code_hash == B256::ZERO {
199 account.code_hash = KECCAK_EMPTY;
200 }
201 }
202
203 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
205 self.insert_contract(&mut info);
206 self.accounts.entry(address).or_default().info = info;
207 }
208
209 pub fn insert_account_storage(&mut self, address: Address, slot: U256, value: U256) -> Result<()> {
211 let account = self.load_account(address)?;
212 account.storage.insert(slot, value);
213 Ok(())
214 }
215
216 pub fn replace_account_storage(&mut self, address: Address, storage: HashMap<U256, U256>) -> Result<()> {
218 let account = self.load_account(address)?;
219 account.account_state = DBAccountState::StorageCleared;
220 account.storage = storage.into_iter().collect();
221 Ok(())
222 }
223
224 pub fn merge_all(self) -> KabuDB {
225 let mut read_only_db = self.read_only_db.unwrap_or_default().as_ref().clone();
226
227 for (k, v) in self.block_hashes.iter() {
228 read_only_db.block_hashes.insert(*k, *v);
229 }
230
231 for (k, v) in self.contracts.iter() {
232 read_only_db.contracts.insert(*k, v.clone());
233 }
234 read_only_db.logs.clone_from(&self.logs);
235
236 for (address, account) in self.accounts.iter() {
237 let mut info = account.info.clone();
238 read_only_db.insert_contract(&mut info);
239
240 let entry = read_only_db.accounts.entry(*address).or_default();
241 entry.info = info;
242 for (k, v) in account.storage.iter() {
243 entry.storage.insert(*k, *v);
244 }
245 }
246
247 let read_only_db = Some(Arc::new(read_only_db));
248
249 KabuDB { read_only_db, ext_db: self.ext_db, ..Default::default() }
250 }
251
252 pub fn merge_accounts(self) -> KabuDB {
253 let read_only_db = if let Some(read_only_db) = self.read_only_db {
254 let mut read_only_db_clone = (*read_only_db).clone();
255
256 for (k, v) in self.block_hashes.iter() {
257 read_only_db_clone.block_hashes.insert(*k, *v);
258 }
259 for (k, v) in self.contracts.iter() {
260 read_only_db_clone.contracts.entry(*k).and_modify(|k| k.clone_from(v));
261 }
262 read_only_db_clone.logs.clone_from(&self.logs);
263
264 for (address, account) in self.accounts.iter() {
265 read_only_db_clone.accounts.entry(*address).and_modify(|db_account| {
266 let info = account.info.clone();
267 db_account.info = info;
268 for (k, v) in account.storage.iter() {
269 db_account.storage.insert(*k, *v);
270 }
271 db_account.account_state = DBAccountState::Touched
272 });
273 }
274 Some(Arc::new(read_only_db_clone))
275 } else {
276 None
277 };
278
279 KabuDB { read_only_db, ext_db: self.ext_db, ..Default::default() }
280 }
281
282 pub fn merge_cells(self) -> KabuDB {
283 let read_only_db = if let Some(read_only_db) = self.read_only_db {
284 let mut read_only_db_clone = (*read_only_db).clone();
285
286 for (k, v) in self.block_hashes.iter() {
287 read_only_db_clone.block_hashes.insert(*k, *v);
288 }
289 for (k, v) in self.contracts.iter() {
290 read_only_db_clone.contracts.entry(*k).and_modify(|k| k.clone_from(v));
291 }
292 read_only_db_clone.logs.clone_from(&self.logs);
293
294 for (address, account) in self.accounts.iter() {
295 read_only_db_clone.accounts.entry(*address).and_modify(|db_account| {
296 let info = account.info.clone();
297 db_account.info = info;
298 for (k, v) in account.storage.iter() {
299 db_account.storage.entry(*k).and_modify(|cv| cv.clone_from(v));
300 }
301 db_account.account_state = DBAccountState::Touched
302 });
303 }
304 Some(Arc::new(read_only_db_clone))
305 } else {
306 None
307 };
308
309 KabuDB { read_only_db, ext_db: self.ext_db, ..Default::default() }
310 }
311
312 pub fn apply_geth_update(&mut self, update: BTreeMap<Address, GethAccountState>) {
313 for (addr, acc_state) in update {
314 trace!("apply_geth_update {} is code {} storage_len {} ", addr, acc_state.code.is_some(), acc_state.storage.len());
315
316 for (k, v) in acc_state.storage.iter() {
317 if let Err(e) = self.insert_account_storage(addr, (*k).into(), (*v).into()) {
318 error!("apply_geth_update :{}", e);
319 }
320 }
321 if let Ok(account) = self.load_account(addr) {
322 if let Some(code) = acc_state.code.clone() {
323 let bytecode = Bytecode::new_raw(code);
324 account.info.code_hash = bytecode.hash_slow();
325 account.info.code = Some(bytecode);
326 }
327 if let Some(nonce) = acc_state.nonce {
328 account.info.nonce = nonce;
330 }
331 if let Some(balance) = acc_state.balance {
332 account.info.balance = balance;
333 }
334 account.account_state = DBAccountState::Touched;
335 }
336 }
337 }
338
339 pub fn apply_geth_update_vec(&mut self, update: Vec<BTreeMap<Address, GethAccountState>>) {
340 for entry in update.into_iter() {
341 self.apply_geth_update(entry);
342 }
343 }
344
345 pub fn apply_account_info_btree(
346 &mut self,
347 address: &Address,
348 account_updated_state: &alloy::rpc::types::trace::geth::AccountState,
349 insert: bool,
350 only_new: bool,
351 ) {
352 let account = self.load_cached_account(*address);
353
354 if let Ok(account) = account {
355 if insert
356 || ((account.account_state == DBAccountState::NotExisting || account.account_state == DBAccountState::None) && only_new)
357 || (!only_new
358 && (account.account_state == DBAccountState::Touched || account.account_state == DBAccountState::StorageCleared))
359 {
360 let code: Option<Bytecode> = match &account_updated_state.code {
361 Some(c) => {
362 if c.len() < 2 {
363 account.info.code.clone()
364 } else {
365 Some(Bytecode::new_raw(c.clone()))
366 }
367 }
368 None => account.info.code.clone(),
369 };
370
371 trace!(
372 "apply_account_info {address}. code len: {} storage len: {}",
373 code.clone().map_or(0, |x| x.len()),
374 account.storage.len()
375 );
376
377 let account_info = AccountInfo {
378 balance: account_updated_state.balance.unwrap_or_default(),
379 nonce: account_updated_state.nonce.unwrap_or_default(),
380 code_hash: if code.is_some() { KECCAK_EMPTY } else { Default::default() },
381 code,
382 };
383
384 self.insert_account_info(*address, account_info);
385 } else {
386 trace!("apply_account_info exists {address}. storage len: {}", account.storage.len(),);
387 }
388 }
389
390 if let Ok(account) = self.load_cached_account(*address) {
391 account.account_state = DBAccountState::Touched;
392 trace!(
393 "after apply_account_info account: {address} state: {:?} storage len: {} code len : {}",
394 account.account_state,
395 account.storage.len(),
396 account.info.code.clone().map_or(0, |c| c.len())
397 );
398 } else {
399 trace!(%address, "account not found after apply");
400 }
401 }
402
403 pub fn apply_account_storage(&mut self, address: &Address, acc_state: &GethAccountState, insert: bool, only_new: bool) {
404 if insert {
405 if let Ok(account) = self.load_cached_account(*address) {
406 for (slot, value) in acc_state.storage.iter() {
407 trace!(%address, ?slot, ?value, "Inserting storage");
408 account.storage.insert((*slot).into(), (*value).into());
409 }
410 }
411 } else if self.is_account(address) {
412 let slots_to_insert: Vec<_> = acc_state
413 .storage
414 .iter()
415 .filter_map(|(slot, value)| {
416 let is_slot = self.is_slot(address, &(*slot).into());
417 if is_slot || only_new { Some(((*slot).into(), (*value).into())) } else { None }
418 })
419 .collect();
420
421 if let Ok(account) = self.load_cached_account(*address) {
422 for (slot, value) in slots_to_insert {
423 account.storage.insert(slot, value);
424 trace!(%address, ?slot, ?value, "Inserting storage");
425 }
426 }
427 }
428 }
429
430 pub fn apply_geth_state_update(
431 &mut self,
432 update_vec: &Vec<BTreeMap<Address, GethAccountState>>,
433 insert: bool,
434 only_new: bool,
435 ) -> &mut Self {
436 for update_record in update_vec {
437 for (address, acc_state) in update_record {
438 trace!(
439 "updating {address} insert: {insert} only_new: {only_new} storage len {} code: {}",
440 acc_state.storage.len(),
441 acc_state.code.is_some()
442 );
443 self.apply_account_info_btree(address, acc_state, insert, only_new);
444 self.apply_account_storage(address, acc_state, insert, only_new);
445 }
446 }
447 self
448 }
449}
450
451impl DatabaseKabuExt for KabuDB {
452 fn with_ext_db(&mut self, arc_db: impl DatabaseRef<Error = KabuDBError> + Send + Sync + 'static) {
453 self.ext_db = Some(Arc::new(arc_db))
454 }
455
456 fn is_account(&self, address: &Address) -> bool {
457 self.is_rw_ro_account(address)
458 }
459
460 fn is_slot(&self, address: &Address, slot: &U256) -> bool {
461 self.is_rw_ro_slot(address, slot)
462 }
463
464 fn contracts_len(&self) -> usize {
465 self.rw_contracts_len() + self.ro_contracts_len()
466 }
467
468 fn accounts_len(&self) -> usize {
469 self.rw_accounts_len() + self.ro_contracts_len()
470 }
471
472 fn storage_len(&self) -> usize {
473 self.rw_storage_len() + self.ro_storage_len()
474 }
475
476 fn load_account(&mut self, address: Address) -> Result<&mut FastDbAccount> {
477 self.load_ro_rw_ext_account(address)
478 }
479
480 fn load_cached_account(&mut self, address: Address) -> Result<&mut FastDbAccount> {
481 self.load_ro_rw_account(address)
482 }
483
484 fn insert_contract(&mut self, account: &mut AccountInfo) {
485 self.insert_contract(account)
486 }
487
488 fn insert_account_info(&mut self, address: Address, info: AccountInfo) {
489 self.insert_account_info(address, info)
490 }
491
492 fn insert_account_storage(&mut self, address: Address, slot: U256, value: U256) -> Result<()> {
493 self.insert_account_storage(address, slot, value)
494 }
495
496 fn replace_account_storage(&mut self, address: Address, storage: HashMap<U256, U256>) -> Result<()> {
497 self.replace_account_storage(address, storage)
498 }
499
500 fn maintain(self) -> Self {
501 self.merge_all()
502 }
503}
504
505impl DatabaseRef for KabuDB {
506 type Error = KabuDBError;
507 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
508 trace!(%address, "basic_ref");
509 match address {
510 Address::ZERO => Ok(Some(AccountInfo::default())),
511 _ => match self.accounts.get(&address) {
512 Some(acc) => {
513 trace!(%address, "account found");
514 Ok(acc.info())
515 }
516 None => Ok(KabuDBHelper::get_or_fetch_basic(&self.read_only_db, &self.ext_db, address).unwrap_or_default()),
517 },
518 }
519 }
520
521 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
522 match self.contracts.get(&code_hash) {
523 Some(entry) => Ok(entry.clone()),
524 None => KabuDBHelper::get_code_by_hash(&self.read_only_db, code_hash),
525 }
526 }
527
528 fn storage_ref(&self, address: Address, slot: U256) -> Result<U256, Self::Error> {
529 trace!(%address, ?slot, "storage_ref");
530
531 match self.accounts.get(&address) {
532 Some(acc_entry) => match acc_entry.storage.get(&slot) {
533 Some(entry) => {
534 trace!(%address, ?slot, %entry, "storage_ref");
535 Ok(*entry)
536 }
537 None => {
538 if matches!(acc_entry.account_state, DBAccountState::StorageCleared | DBAccountState::NotExisting) {
539 trace!(%address, ?slot, state=?acc_entry.account_state, "storage_ref ZERO");
540 Ok(U256::ZERO)
541 } else {
542 KabuDBHelper::get_or_fetch_storage(&self.read_only_db, &self.ext_db, address, slot)
543 }
544 }
545 },
546 None => KabuDBHelper::get_or_fetch_storage(&self.read_only_db, &self.ext_db, address, slot),
547 }
548 }
549
550 fn block_hash_ref(&self, number: BlockNumber) -> Result<B256, Self::Error> {
551 match self.block_hashes.get(&number) {
552 Some(entry) => Ok(*entry),
553 None => KabuDBHelper::get_or_fetch_block_hash(&self.read_only_db, &self.ext_db, number),
554 }
555 }
556}
557
558impl Database for KabuDB {
559 type Error = KabuDBError;
560
561 fn basic(&mut self, address: Address) -> std::result::Result<Option<AccountInfo>, Self::Error> {
562 trace!(%address, "basic");
563
564 let basic = match self.accounts.entry(address) {
565 Entry::Occupied(entry) => entry.into_mut(),
566 Entry::Vacant(entry) => entry.insert(
567 KabuDBHelper::get_or_fetch_basic(&self.read_only_db, &self.ext_db, address)
568 .unwrap_or_default()
569 .map(|info| FastDbAccount { info, ..Default::default() })
570 .unwrap_or_else(FastDbAccount::new_not_existing),
571 ),
572 };
573 Ok(basic.info())
574 }
575
576 fn code_by_hash(&mut self, code_hash: B256) -> std::result::Result<Bytecode, Self::Error> {
577 match self.contracts.entry(code_hash) {
578 Entry::Occupied(entry) => Ok(entry.get().clone()),
579 Entry::Vacant(entry) => {
580 Ok(entry.insert(KabuDBHelper::get_code_by_hash(&self.read_only_db, code_hash)?).clone())
582 }
583 }
584 }
585
586 fn storage(&mut self, address: Address, slot: U256) -> std::result::Result<U256, Self::Error> {
590 trace!(%address, ?slot, "storage");
591
592 match self.accounts.entry(address) {
593 Entry::Occupied(mut acc_entry) => {
594 let acc_entry = acc_entry.get_mut();
595 match acc_entry.storage.entry(slot) {
596 Entry::Occupied(entry) => Ok(*entry.get()),
597 Entry::Vacant(entry) => {
598 if matches!(acc_entry.account_state, DBAccountState::StorageCleared | DBAccountState::NotExisting) {
599 Ok(U256::ZERO)
600 } else {
601 let slot = KabuDBHelper::get_or_fetch_storage(&self.read_only_db, &self.ext_db, address, slot)?;
602 entry.insert(slot);
603 Ok(slot)
604 }
605 }
606 }
607 }
608 Entry::Vacant(acc_entry) => {
609 let info = KabuDBHelper::get_or_fetch_basic(&self.read_only_db, &self.ext_db, address)?;
610 let (account, value) = if info.is_some() {
611 let value = KabuDBHelper::get_or_fetch_storage(&self.read_only_db, &self.ext_db, address, slot)?;
612 let mut account: FastDbAccount = info.into();
613 account.storage.insert(slot, value);
614 (account, value)
615 } else {
616 (info.into(), U256::ZERO)
617 };
618 acc_entry.insert(account);
619 Ok(value)
620 }
621 }
622 }
623
624 fn block_hash(&mut self, number: BlockNumber) -> std::result::Result<B256, Self::Error> {
625 match self.block_hashes.entry(number) {
626 Entry::Occupied(entry) => Ok(*entry.get()),
627 Entry::Vacant(entry) => {
628 let hash = KabuDBHelper::get_or_fetch_block_hash(&self.read_only_db, &self.ext_db, number)?;
629 entry.insert(hash);
630 Ok(hash)
631 }
632 }
633 }
634}
635
636impl DatabaseCommit for KabuDB {
637 fn commit(&mut self, changes: HashMap<Address, Account>) {
638 for (address, mut account) in changes {
639 if !account.is_touched() {
640 continue;
641 }
642 if account.is_selfdestructed() {
643 let db_account = self.accounts.entry(address).or_default();
644 db_account.storage.clear();
645 db_account.account_state = DBAccountState::NotExisting;
646 db_account.info = AccountInfo::default();
647 continue;
648 }
649 let is_newly_created = account.is_created();
650 self.insert_contract(&mut account.info);
651
652 let db_account = self.accounts.entry(address).or_default();
653 db_account.info = account.info;
654
655 db_account.account_state = if is_newly_created {
656 db_account.storage.clear();
657 DBAccountState::StorageCleared
658 } else if db_account.account_state.is_storage_cleared() {
659 DBAccountState::StorageCleared
661 } else {
662 DBAccountState::Touched
663 };
664 db_account.storage.extend(account.storage.into_iter().map(|(key, value)| (key, value.present_value())));
665 }
666 }
667}
668
669#[cfg(test)]
670mod test {
671 use super::GethAccountState;
672 use crate::alloydb::AlloyDB;
673 use crate::error::KabuDBError;
674 use crate::kabu_db::KabuDB;
675 use alloy::eips::BlockNumberOrTag;
676 use alloy::primitives::map::HashMap;
677 use alloy::primitives::{Address, B256, Bytes, I256, U256};
678 use alloy::providers::{Provider, ProviderBuilder};
679 use eyre::ErrReport;
680 use revm::database::EmptyDBTyped;
681 use revm::primitives::KECCAK_EMPTY;
682 use revm::state::{AccountInfo, Bytecode};
683 use revm::{Database, DatabaseRef};
684 use std::collections::BTreeMap;
685
686 #[test]
687 fn test_new_with_provider() {
688 let db = KabuDB::new();
689 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
690
691 let rt = tokio::runtime::Runtime::new().unwrap();
692
693 rt.block_on(async move {
694 let test_addr = Address::parse_checksummed("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", None).unwrap();
695
696 let balance = provider.get_balance(test_addr).await?;
697
698 let db = KabuDB::new_with_ro_db_and_provider(Some(db), provider.clone()).unwrap();
699
700 let info = db.basic_ref(test_addr).unwrap().unwrap();
701
702 assert_eq!(info.balance, U256::from(10000000000000000000000u128));
703 assert_eq!(info.balance, balance);
704 Ok::<(), ErrReport>(())
705 })
706 .unwrap();
707 }
708
709 #[test]
710 fn test_new_with_ext_db() {
711 let db = KabuDB::new();
712 let provider = ProviderBuilder::new().connect_anvil_with_wallet();
713
714 let rt = tokio::runtime::Runtime::new().unwrap();
715
716 rt.block_on(async move {
717 let test_addr = Address::parse_checksummed("0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266", None).unwrap();
718
719 let balance = provider.get_balance(test_addr).await?;
720
721 let ext_db = AlloyDB::new(provider.clone(), BlockNumberOrTag::Latest.into()).unwrap();
722
723 let db = KabuDB::new_with_ext_db(db, ext_db);
724
725 let info = db.basic_ref(test_addr).unwrap().unwrap();
726 assert_eq!(info.balance, U256::from(10000000000000000000000u128));
727 assert_eq!(info.balance, balance);
728
729 Ok::<(), ErrReport>(())
730 })
731 .unwrap();
732 }
733
734 #[test]
735 fn test_insert_account_storage() {
736 let account = Address::with_last_byte(42);
737 let nonce = 42;
738 let mut init_state = KabuDB::new();
739 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
740
741 let (key, value) = (U256::from(123), U256::from(456));
742 let mut new_state = KabuDB::new().with_ro_db(Some(init_state));
743
744 new_state.insert_account_storage(account, key, value).unwrap();
745
746 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
747 assert_eq!(new_state.storage(account, key).unwrap(), value);
748 }
749
750 #[test]
751 fn test_insert_account_storage_inherited() {
752 let account = Address::with_last_byte(42);
753 let nonce = 42;
754 let mut init_state = KabuDB::new();
755 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
756
757 let (key, value) = (U256::from(123), U256::from(456));
758 let mut new_state = KabuDB::new().with_ro_db(Some(init_state));
759 new_state.insert_account_storage(account, key, value).unwrap();
760
761 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
762 assert_eq!(new_state.storage(account, key).unwrap(), value);
763 }
764
765 #[test]
766 fn test_replace_account_storage() {
767 let account = Address::with_last_byte(42);
768 let nonce = 42;
769 let mut init_state = KabuDB::new();
770 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
771
772 let (key0, value0) = (U256::from(123), U256::from(456));
773 let (key1, value1) = (U256::from(789), U256::from(999));
774 init_state.insert_account_storage(account, key0, value0).unwrap();
775
776 let mut new_state = KabuDB::new().with_ro_db(Some(init_state));
777 assert_eq!(new_state.accounts.len(), 0);
778 let mut hm: HashMap<U256, U256> = Default::default();
779 hm.insert(key1, value1);
780
781 new_state.replace_account_storage(account, hm).unwrap();
782
783 let mut new_state = new_state.merge_all();
784
785 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
786 assert_eq!(new_state.storage(account, key0).unwrap(), value0);
787 assert_eq!(new_state.storage(account, key1).unwrap(), value1);
788 assert_eq!(new_state.accounts.len(), 1);
789 }
790
791 #[test]
792 fn test_apply_geth_update() {
793 let account = Address::with_last_byte(42);
794 let nonce = 42;
795 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
796 let mut init_state = KabuDB::new();
797 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
798
799 let (key0, value0) = (U256::from(123), U256::from(456));
800 let (key1, value1) = (U256::from(789), U256::from(999));
801 init_state.insert_account_storage(account, key0, value0).unwrap();
802 init_state.insert_account_storage(account, key1, value1).unwrap();
803
804 let mut new_state = KabuDB::new().with_ro_db(Some(init_state));
805 assert_eq!(new_state.accounts.len(), 0);
806
807 let update_record = GethAccountState {
808 balance: None,
809 code: Some(Bytes::from(vec![1, 2, 3])),
810 nonce: Some(nonce + 1),
811 storage: [(B256::from(I256::try_from(123).unwrap()), B256::from(I256::try_from(333).unwrap()))].into(),
812 };
813
814 let update: BTreeMap<Address, GethAccountState> = [(account, update_record)].into();
815
816 new_state.apply_geth_update(update);
817
818 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
819 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
820 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
821 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
822 assert_eq!(new_state.accounts.len(), 1);
823
824 let mut new_state = new_state.merge_all();
825
826 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
827 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
828 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
829 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
830 assert_eq!(new_state.accounts.len(), 1);
831 }
832
833 #[test]
834 fn test_merge() {
835 let account = Address::with_last_byte(42);
836 let nonce = 42;
837 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
838 let mut init_state = KabuDB::new();
839 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
840
841 let (key0, value0) = (U256::from(123), U256::from(456));
842 let (key1, value1) = (U256::from(789), U256::from(999));
843 let (key2, value2) = (U256::from(999), U256::from(111));
844 init_state.insert_account_storage(account, key0, value0).unwrap();
845 init_state.insert_account_storage(account, key1, value1).unwrap();
846
847 let mut new_state = KabuDB::new().with_ro_db(Some(init_state));
848 assert_eq!(new_state.accounts.len(), 0);
849
850 new_state.insert_account_info(
851 account,
852 AccountInfo {
853 balance: U256::ZERO,
854 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
855 nonce: nonce + 1,
856 code_hash: KECCAK_EMPTY,
857 },
858 );
859
860 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
861 new_state.insert_account_storage(account, key2, value2).unwrap();
862
863 let mut new_state = new_state.merge_all();
864
865 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
866 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
867 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
868 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
869 assert_eq!(new_state.storage_ref(account, key2).unwrap(), value2);
870 assert_eq!(new_state.accounts.len(), 1);
871 }
872
873 #[test]
874 fn test_update_cell() {
875 let account = Address::with_last_byte(42);
876 let account2 = Address::with_last_byte(43);
877 let nonce = 42;
878 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
879 let mut init_state = KabuDB::new();
880 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
881
882 let (key0, value0) = (U256::from(123), U256::from(456));
883 let (key1, value1) = (U256::from(789), U256::from(999));
884 let (key2, value2) = (U256::from(999), U256::from(111));
885 init_state.insert_account_storage(account, key0, value0).unwrap();
886 init_state.insert_account_storage(account, key1, value1).unwrap();
887
888 let mut new_state = KabuDB::new().with_ro_db(Some(init_state)).with_ext_db(EmptyDBTyped::<KabuDBError>::new());
889 assert_eq!(new_state.accounts.len(), 0);
890
891 new_state.insert_account_info(
892 account,
893 AccountInfo {
894 balance: U256::ZERO,
895 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
896 nonce: nonce + 1,
897 code_hash: KECCAK_EMPTY,
898 },
899 );
900
901 new_state.insert_account_info(
902 account2,
903 AccountInfo {
904 balance: U256::ZERO,
905 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
906 nonce: nonce + 1,
907 code_hash: KECCAK_EMPTY,
908 },
909 );
910
911 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
912 new_state.insert_account_storage(account, key2, value2).unwrap();
913
914 let mut new_state = new_state.merge_cells();
915
916 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
917 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
918 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
919 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
920 assert_eq!(new_state.storage_ref(account, key2).unwrap(), U256::ZERO);
921 assert_eq!(new_state.storage_ref(account2, key0).unwrap(), U256::ZERO);
922 assert_eq!(new_state.accounts.len(), 1);
923 assert_eq!(new_state.basic(account2).unwrap(), None);
924 assert_eq!(new_state.accounts.len(), 2);
925 assert_eq!(new_state.basic(account2).unwrap(), None);
926 assert_eq!(new_state.accounts.len(), 2);
927 }
928}