From 5400c3ac8c29dbf0e00539559207e17a4ddd9496 Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Tue, 9 Feb 2021 15:04:07 +0100 Subject: [PATCH] Query verified uses queryRawProof to remove duplication --- packages/stargate/src/queries/queryclient.ts | 79 +++++++------------- 1 file changed, 26 insertions(+), 53 deletions(-) diff --git a/packages/stargate/src/queries/queryclient.ts b/packages/stargate/src/queries/queryclient.ts index 3af4bdf8..780aeda2 100644 --- a/packages/stargate/src/queries/queryclient.ts +++ b/packages/stargate/src/queries/queryclient.ts @@ -167,60 +167,32 @@ export class QueryClient { } public async queryVerified(store: string, key: Uint8Array): Promise { - 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,