From f8cd0c6a19deb1430207f43a84194ccdf5cdc405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Marcos=20Bezerra?= Date: Thu, 28 Nov 2024 11:51:09 -0300 Subject: [PATCH] temp --- Cargo.lock | 35 +++-- Cargo.toml | 4 + src/bin/importer_offline.rs | 28 ++-- src/eth/primitives/address.rs | 3 +- src/eth/storage/cache.rs | 192 ++++++++++++++++++++++++++ src/eth/storage/mod.rs | 19 +++ src/eth/storage/stratus_storage.rs | 139 +++++++++++-------- src/eth/storage/temporary/inmemory.rs | 23 +-- 8 files changed, 343 insertions(+), 100 deletions(-) create mode 100644 src/eth/storage/cache.rs diff --git a/Cargo.lock b/Cargo.lock index 9275440c0..6e67dffdc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -567,9 +567,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.11" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" dependencies = [ "cc", "glob", @@ -663,15 +663,16 @@ dependencies = [ [[package]] name = "c-kzg" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf100c4cea8f207e883ff91ca886d621d8a166cb04971dfaa9bb8fd99ed95df" +checksum = "f0307f72feab3300336fb803a57134159f6e20139af1357f36c54cb90d8e8928" dependencies = [ "blst", "cc", "glob", "hex", "libc", + "once_cell", "serde", ] @@ -1043,6 +1044,20 @@ dependencies = [ "syn 2.0.76", ] +[[package]] +name = "dashmap" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +dependencies = [ + "cfg-if", + "crossbeam-utils", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", +] + [[package]] name = "data-encoding" version = "2.5.0" @@ -3169,9 +3184,9 @@ checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -4691,9 +4706,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" dependencies = [ "serde", ] @@ -4983,6 +4998,7 @@ dependencies = [ "const-hex", "const_format", "crossbeam-channel", + "dashmap", "derive-new", "derive_more", "display_json", @@ -5020,6 +5036,7 @@ dependencies = [ "opentelemetry", "opentelemetry-otlp", "opentelemetry_sdk", + "parking_lot", "paste", "phf", "phf_codegen", @@ -5033,6 +5050,7 @@ dependencies = [ "rlp", "rocksdb", "rust_decimal", + "rustc-hash 2.0.0", "sasl2-sys", "sentry", "sentry-tracing", @@ -5041,6 +5059,7 @@ dependencies = [ "serde_plain", "serde_urlencoded", "serde_with", + "smallvec", "sqlx", "static_assertions", "stringreader", diff --git a/Cargo.toml b/Cargo.toml index 0b2e8d370..ee6cfac8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ cfg-if = "=1.0.0" chrono = { version = "=0.4.38", features = ["serde"] } const_format = "=0.2.32" const-hex = "=1.12.0" +dashmap = { version = "=6.1.0", features = ["inline"] } derive_more = "=0.99.17" derive-new = "=0.6.0" hash_hasher = "=2.0.3" @@ -30,11 +31,13 @@ nanoid = "=0.4.0" nonempty = { version = "=0.10.0", features = ["serialize"] } once_cell = "=1.19.0" oneshot = "=0.1.8" +parking_lot = "=0.12.3" paste = "=1.0.15" phf = "=0.11.2" pin-project = "=1.1.5" rand = { version = "=0.8.5", features = ["small_rng"] } rust_decimal = "=1.36.0" +rustc-hash = "=2.0.0" static_assertions = "=1.1.0" strum = "=0.26.2" sugars = "=3.0.1" @@ -124,6 +127,7 @@ sasl2-sys = { version = "0.1.22", features = ["vendored"] } # Historic events processor indicatif = "=0.17.8" +smallvec = "1.13.2" # ------------------------------------------------------------------------------ # Platform specific dependencies diff --git a/src/bin/importer_offline.rs b/src/bin/importer_offline.rs index f63d418c3..e27329761 100644 --- a/src/bin/importer_offline.rs +++ b/src/bin/importer_offline.rs @@ -49,20 +49,16 @@ const RPC_FETCHER_CHANNEL_CAPACITY: usize = 10; /// /// We want to persist to the storage in batches, this means we don't save a /// block right away, but the information from that block still needs to be -/// found in the storage. +/// found in the cache. /// -/// By using a channel with capacity 0 to send STORAGE_SAVER_BATCH_SIZE blocks, -/// we guarantee that accounts and slots can either be found in the permanent -/// storage, or in the temporary one. -/// -/// In other words, at most (STORAGE_SAVER_BATCH_SIZE) * 2 executed blocks -/// won't be found in the permanent storage, but that's still within the -/// temporary storage capacity. -/// -/// We use half because we want parallelism in execution and persisting, both -/// places need to hold blocks that aren't in the permanent storage yet, it's -/// half for each. -const STORAGE_SAVER_BATCH_SIZE: usize = 64 / 2 - 1; +/// These constants are organized to guarantee that accounts and slots can +/// still be found in the storage cache. +const CACHE_SIZE: usize = 86_400; +const MAX_BLOCKS_NOT_SAVED: usize = CACHE_SIZE - 1; + +const BATCH_COUNT: usize = 12; +const SAVER_BATCH_SIZE: usize = MAX_BLOCKS_NOT_SAVED / BATCH_COUNT; +const SAVER_CHANNEL_CAPACITY: usize = BATCH_COUNT - 2; // TODO: explain why type BlocksToExecute = Vec; type BlocksToSave = Vec; @@ -95,7 +91,7 @@ async fn run(config: ImporterOfflineConfig) -> anyhow::Result<()> { let (fetch_to_execute_tx, fetch_to_execute_rx) = async_mpsc::channel::(RPC_FETCHER_CHANNEL_CAPACITY); // send blocks from executor task to saver task - let (execute_to_save_tx, execute_to_save_rx) = mpsc::sync_channel::(0); + let (execute_to_save_tx, execute_to_save_rx) = mpsc::sync_channel::(SAVER_CHANNEL_CAPACITY); // load genesis accounts let initial_accounts = rpc_storage.read_initial_accounts().await?; @@ -232,8 +228,8 @@ fn run_external_block_executor( let instant_before_execution = Instant::now(); - for blocks in Itertools::chunks(blocks.into_iter(), STORAGE_SAVER_BATCH_SIZE).into_iter() { - let mut executed_batch = Vec::with_capacity(STORAGE_SAVER_BATCH_SIZE); + for blocks in Itertools::chunks(blocks.into_iter(), SAVER_BATCH_SIZE).into_iter() { + let mut executed_batch = Vec::with_capacity(SAVER_BATCH_SIZE); for (mut block, receipts) in blocks { if GlobalState::is_shutdown_warn(TASK_NAME) { diff --git a/src/eth/primitives/address.rs b/src/eth/primitives/address.rs index 8c89e07e8..d5f1409f7 100644 --- a/src/eth/primitives/address.rs +++ b/src/eth/primitives/address.rs @@ -21,8 +21,7 @@ use crate::eth::primitives::LogTopic; use crate::gen_newtype_from; /// Address of an Ethereum account (wallet or contract). -#[derive(DebugAsJson, Clone, Copy, Default, Eq, PartialEq, Hash, serde::Serialize, serde::Deserialize)] -#[cfg_attr(test, derive(PartialOrd, Ord))] +#[derive(DebugAsJson, Clone, Copy, Default, Eq, PartialEq, PartialOrd, Ord, Hash, serde::Serialize, serde::Deserialize)] pub struct Address(pub H160); impl Address { diff --git a/src/eth/storage/cache.rs b/src/eth/storage/cache.rs new file mode 100644 index 000000000..6bb109d3a --- /dev/null +++ b/src/eth/storage/cache.rs @@ -0,0 +1,192 @@ +use std::collections::hash_map::Entry; +use std::collections::BTreeMap; +use std::hash::Hash; +use std::mem; +use std::ops::DerefMut; +use std::sync::atomic::AtomicU64; +use std::sync::atomic::Ordering; + +use parking_lot::RwLock; +use parking_lot::RwLockWriteGuard; +use rustc_hash::FxBuildHasher; +use rustc_hash::FxHashMap; +use smallvec::SmallVec; + +use super::AccountWithSlots; +use crate::eth::primitives::Account; +use crate::eth::primitives::Address; +use crate::eth::primitives::ExecutionChanges; +use crate::eth::primitives::Slot; +use crate::eth::primitives::SlotIndex; +use crate::eth::primitives::SlotValue; + +type EntryId = u64; + +pub struct StorageCache { + slot_cache: Cache<(Address, SlotIndex), SlotValue>, + account_cache: Cache, +} + +impl Default for StorageCache { + fn default() -> Self { + Self { + slot_cache: Cache::with_target_capacity(100_000), + account_cache: Cache::with_target_capacity(20_000), + } + } +} + +impl StorageCache { + pub fn cache_slot(&self, address: Address, slot: Slot) { + self.slot_cache.put((address, slot.index), slot.value); + } + + pub fn cache_account(&self, account: Account) { + self.account_cache.put(account.address, account); + } + + pub fn cache_account_and_slots_from_execution(&self, changes: &ExecutionChanges) { + let mut slot_batch = SmallVec::<[_; 16]>::new(); + let mut account_batch = SmallVec::<[_; 8]>::new(); + + for change in changes.values() { + // cache slots + for &slot in change.slots.values().flat_map(|slot| slot.take_ref()) { + slot_batch.push(((change.address, slot.index), slot.value)); + } + + // cache account + let mut account = AccountWithSlots::new(change.address); + if let Some(nonce) = change.nonce.take_ref() { + account.info.nonce = *nonce; + } + if let Some(balance) = change.balance.take_ref() { + account.info.balance = *balance; + } + if let Some(Some(bytecode)) = change.bytecode.take_ref() { + account.info.bytecode = Some(bytecode.clone()); + } + account_batch.push((change.address, account.info)); + } + + self.slot_cache.put_batch(slot_batch); + self.account_cache.put_batch(account_batch); + } + + pub fn get_slot(&self, address: Address, index: SlotIndex) -> Option { + self.slot_cache.get(&(address, index)).map(|value| Slot { value, index }) + } + + pub fn get_account(&self, address: Address) -> Option { + self.account_cache.get(&address) + } +} + +type Id = u64; + +struct Cache { + target_capacity: usize, + id_counter: AtomicU64, + kv: RwLock>, + eviction_queue: RwLock>, +} + +impl Cache +where + K: Hash + Eq + Clone, + V: Clone, +{ + pub fn with_target_capacity(target_capacity: usize) -> Self { + assert!(target_capacity > 8192); + Self { + target_capacity, + id_counter: AtomicU64::new(0), + kv: RwLock::new(FxHashMap::with_capacity_and_hasher(target_capacity + 8192 * 2, FxBuildHasher)), + eviction_queue: RwLock::new(BTreeMap::new()), + } + } + + pub fn get(&self, key: &K) -> Option { + self.kv.read().get(key).map(|pair| pair.1.clone()) + } + + pub fn put(&self, key: K, value: V) { + self.put_batch([(key, value)]); + } + + pub fn put_batch(&self, iter: I) + where + I: IntoIterator, + { + let mut should_evict = false; + let mut ids_with_keys_to_add = SmallVec::<[(Id, K); 16]>::new(); + let mut ids_with_keys_to_remove = SmallVec::<[(Id, K); 16]>::new(); + + { + let mut kv_lock = self.kv.write(); + + for (key, value) in iter { + let (id, eviction_trigger) = self.next_id(); + should_evict |= eviction_trigger; + ids_with_keys_to_add.push((id, key.clone())); + + let previous = kv_lock.insert(key.clone(), (id, value)); + if let Some((previous_id, _)) = previous { + ids_with_keys_to_remove.push((previous_id, key)); + } + } + } + + let mut queue_lock = self.eviction_queue.write(); + for (id, key) in ids_with_keys_to_remove { + queue_lock.remove(&id); + } + for (id, key) in ids_with_keys_to_add { + queue_lock.insert(id, key); + } + if should_evict { + self.run_eviction(queue_lock); + } + } + + #[inline] + /// Calculates the next entry id and tells if should run eviction. + fn next_id(&self) -> (EntryId, bool) { + let id = self.id_counter.fetch_add(1, Ordering::Relaxed); + // plan eviction every 8192 entries added to this cache + // 8192 == 2^13, which makes this an stupidly fast bitmask check + let should_evict = id % 8192 == 0; + (id, should_evict) + } + + #[inline] + fn run_eviction(&self, mut queue_lock: RwLockWriteGuard>) { + if queue_lock.len() <= self.target_capacity { + return; // nothing to do + } + + // Underflow Safety: + // - queue_lock.len() > self.target_capacity + let amount_to_evict = queue_lock.len() - self.target_capacity; + + // Note: linear search might be a bottleneck, but `.lower_bound()` is unstable + // Unwrap Safety: + // - amount_to_evict < queue_lock.len() + // - because self.target_capacity > 0 + let (&id_to_split_at, _) = queue_lock.iter().nth(amount_to_evict).unwrap(); + + let right_side = queue_lock.split_off(&id_to_split_at); + let elements_to_evict = mem::replace(queue_lock.deref_mut(), right_side); + + drop(queue_lock); + let mut kv_lock = self.kv.write(); + + for (id, key) in elements_to_evict { + if let Entry::Occupied(occupied) = kv_lock.entry(key) { + if occupied.get().0 == id { + occupied.remove(); + } + } + } + } +} diff --git a/src/eth/storage/mod.rs b/src/eth/storage/mod.rs index e53b47964..f922fde17 100644 --- a/src/eth/storage/mod.rs +++ b/src/eth/storage/mod.rs @@ -1,5 +1,6 @@ //! Ethereum / EVM storage. +pub use cache::StorageCache; pub use permanent::InMemoryPermanentStorage; pub use permanent::PermanentStorage; pub use permanent::PermanentStorageConfig; @@ -11,10 +12,12 @@ pub use temporary::TemporaryStorage; pub use temporary::TemporaryStorageConfig; pub use temporary::TemporaryStorageKind; +mod cache; pub mod permanent; mod stratus_storage; mod temporary; +use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; @@ -95,6 +98,22 @@ pub trait Storage: Send + Sync + 'static { fn translate_to_point_in_time(&self, block_filter: BlockFilter) -> Result; } +#[derive(Debug, Clone)] +pub struct AccountWithSlots { + pub info: Account, + pub slots: HashMap, +} + +impl AccountWithSlots { + /// Creates a new temporary account. + fn new(address: Address) -> Self { + Self { + info: Account::new_empty(address), + slots: HashMap::default(), + } + } +} + // ----------------------------------------------------------------------------- // Config // ----------------------------------------------------------------------------- diff --git a/src/eth/storage/stratus_storage.rs b/src/eth/storage/stratus_storage.rs index cd3031e97..e13e49618 100644 --- a/src/eth/storage/stratus_storage.rs +++ b/src/eth/storage/stratus_storage.rs @@ -2,6 +2,7 @@ use anyhow::anyhow; use tracing::Span; use super::Storage; +use super::StorageCache; use crate::eth::primitives::Account; use crate::eth::primitives::Address; use crate::eth::primitives::Block; @@ -35,13 +36,18 @@ mod label { /// Additionaly it tracks metrics that are independent of the storage implementation. pub struct StratusStorage { temp: Box, + cache: StorageCache, perm: Box, } impl StratusStorage { /// Creates a new storage with the specified temporary and permanent implementations. pub fn new(temp: Box, perm: Box) -> Result { - let this = Self { temp, perm }; + let this = Self { + temp, + cache: StorageCache::default(), + perm, + }; // create genesis block and accounts if necessary #[cfg(feature = "dev")] @@ -143,78 +149,99 @@ impl Storage for StratusStorage { #[cfg(feature = "tracing")] let _span = tracing::debug_span!("storage::read_account", %address, %point_in_time).entered(); - // read from temp only if requested - if point_in_time.is_pending() { - tracing::debug!(storage = %label::TEMP, %address, "reading account"); - let temp_account = timed(|| self.temp.read_account(address)).with(|m| { - metrics::inc_storage_read_account(m.elapsed, label::TEMP, point_in_time, m.result.is_ok()); + let account = 'query: { + if point_in_time.is_pending() { + if let Some(account) = self.cache.get_account(address) { + return Ok(account); + }; + + tracing::debug!(storage = %label::TEMP, %address, "reading account"); + let temp_account = timed(|| self.temp.read_account(address)).with(|m| { + metrics::inc_storage_read_account(m.elapsed, label::TEMP, point_in_time, m.result.is_ok()); + if let Err(ref e) = m.result { + tracing::error!(reason = ?e, "failed to read account from temporary storage"); + } + })?; + if let Some(account) = temp_account { + tracing::debug!(storage = %label::TEMP, %address, ?account, "account found in temporary storage"); + break 'query account; + } + } + + // always read from perm if necessary + tracing::debug!(storage = %label::PERM, %address, "reading account"); + let perm_account = timed(|| self.perm.read_account(address, point_in_time)).with(|m| { + metrics::inc_storage_read_account(m.elapsed, label::PERM, point_in_time, m.result.is_ok()); if let Err(ref e) = m.result { - tracing::error!(reason = ?e, "failed to read account from temporary storage"); + tracing::error!(reason = ?e, "failed to read account from permanent storage"); } })?; - if let Some(account) = temp_account { - tracing::debug!(storage = %label::TEMP, %address, ?account, "account found in temporary storage"); - return Ok(account); + match perm_account { + Some(account) => { + tracing::debug!(storage = %label::PERM, %address, ?account, "account found in permanent storage"); + account + } + None => { + tracing::debug!(storage = %label::PERM, %address, "account not found, assuming default value"); + Account::new_empty(address) + } } - } + }; - // always read from perm if necessary - tracing::debug!(storage = %label::PERM, %address, "reading account"); - let perm_account = timed(|| self.perm.read_account(address, point_in_time)).with(|m| { - metrics::inc_storage_read_account(m.elapsed, label::PERM, point_in_time, m.result.is_ok()); - if let Err(ref e) = m.result { - tracing::error!(reason = ?e, "failed to read account from permanent storage"); - } - })?; - match perm_account { - Some(account) => { - tracing::debug!(storage = %label::PERM, %address, ?account, "account found in permanent storage"); - Ok(account) - } - None => { - tracing::debug!(storage = %label::PERM, %address, "account not found, assuming default value"); - Ok(Account::new_empty(address)) - } + if point_in_time.is_pending() { + self.cache.cache_account(account.clone()); } + Ok(account) } fn read_slot(&self, address: Address, index: SlotIndex, point_in_time: PointInTime) -> Result { #[cfg(feature = "tracing")] let _span = tracing::debug_span!("storage::read_slot", %address, %index, %point_in_time).entered(); - // read from temp only if requested - if point_in_time.is_pending() { - tracing::debug!(storage = %label::TEMP, %address, %index, "reading slot"); - let temp_slot = timed(|| self.temp.read_slot(address, index)).with(|m| { - metrics::inc_storage_read_slot(m.elapsed, label::TEMP, point_in_time, m.result.is_ok()); + let slot = 'query: { + if point_in_time.is_pending() { + if let Some(slot) = self.cache.get_slot(address, index) { + return Ok(slot); + }; + + tracing::debug!(storage = %label::TEMP, %address, %index, "reading slot"); + let temp_slot = timed(|| self.temp.read_slot(address, index)).with(|m| { + metrics::inc_storage_read_slot(m.elapsed, label::TEMP, point_in_time, m.result.is_ok()); + if let Err(ref e) = m.result { + tracing::error!(reason = ?e, "failed to read slot from temporary storage"); + } + })?; + if let Some(slot) = temp_slot { + tracing::debug!(storage = %label::TEMP, %address, %index, value = %slot.value, "slot found in temporary storage"); + break 'query slot; + } + } + + // always read from perm if necessary + tracing::debug!(storage = %label::PERM, %address, %index, %point_in_time, "reading slot"); + let perm_slot = timed(|| self.perm.read_slot(address, index, point_in_time)).with(|m| { + metrics::inc_storage_read_slot(m.elapsed, label::PERM, point_in_time, m.result.is_ok()); if let Err(ref e) = m.result { - tracing::error!(reason = ?e, "failed to read slot from temporary storage"); + tracing::error!(reason = ?e, "failed to read slot from permanent storage"); } })?; - if let Some(slot) = temp_slot { - tracing::debug!(storage = %label::TEMP, %address, %index, value = %slot.value, "slot found in temporary storage"); - return Ok(slot); - } - } - // always read from perm if necessary - tracing::debug!(storage = %label::PERM, %address, %index, %point_in_time, "reading slot"); - let perm_slot = timed(|| self.perm.read_slot(address, index, point_in_time)).with(|m| { - metrics::inc_storage_read_slot(m.elapsed, label::PERM, point_in_time, m.result.is_ok()); - if let Err(ref e) = m.result { - tracing::error!(reason = ?e, "failed to read slot from permanent storage"); - } - })?; - match perm_slot { - Some(slot) => { - tracing::debug!(storage = %label::PERM, %address, %index, value = %slot.value, "slot found in permanent storage"); - Ok(slot) - } - None => { - tracing::debug!(storage = %label::PERM, %address, %index, "slot not found, assuming default value"); - Ok(Slot::new_empty(index)) + match perm_slot { + Some(slot) => { + tracing::debug!(storage = %label::PERM, %address, %index, value = %slot.value, "slot found in permanent storage"); + slot + } + None => { + tracing::debug!(storage = %label::PERM, %address, %index, "slot not found, assuming default value"); + Slot::new_empty(index) + } } + }; + + if point_in_time.is_pending() { + self.cache.cache_slot(address, slot); } + Ok(slot) } // ------------------------------------------------------------------------- @@ -222,6 +249,8 @@ impl Storage for StratusStorage { // ------------------------------------------------------------------------- fn save_execution(&self, tx: TransactionExecution, check_conflicts: bool) -> Result<(), StratusError> { + self.cache.cache_account_and_slots_from_execution(&tx.execution().changes); + #[cfg(feature = "tracing")] let _span = tracing::info_span!("storage::save_execution", tx_hash = %tx.hash()).entered(); tracing::debug!(storage = %label::TEMP, tx_hash = %tx.hash(), "saving execution"); diff --git a/src/eth/storage/temporary/inmemory.rs b/src/eth/storage/temporary/inmemory.rs index 12b66e3e9..63cca1ce7 100644 --- a/src/eth/storage/temporary/inmemory.rs +++ b/src/eth/storage/temporary/inmemory.rs @@ -24,10 +24,11 @@ use crate::eth::primitives::TransactionExecution; use crate::eth::primitives::UnixTime; #[cfg(feature = "dev")] use crate::eth::primitives::UnixTimeNow; +use crate::eth::storage::AccountWithSlots; use crate::eth::storage::TemporaryStorage; /// Number of previous blocks to keep inmemory to detect conflicts between different blocks. -const MAX_BLOCKS: usize = 64; +const MAX_BLOCKS: usize = 1; #[derive(Debug)] pub struct InMemoryTemporaryStorage { @@ -66,7 +67,7 @@ pub struct InMemoryTemporaryStorageState { pub block: PendingBlock, /// Last state of accounts and slots. Can be recreated from the executions inside the pending block. - pub accounts: HashMap, + pub accounts: HashMap, } impl InMemoryTemporaryStorageState { @@ -83,22 +84,6 @@ impl InMemoryTemporaryStorageState { } } -#[derive(Debug, Clone)] -pub struct InMemoryTemporaryAccount { - pub info: Account, - pub slots: HashMap, -} - -impl InMemoryTemporaryAccount { - /// Creates a new temporary account. - fn new(address: Address) -> Self { - Self { - info: Account::new_empty(address), - slots: HashMap::default(), - } - } -} - impl TemporaryStorage for InMemoryTemporaryStorage { // ------------------------------------------------------------------------- // Block number @@ -131,7 +116,7 @@ impl TemporaryStorage for InMemoryTemporaryStorage { .head .accounts .entry(change.address) - .or_insert_with(|| InMemoryTemporaryAccount::new(change.address)); + .or_insert_with(|| AccountWithSlots::new(change.address)); // account basic info if let Some(nonce) = change.nonce.take_ref() {