Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Receipt Trie: Refactor MappingInfo Trait in Integration Test #454

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 10 additions & 14 deletions mp2-v1/tests/common/cases/contract.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -166,21 +166,17 @@ impl ContractController for LargeStruct {
}

#[derive(Clone, Debug)]
pub enum MappingUpdate<K, V> {
pub(crate) enum MappingUpdate<T: MappingInfo> {
// 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<K, V> MappingUpdate<K, V>
where
K: StorageSlotMappingKey,
V: StorageSlotValue,
{
pub fn to_tuple(&self) -> (K, V) {
impl<T: MappingInfo> MappingUpdate<T> {
pub fn to_tuple(&self) -> (T::Key, T::Value) {
match self {
MappingUpdate::Insertion(key, value)
| MappingUpdate::Deletion(key, value)
Expand All @@ -189,8 +185,8 @@ where
}
}

impl<K, V> From<&MappingUpdate<K, V>> for MappingOperation {
fn from(update: &MappingUpdate<K, V>) -> Self {
impl<T: MappingInfo> From<&MappingUpdate<T>> for MappingOperation {
fn from(update: &MappingUpdate<T>) -> Self {
Self::from(match update {
MappingUpdate::Deletion(_, _) => 0,
MappingUpdate::Update(_, _, _) => 1,
Expand All @@ -199,7 +195,7 @@ impl<K, V> From<&MappingUpdate<K, V>> for MappingOperation {
}
}

impl<T: MappingInfo> ContractController for Vec<MappingUpdate<T, T::Value>> {
impl<T: MappingInfo> ContractController for Vec<MappingUpdate<T>> {
async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self {
unimplemented!("Unimplemented for fetching the all mapping values")
}
Expand Down
208 changes: 29 additions & 179 deletions mp2-v1/tests/common/cases/slot_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, Self::Value>) -> Self::Call;
fn to_call(update: &MappingUpdate<Self>) -> Self::Call;

fn call_contract<T: Transport + Clone, P: Provider<T, N>, N: Network>(
contract: &SimpleInstance<T, P, N>,
changes: Vec<Self::Call>,
) -> impl Future<Output = ()> + 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<SlotInput>, length: Option<u8>) -> SlotInputs {
if let Some(length_slot) = length {
SlotInputs::MappingWithLength(slot_inputs, length_slot)
} else {
SlotInputs::MappingOfMappings(slot_inputs)
}
}
fn to_u256_vec(&self) -> Vec<U256> {
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<Self, Self::Value>) -> MappingOfStructMappingsChange {
fn to_call(update: &MappingUpdate<Self>) -> 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,
Expand All @@ -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<SlotInput>, length: Option<u8>) -> SlotInputs {
if let Some(length_slot) = length {
SlotInputs::MappingWithLength(slot_inputs, length_slot)
} else {
SlotInputs::MappingOfMappings(slot_inputs)
}
}
fn to_u256_vec(&self) -> Vec<U256> {
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<Self, Self::Value>) -> MappingOfSingleValueMappingsChange {
fn to_call(update: &MappingUpdate<Self>) -> 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(),
}
Expand All @@ -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<SlotInput>, length: Option<u8>) -> SlotInputs {
if let Some(length_slot) = length {
SlotInputs::MappingWithLength(slot_inputs, length_slot)
} else {
SlotInputs::Mapping(slot_inputs)
}
}
fn to_u256_vec(&self) -> Vec<U256> {
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, Self::Value>) -> Self::Call {
fn to_call(update: &MappingUpdate<Self>) -> Self::Call {
let op: MappingOperation = update.into();

let (key, value) = update.to_tuple();

MappingChange {
key: key.inner,
key,
value,
operation: op.into(),
}
Expand All @@ -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<SlotInput>, length: Option<u8>) -> SlotInputs {
if let Some(length_slot) = length {
SlotInputs::MappingWithLength(slot_inputs, length_slot)
} else {
SlotInputs::Mapping(slot_inputs)
}
}
fn to_u256_vec(&self) -> Vec<U256> {
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<Self, Self::Value>) -> MappingStructChange {
fn to_call(update: &MappingUpdate<Self>) -> 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,
Expand All @@ -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;

Expand Down
Loading