From 858142c8fc5f0022a656307b2394127edc1a0e63 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 10:20:33 +0200 Subject: [PATCH 1/6] Let prepareBuilder return undefined --- packages/cosmwasm-stargate/src/signingcosmwasmclient.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index c95632b3..8d614adc 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -57,9 +57,9 @@ import { MsgUpdateAdminEncodeObject, } from "./encodeobjects"; -function prepareBuilder(builder: string | undefined): string { - if (builder === undefined) { - return ""; // normalization needed by backend +function prepareBuilder(builder: string | undefined): string | undefined { + if (!builder) { + return undefined; } else { if (!isValidBuilder(builder)) throw new Error("The builder (Docker Hub image with tag) is not valid"); return builder; From 03a9a39ac759802f980a8df6a1e887701287563d Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 10:25:35 +0200 Subject: [PATCH 2/6] Export isValidBuilder from @cosmjs/cosmwasm-stargate --- CHANGELOG.md | 2 + .../cosmwasm-stargate/src/builder.spec.ts | 63 +++++++++++++++++++ packages/cosmwasm-stargate/src/builder.ts | 20 ++++++ packages/cosmwasm-stargate/src/index.ts | 1 + .../src/signingcosmwasmclient.ts | 2 +- 5 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 packages/cosmwasm-stargate/src/builder.spec.ts create mode 100644 packages/cosmwasm-stargate/src/builder.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 62517f86..a40b46d1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,8 @@ and this project adheres to available under `tendermint33`. - @cosmjs/proto-signing and @cosmjs/stargate: Create a Stargate-ready `parseCoins` that replaces the `parseCoins` re-export from `@cosmjs/amino`. +- @cosmjs/cosmwasm-stargate: Export `isValidBuilder`, which is a clone of + `isValidBuilder` from @cosmjs/cosmwasm-launchpad. ### Changed diff --git a/packages/cosmwasm-stargate/src/builder.spec.ts b/packages/cosmwasm-stargate/src/builder.spec.ts new file mode 100644 index 00000000..20926f4c --- /dev/null +++ b/packages/cosmwasm-stargate/src/builder.spec.ts @@ -0,0 +1,63 @@ +import { isValidBuilder } from "./builder"; + +describe("builder", () => { + describe("isValidBuilder", () => { + // Valid cases + + it("returns true for simple examples", () => { + expect(isValidBuilder("myorg/super-optimizer:0.1.2")).toEqual(true); + expect(isValidBuilder("myorg/super-optimizer:42")).toEqual(true); + }); + + it("supports images with multi level names", () => { + expect(isValidBuilder("myorg/department-x/office-y/technology-z/super-optimizer:0.1.2")).toEqual(true); + }); + + it("returns true for tags with lower and upper chars", () => { + expect(isValidBuilder("myorg/super-optimizer:0.1.2-alpha")).toEqual(true); + expect(isValidBuilder("myorg/super-optimizer:0.1.2-Alpha")).toEqual(true); + }); + + // Invalid cases + + it("returns false for missing or empty tag", () => { + expect(isValidBuilder("myorg/super-optimizer")).toEqual(false); + expect(isValidBuilder("myorg/super-optimizer:")).toEqual(false); + }); + + it("returns false for name components starting or ending with a separator", () => { + expect(isValidBuilder(".myorg/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("-myorg/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("_myorg/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg./super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg-/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg_/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg/.super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg/-super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg/_super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg/super-optimizer.:42")).toEqual(false); + expect(isValidBuilder("myorg/super-optimizer-:42")).toEqual(false); + expect(isValidBuilder("myorg/super-optimizer_:42")).toEqual(false); + }); + + it("returns false for upper case character in name component", () => { + expect(isValidBuilder("mYorg/super-optimizer:42")).toEqual(false); + expect(isValidBuilder("myorg/super-Optimizer:42")).toEqual(false); + }); + + it("returns false for long images", () => { + expect( + isValidBuilder( + "myorgisnicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenicenice/super-optimizer:42", + ), + ).toEqual(false); + }); + + it("returns false for images with no organization", () => { + // Those are valid dockerhub images from https://hub.docker.com/_/ubuntu and https://hub.docker.com/_/rust + // but not valid in the context of CosmWasm Verify + expect(isValidBuilder("ubuntu:xenial-20200212")).toEqual(false); + expect(isValidBuilder("rust:1.40.0")).toEqual(false); + }); + }); +}); diff --git a/packages/cosmwasm-stargate/src/builder.ts b/packages/cosmwasm-stargate/src/builder.ts new file mode 100644 index 00000000..31a790c7 --- /dev/null +++ b/packages/cosmwasm-stargate/src/builder.ts @@ -0,0 +1,20 @@ +// A docker image regexp. We remove support for non-standard registries for simplicity. +// https://docs.docker.com/engine/reference/commandline/tag/#extended-description +// +// An image name is made up of slash-separated name components (optionally prefixed by a registry hostname). +// Name components may contain lowercase characters, digits and separators. +// A separator is defined as a period, one or two underscores, or one or more dashes. A name component may not start or end with a separator. +// +// A tag name must be valid ASCII and may contain lowercase and uppercase letters, digits, underscores, periods and dashes. +// A tag name may not start with a period or a dash and may contain a maximum of 128 characters. +const dockerImagePattern = new RegExp( + "^[a-z0-9][a-z0-9._-]*[a-z0-9](/[a-z0-9][a-z0-9._-]*[a-z0-9])+:[a-zA-Z0-9_][a-zA-Z0-9_.-]{0,127}$", +); + +/** Max length in bytes/characters (regexp enforces all ASCII, even if that is not required by the standard) */ +const builderMaxLength = 128; + +export function isValidBuilder(builder: string): boolean { + if (builder.length > builderMaxLength) return false; + return !!builder.match(dockerImagePattern); +} diff --git a/packages/cosmwasm-stargate/src/index.ts b/packages/cosmwasm-stargate/src/index.ts index e90bbc57..c02bdae8 100644 --- a/packages/cosmwasm-stargate/src/index.ts +++ b/packages/cosmwasm-stargate/src/index.ts @@ -1,4 +1,5 @@ export { cosmWasmTypes } from "./aminotypes"; +export { isValidBuilder } from "./builder"; export { Code, CodeDetails, diff --git a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts index 8d614adc..f02a4f84 100644 --- a/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/signingcosmwasmclient.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ import { encodeSecp256k1Pubkey, makeSignDoc as makeSignDocAmino } from "@cosmjs/amino"; -import { isValidBuilder } from "@cosmjs/cosmwasm-launchpad"; import { sha256 } from "@cosmjs/crypto"; import { fromBase64, toHex, toUtf8 } from "@cosmjs/encoding"; import { Int53, Uint53 } from "@cosmjs/math"; @@ -47,6 +46,7 @@ import Long from "long"; import pako from "pako"; import { cosmWasmTypes } from "./aminotypes"; +import { isValidBuilder } from "./builder"; import { CosmWasmClient } from "./cosmwasmclient"; import { MsgClearAdminEncodeObject, From 6ec6994a792d3f5e4a78ab9b64dec9ec62d9a9c4 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 11:23:11 +0200 Subject: [PATCH 3/6] Copy Code and CodeDetails --- .../cosmwasm-launchpad/src/cosmwasmclient.ts | 2 +- .../src/cosmwasmclient.spec.ts | 3 +- .../cosmwasm-stargate/src/cosmwasmclient.ts | 36 ++++++++++++++----- 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/cosmwasm-launchpad/src/cosmwasmclient.ts b/packages/cosmwasm-launchpad/src/cosmwasmclient.ts index 1f7324e1..3915971b 100644 --- a/packages/cosmwasm-launchpad/src/cosmwasmclient.ts +++ b/packages/cosmwasm-launchpad/src/cosmwasmclient.ts @@ -95,7 +95,7 @@ export interface Code { } export interface CodeDetails extends Code { - /** The original wasm bytes */ + /** The original Wasm bytes */ readonly data: Uint8Array; } diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts index 3092ded5..83647705 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.spec.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { Code } from "@cosmjs/cosmwasm-launchpad"; import { sha256 } from "@cosmjs/crypto"; import { fromAscii, fromBase64, fromHex, toAscii } from "@cosmjs/encoding"; import { Int53 } from "@cosmjs/math"; @@ -16,7 +15,7 @@ import { assert, sleep } from "@cosmjs/utils"; import { TxRaw } from "cosmjs-types/cosmos/tx/v1beta1/tx"; import { ReadonlyDate } from "readonly-date"; -import { CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient"; +import { Code, CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient"; import { SigningCosmWasmClient } from "./signingcosmwasmclient"; import { alice, diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.ts index 147ead52..5e04ba05 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.ts @@ -1,11 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { - Code, - CodeDetails, - Contract, - ContractCodeHistoryEntry, - JsonObject, -} from "@cosmjs/cosmwasm-launchpad"; +import { Contract, ContractCodeHistoryEntry, JsonObject } from "@cosmjs/cosmwasm-launchpad"; import { fromAscii, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { @@ -38,13 +32,37 @@ import { setupWasmExtension, WasmExtension } from "./queries"; // Those types can be copied over to allow them to evolve independently of @cosmjs/cosmwasm-launchpad. // For now just re-export them such that they can be imported via @cosmjs/cosmwasm-stargate. export { - Code, // returned by CosmWasmClient.getCode - CodeDetails, // returned by CosmWasmClient.getCodeDetails Contract, // returned by CosmWasmClient.getContract ContractCodeHistoryEntry, // returned by CosmWasmClient.getContractCodeHistory JsonObject, // returned by CosmWasmClient.queryContractSmart }; +export interface Code { + readonly id: number; + /** Bech32 account address */ + readonly creator: string; + /** Hex-encoded sha256 hash of the code stored here */ + readonly checksum: string; + /** + * An URL to a .tar.gz archive of the source code of the contract, which can be used to reproducibly build the Wasm bytecode. + * + * @see https://github.com/CosmWasm/cosmwasm-verify + */ + readonly source?: string; + /** + * A docker image (including version) to reproducibly build the Wasm bytecode from the source code. + * + * @example ```cosmwasm/rust-optimizer:0.8.0``` + * @see https://github.com/CosmWasm/cosmwasm-verify + */ + readonly builder?: string; +} + +export interface CodeDetails extends Code { + /** The original Wasm bytes */ + readonly data: Uint8Array; +} + /** Use for testing only */ export interface PrivateCosmWasmClient { readonly tmClient: Tendermint34Client | undefined; From 77bd2e70a154fbf25304f3e6028346de35c37343 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 11:28:47 +0200 Subject: [PATCH 4/6] Copy JsonObject to cosmwasm-stargate --- packages/cosmwasm-stargate/src/cosmwasmclient.ts | 8 ++++++-- packages/cosmwasm-stargate/src/queries/index.ts | 2 +- packages/cosmwasm-stargate/src/queries/wasm.ts | 9 ++++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.ts index 5e04ba05..165dc9d3 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { Contract, ContractCodeHistoryEntry, JsonObject } from "@cosmjs/cosmwasm-launchpad"; +import { Contract, ContractCodeHistoryEntry } from "@cosmjs/cosmwasm-launchpad"; import { fromAscii, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { @@ -27,13 +27,17 @@ import { assert, sleep } from "@cosmjs/utils"; import { CodeInfoResponse } from "cosmjs-types/cosmwasm/wasm/v1beta1/query"; import { ContractCodeHistoryOperationType } from "cosmjs-types/cosmwasm/wasm/v1beta1/types"; -import { setupWasmExtension, WasmExtension } from "./queries"; +import { JsonObject, setupWasmExtension, WasmExtension } from "./queries"; // Those types can be copied over to allow them to evolve independently of @cosmjs/cosmwasm-launchpad. // For now just re-export them such that they can be imported via @cosmjs/cosmwasm-stargate. export { Contract, // returned by CosmWasmClient.getContract ContractCodeHistoryEntry, // returned by CosmWasmClient.getContractCodeHistory +}; + +// Re-exports that belong to public CosmWasmClient interfaces +export { JsonObject, // returned by CosmWasmClient.queryContractSmart }; diff --git a/packages/cosmwasm-stargate/src/queries/index.ts b/packages/cosmwasm-stargate/src/queries/index.ts index c0692523..c33027c9 100644 --- a/packages/cosmwasm-stargate/src/queries/index.ts +++ b/packages/cosmwasm-stargate/src/queries/index.ts @@ -1 +1 @@ -export { setupWasmExtension, WasmExtension } from "./wasm"; +export { setupWasmExtension, JsonObject, WasmExtension } from "./wasm"; diff --git a/packages/cosmwasm-stargate/src/queries/wasm.ts b/packages/cosmwasm-stargate/src/queries/wasm.ts index 579ab1d0..229a0cb8 100644 --- a/packages/cosmwasm-stargate/src/queries/wasm.ts +++ b/packages/cosmwasm-stargate/src/queries/wasm.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { JsonObject } from "@cosmjs/cosmwasm-launchpad"; import { fromUtf8, toAscii } from "@cosmjs/encoding"; import { createPagination, createProtobufRpcClient, QueryClient } from "@cosmjs/stargate"; import { @@ -14,6 +13,14 @@ import { } from "cosmjs-types/cosmwasm/wasm/v1beta1/query"; import Long from "long"; +/** + * An object containing a parsed JSON document. The result of JSON.parse(). + * This doesn't provide any type safety over `any` but expresses intent in the code. + * + * This type is returned by `queryContractSmart`. + */ +export type JsonObject = any; + export interface WasmExtension { readonly wasm: { readonly listCodeInfo: (paginationKey?: Uint8Array) => Promise; From 7a9963d6e26df4381ef88d9931649c1f53e48486 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 11:37:37 +0200 Subject: [PATCH 5/6] Copy Contract and ContractCodeHistoryEntry --- .../cosmwasm-stargate/src/cosmwasmclient.ts | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/packages/cosmwasm-stargate/src/cosmwasmclient.ts b/packages/cosmwasm-stargate/src/cosmwasmclient.ts index 165dc9d3..c0529b86 100644 --- a/packages/cosmwasm-stargate/src/cosmwasmclient.ts +++ b/packages/cosmwasm-stargate/src/cosmwasmclient.ts @@ -1,5 +1,4 @@ /* eslint-disable @typescript-eslint/naming-convention */ -import { Contract, ContractCodeHistoryEntry } from "@cosmjs/cosmwasm-launchpad"; import { fromAscii, toHex } from "@cosmjs/encoding"; import { Uint53 } from "@cosmjs/math"; import { @@ -29,13 +28,6 @@ import { ContractCodeHistoryOperationType } from "cosmjs-types/cosmwasm/wasm/v1b import { JsonObject, setupWasmExtension, WasmExtension } from "./queries"; -// Those types can be copied over to allow them to evolve independently of @cosmjs/cosmwasm-launchpad. -// For now just re-export them such that they can be imported via @cosmjs/cosmwasm-stargate. -export { - Contract, // returned by CosmWasmClient.getContract - ContractCodeHistoryEntry, // returned by CosmWasmClient.getContractCodeHistory -}; - // Re-exports that belong to public CosmWasmClient interfaces export { JsonObject, // returned by CosmWasmClient.queryContractSmart @@ -67,6 +59,23 @@ export interface CodeDetails extends Code { readonly data: Uint8Array; } +export interface Contract { + readonly address: string; + readonly codeId: number; + /** Bech32 account address */ + readonly creator: string; + /** Bech32-encoded admin address */ + readonly admin: string | undefined; + readonly label: string; +} + +export interface ContractCodeHistoryEntry { + /** The source of this history entry */ + readonly operation: "Genesis" | "Init" | "Migrate"; + readonly codeId: number; + readonly msg: Record; +} + /** Use for testing only */ export interface PrivateCosmWasmClient { readonly tmClient: Tendermint34Client | undefined; From 93d547b17d20bb5d9ef8f37e673c0786409ea161 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Thu, 22 Jul 2021 11:42:33 +0200 Subject: [PATCH 6/6] Remove dependency on @cosmjs/cosmwasm-launchpad --- .pnp.js | 1 - CHANGELOG.md | 3 +++ packages/cosmwasm-stargate/package.json | 1 - yarn.lock | 1 - 4 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.pnp.js b/.pnp.js index caf080db..c013dda2 100755 --- a/.pnp.js +++ b/.pnp.js @@ -3398,7 +3398,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageDependencies": [ ["@cosmjs/cosmwasm-stargate", "workspace:packages/cosmwasm-stargate"], ["@cosmjs/amino", "workspace:packages/amino"], - ["@cosmjs/cosmwasm-launchpad", "workspace:packages/cosmwasm-launchpad"], ["@cosmjs/crypto", "workspace:packages/crypto"], ["@cosmjs/encoding", "workspace:packages/encoding"], ["@cosmjs/math", "workspace:packages/math"], diff --git a/CHANGELOG.md b/CHANGELOG.md index a40b46d1..bfcad33c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,9 @@ and this project adheres to `parseCoins` that replaces the `parseCoins` re-export from `@cosmjs/amino`. - @cosmjs/cosmwasm-stargate: Export `isValidBuilder`, which is a clone of `isValidBuilder` from @cosmjs/cosmwasm-launchpad. +- @cosmjs/cosmwasm-stargate: Copy symbols `Code`, `CodeDetails`, `Contract`, + `ContractCodeHistoryEntry` and `JsonObject` from @cosmjs/cosmwasm-launchpad + and remove dependency on @cosmjs/cosmwasm-launchpad. ### Changed diff --git a/packages/cosmwasm-stargate/package.json b/packages/cosmwasm-stargate/package.json index 8e21300e..3333a1b4 100644 --- a/packages/cosmwasm-stargate/package.json +++ b/packages/cosmwasm-stargate/package.json @@ -38,7 +38,6 @@ }, "dependencies": { "@cosmjs/amino": "workspace:packages/amino", - "@cosmjs/cosmwasm-launchpad": "workspace:packages/cosmwasm-launchpad", "@cosmjs/crypto": "workspace:packages/crypto", "@cosmjs/encoding": "workspace:packages/encoding", "@cosmjs/math": "workspace:packages/math", diff --git a/yarn.lock b/yarn.lock index a701535e..200e87d1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -446,7 +446,6 @@ __metadata: resolution: "@cosmjs/cosmwasm-stargate@workspace:packages/cosmwasm-stargate" dependencies: "@cosmjs/amino": "workspace:packages/amino" - "@cosmjs/cosmwasm-launchpad": "workspace:packages/cosmwasm-launchpad" "@cosmjs/crypto": "workspace:packages/crypto" "@cosmjs/encoding": "workspace:packages/encoding" "@cosmjs/math": "workspace:packages/math"