Skip to content

Commit

Permalink
Add mapping of mappings test cases to the integration test.
Browse files Browse the repository at this point in the history
  • Loading branch information
silathdiir committed Nov 13, 2024
1 parent c21fe13 commit 22ea1d2
Show file tree
Hide file tree
Showing 12 changed files with 2,980 additions and 600 deletions.
2 changes: 1 addition & 1 deletion mp2-v1/src/values_extraction/leaf_mapping_of_mappings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ where
.collect();
let hash = b.hash_n_to_hash_no_pad::<CHasher>(inputs);
let row_id = hash_to_int_target(b, hash);
let row_id = b.biguint_to_nonnative(&row_id);

// values_digest = values_digest * row_id
let row_id = b.biguint_to_nonnative(&row_id);
let values_digest = b.curve_scalar_mul(values_digest, &row_id);

// Only one leaf in this node.
Expand Down
69 changes: 67 additions & 2 deletions mp2-v1/test-contracts/src/Simple.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,22 @@ contract Simple {
MappingOperation operation;
}

struct MappingOfSingleValueMappingsChange {
uint256 outerKey;
uint256 innerKey;
uint256 value;
MappingOperation operation;
}

struct MappingOfStructMappingsChange {
uint256 outerKey;
uint256 innerKey;
uint256 field1;
uint128 field2;
uint128 field3;
MappingOperation operation;
}

struct LargeStruct {
// This field should live in one EVM word
uint256 field1;
Expand All @@ -48,9 +64,13 @@ contract Simple {
// Test mapping struct (slot 8)
mapping(uint256 => LargeStruct) public structMapping;

// Test mapping of mappings (slot 9)
// Test mapping of single value mappings (slot 9)
mapping(uint256 => mapping(uint256 => uint256))
public mappingOfSingleValueMappings;

// Test mapping of struct mappings (slot 10)
mapping(uint256 => mapping(uint256 => LargeStruct))
public mappingOfMappings;
public mappingOfStructMappings;

// Set the simple slots.
function setSimples(
Expand Down Expand Up @@ -125,4 +145,49 @@ contract Simple {
}
}

// Set mapping of single value mappings.
function setMappingOfSingleValueMappings(
uint256 outerKey,
uint256 innerKey,
uint256 value
) public {
mappingOfSingleValueMappings[outerKey][innerKey] = value;
}

function changeMappingOfSingleValueMappings(MappingOfSingleValueMappingsChange[] memory changes) public {
for (uint256 i = 0; i < changes.length; i++) {
if (changes[i].operation == MappingOperation.Deletion) {
delete mappingOfSingleValueMappings[changes[i].outerKey][changes[i].innerKey];
} else if (
changes[i].operation == MappingOperation.Insertion ||
changes[i].operation == MappingOperation.Update
) {
setMappingOfSingleValueMappings(changes[i].outerKey, changes[i].innerKey, changes[i].value);
}
}
}

// Set mapping of struct mappings.
function setMappingOfStructMappings(
uint256 outerKey,
uint256 innerKey,
uint256 field1,
uint128 field2,
uint128 field3
) public {
mappingOfStructMappings[outerKey][innerKey] = LargeStruct(field1, field2, field3);
}

function changeMappingOfStructMappings(MappingOfStructMappingsChange[] memory changes) public {
for (uint256 i = 0; i < changes.length; i++) {
if (changes[i].operation == MappingOperation.Deletion) {
delete mappingOfStructMappings[changes[i].outerKey][changes[i].innerKey];
} else if (
changes[i].operation == MappingOperation.Insertion ||
changes[i].operation == MappingOperation.Update
) {
setMappingOfStructMappings(changes[i].outerKey, changes[i].innerKey, changes[i].field1, changes[i].field2, changes[i].field3);
}
}
}
}
2,231 changes: 1,920 additions & 311 deletions mp2-v1/tests/common/bindings/simple.rs

Large diffs are not rendered by default.

171 changes: 166 additions & 5 deletions mp2-v1/tests/common/cases/contract.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use super::{
indexing::MappingUpdate,
storage_slot_value::{LargeStruct, StorageSlotValue},
slot_info::{LargeStruct, MappingKey, MappingOfMappingsKey, StorageSlotValue},
table_source::DEFAULT_ADDRESS,
};
use crate::common::{
bindings::simple::{
Simple,
Simple::{MappingChange, MappingOperation, MappingStructChange},
Simple::{
MappingChange, MappingOfSingleValueMappingsChange, MappingOfStructMappingsChange,
MappingOperation, MappingStructChange,
},
},
TestContext,
};
Expand Down Expand Up @@ -121,7 +123,27 @@ impl ContractController for LargeStruct {
}
}

impl ContractController for Vec<MappingUpdate<Address>> {
#[derive(Clone, Debug)]
pub enum MappingUpdate<K, V> {
// key and value
Insertion(K, V),
// key and value
Deletion(K, V),
// key, previous value and new value
Update(K, V, V),
}

impl<K, V> From<&MappingUpdate<K, V>> for MappingOperation {
fn from(update: &MappingUpdate<K, V>) -> Self {
Self::from(match update {
MappingUpdate::Deletion(_, _) => 0,
MappingUpdate::Update(_, _, _) => 1,
MappingUpdate::Insertion(_, _) => 2,
})
}
}

impl ContractController for Vec<MappingUpdate<MappingKey, Address>> {
async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self {
unimplemented!("Unimplemented for fetching the all mapping values")
}
Expand Down Expand Up @@ -178,7 +200,7 @@ impl ContractController for Vec<MappingUpdate<Address>> {
}
}

impl ContractController for Vec<MappingUpdate<LargeStruct>> {
impl ContractController for Vec<MappingUpdate<MappingKey, LargeStruct>> {
async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self {
unimplemented!("Unimplemented for fetching the all mapping values")
}
Expand Down Expand Up @@ -233,3 +255,142 @@ impl ContractController for Vec<MappingUpdate<LargeStruct>> {
log::info!("Updated simple contract for mapping values of LargeStruct");
}
}

impl ContractController for Vec<MappingUpdate<MappingOfMappingsKey, U256>> {
async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self {
unimplemented!("Unimplemented for fetching the all mapping of mappings")
}

async fn update_contract(&self, ctx: &TestContext, contract: &Contract) {
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(ctx.wallet())
.on_http(ctx.rpc_url.parse().unwrap());
let contract = Simple::new(contract.address, &provider);

let changes = self
.iter()
.map(|tuple| {
let operation: MappingOperation = tuple.into();
let operation = operation.into();
let (k, v) = match tuple {
MappingUpdate::Insertion(k, v)
| MappingUpdate::Deletion(k, v)
| MappingUpdate::Update(k, _, v) => (k, v),
};

MappingOfSingleValueMappingsChange {
operation,
outerKey: k.outer_key,
innerKey: k.inner_key,
value: v.clone(),
}
})
.collect_vec();

let call = contract.changeMappingOfSingleValueMappings(changes);
call.send().await.unwrap().watch().await.unwrap();
// Sanity check
for update in self.iter() {
match update {
MappingUpdate::Insertion(k, v) => {
let res = contract
.mappingOfSingleValueMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
assert_eq!(&res._0, v, "Insertion is wrong on contract");
}
MappingUpdate::Deletion(k, _) => {
let res = contract
.mappingOfSingleValueMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
assert_eq!(res._0, U256::ZERO, "Deletion is wrong on contract");
}
MappingUpdate::Update(k, _, v) => {
let res = contract
.mappingOfSingleValueMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
assert_eq!(&res._0, v, "Update is wrong on contract");
}
}
}
log::info!("Updated simple contract for mapping of single value mappings");
}
}

impl ContractController for Vec<MappingUpdate<MappingOfMappingsKey, LargeStruct>> {
async fn current_values(_ctx: &TestContext, _contract: &Contract) -> Self {
unimplemented!("Unimplemented for fetching the all mapping of mappings")
}

async fn update_contract(&self, ctx: &TestContext, contract: &Contract) {
let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(ctx.wallet())
.on_http(ctx.rpc_url.parse().unwrap());
let contract = Simple::new(contract.address, &provider);

let changes = self
.iter()
.map(|tuple| {
let operation: MappingOperation = tuple.into();
let operation = operation.into();
let (k, v) = match tuple {
MappingUpdate::Insertion(k, v)
| MappingUpdate::Deletion(k, v)
| MappingUpdate::Update(k, _, v) => (k, v),
};

MappingOfStructMappingsChange {
operation,
outerKey: k.outer_key,
innerKey: k.inner_key,
field1: v.field1,
field2: v.field2,
field3: v.field3,
}
})
.collect_vec();

let call = contract.changeMappingOfStructMappings(changes);
call.send().await.unwrap().watch().await.unwrap();
// Sanity check
for update in self.iter() {
match update {
MappingUpdate::Insertion(k, v) => {
let res = contract
.mappingOfStructMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
let res = LargeStruct::from(res);
assert_eq!(&res, v, "Insertion is wrong on contract");
}
MappingUpdate::Deletion(k, _) => {
let res = contract
.mappingOfStructMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
let res = LargeStruct::from(res);
assert_eq!(res, LargeStruct::default(), "Deletion is wrong on contract");
}
MappingUpdate::Update(k, _, v) => {
let res = contract
.mappingOfStructMappings(k.outer_key, k.inner_key)
.call()
.await
.unwrap();
let res = LargeStruct::from(res);
assert_eq!(&res, v, "Update is wrong on contract");
}
}
}
log::info!("Updated simple contract for mapping of LargeStruct mappings");
}
}
Loading

0 comments on commit 22ea1d2

Please sign in to comment.