Assert proof data when running against GQL endpoint (#86)

* Assert proof data for intial test cases of value type variables.

* Assert proof data for value type variables integers and bytes.

* Assert proof for dynamic byte arrays and strings.

* Assert proof for fixed array types.

* Assert proof for dynamic array types.

* Assert proofs for nested arrays.

* Assert proof for struct type variables.

* Assert proof for mapping type variables.

Co-authored-by: nikugogoi <95nikass@gmail.com>
This commit is contained in:
Ashwin Phatak 2021-06-23 09:33:42 +05:30 committed by GitHub
parent 2adc5e9c34
commit fc30290685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 708 additions and 116 deletions

File diff suppressed because it is too large Load Diff

View File

@ -298,7 +298,7 @@ const getStructureValue = async (getStorageAt: GetStorageAt, blockHash: string,
return members.reduce((acc, member, index) => { return members.reduce((acc, member, index) => {
acc.value[member.label] = results[index].value; acc.value[member.label] = results[index].value;
const proofData = JSON.parse(acc.proof.data); const proofData = JSON.parse(acc.proof.data);
proofData[member.label] = results[index].proof; proofData[member.label] = JSON.parse(results[index].proof.data);
acc.proof.data = JSON.stringify(proofData); acc.proof.data = JSON.stringify(proofData);
return acc; return acc;
}, initialValue); }, initialValue);
@ -336,6 +336,7 @@ const getInplaceValue = async (getStorageAt: GetStorageAt, blockHash: string, ad
const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string) => { const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, address: string, slot: string) => {
const { value, proof } = await getStorageAt({ blockHash, contract: address, slot }); const { value, proof } = await getStorageAt({ blockHash, contract: address, slot });
let length = 0; let length = 0;
const proofs = [JSON.parse(proof.data)];
// Get length of bytes stored. // Get length of bytes stored.
if (BigNumber.from(utils.hexDataSlice(value, 0, 1)).isZero()) { if (BigNumber.from(utils.hexDataSlice(value, 0, 1)).isZero()) {
@ -353,14 +354,13 @@ const getBytesValue = async (getStorageAt: GetStorageAt, blockHash: string, addr
if (length < 32) { if (length < 32) {
return { return {
value: utils.hexDataSlice(value, 0, length), value: utils.hexDataSlice(value, 0, length),
proof proof: {
data: JSON.stringify(proofs)
}
}; };
} }
// Array to hold multiple bytes32 data. // Array to hold multiple bytes32 data.
const proofs = [
JSON.parse(proof.data)
];
const hexStringArray = []; const hexStringArray = [];
// Compute zero padded hexstring to calculate hashed position of storage. // Compute zero padded hexstring to calculate hashed position of storage.

View File

@ -1,7 +1,11 @@
/* eslint-disable no-unused-expressions */
/* eslint-disable @typescript-eslint/no-explicit-any */
import { ContractInterface } from '@ethersproject/contracts'; import { ContractInterface } from '@ethersproject/contracts';
import '@nomiclabs/hardhat-ethers'; import '@nomiclabs/hardhat-ethers';
import { artifacts, ethers } from 'hardhat'; import { artifacts, ethers } from 'hardhat';
import { CompilerOutput, CompilerOutputBytecode } from 'hardhat/types'; import { CompilerOutput, CompilerOutputBytecode } from 'hardhat/types';
import { expect } from 'chai';
import isArray from 'lodash/isArray';
import { StorageLayout, GetStorageAt } from '../src'; import { StorageLayout, GetStorageAt } from '../src';
@ -25,6 +29,17 @@ interface StorageCompilerOutput extends CompilerOutput {
}; };
} }
interface ProofData {
blockHash: string;
account: {
address: string;
storage: {
ipldBlock: string;
cid: string;
}
}
}
/** /**
* Get storage layout of specified contract. * Get storage layout of specified contract.
* @param contractName * @param contractName
@ -79,3 +94,77 @@ export const generateDummyAddresses = (length: number): Array<string> => {
return ethers.utils.hexlify(ethers.utils.randomBytes(20)); return ethers.utils.hexlify(ethers.utils.randomBytes(20));
}); });
}; };
/**
* Get latest blockHash.
*/
export const getBlockHash = async (): Promise<string> => {
const blockNumber = await ethers.provider.getBlockNumber();
const { hash } = await ethers.provider.getBlock(blockNumber);
return hash;
};
/**
* Assert proof data returned from ipld graphql server.
* @param blockHash
* @param address
* @param proofData
*/
export const assertProofData = (blockHash: string, address: string, proofData: ProofData): void => {
const {
blockHash: proofBlockHash,
account: {
address: proofAddress,
storage
}
} = proofData;
expect(proofBlockHash).to.equal(blockHash);
expect(proofAddress).to.equal(address);
expect(storage.cid).to.not.be.empty;
expect(storage.ipldBlock).to.not.be.empty;
};
/**
* Assert array of proof data.
* @param blockHash
* @param address
* @param proofArray
*/
export const assertProofArray = (blockHash: string, address: string, proofArray: Array<any>): void => {
proofArray.forEach(proofData => {
if (isArray(proofData)) {
assertProofArray(blockHash, address, proofData);
return;
}
if (['blockHash', 'account'].every(key => key in proofData)) {
assertProofData(blockHash, address, proofData);
return;
}
assertProofStruct(blockHash, address, proofData);
});
};
/**
* Assert array of proof data from structure type.
* @param blockHash
* @param address
* @param proofStruct
*/
export const assertProofStruct = (blockHash: string, address: string, proofStruct: {[key: string]: any}): void => {
Object.values(proofStruct).forEach(proofData => {
if (isArray(proofData)) {
assertProofArray(blockHash, address, proofData);
return;
}
if (['blockHash', 'account'].every(key => key in proofData)) {
assertProofData(blockHash, address, proofData);
return;
}
assertProofStruct(blockHash, address, proofData);
});
};