Fix getting values for arrays. (#73)

Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
Ashwin Phatak
2021-06-17 11:59:53 +05:30
committed by GitHub
co-authored by nikugogoi
parent 7d609f9a2b
commit e3ef17d547
3 changed files with 32 additions and 24 deletions
+8 -5
View File
@@ -367,7 +367,7 @@ describe('Get value from storage', () => {
expect(proofData.length).to.equal(addressArray.length);
});
it.skip('get value for fixed size arrays of fixed size bytes type', async () => {
it('get value for fixed size arrays of fixed size bytes type', async () => {
const expectedValue = Array.from({ length: 5 }, () => ethers.utils.hexlify(ethers.utils.randomBytes(10)));
await testFixedArrays.setFixedBytesArray(expectedValue);
@@ -592,7 +592,7 @@ describe('Get value from storage', () => {
expect(value).to.equal(addressArray[arrayIndex]);
});
it.skip('get value for dynamic sized array of fixed size byte array', async () => {
it('get value for dynamic sized array of fixed size byte array', async () => {
const fixedBytesArray = Array.from({ length: 4 }, () => ethers.utils.hexlify(ethers.utils.randomBytes(10)));
await testDynamicArrays.setFixedBytesArray(fixedBytesArray);
const blockHash = await getBlockHash();
@@ -1072,7 +1072,7 @@ describe('Get value from storage', () => {
};
dynamicArrayStruct = {
address1: signers[4].address,
address1: signers[4].address.toLowerCase(),
uintArray: [1, 2, 3, 4, 5].map(BigInt)
};
});
@@ -1099,7 +1099,7 @@ describe('Get value from storage', () => {
expect(value).to.eql(stringStruct);
});
it.skip('get value for struct with dynamic array members', async () => {
it('get value for struct with dynamic array members', async () => {
await testReferenceStructs.setDynamicArrayStruct(dynamicArrayStruct);
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'dynamicArrayStruct');
@@ -1138,7 +1138,7 @@ describe('Get value from storage', () => {
expect(value).to.eql(stringStruct[member]);
});
it.skip('get value of dynamic array member in a struct', async () => {
it('get value of dynamic array member in a struct', async () => {
const member = 'uintArray';
const blockHash = await getBlockHash();
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testReferenceStructs.address, 'dynamicArrayStruct', member);
@@ -1247,6 +1247,9 @@ describe('Get value from storage', () => {
expect(value).to.equal(expectedValue);
});
// TODO: Fix getting value for mapping with keys as fixed-size byte array
// Zero value is returned if using fixed-sized byte array keys of length less than 32 bytes
// Type Bytes32 works whereas types like bytes16, bytes24 do not work.
it.skip('get value for mapping with fixed-size byte array keys', async () => {
const mapKey = ethers.utils.hexlify(ethers.utils.randomBytes(8));
const [, signer1] = await ethers.getSigners();
+15 -10
View File
@@ -219,17 +219,22 @@ const getDynamicArrayInfo = async (getStorageAt: GetStorageAt, blockHash: string
const getArrayValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, types: Types, mappingKeys: MappingKey[], slot: string, base: string, arraySize: number) => {
const resultArray = [];
const proofs = [];
let { numberOfBytes: baseNumberOfBytes, label: baseTypeLabel } = types[base];
// Address type elements use an entire single slot i.e. 32 bytes.
if (baseTypeLabel === 'address' || baseTypeLabel.includes('contract')) {
baseNumberOfBytes = '32';
}
const { numberOfBytes: baseNumberOfBytes } = types[base];
const getArrayElement = async (mappingKeys: MappingKey[], index: number) => {
const arrayOffset = index * Number(baseNumberOfBytes);
const arraySlot = BigNumber.from(slot).add(Math.floor(arrayOffset / 32)).toHexString();
const arraySlotOffset = arrayOffset % 32;
let arraySlotOffset = 0;
let slotIndex;
if (Number(baseNumberOfBytes) <= 32) {
const elementsInSlot = Math.floor(32 / Number(baseNumberOfBytes));
slotIndex = Math.floor(index / elementsInSlot);
arraySlotOffset = (index % elementsInSlot) * Number(baseNumberOfBytes);
} else {
const slotsUsedByElement = Math.ceil(Number(baseNumberOfBytes) / 32);
slotIndex = slotsUsedByElement * index;
}
const arraySlot = BigNumber.from(slot).add(slotIndex).toHexString();
return getDecodedValue(getStorageAt, blockHash, address, types, { slot: arraySlot, offset: arraySlotOffset, type: base }, mappingKeys);
};
@@ -240,7 +245,6 @@ const getArrayValue = async (getStorageAt: GetStorageAt, blockHash: string, addr
return getArrayElement(remainingKeys, arrayIndex);
}
// TODO: Get values in single call and parse according to type.
// Loop over elements of array and get value.
for (let i = 0; i < arraySize; i++) {
const { value, proof } = await getArrayElement(mappingKeys, i);
@@ -309,6 +313,7 @@ const getStructureValue = async (getStorageAt: GetStorageAt, blockHash: string,
* @param getStorageAt
*/
const getInplaceValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string, offset: number, numberOfBytes: string) => {
// TODO: Memoize getStorageAt function for duplicate multiple calls.
const { value, proof } = await getStorageAt({ blockHash, contract: address, slot });
const valueLength = utils.hexDataLength(value);