mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-09 04:48:05 +00:00
Get array element by specifying index.
This commit is contained in:
parent
8851882144
commit
b33ce0b640
@ -29,7 +29,7 @@ $ yarn test
|
|||||||
* [ ] Reference Types
|
* [ ] Reference Types
|
||||||
* [ ] Arrays
|
* [ ] Arrays
|
||||||
* [x] Get all elements in array
|
* [x] Get all elements in array
|
||||||
* [ ] Get element in array by index
|
* [x] Get element in array by index
|
||||||
* [ ] Fixed size arrays
|
* [ ] Fixed size arrays
|
||||||
* [x] Integer Type
|
* [x] Integer Type
|
||||||
* [x] Boolean Type
|
* [x] Boolean Type
|
||||||
|
@ -271,64 +271,64 @@ describe('Get value from storage', () => {
|
|||||||
|
|
||||||
describe('fixed size arrays', () => {
|
describe('fixed size arrays', () => {
|
||||||
let testFixedArrays: Contract, storageLayout: StorageLayout;
|
let testFixedArrays: Contract, storageLayout: StorageLayout;
|
||||||
|
const int128Array = [100, 200, 300, 400, 500];
|
||||||
|
const uint16Array = [10, 20, 30, 40, 50];
|
||||||
|
const boolArray = [true, false];
|
||||||
|
let addressArray: string[] = [];
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
const TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
const TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
||||||
testFixedArrays = await TestFixedArrays.deploy();
|
testFixedArrays = await TestFixedArrays.deploy();
|
||||||
await testFixedArrays.deployed();
|
await testFixedArrays.deployed();
|
||||||
storageLayout = await getStorageLayout('TestFixedArrays');
|
storageLayout = await getStorageLayout('TestFixedArrays');
|
||||||
|
|
||||||
|
const signers = await ethers.getSigners();
|
||||||
|
addressArray = signers.map(signer => signer.address.toLowerCase())
|
||||||
|
.slice(0, 4);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Get all elements of array.
|
||||||
// Test for array variables which are 32 bytes or less and packed into a single slot.
|
// Test for array variables which are 32 bytes or less and packed into a single slot.
|
||||||
it('get value for fixed size arrays using single slot', async () => {
|
it('get value for fixed size arrays using single slot', async () => {
|
||||||
let expectedValue: Array<number|boolean> = [true, false];
|
await testFixedArrays.setBoolArray(boolArray);
|
||||||
|
|
||||||
await testFixedArrays.setBoolArray(expectedValue);
|
|
||||||
let blockHash = await getBlockHash();
|
let blockHash = await getBlockHash();
|
||||||
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'boolArray');
|
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'boolArray');
|
||||||
expect(value).to.eql(expectedValue);
|
expect(value).to.eql(boolArray);
|
||||||
let proofData = JSON.parse(proof.data);
|
let proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
expect(proofData.length).to.equal(boolArray.length);
|
||||||
|
|
||||||
expectedValue = [1, 2, 3, 4, 5];
|
await testFixedArrays.setUint16Array(uint16Array);
|
||||||
await testFixedArrays.setUint16Array(expectedValue);
|
|
||||||
blockHash = await getBlockHash();
|
blockHash = await getBlockHash();
|
||||||
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uint16Array'));
|
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uint16Array'));
|
||||||
expect(value).to.eql(expectedValue.map(el => BigInt(el)));
|
expect(value).to.eql(uint16Array.map(el => BigInt(el)));
|
||||||
proofData = JSON.parse(proof.data);
|
proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
expect(proofData.length).to.equal(uint16Array.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Test for array variables which are more than 32 bytes and use multiple slots.
|
// Test for array variables which are more than 32 bytes and use multiple slots.
|
||||||
it('get value for fixed size arrays using multiple slots', async () => {
|
it('get value for fixed size arrays using multiple slots', async () => {
|
||||||
const expectedValue = [1, 2, 3, 4, 5];
|
await testFixedArrays.setInt128Array(int128Array);
|
||||||
|
|
||||||
await testFixedArrays.setInt128Array(expectedValue);
|
|
||||||
let blockHash = await getBlockHash();
|
let blockHash = await getBlockHash();
|
||||||
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'int128Array');
|
let { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'int128Array');
|
||||||
expect(value).to.eql(expectedValue.map(el => BigInt(el)));
|
expect(value).to.eql(int128Array.map(el => BigInt(el)));
|
||||||
let proofData = JSON.parse(proof.data);
|
let proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
expect(proofData.length).to.equal(int128Array.length);
|
||||||
|
|
||||||
await testFixedArrays.setUintArray(expectedValue);
|
await testFixedArrays.setUintArray(uint16Array);
|
||||||
blockHash = await getBlockHash();
|
blockHash = await getBlockHash();
|
||||||
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uintArray'));
|
({ value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uintArray'));
|
||||||
expect(value).to.eql(expectedValue.map(el => BigInt(el)));
|
expect(value).to.eql(uint16Array.map(el => BigInt(el)));
|
||||||
proofData = JSON.parse(proof.data);
|
proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
expect(proofData.length).to.equal(uint16Array.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('get value for fixed size arrays of address type', async () => {
|
it('get value for fixed size arrays of address type', async () => {
|
||||||
const signers = await ethers.getSigners();
|
await testFixedArrays.setAddressArray(addressArray);
|
||||||
const expectedValue = signers.map(signer => signer.address.toLowerCase())
|
|
||||||
.slice(0, 4);
|
|
||||||
|
|
||||||
await testFixedArrays.setAddressArray(expectedValue);
|
|
||||||
const blockHash = await getBlockHash();
|
const blockHash = await getBlockHash();
|
||||||
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray');
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray');
|
||||||
expect(value).to.eql(expectedValue);
|
expect(value).to.eql(addressArray);
|
||||||
const proofData = JSON.parse(proof.data);
|
const proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
expect(proofData.length).to.equal(addressArray.length);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('get value for fixed size arrays of fixed size bytes type', async () => {
|
it.skip('get value for fixed size arrays of fixed size bytes type', async () => {
|
||||||
@ -341,6 +341,39 @@ describe('Get value from storage', () => {
|
|||||||
const proofData = JSON.parse(proof.data);
|
const proofData = JSON.parse(proof.data);
|
||||||
expect(proofData.length).to.equal(expectedValue.length);
|
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;
|
||||||
|
await testFixedArrays.setInt128Array(int128Array);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'int128Array', arrayIndex);
|
||||||
|
expect(value).to.equal(BigInt(int128Array[arrayIndex]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get value of unsigned integer type array by index', async () => {
|
||||||
|
const arrayIndex = 3;
|
||||||
|
await testFixedArrays.setUint16Array(uint16Array);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'uint16Array', arrayIndex);
|
||||||
|
expect(value).to.equal(BigInt(uint16Array[arrayIndex]));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get value of boolean type array by index', async () => {
|
||||||
|
const arrayIndex = 0;
|
||||||
|
await testFixedArrays.setBoolArray(boolArray);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'boolArray', arrayIndex);
|
||||||
|
expect(value).to.equal(boolArray[arrayIndex]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get value of address type array by index', async () => {
|
||||||
|
const arrayIndex = 1;
|
||||||
|
await testFixedArrays.setAddressArray(addressArray);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray', arrayIndex);
|
||||||
|
expect(value).to.equal(addressArray[arrayIndex]);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('structs type', () => {
|
describe('structs type', () => {
|
||||||
|
@ -119,12 +119,24 @@ const getDecodedValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
baseNumberOfBytes = '32';
|
baseNumberOfBytes = '32';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getArrayElement = async (index: number, mappingKeys: MappingKey[]) => {
|
||||||
|
const arrayOffset = index * Number(baseNumberOfBytes);
|
||||||
|
const arraySlot = BigNumber.from(slot).add(Math.floor(arrayOffset / 32)).toHexString();
|
||||||
|
const arraySlotOffset = arrayOffset % 32;
|
||||||
|
|
||||||
|
return getDecodedValue(getStorageAt, blockHash, address, types, { slot: arraySlot, offset: arraySlotOffset, type: base }, mappingKeys);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [arrayIndex, ...remainingKeys] = mappingKeys;
|
||||||
|
|
||||||
|
if (typeof arrayIndex === 'number') {
|
||||||
|
return getArrayElement(arrayIndex, remainingKeys);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Get values in single call and parse according to type.
|
// TODO: Get values in single call and parse according to type.
|
||||||
// Loop over elements of array and get value.
|
// Loop over elements of array and get value.
|
||||||
for (let i = 0; i < Number(baseNumberOfBytes) * Number(arraySize); i = i + Number(baseNumberOfBytes)) {
|
for (let i = 0; i < Number(arraySize); i++) {
|
||||||
const arraySlot = BigNumber.from(slot).add(Math.floor(i / 32)).toHexString();
|
({ value, proof } = await getArrayElement(i, mappingKeys));
|
||||||
const slotOffset = i % 32;
|
|
||||||
({ value, proof } = await getDecodedValue(getStorageAt, blockHash, address, types, { slot: arraySlot, offset: slotOffset, type: base }, []));
|
|
||||||
resultArray.push(value);
|
resultArray.push(value);
|
||||||
|
|
||||||
// Each element in array gets its own proof even if it is packed.
|
// Each element in array gets its own proof even if it is packed.
|
||||||
|
Loading…
Reference in New Issue
Block a user