diff --git a/mp2-v1/tests/common/cases/contract.rs b/mp2-v1/tests/common/cases/contract.rs index 029b11d2c..21dc82301 100644 --- a/mp2-v1/tests/common/cases/contract.rs +++ b/mp2-v1/tests/common/cases/contract.rs @@ -1,6 +1,6 @@ use std::future::Future; -use super::slot_info::{LargeStruct, MappingInfo, StorageSlotMappingKey, StorageSlotValue}; +use super::slot_info::{LargeStruct, MappingInfo}; use crate::common::{ bindings::{ eventemitter::EventEmitter::{self, EventEmitterInstance}, @@ -166,21 +166,17 @@ impl ContractController for LargeStruct { } #[derive(Clone, Debug)] -pub enum MappingUpdate { +pub(crate) enum MappingUpdate { // key and value - Insertion(K, V), + Insertion(T::Key, T::Value), // key and value - Deletion(K, V), + Deletion(T::Key, T::Value), // key, previous value and new value - Update(K, V, V), + Update(T::Key, T::Value, T::Value), } -impl MappingUpdate -where - K: StorageSlotMappingKey, - V: StorageSlotValue, -{ - pub fn to_tuple(&self) -> (K, V) { +impl MappingUpdate { + pub fn to_tuple(&self) -> (T::Key, T::Value) { match self { MappingUpdate::Insertion(key, value) | MappingUpdate::Deletion(key, value) @@ -189,8 +185,8 @@ where } } -impl From<&MappingUpdate> for MappingOperation { - fn from(update: &MappingUpdate) -> Self { +impl From<&MappingUpdate> for MappingOperation { + fn from(update: &MappingUpdate) -> Self { Self::from(match update { MappingUpdate::Deletion(_, _) => 0, MappingUpdate::Update(_, _, _) => 1, @@ -199,7 +195,7 @@ impl From<&MappingUpdate> for MappingOperation { } } -impl ContractController for Vec> { +impl ContractController for Vec> { async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self { unimplemented!("Unimplemented for fetching the all mapping values") } diff --git a/mp2-v1/tests/common/cases/slot_info.rs b/mp2-v1/tests/common/cases/slot_info.rs index 1e099df05..2d544fbee 100644 --- a/mp2-v1/tests/common/cases/slot_info.rs +++ b/mp2-v1/tests/common/cases/slot_info.rs @@ -26,97 +26,52 @@ use mp2_common::{ }; use mp2_v1::api::{SlotInput, SlotInputs}; use rand::{thread_rng, Rng}; +use serde::de::DeserializeOwned; use std::{array, fmt::Debug, future::Future, hash::Hash}; use super::contract::MappingUpdate; -pub(crate) trait MappingInfo: StorageSlotMappingKey { +pub(crate) trait MappingInfo: Sized { + type Key: StorageSlotMappingKey; type Value: StorageSlotValue; type Call; - fn to_call(update: &MappingUpdate) -> Self::Call; + fn to_call(update: &MappingUpdate) -> Self::Call; fn call_contract, N: Network>( contract: &SimpleInstance, changes: Vec, ) -> impl Future + Send; -} -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -pub struct SimpleMapping { - inner: U256, + fn sample_key() -> Self::Key { + Self::Key::sample_key() + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -pub struct StructMapping { - inner: U256, -} +pub struct SimpleMapping {} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -pub struct SimpleNestedMapping { - outer: U256, - inner: U256, -} +pub struct StructMapping {} #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] -pub struct StructNestedMapping { - outer: U256, - inner: U256, -} - -impl StorageSlotMappingKey for StructNestedMapping { - type Key = U256; +pub struct SimpleNestedMapping {} - const NO_KEYS: usize = 2; - - fn sample_key() -> Self { - let rng = &mut thread_rng(); - StructNestedMapping { - outer: U256::from_limbs(rng.gen()), - inner: U256::from_limbs(rng.gen()), - } - } - - fn slot_inputs(slot_inputs: Vec, length: Option) -> SlotInputs { - if let Some(length_slot) = length { - SlotInputs::MappingWithLength(slot_inputs, length_slot) - } else { - SlotInputs::MappingOfMappings(slot_inputs) - } - } - fn to_u256_vec(&self) -> Vec { - vec![self.outer, self.inner] - } - fn storage_slot(&self, slot: u8, evm_word: u32) -> StorageSlot { - let storage_slot = { - let parent_slot = StorageSlot::Mapping(self.outer.to_be_bytes_vec(), slot as usize); - StorageSlot::Node( - StorageSlotNode::new_mapping(parent_slot, self.inner.to_be_bytes_vec()).unwrap(), - ) - }; - if evm_word == 0 { - // We could construct the mapping slot for the EVM word of 0 directly even if the - // mapping value is a Struct, since the returned storage slot is only used to compute - // the slot location, and it's same with the Struct mapping and the EVM word of 0. - return storage_slot; - } - - // It's definitely a Struct if the EVM word is non zero. - StorageSlot::Node(StorageSlotNode::new_struct(storage_slot, evm_word)) - } -} +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)] +pub struct StructNestedMapping {} impl MappingInfo for StructNestedMapping { + type Key = MappingOfMappingsKey; type Value = LargeStruct; type Call = MappingOfStructMappingsChange; - fn to_call(update: &MappingUpdate) -> MappingOfStructMappingsChange { + fn to_call(update: &MappingUpdate) -> MappingOfStructMappingsChange { let op: MappingOperation = update.into(); let (key, value) = update.to_tuple(); MappingOfStructMappingsChange { - outerKey: key.outer, - innerKey: key.inner, + outerKey: key.outer_key, + innerKey: key.inner_key, field1: value.field1, field2: value.field2, field3: value.field3, @@ -133,59 +88,18 @@ impl MappingInfo for StructNestedMapping { } } -impl StorageSlotMappingKey for SimpleNestedMapping { - type Key = U256; - - const NO_KEYS: usize = 2; - - fn sample_key() -> Self { - let rng = &mut thread_rng(); - SimpleNestedMapping { - outer: U256::from_limbs(rng.gen()), - inner: U256::from_limbs(rng.gen()), - } - } - - fn slot_inputs(slot_inputs: Vec, length: Option) -> SlotInputs { - if let Some(length_slot) = length { - SlotInputs::MappingWithLength(slot_inputs, length_slot) - } else { - SlotInputs::MappingOfMappings(slot_inputs) - } - } - fn to_u256_vec(&self) -> Vec { - vec![self.outer, self.inner] - } - fn storage_slot(&self, slot: u8, evm_word: u32) -> StorageSlot { - let storage_slot = { - let parent_slot = StorageSlot::Mapping(self.outer.to_be_bytes_vec(), slot as usize); - StorageSlot::Node( - StorageSlotNode::new_mapping(parent_slot, self.inner.to_be_bytes_vec()).unwrap(), - ) - }; - if evm_word == 0 { - // We could construct the mapping slot for the EVM word of 0 directly even if the - // mapping value is a Struct, since the returned storage slot is only used to compute - // the slot location, and it's same with the Struct mapping and the EVM word of 0. - return storage_slot; - } - - // It's definitely a Struct if the EVM word is non zero. - StorageSlot::Node(StorageSlotNode::new_struct(storage_slot, evm_word)) - } -} - impl MappingInfo for SimpleNestedMapping { + type Key = MappingOfMappingsKey; type Value = U256; type Call = MappingOfSingleValueMappingsChange; - fn to_call(update: &MappingUpdate) -> MappingOfSingleValueMappingsChange { + fn to_call(update: &MappingUpdate) -> MappingOfSingleValueMappingsChange { let op: MappingOperation = update.into(); let (key, value) = update.to_tuple(); MappingOfSingleValueMappingsChange { - outerKey: key.outer, - innerKey: key.inner, + outerKey: key.outer_key, + innerKey: key.inner_key, value, operation: op.into(), } @@ -200,51 +114,18 @@ impl MappingInfo for SimpleNestedMapping { } } -impl StorageSlotMappingKey for SimpleMapping { - type Key = U256; - - const NO_KEYS: usize = 1; - - fn sample_key() -> Self { - SimpleMapping { - inner: sample_u256(), - } - } - fn slot_inputs(slot_inputs: Vec, length: Option) -> SlotInputs { - if let Some(length_slot) = length { - SlotInputs::MappingWithLength(slot_inputs, length_slot) - } else { - SlotInputs::Mapping(slot_inputs) - } - } - fn to_u256_vec(&self) -> Vec { - vec![self.inner] - } - fn storage_slot(&self, slot: u8, evm_word: u32) -> StorageSlot { - let storage_slot = StorageSlot::Mapping(self.inner.to_be_bytes_vec(), slot as usize); - if evm_word == 0 { - // We could construct the mapping slot for the EVM word of 0 directly even if the - // mapping value is a Struct, since the returned storage slot is only used to compute - // the slot location, and it's same with the Struct mapping and the EVM word of 0. - return storage_slot; - } - - // It's definitely a Struct if the EVM word is non zero. - StorageSlot::Node(StorageSlotNode::new_struct(storage_slot, evm_word)) - } -} - impl MappingInfo for SimpleMapping { + type Key = MappingKey; type Value = Address; type Call = MappingChange; - fn to_call(update: &MappingUpdate) -> Self::Call { + fn to_call(update: &MappingUpdate) -> Self::Call { let op: MappingOperation = update.into(); let (key, value) = update.to_tuple(); MappingChange { - key: key.inner, + key, value, operation: op.into(), } @@ -259,51 +140,18 @@ impl MappingInfo for SimpleMapping { } } -impl StorageSlotMappingKey for StructMapping { - type Key = U256; - - const NO_KEYS: usize = 1; - - fn sample_key() -> Self { - StructMapping { - inner: sample_u256(), - } - } - fn slot_inputs(slot_inputs: Vec, length: Option) -> SlotInputs { - if let Some(length_slot) = length { - SlotInputs::MappingWithLength(slot_inputs, length_slot) - } else { - SlotInputs::Mapping(slot_inputs) - } - } - fn to_u256_vec(&self) -> Vec { - vec![self.inner] - } - fn storage_slot(&self, slot: u8, evm_word: u32) -> StorageSlot { - let storage_slot = StorageSlot::Mapping(self.inner.to_be_bytes_vec(), slot as usize); - if evm_word == 0 { - // We could construct the mapping slot for the EVM word of 0 directly even if the - // mapping value is a Struct, since the returned storage slot is only used to compute - // the slot location, and it's same with the Struct mapping and the EVM word of 0. - return storage_slot; - } - - // It's definitely a Struct if the EVM word is non zero. - StorageSlot::Node(StorageSlotNode::new_struct(storage_slot, evm_word)) - } -} - impl MappingInfo for StructMapping { + type Key = MappingKey; type Value = LargeStruct; type Call = MappingStructChange; - fn to_call(update: &MappingUpdate) -> MappingStructChange { + fn to_call(update: &MappingUpdate) -> MappingStructChange { let op: MappingOperation = update.into(); let (key, value) = update.to_tuple(); MappingStructChange { - key: key.inner, + key, field1: value.field1, field2: value.field2, field3: value.field3, @@ -323,7 +171,9 @@ impl MappingInfo for StructMapping { /// Abstract for the mapping key of the storage slot. /// It could be a normal mapping key, or a pair of keys which identifies the /// mapping of mapppings key. -pub trait StorageSlotMappingKey: Clone + Debug + PartialOrd + Ord + Send + Sync { +pub trait StorageSlotMappingKey: + Clone + Debug + PartialOrd + Ord + Send + Sync + Serialize + DeserializeOwned +{ /// This is what the keys actually look like. type Key; diff --git a/mp2-v1/tests/common/cases/table_source.rs b/mp2-v1/tests/common/cases/table_source.rs index f9ece8b6a..984a7f208 100644 --- a/mp2-v1/tests/common/cases/table_source.rs +++ b/mp2-v1/tests/common/cases/table_source.rs @@ -1274,7 +1274,7 @@ pub(crate) struct MappingExtractionArgs { /// need to know an existing key /// * doing the MPT proofs over, since this test doesn't implement the copy on write for MPT /// (yet), we're just recomputing all the proofs at every block and we need the keys for that. - mapping_keys: BTreeSet, + mapping_keys: BTreeSet, /// The optional length extraction parameters length_args: Option, } @@ -1282,15 +1282,15 @@ pub(crate) struct MappingExtractionArgs { impl TableSource for MappingExtractionArgs where T: MappingInfo, - Vec>: ContractController, + Vec>: ContractController, { type Metadata = SlotInputs; fn get_data(&self) -> Self::Metadata { if let Some(l_args) = self.length_args.as_ref() { - T::slot_inputs(self.slot_inputs.clone(), Some(l_args.slot)) + T::Key::slot_inputs(self.slot_inputs.clone(), Some(l_args.slot)) } else { - T::slot_inputs(self.slot_inputs.clone(), None) + T::Key::slot_inputs(self.slot_inputs.clone(), None) } } @@ -1510,7 +1510,7 @@ where } MappingUpdate::Insertion(key_to_insert, _) => { info!("Inserting key {key_to_insert:?} to tracking mapping keys"); - self.mapping_keys.insert(key_to_insert.clone()); + self.mapping_keys.insert(Clone::clone(key_to_insert)); } // the mapping key doesn't change here so no need to update the list MappingUpdate::Update(_, _, _) => {} @@ -1556,7 +1556,7 @@ impl MappingExtractionArgs { &self, block_number: BlockPrimaryIndex, contract: &Contract, - updates: &[MappingUpdate], + updates: &[MappingUpdate], ) -> Vec> { updates .iter() @@ -1659,7 +1659,7 @@ impl MappingExtractionArgs { &self, evm_word: u32, table_info: Vec, - mapping_key: &T, + mapping_key: &T::Key, ) -> StorageSlotInfo { let storage_slot = mapping_key.storage_slot(self.slot, evm_word); @@ -1684,7 +1684,7 @@ impl MappingExtractionArgs { &self, ctx: &mut TestContext, contract: &Contract, - mapping_key: &T, + mapping_key: &T::Key, ) -> T::Value { let mut extracted_values = vec![]; let evm_word_cols = self.evm_word_column_info(contract);