mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-05-21 11:35:37 +00:00
Get fixed size array of type address (#53)
* Add test for fixed array of address type. * Add tests for verifying proof data. Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
parent
df025433ec
commit
5316b19fbf
@ -28,10 +28,12 @@ $ yarn test
|
|||||||
* [ ] Function Types
|
* [ ] Function Types
|
||||||
* [ ] Reference Types
|
* [ ] Reference Types
|
||||||
* [ ] Arrays
|
* [ ] Arrays
|
||||||
|
* [x] Get all elements in array
|
||||||
|
* [ ] Get element in array by index
|
||||||
* [ ] Fixed size arrays
|
* [ ] Fixed size arrays
|
||||||
* [x] Integer Type
|
* [x] Integer Type
|
||||||
* [x] Boolean Type
|
* [x] Boolean Type
|
||||||
* [ ] Address Type
|
* [x] Address Type
|
||||||
* [ ] Fixed-size byte arrays
|
* [ ] Fixed-size byte arrays
|
||||||
* [ ] Enum type
|
* [ ] Enum type
|
||||||
* [ ] Dynamically-sized byte array
|
* [ ] Dynamically-sized byte array
|
||||||
|
@ -269,45 +269,78 @@ describe('Get value from storage', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('fixed size arrays', () => {
|
||||||
|
let testFixedArrays: Contract, storageLayout: StorageLayout;
|
||||||
|
|
||||||
|
before(async () => {
|
||||||
|
const TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
||||||
|
testFixedArrays = await TestFixedArrays.deploy();
|
||||||
|
await testFixedArrays.deployed();
|
||||||
|
storageLayout = await getStorageLayout('TestFixedArrays');
|
||||||
|
});
|
||||||
|
|
||||||
// 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 () => {
|
||||||
const TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
|
||||||
const testFixedArrays = await TestFixedArrays.deploy();
|
|
||||||
await testFixedArrays.deployed();
|
|
||||||
const storageLayout = await getStorageLayout('TestFixedArrays');
|
|
||||||
|
|
||||||
let expectedValue: Array<number|boolean> = [true, false];
|
let expectedValue: Array<number|boolean> = [true, false];
|
||||||
|
|
||||||
await testFixedArrays.setBoolArray(expectedValue);
|
await testFixedArrays.setBoolArray(expectedValue);
|
||||||
let blockHash = await getBlockHash();
|
let blockHash = await getBlockHash();
|
||||||
let { value } = 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(expectedValue);
|
||||||
|
let proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.length);
|
||||||
|
|
||||||
expectedValue = [1, 2, 3, 4, 5];
|
expectedValue = [1, 2, 3, 4, 5];
|
||||||
await testFixedArrays.setUint16Array(expectedValue);
|
await testFixedArrays.setUint16Array(expectedValue);
|
||||||
blockHash = await getBlockHash();
|
blockHash = await getBlockHash();
|
||||||
({ value } = 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(expectedValue.map(el => BigInt(el)));
|
||||||
|
proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.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 TestFixedArrays = await ethers.getContractFactory('TestFixedArrays');
|
|
||||||
const testFixedArrays = await TestFixedArrays.deploy();
|
|
||||||
await testFixedArrays.deployed();
|
|
||||||
const storageLayout = await getStorageLayout('TestFixedArrays');
|
|
||||||
|
|
||||||
const expectedValue = [1, 2, 3, 4, 5];
|
const expectedValue = [1, 2, 3, 4, 5];
|
||||||
|
|
||||||
await testFixedArrays.setInt128Array(expectedValue);
|
await testFixedArrays.setInt128Array(expectedValue);
|
||||||
let blockHash = await getBlockHash();
|
let blockHash = await getBlockHash();
|
||||||
let { value } = 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(expectedValue.map(el => BigInt(el)));
|
||||||
|
let proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.length);
|
||||||
|
|
||||||
await testFixedArrays.setUintArray(expectedValue);
|
await testFixedArrays.setUintArray(expectedValue);
|
||||||
blockHash = await getBlockHash();
|
blockHash = await getBlockHash();
|
||||||
({ value } = 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(expectedValue.map(el => BigInt(el)));
|
||||||
|
proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('get value for fixed size arrays of address type', async () => {
|
||||||
|
const signers = await ethers.getSigners();
|
||||||
|
const expectedValue = signers.map(signer => signer.address.toLowerCase())
|
||||||
|
.slice(0, 4);
|
||||||
|
|
||||||
|
await testFixedArrays.setAddressArray(expectedValue);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'addressArray');
|
||||||
|
expect(value).to.eql(expectedValue);
|
||||||
|
const proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.length);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip('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.setBytesArray(expectedValue);
|
||||||
|
const blockHash = await getBlockHash();
|
||||||
|
const { value, proof } = await getStorageValue(storageLayout, getStorageAt, blockHash, testFixedArrays.address, 'bytesArray');
|
||||||
|
expect(value).to.eql(expectedValue);
|
||||||
|
const proofData = JSON.parse(proof.data);
|
||||||
|
expect(proofData.length).to.equal(expectedValue.length);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('basic mapping type', () => {
|
describe('basic mapping type', () => {
|
||||||
|
@ -111,7 +111,12 @@ const getDecodedValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
if (isArray && base) {
|
if (isArray && base) {
|
||||||
const resultArray = [];
|
const resultArray = [];
|
||||||
const proofs = [];
|
const proofs = [];
|
||||||
const { numberOfBytes: baseNumberOfBytes } = types[base];
|
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';
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
@ -120,6 +125,8 @@ const getDecodedValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
|
|||||||
const slotOffset = i % 32;
|
const slotOffset = i % 32;
|
||||||
({ value, proof } = await getDecodedValue(getStorageAt, blockHash, address, types, { slot: arraySlot, offset: slotOffset, type: base }, []));
|
({ 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.
|
||||||
proofs.push(JSON.parse(proof.data));
|
proofs.push(JSON.parse(proof.data));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -15,23 +15,37 @@ contract TestFixedArrays {
|
|||||||
// https://docs.soliditylang.org/en/v0.7.4/internals/layout_in_storage.html#layout-of-state-variables-in-storage
|
// https://docs.soliditylang.org/en/v0.7.4/internals/layout_in_storage.html#layout-of-state-variables-in-storage
|
||||||
uint16[5] uint16Array;
|
uint16[5] uint16Array;
|
||||||
|
|
||||||
// Set varaible boolArray.
|
address[4] addressArray;
|
||||||
|
|
||||||
|
bytes10[5] bytesArray;
|
||||||
|
|
||||||
|
// Set variable boolArray.
|
||||||
function setBoolArray(bool[2] calldata value) external {
|
function setBoolArray(bool[2] calldata value) external {
|
||||||
boolArray = value;
|
boolArray = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set varaible uintArray.
|
// Set variable uintArray.
|
||||||
function setUintArray(uint[5] calldata value) external {
|
function setUintArray(uint[5] calldata value) external {
|
||||||
uintArray = value;
|
uintArray = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set varaible uint16Array.
|
// Set variable uint16Array.
|
||||||
function setUint16Array(uint16[5] calldata value) external {
|
function setUint16Array(uint16[5] calldata value) external {
|
||||||
uint16Array = value;
|
uint16Array = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set varaible uint128Array.
|
// Set variable int128Array.
|
||||||
function setInt128Array(int128[5] calldata value) external {
|
function setInt128Array(int128[5] calldata value) external {
|
||||||
int128Array = value;
|
int128Array = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set variable addressArray.
|
||||||
|
function setAddressArray(address[4] calldata value) external {
|
||||||
|
addressArray = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set variable bytesArray.
|
||||||
|
function setBytesArray(bytes10[5] calldata value) external {
|
||||||
|
bytesArray = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user