Merge pull request #747 from cosmos/742-wasm-extension

Rearrange wasm query extension
This commit is contained in:
Simon Warta 2021-03-31 13:10:19 +02:00 committed by GitHub
commit 268b2dc336
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 127 additions and 149 deletions

View File

@ -79,6 +79,8 @@ and this project adheres to
- @cosmjs/stargate: `parseRawLog` is now nested under the `logs` export.
- @cosmjs/stargate: `auth` and `bank` extensions now have unverified queries at
the root and verified queries nested under `.verified`.
- @cosmjs/cosmwasm-stargate: `wasm` extension now has unverified queries at the
root.
- @cosmjs/stargate: `StargateClient.getAccount` now uses an unverified query and
`StargateClient.getAccountUnverified` has been removed.
`StargateClient.getAccountVerified` has been added, which performs a verified

View File

@ -258,7 +258,7 @@ describe("CosmWasmClient", () => {
pendingWithoutWasmd();
const client = await CosmWasmClient.connect(wasmd.endpoint);
const openedClient = (client as unknown) as PrivateCosmWasmClient;
const getCodeSpy = spyOn(openedClient.queryClient!.unverified.wasm, "getCode").and.callThrough();
const getCodeSpy = spyOn(openedClient.queryClient!.wasm, "getCode").and.callThrough();
const result1 = await client.getCodeDetails(deployedHackatom.codeId); // from network
const result2 = await client.getCodeDetails(deployedHackatom.codeId); // from cache

View File

@ -229,7 +229,7 @@ export class CosmWasmClient {
}
public async getCodes(): Promise<readonly Code[]> {
const { codeInfos } = await this.forceGetQueryClient().unverified.wasm.listCodeInfo();
const { codeInfos } = await this.forceGetQueryClient().wasm.listCodeInfo();
return (codeInfos || []).map(
(entry: CodeInfoResponse): Code => {
assert(entry.creator && entry.codeId && entry.dataHash, "entry incomplete");
@ -248,7 +248,7 @@ export class CosmWasmClient {
const cached = this.codesCache.get(codeId);
if (cached) return cached;
const { codeInfo, data } = await this.forceGetQueryClient().unverified.wasm.getCode(codeId);
const { codeInfo, data } = await this.forceGetQueryClient().wasm.getCode(codeId);
assert(
codeInfo && codeInfo.codeId && codeInfo.creator && codeInfo.dataHash && data,
"codeInfo missing or incomplete",
@ -266,7 +266,7 @@ export class CosmWasmClient {
}
public async getContracts(codeId: number): Promise<readonly Contract[]> {
const { contractInfos } = await this.forceGetQueryClient().unverified.wasm.listContractsByCodeId(codeId);
const { contractInfos } = await this.forceGetQueryClient().wasm.listContractsByCodeId(codeId);
return (contractInfos || []).map(
({ address, contractInfo }): Contract => {
assert(address, "address missing");
@ -289,10 +289,9 @@ export class CosmWasmClient {
* Throws an error if no contract was found at the address
*/
public async getContract(address: string): Promise<Contract> {
const {
address: retrievedAddress,
contractInfo,
} = await this.forceGetQueryClient().unverified.wasm.getContractInfo(address);
const { address: retrievedAddress, contractInfo } = await this.forceGetQueryClient().wasm.getContractInfo(
address,
);
if (!contractInfo) throw new Error(`No contract found at address "${address}"`);
assert(retrievedAddress, "address missing");
assert(contractInfo.codeId && contractInfo.creator && contractInfo.label, "contractInfo incomplete");
@ -309,7 +308,7 @@ export class CosmWasmClient {
* Throws an error if no contract was found at the address
*/
public async getContractCodeHistory(address: string): Promise<readonly ContractCodeHistoryEntry[]> {
const result = await this.forceGetQueryClient().unverified.wasm.getContractCodeHistory(address);
const result = await this.forceGetQueryClient().wasm.getContractCodeHistory(address);
if (!result) throw new Error(`No contract history found for address "${address}"`);
const operations: Record<number, "Init" | "Genesis" | "Migrate"> = {
[ContractCodeHistoryOperationType.CONTRACT_CODE_HISTORY_OPERATION_TYPE_INIT]: "Init",
@ -338,7 +337,7 @@ export class CosmWasmClient {
// just test contract existence
await this.getContract(address);
const { data } = await this.forceGetQueryClient().unverified.wasm.queryContractRaw(address, key);
const { data } = await this.forceGetQueryClient().wasm.queryContractRaw(address, key);
return data ?? null;
}
@ -351,7 +350,7 @@ export class CosmWasmClient {
*/
public async queryContractSmart(address: string, queryMsg: Record<string, unknown>): Promise<JsonObject> {
try {
return await this.forceGetQueryClient().unverified.wasm.queryContractSmart(address, queryMsg);
return await this.forceGetQueryClient().wasm.queryContractSmart(address, queryMsg);
} catch (error) {
if (error instanceof Error) {
if (error.message.startsWith("not found: contract")) {

View File

@ -156,7 +156,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
assert(hackatomCodeId);
const client = await makeWasmClient(wasmd.endpoint);
const { codeInfos } = await client.unverified.wasm.listCodeInfo();
const { codeInfos } = await client.wasm.listCodeInfo();
assert(codeInfos);
const lastCode = codeInfos[codeInfos.length - 1];
expect(lastCode.codeId.toNumber()).toEqual(hackatomCodeId);
@ -172,7 +172,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
assert(hackatomCodeId);
const client = await makeWasmClient(wasmd.endpoint);
const { codeInfo, data } = await client.unverified.wasm.getCode(hackatomCodeId);
const { codeInfo, data } = await client.wasm.getCode(hackatomCodeId);
expect(codeInfo!.codeId.toNumber()).toEqual(hackatomCodeId);
expect(codeInfo!.creator).toEqual(alice.address0);
expect(codeInfo!.source).toEqual(hackatom.source ?? "");
@ -193,7 +193,7 @@ describe("WasmExtension", () => {
const transferAmount = coins(707707, "ucosm");
// create new instance and compare before and after
const { contractInfos: existingContractInfos } = await client.unverified.wasm.listContractsByCodeId(
const { contractInfos: existingContractInfos } = await client.wasm.listContractsByCodeId(
hackatomCodeId,
);
assert(existingContractInfos);
@ -211,9 +211,7 @@ describe("WasmExtension", () => {
.events.find((event: any) => event.type === "message")
.attributes!.find((attribute: any) => attribute.key === "contract_address").value;
const { contractInfos: newContractInfos } = await client.unverified.wasm.listContractsByCodeId(
hackatomCodeId,
);
const { contractInfos: newContractInfos } = await client.wasm.listContractsByCodeId(hackatomCodeId);
assert(newContractInfos);
expect(newContractInfos.length).toEqual(existingContractInfos.length + 1);
const newContract = newContractInfos[newContractInfos.length - 1];
@ -225,7 +223,7 @@ describe("WasmExtension", () => {
ibcPortId: "",
});
const { contractInfo } = await client.unverified.wasm.getContractInfo(myAddress);
const { contractInfo } = await client.wasm.getContractInfo(myAddress);
assert(contractInfo);
expect({ ...contractInfo }).toEqual({
codeId: Long.fromNumber(hackatomCodeId, true),
@ -242,9 +240,7 @@ describe("WasmExtension", () => {
assert(hackatomCodeId);
const client = await makeWasmClient(wasmd.endpoint);
const nonExistentAddress = makeRandomAddress();
await expectAsync(client.unverified.wasm.getContractInfo(nonExistentAddress)).toBeRejectedWithError(
/not found/i,
);
await expectAsync(client.wasm.getContractInfo(nonExistentAddress)).toBeRejectedWithError(/not found/i);
});
});
@ -265,7 +261,7 @@ describe("WasmExtension", () => {
.events.find((event: any) => event.type === "message")
.attributes!.find((attribute: any) => attribute.key === "contract_address").value;
const history = await client.unverified.wasm.getContractCodeHistory(myAddress);
const history = await client.wasm.getContractCodeHistory(myAddress);
assert(history.entries);
expect(history.entries).toContain(
jasmine.objectContaining({
@ -286,7 +282,7 @@ describe("WasmExtension", () => {
assert(hackatomCodeId);
const client = await makeWasmClient(wasmd.endpoint);
const nonExistentAddress = makeRandomAddress();
const history = await client.unverified.wasm.getContractCodeHistory(nonExistentAddress);
const history = await client.wasm.getContractCodeHistory(nonExistentAddress);
expect(history.entries).toEqual([]);
});
});
@ -296,7 +292,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
assert(hackatomContractAddress);
const client = await makeWasmClient(wasmd.endpoint);
const { models } = await client.unverified.wasm.getAllContractState(hackatomContractAddress);
const { models } = await client.wasm.getAllContractState(hackatomContractAddress);
assert(models);
expect(models.length).toEqual(1);
const data = models[0];
@ -310,7 +306,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
const client = await makeWasmClient(wasmd.endpoint);
const nonExistentAddress = makeRandomAddress();
await expectAsync(client.unverified.wasm.getAllContractState(nonExistentAddress)).toBeRejectedWithError(
await expectAsync(client.wasm.getAllContractState(nonExistentAddress)).toBeRejectedWithError(
/not found/i,
);
});
@ -321,7 +317,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
assert(hackatomContractAddress);
const client = await makeWasmClient(wasmd.endpoint);
const raw = await client.unverified.wasm.queryContractRaw(hackatomContractAddress, hackatomConfigKey);
const raw = await client.wasm.queryContractRaw(hackatomContractAddress, hackatomConfigKey);
assert(raw.data, "must get result");
const model = JSON.parse(fromAscii(raw.data));
expect(model.verifier).toMatch(base64Matcher);
@ -332,10 +328,7 @@ describe("WasmExtension", () => {
pendingWithoutWasmd();
assert(hackatomContractAddress);
const client = await makeWasmClient(wasmd.endpoint);
const { data } = await client.unverified.wasm.queryContractRaw(
hackatomContractAddress,
fromHex("cafe0dad"),
);
const { data } = await client.wasm.queryContractRaw(hackatomContractAddress, fromHex("cafe0dad"));
expect(data).toBeUndefined();
});
@ -344,7 +337,7 @@ describe("WasmExtension", () => {
const client = await makeWasmClient(wasmd.endpoint);
const nonExistentAddress = makeRandomAddress();
await expectAsync(
client.unverified.wasm.queryContractRaw(nonExistentAddress, hackatomConfigKey),
client.wasm.queryContractRaw(nonExistentAddress, hackatomConfigKey),
).toBeRejectedWithError(/not found/i);
});
});
@ -355,7 +348,7 @@ describe("WasmExtension", () => {
assert(hackatomContractAddress);
const client = await makeWasmClient(wasmd.endpoint);
const request = { verifier: {} };
const result = await client.unverified.wasm.queryContractSmart(hackatomContractAddress, request);
const result = await client.wasm.queryContractSmart(hackatomContractAddress, request);
expect(result).toEqual({ verifier: alice.address0 });
});
@ -365,7 +358,7 @@ describe("WasmExtension", () => {
const client = await makeWasmClient(wasmd.endpoint);
const request = { nosuchkey: {} };
await expectAsync(
client.unverified.wasm.queryContractSmart(hackatomContractAddress, request),
client.wasm.queryContractSmart(hackatomContractAddress, request),
).toBeRejectedWithError(/Error parsing into type hackatom::contract::QueryMsg: unknown variant/i);
});
@ -374,9 +367,9 @@ describe("WasmExtension", () => {
const client = await makeWasmClient(wasmd.endpoint);
const nonExistentAddress = makeRandomAddress();
const request = { verifier: {} };
await expectAsync(
client.unverified.wasm.queryContractSmart(nonExistentAddress, request),
).toBeRejectedWithError(/not found/i);
await expectAsync(client.wasm.queryContractSmart(nonExistentAddress, request)).toBeRejectedWithError(
/not found/i,
);
});
});

View File

@ -16,49 +16,47 @@ import {
} from "../codec/x/wasm/internal/types/query";
export interface WasmExtension {
readonly unverified: {
readonly wasm: {
readonly listCodeInfo: (paginationKey?: Uint8Array) => Promise<QueryCodesResponse>;
/**
* Downloads the original wasm bytecode by code ID.
*
* Throws an error if no code with this id
*/
readonly getCode: (id: number) => Promise<QueryCodeResponse>;
readonly listContractsByCodeId: (
id: number,
paginationKey?: Uint8Array,
) => Promise<QueryContractsByCodeResponse>;
/**
* Returns null when contract was not found at this address.
*/
readonly getContractInfo: (address: string) => Promise<QueryContractInfoResponse>;
/**
* Returns null when contract history was not found for this address.
*/
readonly getContractCodeHistory: (
address: string,
paginationKey?: Uint8Array,
) => Promise<QueryContractHistoryResponse>;
/**
* Returns all contract state.
* This is an empty array if no such contract, or contract has no data.
*/
readonly getAllContractState: (
address: string,
paginationKey?: Uint8Array,
) => Promise<QueryAllContractStateResponse>;
/**
* Returns the data at the key if present (unknown decoded json),
* or null if no data at this (contract address, key) pair
*/
readonly queryContractRaw: (address: string, key: Uint8Array) => Promise<QueryRawContractStateResponse>;
/**
* Makes a smart query on the contract and parses the response as JSON.
* Throws error if no such contract exists, the query format is invalid or the response is invalid.
*/
readonly queryContractSmart: (address: string, query: Record<string, unknown>) => Promise<JsonObject>;
};
readonly wasm: {
readonly listCodeInfo: (paginationKey?: Uint8Array) => Promise<QueryCodesResponse>;
/**
* Downloads the original wasm bytecode by code ID.
*
* Throws an error if no code with this id
*/
readonly getCode: (id: number) => Promise<QueryCodeResponse>;
readonly listContractsByCodeId: (
id: number,
paginationKey?: Uint8Array,
) => Promise<QueryContractsByCodeResponse>;
/**
* Returns null when contract was not found at this address.
*/
readonly getContractInfo: (address: string) => Promise<QueryContractInfoResponse>;
/**
* Returns null when contract history was not found for this address.
*/
readonly getContractCodeHistory: (
address: string,
paginationKey?: Uint8Array,
) => Promise<QueryContractHistoryResponse>;
/**
* Returns all contract state.
* This is an empty array if no such contract, or contract has no data.
*/
readonly getAllContractState: (
address: string,
paginationKey?: Uint8Array,
) => Promise<QueryAllContractStateResponse>;
/**
* Returns the data at the key if present (unknown decoded json),
* or null if no data at this (contract address, key) pair
*/
readonly queryContractRaw: (address: string, key: Uint8Array) => Promise<QueryRawContractStateResponse>;
/**
* Makes a smart query on the contract and parses the response as JSON.
* Throws error if no such contract exists, the query format is invalid or the response is invalid.
*/
readonly queryContractSmart: (address: string, query: Record<string, unknown>) => Promise<JsonObject>;
};
}
@ -69,61 +67,59 @@ export function setupWasmExtension(base: QueryClient): WasmExtension {
const queryService = new QueryClientImpl(rpc);
return {
unverified: {
wasm: {
listCodeInfo: async (paginationKey?: Uint8Array) => {
const request = {
pagination: createPagination(paginationKey),
};
return queryService.Codes(request);
},
getCode: async (id: number) => {
const request = { codeId: Long.fromNumber(id) };
return queryService.Code(request);
},
listContractsByCodeId: async (id: number, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, codeId: Long.fromNumber(id) };
return queryService.ContractsByCode(request);
},
getContractInfo: async (address: string) => {
const request = { address: address };
return queryService.ContractInfo(request);
},
wasm: {
listCodeInfo: async (paginationKey?: Uint8Array) => {
const request = {
pagination: createPagination(paginationKey),
};
return queryService.Codes(request);
},
getCode: async (id: number) => {
const request = { codeId: Long.fromNumber(id) };
return queryService.Code(request);
},
listContractsByCodeId: async (id: number, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, codeId: Long.fromNumber(id) };
return queryService.ContractsByCode(request);
},
getContractInfo: async (address: string) => {
const request = { address: address };
return queryService.ContractInfo(request);
},
getContractCodeHistory: async (address: string, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, address: address };
return queryService.ContractHistory(request);
},
getContractCodeHistory: async (address: string, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, address: address };
return queryService.ContractHistory(request);
},
getAllContractState: async (address: string, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, address: address };
return queryService.AllContractState(request);
},
getAllContractState: async (address: string, paginationKey?: Uint8Array) => {
const pagination = {
pagination: createPagination(paginationKey),
};
const request = { ...pagination, address: address };
return queryService.AllContractState(request);
},
queryContractRaw: async (address: string, key: Uint8Array) => {
const request = { address: address, queryData: key };
return queryService.RawContractState(request);
},
queryContractRaw: async (address: string, key: Uint8Array) => {
const request = { address: address, queryData: key };
return queryService.RawContractState(request);
},
queryContractSmart: async (address: string, query: Record<string, unknown>) => {
const request = { address: address, queryData: toAscii(JSON.stringify(query)) };
const { data } = await queryService.SmartContractState(request);
// By convention, smart queries must return a valid JSON document (see https://github.com/CosmWasm/cosmwasm/issues/144)
try {
return JSON.parse(fromUtf8(data));
} catch (error) {
throw new Error("Contract did not return valid JSON data");
}
},
queryContractSmart: async (address: string, query: Record<string, unknown>) => {
const request = { address: address, queryData: toAscii(JSON.stringify(query)) };
const { data } = await queryService.SmartContractState(request);
// By convention, smart queries must return a valid JSON document (see https://github.com/CosmWasm/cosmwasm/issues/144)
try {
return JSON.parse(fromUtf8(data));
} catch (error) {
throw new Error("Contract did not return valid JSON data");
}
},
},
};

View File

@ -295,7 +295,7 @@ describe("SigningCosmWasmClient", () => {
{ admin: unused.address },
);
const wasmClient = await makeWasmClient(wasmd.endpoint);
const { contractInfo } = await wasmClient.unverified.wasm.getContractInfo(contractAddress);
const { contractInfo } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo);
expect(contractInfo.admin).toEqual(unused.address);
});
@ -349,16 +349,12 @@ describe("SigningCosmWasmClient", () => {
},
);
const wasmClient = await makeWasmClient(wasmd.endpoint);
const { contractInfo: contractInfo1 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo1 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo1);
expect(contractInfo1.admin).toEqual(alice.address0);
await client.updateAdmin(alice.address0, contractAddress, unused.address);
const { contractInfo: contractInfo2 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo2);
expect(contractInfo2.admin).toEqual(unused.address);
});
@ -385,16 +381,12 @@ describe("SigningCosmWasmClient", () => {
},
);
const wasmClient = await makeWasmClient(wasmd.endpoint);
const { contractInfo: contractInfo1 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo1 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo1);
expect(contractInfo1.admin).toEqual(alice.address0);
await client.clearAdmin(alice.address0, contractAddress);
const { contractInfo: contractInfo2 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo2);
expect(contractInfo2.admin).toEqual("");
});
@ -422,17 +414,13 @@ describe("SigningCosmWasmClient", () => {
},
);
const wasmClient = await makeWasmClient(wasmd.endpoint);
const { contractInfo: contractInfo1 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo1 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo1);
expect(contractInfo1.admin).toEqual(alice.address0);
const newVerifier = makeRandomAddress();
await client.migrate(alice.address0, contractAddress, codeId2, { verifier: newVerifier });
const { contractInfo: contractInfo2 } = await wasmClient.unverified.wasm.getContractInfo(
contractAddress,
);
const { contractInfo: contractInfo2 } = await wasmClient.wasm.getContractInfo(contractAddress);
assert(contractInfo2);
expect({ ...contractInfo2 }).toEqual({
...contractInfo1,