Tests for maps with struct type value and double nested maps (#58)

* Tests for fixed array of struct type.

* Add tests for maps with struct type value and double nested maps.

Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
Ashwin Phatak 2021-06-14 16:23:41 +05:30 committed by GitHub
parent f5c1a22fdc
commit eb20708faf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 178 additions and 29 deletions

View File

@ -37,7 +37,7 @@ $ yarn test
* [ ] Fixed-size byte arrays
* [ ] Enum type
* [ ] Dynamically-sized byte array
* [ ] Struct Type
* [x] Struct Type
* [ ] Mapping Type
* [ ] Dynamically-sized arrays
* [ ] Integer Type
@ -64,6 +64,9 @@ $ yarn test
* [ ] Fixed-size byte array keys
* [x] Dynamically-sized byte array keys
* [ ] Reference Type Mapping values
* [x] Struct type values
* [ ] Array type values
* [ ] Dynamically sized Bytes and string type values
* [x] Nested Mapping
## Observations

View File

@ -16,7 +16,7 @@ task('accounts', 'Prints the list of accounts', async (args, hre) => {
const config: HardhatUserConfig = {
solidity: {
version: '0.7.3',
version: '0.7.6',
settings: {
outputSelection: {
'*': {

View File

@ -342,6 +342,27 @@ describe('Get value from storage', () => {
expect(proofData.length).to.equal(expectedValue.length);
});
it('get value for fixed size array of struct type', async () => {
const expectedValue = [];
for (let i = 0; i < 5; i++) {
const structElement = {
int1: BigInt(i + 1),
uint1: BigInt(i + 2),
bool1: Boolean(i % 2)
};
expectedValue[i] = structElement;
await testFixedArrays.setStructArray(structElement, i);
}
const blockHash = await getBlockHash();
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray');
expect(value).to.eql(expectedValue);
const proofData = JSON.parse(proof.data);
expect(proofData.length).to.equal(expectedValue.length);
});
// Get element of array by index.
it('get value of signed integer type array by index', async () => {
const arrayIndex = 2;
@ -374,6 +395,25 @@ describe('Get value from storage', () => {
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray', arrayIndex);
expect(value).to.equal(addressArray[arrayIndex]);
});
it('get value of struct type array by index', async () => {
const expectedValue = {
int1: BigInt(123),
uint1: BigInt(456),
bool1: false
};
const arrayIndex = 2;
await testFixedArrays.setStructArray(expectedValue, arrayIndex);
const blockHash = await getBlockHash();
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray', arrayIndex);
expect(value).to.eql(expectedValue);
// Get value of specified struct member in array element.
const structMember = 'uint1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'structArray', arrayIndex, structMember));
expect(value).to.eql(expectedValue[structMember]);
});
});
describe('structs with value type members', () => {
@ -381,7 +421,12 @@ describe('Get value from storage', () => {
/* eslint-disable @typescript-eslint/no-explicit-any */
let addressStruct: { [key: string]: any }, contractStruct: { [key: string]: any };
const multipleSlotStruct = {
const singleSlotStruct = {
int1: BigInt(123),
uint1: BigInt(4)
};
const multipleSlotStruct: { [key: string]: any } = {
uint1: BigInt(123),
bool1: false,
int1: BigInt(456)
@ -426,15 +471,10 @@ describe('Get value from storage', () => {
// Get all members of a struct.
it('get value for struct using a single slot', async () => {
const expectedValue = {
int1: BigInt(123),
uint1: BigInt(4)
};
await testValueStructs.setSingleSlotStruct(expectedValue.int1, expectedValue.uint1);
await testValueStructs.setSingleSlotStruct(singleSlotStruct.int1, singleSlotStruct.uint1);
const blockHash = await getBlockHash();
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct');
expect(value).to.eql(expectedValue);
expect(value).to.eql(singleSlotStruct);
const proofData = JSON.parse(proof.data);
expect(proofData).to.have.all.keys('int1', 'uint1');
});
@ -449,7 +489,7 @@ describe('Get value from storage', () => {
});
it('get value for struct with address type members', async () => {
await testValueStructs.setAddressStruct(addressStruct.int1, addressStruct.address1, addressStruct.address2, addressStruct.uint1);
await testValueStructs.setAddressStruct(addressStruct);
const blockHash = await getBlockHash();
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct');
expect(value).to.eql(addressStruct);
@ -487,31 +527,45 @@ describe('Get value from storage', () => {
// Get value of a member in a struct
it('get value of signed integer type member in a struct', async () => {
const member = 'int1';
await testValueStructs.setMultipleSlotStruct(multipleSlotStruct.uint1, multipleSlotStruct.bool1, multipleSlotStruct.int1);
await testValueStructs.setSingleSlotStruct(singleSlotStruct.int1, singleSlotStruct.uint1);
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member);
expect(value).to.equal(multipleSlotStruct[member]);
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct', member);
expect(value).to.equal(singleSlotStruct[member]);
});
it('get value of unsigned integer type member in a struct', async () => {
const member = 'uint1';
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member);
expect(value).to.equal(multipleSlotStruct[member]);
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'singleSlotStruct', member);
expect(value).to.equal(singleSlotStruct[member]);
});
it('get value of boolean type member in a struct', async () => {
const member = 'bool1';
await testValueStructs.setMultipleSlotStruct(multipleSlotStruct.uint1, multipleSlotStruct.bool1, multipleSlotStruct.int1);
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member);
let member = 'bool1';
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member);
expect(value).to.equal(multipleSlotStruct[member]);
member = 'int1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member));
expect(value).to.equal(multipleSlotStruct[member]);
member = 'uint1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'multipleSlotStruct', member));
expect(value).to.equal(multipleSlotStruct[member]);
});
it('get value of address type member in a struct', async () => {
const member = 'address1';
await testValueStructs.setAddressStruct(addressStruct.int1, addressStruct.address1, addressStruct.address2, addressStruct.uint1);
await testValueStructs.setAddressStruct(addressStruct);
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct', member);
let member = 'address1';
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct', member);
expect(value).to.equal(addressStruct[member]);
member = 'uint1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testValueStructs.address, 'addressStruct', member));
expect(value).to.equal(addressStruct[member]);
});
@ -644,6 +698,7 @@ describe('Get value from storage', () => {
storageLayout = await getStorageLayout('TestBasicMapping');
});
// Tests for value type keys.
it('get value for mapping with address type keys', async () => {
const expectedValue = 123;
const [, signer1] = await ethers.getSigners();
@ -698,6 +753,7 @@ describe('Get value from storage', () => {
expect(value).to.equal(BigInt(expectedValue));
});
// Tests for reference type keys.
it('get value for mapping with string type keys', async () => {
const mapKey = 'abc';
const expectedValue = 123;
@ -715,6 +771,45 @@ describe('Get value from storage', () => {
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'bytesUintMap', mapKey);
expect(value).to.equal(BigInt(expectedValue));
});
// Tests for reference type values.
it('get value for mapping with struct type values', async () => {
const expectedValue = {
uint1: BigInt(123),
int1: BigInt(456),
bool1: true
};
const mapKey = 123;
await testMappingTypes.setIntStructMap(mapKey, expectedValue);
const blockHash = await getBlockHash();
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intStructMap', mapKey);
expect(value).to.eql(expectedValue);
// Get value of specified struct member in mapping.
const structMember = 'bool1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'intStructMap', mapKey, structMember));
expect(value).to.equal(expectedValue[structMember]);
});
it('get value for mapping of fixed size bytes keys and struct type values', async () => {
const expectedValue = {
uint1: BigInt(123),
int1: BigInt(456),
bool1: true
};
const mapKey = ethers.utils.hexlify(ethers.utils.randomBytes(32));
await testMappingTypes.setFixedBytesStructMap(mapKey, expectedValue);
const blockHash = await getBlockHash();
let { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey);
expect(value).to.eql(expectedValue);
// Get value of specified struct member in mapping.
const structMember = 'int1';
({ value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testMappingTypes.address, 'fixedBytesStructMap', mapKey, structMember));
expect(value).to.equal(expectedValue[structMember]);
});
});
describe('nested mapping type', () => {
@ -775,5 +870,14 @@ describe('Get value from storage', () => {
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'stringAddressIntMap', key, signer1.address);
expect(value).to.equal(BigInt(expectedValue));
});
it('get value for double nested mapping with address type keys', async () => {
const [signer1, signer2, signer3] = await ethers.getSigners();
const uintKey = 123;
await testNestedMapping.setDoubleNestedAddressMap(signer1.address, signer2.address, uintKey, signer3.address);
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testNestedMapping.address, 'doubleNestedAddressMap', signer1.address, signer2.address, uintKey);
expect(value).to.equal(signer3.address.toLowerCase());
});
});
});

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.7.6;
pragma abicoder v2;
contract TestBasicMapping {
// Mapping type variable occupies one single slot but the actual elements are stored at a different storage slot that is computed using a Keccak-256 hash.
@ -30,6 +31,18 @@ contract TestBasicMapping {
// Mapping with dynamically-sized byte array as keys and unsigned integer type values.
mapping(bytes => uint) public bytesUintMap;
struct TestStruct {
uint128 uint1;
int56 int1;
bool bool1;
}
// Mapping with signed integer as keys and struct type values.
mapping(int24 => TestStruct) public intStructMap;
// Mapping with signed integer as keys and struct type values.
mapping(bytes32 => TestStruct) public fixedBytesStructMap;
// Set variable addressUintMap.
function setAddressUintMap(uint value) external {
addressUintMap[msg.sender] = value;
@ -69,4 +82,14 @@ contract TestBasicMapping {
function setBytesUintMap(bytes calldata key, uint value) external {
bytesUintMap[key] = value;
}
// Set variable intStruct.
function setIntStructMap(int24 key, TestStruct calldata value) external {
intStructMap[key] = value;
}
// Set variable fixedBytesStructMap.
function setFixedBytesStructMap(bytes32 key, TestStruct calldata value) external {
fixedBytesStructMap[key] = value;
}
}

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.7.6;
pragma abicoder v2;
contract TestFixedArrays {
// Fixed size array variable will use 5 consecutive slots as size of 1 element is 32 bytes.
@ -19,6 +20,14 @@ contract TestFixedArrays {
bytes10[5] bytesArray;
struct TestStruct {
uint32 uint1;
int56 int1;
bool bool1;
}
TestStruct[5] structArray;
// Set variable boolArray.
function setBoolArray(bool[2] calldata value) external {
boolArray = value;
@ -48,4 +57,9 @@ contract TestFixedArrays {
function setBytesArray(bytes10[5] calldata value) external {
bytesArray = value;
}
// Set variable structArray.
function setStructArray(TestStruct calldata value, uint index) external {
structArray[index] = value;
}
}

View File

@ -14,6 +14,8 @@ contract TestNestedMapping {
mapping (string => mapping (address => int)) private stringAddressIntMap;
mapping (address => mapping (address => mapping (uint24 => address))) public doubleNestedAddressMap;
// Set variable nestedAddressUintMap.
function setNestedAddressUintMap(address nestedKey, uint value) external {
nestedAddressUintMap[msg.sender][nestedKey] = value;
@ -38,4 +40,9 @@ contract TestNestedMapping {
function setStringAddressIntMap(string calldata key, address nestedKey, int value) external {
stringAddressIntMap[key][nestedKey] = value;
}
// Set variable doubleNestedAddressMap.
function setDoubleNestedAddressMap(address key, address nestedKey, uint24 doubleNestedKey, address value) external {
doubleNestedAddressMap[key][nestedKey][doubleNestedKey] = value;
}
}

View File

@ -1,5 +1,6 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.7.0;
pragma solidity ^0.7.6;
pragma abicoder v2;
import "./TestContractTypes.sol";
@ -69,11 +70,8 @@ contract TestValueStructs {
}
// Set variable addressStruct.
function setAddressStruct(int8 int1Value, address address1Value, address address2Value, uint16 uint1Value) external {
addressStruct.int1 = int1Value;
addressStruct.address1 = address1Value;
addressStruct.address2 = address2Value;
addressStruct.uint1 = uint1Value;
function setAddressStruct(AddressStruct calldata value) external {
addressStruct = value;
}
// Set variable contractStruct.