Remove support for verified queries

This commit is contained in:
Simon Warta 2025-01-14 12:20:44 +01:00
parent e819a1fc0e
commit 28dc7e42b9
No known key found for this signature in database
8 changed files with 10 additions and 248 deletions

16
.pnp.cjs generated
View File

@ -206,10 +206,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"@babel/types",\
"npm:7.23.0"\
],\
[\
"@confio/ics23",\
"npm:0.6.8"\
],\
[\
"@cosmjs/amino",\
"workspace:packages/amino"\
@ -3228,17 +3224,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD"\
}]\
]],\
["@confio/ics23", [\
["npm:0.6.8", {\
"packageLocation": "./.yarn/cache/@confio-ics23-npm-0.6.8-c87607eb2c-376d72f644.zip/node_modules/@confio/ics23/",\
"packageDependencies": [\
["@confio/ics23", "npm:0.6.8"],\
["@noble/hashes", "npm:1.0.0"],\
["protobufjs", "npm:6.11.4"]\
],\
"linkType": "HARD"\
}]\
]],\
["@cosmjs/amino", [\
["workspace:packages/amino", {\
"packageLocation": "./packages/amino/",\
@ -3809,7 +3794,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"packageLocation": "./packages/stargate/",\
"packageDependencies": [\
["@cosmjs/stargate", "workspace:packages/stargate"],\
["@confio/ics23", "npm:0.6.8"],\
["@cosmjs/amino", "workspace:packages/amino"],\
["@cosmjs/crypto", "workspace:packages/crypto"],\
["@cosmjs/encoding", "workspace:packages/encoding"],\

Binary file not shown.

View File

@ -6,6 +6,13 @@ and this project adheres to
## [Unreleased]
### Changed
- @cosmjs/stargate: Removed support for verified queries. This feature depends
on a JavaScript implementation of ICS-23 but
[@confio/ics23 is unmaintained](https://github.com/cosmos/cosmjs/issues/1618)
without replacement.
## [0.32.4] - 2024-06-26
### Fixed

View File

@ -38,7 +38,6 @@
"pack-web": "yarn build-or-skip && webpack --mode development --config webpack.web.config.js"
},
"dependencies": {
"@confio/ics23": "^0.6.8",
"@cosmjs/amino": "workspace:^",
"@cosmjs/encoding": "workspace:^",
"@cosmjs/math": "workspace:^",

View File

@ -1,6 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { toAscii } from "@cosmjs/encoding";
import { Uint64 } from "@cosmjs/math";
import { Any } from "cosmjs-types/google/protobuf/any";
import {
QueryClientImpl as TransferQuery,
@ -8,7 +6,6 @@ import {
QueryDenomTracesResponse,
QueryParamsResponse as QueryTransferParamsResponse,
} from "cosmjs-types/ibc/applications/transfer/v1/query";
import { Channel } from "cosmjs-types/ibc/core/channel/v1/channel";
import {
QueryChannelClientStateResponse,
QueryChannelConsensusStateResponse,
@ -166,22 +163,6 @@ export interface IbcExtension {
readonly allDenomTraces: () => Promise<QueryDenomTracesResponse>;
readonly params: () => Promise<QueryTransferParamsResponse>;
};
readonly verified: {
readonly channel: {
readonly channel: (portId: string, channelId: string) => Promise<Channel | null>;
readonly packetCommitment: (
portId: string,
channelId: string,
sequence: number,
) => Promise<Uint8Array>;
readonly packetAcknowledgement: (
portId: string,
channelId: string,
sequence: number,
) => Promise<Uint8Array>;
readonly nextSequenceReceive: (portId: string, channelId: string) => Promise<number | null>;
};
};
};
}
@ -502,40 +483,6 @@ export function setupIbcExtension(base: QueryClient): IbcExtension {
},
params: async () => transferQueryService.Params({}),
},
verified: {
channel: {
channel: async (portId: string, channelId: string) => {
// keeper: https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/ibc/04-channel/keeper/keeper.go#L55-L65
// key: https://github.com/cosmos/cosmos-sdk/blob/ef0a7344af345882729598bc2958a21143930a6b/x/ibc/24-host/keys.go#L117-L120
const key = toAscii(`channelEnds/ports/${portId}/channels/${channelId}`);
const { value } = await base.queryStoreVerified("ibc", key);
return value.length ? Channel.decode(value) : null;
},
packetCommitment: async (portId: string, channelId: string, sequence: number) => {
// keeper: https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/ibc/04-channel/keeper/keeper.go#L128-L133
// key: https://github.com/cosmos/cosmos-sdk/blob/ef0a7344af345882729598bc2958a21143930a6b/x/ibc/24-host/keys.go#L183-L185
const key = toAscii(`commitments/ports/${portId}/channels/${channelId}/packets/${sequence}`);
const { value } = await base.queryStoreVerified("ibc", key);
// keeper code doesn't parse, but returns raw
return value;
},
packetAcknowledgement: async (portId: string, channelId: string, sequence: number) => {
// keeper: https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/ibc/04-channel/keeper/keeper.go#L159-L166
// key: https://github.com/cosmos/cosmos-sdk/blob/ef0a7344af345882729598bc2958a21143930a6b/x/ibc/24-host/keys.go#L153-L156
const key = toAscii(`acks/ports/${portId}/channels/${channelId}/acknowledgements/${sequence}`);
const { value } = await base.queryStoreVerified("ibc", key);
// keeper code doesn't parse, but returns raw
return value;
},
nextSequenceReceive: async (portId: string, channelId: string) => {
// keeper: https://github.com/cosmos/cosmos-sdk/blob/3bafd8255a502e5a9cee07391cf8261538245dfd/x/ibc/04-channel/keeper/keeper.go#L92-L101
// key: https://github.com/cosmos/cosmos-sdk/blob/ef0a7344af345882729598bc2958a21143930a6b/x/ibc/24-host/keys.go#L133-L136
const key = toAscii(`seqAcks/ports/${portId}/channels/${channelId}/nextSequenceAck`);
const { value } = await base.queryStoreVerified("ibc", key);
return value.length ? Uint64.fromBytes(value).toNumber() : null;
},
},
},
},
};
}

View File

@ -1,10 +1,8 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { coin } from "@cosmjs/amino";
import { toAscii } from "@cosmjs/encoding";
import { DirectSecp256k1HdWallet } from "@cosmjs/proto-signing";
import { CometClient, Tendermint34Client } from "@cosmjs/tendermint-rpc";
import { assert } from "@cosmjs/utils";
import { Metadata } from "cosmjs-types/cosmos/bank/v1beta1/bank";
import {
QueryAllBalancesRequest,
QueryAllBalancesResponse,
@ -19,7 +17,6 @@ import {
makeRandomAddress,
pendingWithoutSimapp,
simapp,
simapp44Enabled,
unused,
} from "../testutils.spec";
import { QueryClient } from "./queryclient";
@ -29,69 +26,7 @@ async function makeClient(rpcUrl: string): Promise<[QueryClient, CometClient]> {
return [QueryClient.withExtensions(cometClient), cometClient];
}
/**
* See
* - https://github.com/cosmos/cosmos-sdk/blob/v0.42.10/x/bank/types/key.go#L27
* - https://github.com/cosmos/cosmos-sdk/blob/v0.44.2/x/bank/types/key.go#L28
*/
const denomMetadataPrefix = new Uint8Array([0x01]);
describe("QueryClient", () => {
describe("queryStoreVerified", () => {
it("works via WebSockets", async () => {
pendingWithoutSimapp();
const [client, cometClient] = await makeClient(simapp.tendermintUrlWs);
// "keys before 0.45 had denom two times in the key"
// https://github.com/cosmos/cosmos-sdk/blob/10ad61a4dd/x/bank/migrations/v045/store_test.go#L91
let queryKey: Uint8Array;
if (simapp44Enabled()) {
queryKey = Uint8Array.from([
...denomMetadataPrefix,
...toAscii(simapp.denomFee),
...toAscii(simapp.denomFee),
]);
} else {
queryKey = Uint8Array.from([...denomMetadataPrefix, ...toAscii(simapp.denomFee)]);
}
const { key, value, height } = await client.queryStoreVerified("bank", queryKey);
expect(height).toBeGreaterThanOrEqual(1);
expect(key).toEqual(queryKey);
const response = Metadata.decode(value);
expect(response.base).toEqual(simapp.denomFee);
expect(response.description).toEqual("The fee token of this test chain");
cometClient.disconnect();
});
it("works via http", async () => {
pendingWithoutSimapp();
const [client, cometClient] = await makeClient(simapp.tendermintUrlHttp);
// "keys before 0.45 had denom two times in the key"
// https://github.com/cosmos/cosmos-sdk/blob/10ad61a4dd/x/bank/migrations/v045/store_test.go#L91
let queryKey: Uint8Array;
if (simapp44Enabled()) {
queryKey = Uint8Array.from([
...denomMetadataPrefix,
...toAscii(simapp.denomFee),
...toAscii(simapp.denomFee),
]);
} else {
queryKey = Uint8Array.from([...denomMetadataPrefix, ...toAscii(simapp.denomFee)]);
}
const { key, value, height } = await client.queryStoreVerified("bank", queryKey);
expect(height).toBeGreaterThanOrEqual(1);
expect(key).toEqual(queryKey);
const response = Metadata.decode(value);
expect(response.base).toEqual(simapp.denomFee);
expect(response.description).toEqual("The fee token of this test chain");
cometClient.disconnect();
});
});
describe("queryAbci", () => {
it("works via WebSockets", async () => {
pendingWithoutSimapp();

View File

@ -1,24 +1,12 @@
/* eslint-disable no-dupe-class-members, @typescript-eslint/ban-types, @typescript-eslint/naming-convention */
import { iavlSpec, ics23, tendermintSpec, verifyExistence, verifyNonExistence } from "@confio/ics23";
import { toAscii, toHex } from "@cosmjs/encoding";
import { firstEvent } from "@cosmjs/stream";
import { CometClient, tendermint34 } from "@cosmjs/tendermint-rpc";
import { arrayContentEquals, assert, assertDefined, isNonNullObject, sleep } from "@cosmjs/utils";
import { assert, assertDefined, isNonNullObject, sleep } from "@cosmjs/utils";
import { ProofOps } from "cosmjs-types/tendermint/crypto/proof";
import { Stream } from "xstream";
type QueryExtensionSetup<P> = (base: QueryClient) => P;
function checkAndParseOp(op: tendermint34.ProofOp, kind: string, key: Uint8Array): ics23.CommitmentProof {
if (op.type !== kind) {
throw new Error(`Op expected to be ${kind}, got "${op.type}`);
}
if (!arrayContentEquals(key, op.key)) {
throw new Error(`Proven key different than queried key.\nQuery: ${toHex(key)}\nProven: ${toHex(op.key)}`);
}
return ics23.CommitmentProof.decode(op.data);
}
export interface ProvenQuery {
readonly key: Uint8Array;
readonly value: Uint8Array;
@ -512,90 +500,6 @@ export class QueryClient {
this.cometClient = cometClient;
}
/**
* Queries the database store with a proof, which is then verified.
*
* Please note: the current implementation trusts block headers it gets from the PRC endpoint.
*/
public async queryStoreVerified(
store: string,
queryKey: Uint8Array,
desiredHeight?: number,
): Promise<QueryStoreResponse> {
const { height, proof, key, value } = await this.queryRawProof(store, queryKey, desiredHeight);
const subProof = checkAndParseOp(proof.ops[0], "ics23:iavl", queryKey);
const storeProof = checkAndParseOp(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 (!value || 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, queryKey);
} 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, queryKey, value);
}
// the store proof must map its declared value (root of subProof) to the appHash of the next block
const header = await this.getNextHeader(height);
verifyExistence(storeProof.exist, tendermintSpec, header.appHash, toAscii(store), storeProof.exist.value);
return { key, value, height };
}
public async queryRawProof(
store: string,
queryKey: Uint8Array,
desiredHeight?: number,
): Promise<ProvenQuery> {
const { key, value, height, proof, code, log } = await this.cometClient.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: queryKey,
prove: true,
height: desiredHeight,
});
if (code) {
throw new Error(`Query failed with (${code}): ${log}`);
}
if (!arrayContentEquals(queryKey, key)) {
throw new Error(`Response key ${toHex(key)} doesn't match query key ${toHex(queryKey)}`);
}
if (!height) {
throw new Error("No query height returned");
}
if (!proof || proof.ops.length !== 2) {
throw new Error(`Expected 2 proof ops, got ${proof?.ops.length ?? 0}. Are you using stargate?`);
}
// 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: key,
value: value,
height: height,
// need to clone this: readonly input / writeable output
proof: {
ops: [...proof.ops],
},
};
}
/**
* Performs an ABCI query to Tendermint without requesting a proof.
*

View File

@ -279,16 +279,6 @@ __metadata:
languageName: node
linkType: hard
"@confio/ics23@npm:^0.6.8":
version: 0.6.8
resolution: "@confio/ics23@npm:0.6.8"
dependencies:
"@noble/hashes": ^1.0.0
protobufjs: ^6.8.8
checksum: 376d72f6440db60611b002b00a13e3a5bfd0d3503e7682358dbcf79641e74d8c26c234c321452fb4a758baf66eecef25d950e08bdea270486d9d03ee489e2960
languageName: node
linkType: hard
"@cosmjs/amino@workspace:^, @cosmjs/amino@workspace:packages/amino":
version: 0.0.0-use.local
resolution: "@cosmjs/amino@workspace:packages/amino"
@ -838,7 +828,6 @@ __metadata:
version: 0.0.0-use.local
resolution: "@cosmjs/stargate@workspace:packages/stargate"
dependencies:
"@confio/ics23": ^0.6.8
"@cosmjs/amino": "workspace:^"
"@cosmjs/crypto": "workspace:^"
"@cosmjs/encoding": "workspace:^"
@ -1250,7 +1239,7 @@ __metadata:
languageName: node
linkType: hard
"@noble/hashes@npm:^1, @noble/hashes@npm:^1.0.0":
"@noble/hashes@npm:^1":
version: 1.0.0
resolution: "@noble/hashes@npm:1.0.0"
checksum: bdf1c28a4b587e72ec6b0c504903239c6f96680b2c15a6d90d367512f468eeca12f2ee7bd25967a9529be2bedbf3f8d0a50c33368937f8dfef2a973d0661c7b5
@ -6414,7 +6403,7 @@ __metadata:
languageName: node
linkType: hard
"protobufjs@npm:^6.8.8, protobufjs@npm:~6.11.4":
"protobufjs@npm:~6.11.4":
version: 6.11.4
resolution: "protobufjs@npm:6.11.4"
dependencies: