Query verified uses queryRawProof to remove duplication

This commit is contained in:
Ethan Frey 2021-02-09 15:04:07 +01:00
parent 62afab1936
commit 5400c3ac8c

View File

@ -167,60 +167,32 @@ export class QueryClient {
}
public async queryVerified(store: string, key: Uint8Array): Promise<Uint8Array> {
const response = await this.tmClient.abciQuery({
// we need the StoreKey for the module, not the module name
// https://github.com/cosmos/cosmos-sdk/blob/8cab43c8120fec5200c3459cbf4a92017bb6f287/x/auth/types/keys.go#L12
path: `/store/${store}/key`,
data: key,
prove: true,
});
const response = await this.queryRawProof(store, key);
if (response.code) {
throw new Error(`Query failed with (${response.code}): ${response.log}`);
const subProof = checkAndParseOp(response.proof.ops[0], "ics23:iavl", key);
const storeProof = checkAndParseOp(response.proof.ops[1], "ics23:simple", toAscii(store));
// this must always be existence, if the store is not a typo
assert(storeProof.exist);
assert(storeProof.exist.value);
// this may be exist or non-exist, depends on response
if (!response.value || response.value.length === 0) {
// non-existence check
assert(subProof.nonexist);
// the subproof must map the desired key to the "value" of the storeProof
verifyNonExistence(subProof.nonexist, iavlSpec, storeProof.exist.value, key);
} else {
// existence check
assert(subProof.exist);
assert(subProof.exist.value);
// the subproof must map the desired key to the "value" of the storeProof
verifyExistence(subProof.exist, iavlSpec, storeProof.exist.value, key, response.value);
}
if (!arrayContentEquals(response.key, key)) {
throw new Error(`Response key ${toHex(response.key)} doesn't match query key ${toHex(key)}`);
}
if (response.proof) {
if (response.proof.ops.length !== 2) {
throw new Error(
`Expected 2 proof ops, got ${response.proof?.ops.length ?? 0}. Are you using stargate?`,
);
}
const subProof = checkAndParseOp(response.proof.ops[0], "ics23:iavl", key);
const storeProof = checkAndParseOp(response.proof.ops[1], "ics23:simple", toAscii(store));
// this must always be existence, if the store is not a typo
assert(storeProof.exist);
assert(storeProof.exist.value);
// this may be exist or non-exist, depends on response
if (!response.value || response.value.length === 0) {
// non-existence check
assert(subProof.nonexist);
// the subproof must map the desired key to the "value" of the storeProof
verifyNonExistence(subProof.nonexist, iavlSpec, storeProof.exist.value, key);
} else {
// existence check
assert(subProof.exist);
assert(subProof.exist.value);
// the subproof must map the desired key to the "value" of the storeProof
verifyExistence(subProof.exist, iavlSpec, storeProof.exist.value, key, response.value);
}
// the storeproof must map it's declared value (root of subProof) to the appHash of the next block
const header = await this.getNextHeader(response.height);
verifyExistence(
storeProof.exist,
tendermintSpec,
header.appHash,
toAscii(store),
storeProof.exist.value,
);
}
// the storeproof must map it's declared value (root of subProof) to the appHash of the next block
const header = await this.getNextHeader(response.height);
verifyExistence(storeProof.exist, tendermintSpec, header.appHash, toAscii(store), storeProof.exist.value);
return response.value;
}
@ -249,8 +221,9 @@ export class QueryClient {
throw new Error(`Expected 2 proof ops, got ${proof?.ops.length ?? 0}. Are you using stargate?`);
}
// const subProof = checkAndParseOp(response.proof.ops[0], "ics23:iavl", key);
// const storeProof = checkAndParseOp(response.proof.ops[1], "ics23:simple", toAscii(store));
// we don't need the results, but we can ensure the data is the proper format
checkAndParseOp(proof.ops[0], "ics23:iavl", key);
checkAndParseOp(proof.ops[1], "ics23:simple", toAscii(store));
return {
key,