mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-23 03:29:05 +00:00
Fix getting values for arrays. (#73)
Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
parent
7d609f9a2b
commit
e3ef17d547
@ -26,24 +26,24 @@ $ yarn test
|
||||
* [x] Fixed-size byte arrays
|
||||
* [x] Enums
|
||||
* [ ] Function Types
|
||||
* [ ] Reference Types
|
||||
* [ ] Arrays
|
||||
* [x] Reference Types
|
||||
* [x] Arrays
|
||||
* [x] Get all elements in array
|
||||
* [x] Get element in array by index
|
||||
* [ ] Fixed size arrays
|
||||
* [x] Fixed size arrays
|
||||
* [x] Integer Type
|
||||
* [x] Boolean Type
|
||||
* [x] Address Type
|
||||
* [ ] Fixed-size byte arrays
|
||||
* [x] Fixed-size byte arrays
|
||||
* [x] Enum type
|
||||
* [x] Dynamically-sized byte array
|
||||
* [x] Struct Type
|
||||
* [x] Mapping Type
|
||||
* [ ] Dynamically-sized arrays
|
||||
* [x] Dynamically-sized arrays
|
||||
* [x] Integer Type
|
||||
* [x] Boolean Type
|
||||
* [x] Address Type
|
||||
* [ ] Fixed-size byte arrays
|
||||
* [x] Fixed-size byte arrays
|
||||
* [x] Enum Type
|
||||
* [x] Dynamically-sized byte array
|
||||
* [x] Struct Type
|
||||
@ -54,14 +54,14 @@ $ yarn test
|
||||
* [x] Dynamically-sized byte array
|
||||
* [x] Bytes
|
||||
* [x] String
|
||||
* [ ] Structs
|
||||
* [x] Structs
|
||||
* [x] Get struct value with all members
|
||||
* [x] Value Types
|
||||
* [x] Get value of a single member in struct
|
||||
* [ ] Reference Types
|
||||
* [x] Reference Types
|
||||
* [x] Struct type members (nested)
|
||||
* [x] Fixed size Array members
|
||||
* [ ] Dynamically sized Array members
|
||||
* [x] Dynamically sized Array members
|
||||
* [x] Bytes and string type members
|
||||
* [x] Mapping type members
|
||||
* [ ] Mapping Types
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user