From 432a49ebc3e44f3aea2f5b9d05b0e2c3fc847ba2 Mon Sep 17 00:00:00 2001 From: Renato Dinhani <101204870+dinhani-cw@users.noreply.github.com> Date: Mon, 29 Apr 2024 15:10:40 -0300 Subject: [PATCH] refactor: extract slot_index module from slot module (#718) --- src/eth/primitives/mod.rs | 3 +- src/eth/primitives/slot.rs | 156 +---------------------------- src/eth/primitives/slot_index.rs | 166 +++++++++++++++++++++++++++++++ src/eth/storage/rocks/types.rs | 4 +- 4 files changed, 171 insertions(+), 158 deletions(-) create mode 100644 src/eth/primitives/slot_index.rs diff --git a/src/eth/primitives/mod.rs b/src/eth/primitives/mod.rs index 2730f58f7..13a8b9e28 100644 --- a/src/eth/primitives/mod.rs +++ b/src/eth/primitives/mod.rs @@ -112,6 +112,7 @@ mod miner_nonce; mod nonce; mod size; mod slot; +mod slot_index; mod storage_point_in_time; mod transaction_input; mod transaction_mined; @@ -164,10 +165,10 @@ pub use nonce::Nonce; pub use size::Size; pub use slot::Slot; pub use slot::SlotAccess; -pub use slot::SlotIndex; pub use slot::SlotIndexes; pub use slot::SlotSample; pub use slot::SlotValue; +pub use slot_index::SlotIndex; pub use storage_point_in_time::StoragePointInTime; pub use transaction_input::TransactionInput; pub use transaction_mined::TransactionMined; diff --git a/src/eth/primitives/slot.rs b/src/eth/primitives/slot.rs index 48c8b00f0..ac8e6c8f6 100644 --- a/src/eth/primitives/slot.rs +++ b/src/eth/primitives/slot.rs @@ -9,11 +9,9 @@ use std::collections::HashSet; use std::fmt::Debug; use std::fmt::Display; -use std::io::Read; use std::str::FromStr; use ethereum_types::U256; -use ethers_core::utils::keccak256; use fake::Dummy; use fake::Faker; use revm::primitives::U256 as RevmU256; @@ -27,6 +25,7 @@ use sqlx::Decode; use super::Address; use crate::eth::primitives::BlockNumber; +use crate::eth::primitives::SlotIndex; use crate::gen_newtype_from; #[derive(Debug, Clone, Copy, Default, PartialEq, Eq, fake::Dummy, serde::Serialize, serde::Deserialize)] @@ -65,159 +64,6 @@ impl Display for Slot { // SlotIndex // ----------------------------------------------------------------------------- -#[derive(Clone, Copy, Default, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] -pub struct SlotIndex(U256); - -impl SlotIndex { - pub const ZERO: SlotIndex = SlotIndex(U256::zero()); - pub const ONE: SlotIndex = SlotIndex(U256::one()); - - /// Converts itself to [`U256`]. - pub fn as_u256(&self) -> U256 { - self.0 - } - - /// Computes the mapping index of a key. - pub fn to_mapping_index(&self, key: Vec) -> SlotIndex { - // populate self to bytes - let mut slot_index_bytes = [0u8; 32]; - self.0.to_big_endian(&mut slot_index_bytes); - - // populate key to bytes - let mut key_bytes = [0u8; 32]; - let _ = key.take(32).read(&mut key_bytes[32usize.saturating_sub(key.len())..32]); - - // populate value to be hashed to bytes - let mut mapping_index_bytes = [0u8; 64]; - mapping_index_bytes[0..32].copy_from_slice(&key_bytes); - mapping_index_bytes[32..64].copy_from_slice(&slot_index_bytes); - - let hashed_bytes = keccak256(mapping_index_bytes); - Self::from(hashed_bytes) - } - - pub fn new(value: U256) -> Self { - Self(value) - } - - pub fn inner_value(&self) -> U256 { - self.0 - } -} - -impl FromStr for SlotIndex { - type Err = anyhow::Error; - - fn from_str(s: &str) -> anyhow::Result { - // This assumes that U256 has a from_str method that returns Result - let inner = U256::from_str(s)?; - Ok(SlotIndex(inner)) - } -} - -impl Dummy for SlotIndex { - fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { - rng.next_u64().into() - } -} - -impl Debug for SlotIndex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "SlotIndex({:#x})", self.0) - } -} - -impl Display for SlotIndex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:#x}", self.0) - } -} - -gen_newtype_from!(self = SlotIndex, other = u64, U256, [u8; 32]); - -impl From> for SlotIndex { - fn from(bytes: Vec) -> Self { - // Initialize U256 to zero - // Assuming the byte array is in big-endian format, - let u256: U256 = if bytes.len() <= 32 { - let mut padded_bytes = [0u8; 32]; - padded_bytes[32 - bytes.len()..].copy_from_slice(&bytes); - U256::from_big_endian(&padded_bytes) - } else { - // Handle the error or truncate the Vec as needed - // For simplicity, this example will only load the first 32 bytes if the Vec is too large - U256::from_big_endian(&bytes[0..32]) - }; - SlotIndex(u256) - } -} - -impl From for SlotIndex { - fn from(value: RevmU256) -> Self { - Self(value.to_be_bytes().into()) - } -} - -impl From for ethereum_types::U256 { - fn from(value: SlotIndex) -> ethereum_types::U256 { - value.0 - } -} - -impl From for Vec { - fn from(value: SlotIndex) -> Self { - let mut vec = vec![0u8; 32]; - value.0.to_big_endian(&mut vec); - vec - } -} - -// ----------------------------------------------------------------------------- -// sqlx traits for SlotIndex -// ----------------------------------------------------------------------------- -impl<'r> sqlx::Decode<'r, sqlx::Postgres> for SlotIndex { - fn decode(value: >::ValueRef) -> Result { - let value = <[u8; 32] as Decode>::decode(value)?; - Ok(value.into()) - } -} - -impl sqlx::Type for SlotIndex { - fn type_info() -> ::TypeInfo { - sqlx::postgres::PgTypeInfo::with_name("BYTEA") - } -} - -impl<'q> sqlx::Encode<'q, sqlx::Postgres> for SlotIndex { - fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { - <[u8; 32] as sqlx::Encode>::encode((*self).into(), buf) - } - - fn encode(self, buf: &mut >::ArgumentBuffer) -> IsNull - where - Self: Sized, - { - <[u8; 32] as sqlx::Encode>::encode(self.into(), buf) - } -} - -impl PgHasArrayType for SlotIndex { - fn array_type_info() -> sqlx::postgres::PgTypeInfo { - <[u8; 32] as PgHasArrayType>::array_type_info() - } -} - -// ----------------------------------------------------------------------------- -// Conversions: SlotIndex -> Other -// ----------------------------------------------------------------------------- -impl From for [u8; 32] { - fn from(value: SlotIndex) -> [u8; 32] { - let mut buf: [u8; 32] = [1; 32]; - U256::from(value).to_big_endian(&mut buf); - buf - } -} - // ----------------------------------------------------------------------------- // SlotValue // ----------------------------------------------------------------------------- diff --git a/src/eth/primitives/slot_index.rs b/src/eth/primitives/slot_index.rs new file mode 100644 index 000000000..788dd5636 --- /dev/null +++ b/src/eth/primitives/slot_index.rs @@ -0,0 +1,166 @@ +use std::fmt::Debug; +use std::fmt::Display; +use std::io::Read; +use std::str::FromStr; + +use ethereum_types::U256; +use ethers_core::utils::keccak256; +use fake::Dummy; +use fake::Faker; +use revm::primitives::U256 as RevmU256; +use sqlx::database::HasArguments; +use sqlx::database::HasValueRef; +use sqlx::encode::IsNull; +use sqlx::error::BoxDynError; +use sqlx::postgres::PgHasArrayType; +use sqlx::Decode; + +use crate::gen_newtype_from; + +#[derive(Clone, Copy, Default, Hash, Eq, PartialEq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +pub struct SlotIndex(U256); + +impl SlotIndex { + pub const ZERO: SlotIndex = SlotIndex(U256::zero()); + pub const ONE: SlotIndex = SlotIndex(U256::one()); + + /// Converts itself to [`U256`]. + pub fn as_u256(&self) -> U256 { + self.0 + } + + /// Computes the mapping index of a key. + pub fn to_mapping_index(&self, key: Vec) -> SlotIndex { + // populate self to bytes + let mut slot_index_bytes = [0u8; 32]; + self.0.to_big_endian(&mut slot_index_bytes); + + // populate key to bytes + let mut key_bytes = [0u8; 32]; + let _ = key.take(32).read(&mut key_bytes[32usize.saturating_sub(key.len())..32]); + + // populate value to be hashed to bytes + let mut mapping_index_bytes = [0u8; 64]; + mapping_index_bytes[0..32].copy_from_slice(&key_bytes); + mapping_index_bytes[32..64].copy_from_slice(&slot_index_bytes); + + let hashed_bytes = keccak256(mapping_index_bytes); + Self::from(hashed_bytes) + } +} + +impl Dummy for SlotIndex { + fn dummy_with_rng(_: &Faker, rng: &mut R) -> Self { + rng.next_u64().into() + } +} + +impl Debug for SlotIndex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "SlotIndex({:#x})", self.0) + } +} + +impl Display for SlotIndex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:#x}", self.0) + } +} + +// ----------------------------------------------------------------------------- +// Conversions: Other -> Self +// ----------------------------------------------------------------------------- +gen_newtype_from!(self = SlotIndex, other = u64, U256, [u8; 32]); + +impl From> for SlotIndex { + fn from(bytes: Vec) -> Self { + // Initialize U256 to zero + // Assuming the byte array is in big-endian format, + let u256: U256 = if bytes.len() <= 32 { + let mut padded_bytes = [0u8; 32]; + padded_bytes[32 - bytes.len()..].copy_from_slice(&bytes); + U256::from_big_endian(&padded_bytes) + } else { + // Handle the error or truncate the Vec as needed + // For simplicity, this example will only load the first 32 bytes if the Vec is too large + U256::from_big_endian(&bytes[0..32]) + }; + SlotIndex(u256) + } +} + +impl From for SlotIndex { + fn from(value: RevmU256) -> Self { + Self(value.to_be_bytes().into()) + } +} + +impl FromStr for SlotIndex { + type Err = anyhow::Error; + + fn from_str(s: &str) -> anyhow::Result { + // This assumes that U256 has a from_str method that returns Result + let inner = U256::from_str(s)?; + Ok(SlotIndex(inner)) + } +} + +// ----------------------------------------------------------------------------- +// Conversions: Self -> Other +// ----------------------------------------------------------------------------- +impl From for [u8; 32] { + fn from(value: SlotIndex) -> [u8; 32] { + let mut buf: [u8; 32] = [1; 32]; + U256::from(value).to_big_endian(&mut buf); + buf + } +} + +impl From for Vec { + fn from(value: SlotIndex) -> Self { + let mut vec = vec![0u8; 32]; + value.0.to_big_endian(&mut vec); + vec + } +} + +impl From for ethereum_types::U256 { + fn from(value: SlotIndex) -> ethereum_types::U256 { + value.0 + } +} + +// ----------------------------------------------------------------------------- +// sqlx traits +// ----------------------------------------------------------------------------- +impl<'r> sqlx::Decode<'r, sqlx::Postgres> for SlotIndex { + fn decode(value: >::ValueRef) -> Result { + let value = <[u8; 32] as Decode>::decode(value)?; + Ok(value.into()) + } +} + +impl sqlx::Type for SlotIndex { + fn type_info() -> ::TypeInfo { + sqlx::postgres::PgTypeInfo::with_name("BYTEA") + } +} + +impl<'q> sqlx::Encode<'q, sqlx::Postgres> for SlotIndex { + fn encode_by_ref(&self, buf: &mut >::ArgumentBuffer) -> IsNull { + <[u8; 32] as sqlx::Encode>::encode((*self).into(), buf) + } + + fn encode(self, buf: &mut >::ArgumentBuffer) -> IsNull + where + Self: Sized, + { + <[u8; 32] as sqlx::Encode>::encode(self.into(), buf) + } +} + +impl PgHasArrayType for SlotIndex { + fn array_type_info() -> sqlx::postgres::PgTypeInfo { + <[u8; 32] as PgHasArrayType>::array_type_info() + } +} diff --git a/src/eth/storage/rocks/types.rs b/src/eth/storage/rocks/types.rs index cee480f51..fbb99010c 100644 --- a/src/eth/storage/rocks/types.rs +++ b/src/eth/storage/rocks/types.rs @@ -240,13 +240,13 @@ impl SlotIndexRocksdb { impl From for SlotIndexRocksdb { fn from(item: SlotIndex) -> Self { - SlotIndexRocksdb(item.inner_value()) + SlotIndexRocksdb(item.as_u256()) } } impl From for SlotIndex { fn from(item: SlotIndexRocksdb) -> Self { - SlotIndex::new(item.inner_value()) + SlotIndex::from(item.inner_value()) } }