diff --git a/src/eth/rpc/rpc_server.rs b/src/eth/rpc/rpc_server.rs index 4f1b7b025..c512ba664 100644 --- a/src/eth/rpc/rpc_server.rs +++ b/src/eth/rpc/rpc_server.rs @@ -131,6 +131,7 @@ fn register_methods(mut module: RpcModule) -> anyhow::Result, ctx: Arc) Ok(serde_json::to_value(timestamp).expect_infallible()) } +#[cfg(feature = "dev")] +async fn debug_read_all_slots(params: Params<'_>, ctx: Arc) -> anyhow::Result { + let (_, address) = next_rpc_param::
(params.sequence())?; + Ok(serde_json::to_value(ctx.storage.read_all_slots(&address).await?).expect_infallible()) +} + // Status async fn net_listening(params: Params<'_>, arc: Arc) -> anyhow::Result { stratus_readiness(params, arc).await diff --git a/src/eth/storage/inmemory/inmemory_permanent.rs b/src/eth/storage/inmemory/inmemory_permanent.rs index b3dea0624..270d1bea1 100644 --- a/src/eth/storage/inmemory/inmemory_permanent.rs +++ b/src/eth/storage/inmemory/inmemory_permanent.rs @@ -219,6 +219,17 @@ impl PermanentStorage for InMemoryPermanentStorage { Ok(slots) } + async fn read_all_slots(&self, address: &Address) -> anyhow::Result> { + let state = self.lock_read().await; + + let Some(account) = state.accounts.get(address) else { + tracing::trace!(%address, "account not found in permanent"); + return Ok(Default::default()); + }; + + Ok(account.slots.clone().into_values().map(|slot| slot.get_current()).collect()) + } + async fn read_block(&self, selection: &BlockSelection) -> anyhow::Result> { tracing::debug!(?selection, "reading block"); diff --git a/src/eth/storage/permanent_storage.rs b/src/eth/storage/permanent_storage.rs index 709ada995..ac97a1c47 100644 --- a/src/eth/storage/permanent_storage.rs +++ b/src/eth/storage/permanent_storage.rs @@ -81,6 +81,9 @@ pub trait PermanentStorage: Send + Sync { /// Retrieves a random sample of slots, from the provided start and end blocks. async fn read_slots_sample(&self, start: BlockNumber, end: BlockNumber, max_samples: u64, seed: u64) -> anyhow::Result>; + /// Retrieves all current slots associated to an address. + async fn read_all_slots(&self, address: &Address) -> anyhow::Result>; + // ------------------------------------------------------------------------- // Global state // ------------------------------------------------------------------------- diff --git a/src/eth/storage/postgres_permanent/postgres_permanent.rs b/src/eth/storage/postgres_permanent/postgres_permanent.rs index 617e0021d..f267243a2 100644 --- a/src/eth/storage/postgres_permanent/postgres_permanent.rs +++ b/src/eth/storage/postgres_permanent/postgres_permanent.rs @@ -97,6 +97,10 @@ impl PermanentStorage for PostgresPermanentStorage { PermanentStorageKind::Postgres { url: self.url.clone() } } + async fn read_all_slots(&self, _address: &Address) -> anyhow::Result> { + todo!(); + } + async fn allocate_evm_thread_resources(&self) -> anyhow::Result<()> { let conn = self.pool.acquire().await?; let conn = conn.leak(); diff --git a/src/eth/storage/rocks/rocks_permanent.rs b/src/eth/storage/rocks/rocks_permanent.rs index 64c82af7f..626eaebe2 100644 --- a/src/eth/storage/rocks/rocks_permanent.rs +++ b/src/eth/storage/rocks/rocks_permanent.rs @@ -9,6 +9,8 @@ use async_trait::async_trait; use futures::future::join_all; use super::rocks_state::RocksStorageState; +use super::types::AddressRocksdb; +use super::types::SlotIndexRocksdb; use crate::config::PermanentStorageKind; use crate::eth::primitives::Account; use crate::eth::primitives::Address; @@ -229,4 +231,18 @@ impl PermanentStorage for RocksPermanentStorage { async fn read_slots_sample(&self, _start: BlockNumber, _end: BlockNumber, _max_samples: u64, _seed: u64) -> anyhow::Result> { todo!() } + + async fn read_all_slots(&self, address: &Address) -> anyhow::Result> { + let address: AddressRocksdb = (*address).into(); + Ok(self + .state + .account_slots + .iter_from((address, SlotIndexRocksdb::from(0)), rocksdb::Direction::Forward) + .take_while(|((addr, _), _)| &address == addr) + .map(|((_, idx), value)| Slot { + index: idx.into(), + value: value.into(), + }) + .collect()) + } } diff --git a/src/eth/storage/rocks/types.rs b/src/eth/storage/rocks/types.rs index e3712e7ce..6c5bf66a6 100644 --- a/src/eth/storage/rocks/types.rs +++ b/src/eth/storage/rocks/types.rs @@ -238,6 +238,8 @@ impl From for u64 { #[derive(Clone, Default, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] pub struct SlotIndexRocksdb(U256); +gen_newtype_from!(self = SlotIndexRocksdb, other = u64); + impl SlotIndexRocksdb { pub fn inner_value(&self) -> U256 { self.0 diff --git a/src/eth/storage/stratus_storage.rs b/src/eth/storage/stratus_storage.rs index 5bcfc26c0..8eeefd9d7 100644 --- a/src/eth/storage/stratus_storage.rs +++ b/src/eth/storage/stratus_storage.rs @@ -327,6 +327,11 @@ impl StratusStorage { Ok(slots) } + #[tracing::instrument(skip_all)] + pub async fn read_all_slots(&self, address: &Address) -> anyhow::Result> { + self.perm.read_all_slots(address).await + } + // ------------------------------------------------------------------------- // Blocks // -------------------------------------------------------------------------