From 3c59a68b3a394ffb3d00b9d5e0d2def42ddbc649 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 12 Feb 2020 09:40:36 +0100 Subject: [PATCH 1/3] Improve interface of CosmWasmConnection.identifier --- packages/bcp/src/cosmwasmconnection.spec.ts | 8 +++----- packages/bcp/src/cosmwasmconnection.ts | 19 +++++++++---------- packages/bcp/types/cosmwasmconnection.d.ts | 7 ++++++- packages/sdk/src/restclient.spec.ts | 3 +-- packages/sdk/src/restclient.ts | 4 +--- packages/sdk/types/restclient.d.ts | 4 ++-- 6 files changed, 22 insertions(+), 23 deletions(-) diff --git a/packages/bcp/src/cosmwasmconnection.spec.ts b/packages/bcp/src/cosmwasmconnection.spec.ts index d3f3ae56..74c4f977 100644 --- a/packages/bcp/src/cosmwasmconnection.spec.ts +++ b/packages/bcp/src/cosmwasmconnection.spec.ts @@ -18,7 +18,7 @@ import { assert } from "@iov/utils"; import { CosmWasmCodec } from "./cosmwasmcodec"; import { CosmWasmConnection, TokenConfiguration } from "./cosmwasmconnection"; -import { signedTxJson, txId } from "./testdata.spec"; +import * as testdata from "./testdata.spec"; const { fromBase64, toHex } = Encoding; @@ -197,12 +197,10 @@ describe("CosmWasmConnection", () => { describe("identifier", () => { it("calculates tx hash from PostableBytes", async () => { pendingWithoutCosmos(); - const codec = new CosmWasmCodec(defaultPrefix, atomConfig.bankTokens); const connection = await CosmWasmConnection.establish(httpUrl, defaultPrefix, atomConfig); - const postable = codec.bytesToPost(signedTxJson); - const id = await connection.identifier(postable); + const id = await connection.identifier(testdata.signedTxJson); expect(id).toMatch(/^[0-9A-F]{64}$/); - expect(id).toEqual(txId); + expect(id).toEqual(testdata.txId); }); }); diff --git a/packages/bcp/src/cosmwasmconnection.ts b/packages/bcp/src/cosmwasmconnection.ts index 801ec313..a44be650 100644 --- a/packages/bcp/src/cosmwasmconnection.ts +++ b/packages/bcp/src/cosmwasmconnection.ts @@ -1,12 +1,5 @@ /* eslint-disable @typescript-eslint/camelcase */ -import { - CosmosAddressBech32Prefix, - CosmWasmClient, - RestClient, - TxsResponse, - types, - unmarshalTx, -} from "@cosmwasm/sdk"; +import { CosmosAddressBech32Prefix, CosmWasmClient, RestClient, TxsResponse, types } from "@cosmwasm/sdk"; import { Account, AccountQuery, @@ -28,6 +21,7 @@ import { PostableBytes, PostTxResponse, PubkeyQuery, + SignedTransaction, Token, TokenTicker, TransactionId, @@ -46,6 +40,7 @@ import { Stream } from "xstream"; import { decodeCosmosPubkey, pubkeyToAddress } from "./address"; import { Caip5 } from "./caip5"; import { decodeAmount, parseTxsResponse } from "./decode"; +import { buildSignedTx } from "./encode"; import { accountToNonce, BankToken, Erc20Token } from "./types"; const { fromAscii, toHex } = Encoding; @@ -162,8 +157,12 @@ export class CosmWasmConnection implements BlockchainConnection { return this.supportedTokens; } - public async identifier(signed: PostableBytes): Promise { - const tx = unmarshalTx(signed); + /** + * This is a replacement for the unimplemented CosmWasmCodec.identifier. Here we have more + * context and network available, which we might use to implement the API in an async way. + */ + public async identifier(signed: SignedTransaction): Promise { + const tx = buildSignedTx(signed, this.bankTokens, this.erc20Tokens); // tslint:disable-next-line: deprecation const bytes = await this.restClient.encodeTx(tx); const hash = new Sha256(bytes).digest(); diff --git a/packages/bcp/types/cosmwasmconnection.d.ts b/packages/bcp/types/cosmwasmconnection.d.ts index 6d15edea..66305e8c 100644 --- a/packages/bcp/types/cosmwasmconnection.d.ts +++ b/packages/bcp/types/cosmwasmconnection.d.ts @@ -14,6 +14,7 @@ import { PostableBytes, PostTxResponse, PubkeyQuery, + SignedTransaction, Token, TokenTicker, TransactionId, @@ -58,7 +59,11 @@ export declare class CosmWasmConnection implements BlockchainConnection { height(): Promise; getToken(searchTicker: TokenTicker): Promise; getAllTokens(): Promise; - identifier(signed: PostableBytes): Promise; + /** + * This is a replacement for the unimplemented CosmWasmCodec.identifier. Here we have more + * context and network available, which we might use to implement the API in an async way. + */ + identifier(signed: SignedTransaction): Promise; getAccount(query: AccountQuery): Promise; watchAccount(_account: AccountQuery): Stream; getNonce(query: AddressQuery | PubkeyQuery): Promise; diff --git a/packages/sdk/src/restclient.spec.ts b/packages/sdk/src/restclient.spec.ts index 9862d178..276de57b 100644 --- a/packages/sdk/src/restclient.spec.ts +++ b/packages/sdk/src/restclient.spec.ts @@ -221,9 +221,8 @@ describe("RestClient", () => { describe("encodeTx", () => { it("works for cosmoshub example", async () => { pendingWithoutCosmos(); - const tx = cosmoshub.tx.value; const client = new RestClient(httpUrl); - expect(await client.encodeTx(tx)).toEqual(fromBase64(cosmoshub.tx_data)); + expect(await client.encodeTx(cosmoshub.tx)).toEqual(fromBase64(cosmoshub.tx_data)); }); }); diff --git a/packages/sdk/src/restclient.ts b/packages/sdk/src/restclient.ts index b6ee7e05..8815981d 100644 --- a/packages/sdk/src/restclient.ts +++ b/packages/sdk/src/restclient.ts @@ -9,7 +9,6 @@ import { isStdTx, Model, parseWasmData, - StdTx, WasmData, } from "./types"; @@ -221,8 +220,7 @@ export class RestClient { } /** returns the amino-encoding of the transaction performed by the server */ - public async encodeTx(stdTx: StdTx): Promise { - const tx = { type: "cosmos-sdk/StdTx", value: stdTx }; + public async encodeTx(tx: CosmosSdkTx): Promise { const responseData = await this.post("/txs/encode", tx); if (!(responseData as any).tx) { throw new Error("Unexpected response data format"); diff --git a/packages/sdk/types/restclient.d.ts b/packages/sdk/types/restclient.d.ts index 8f41d03a..a7e87e27 100644 --- a/packages/sdk/types/restclient.d.ts +++ b/packages/sdk/types/restclient.d.ts @@ -1,4 +1,4 @@ -import { CodeInfo, ContractInfo, CosmosSdkAccount, CosmosSdkTx, Model, StdTx } from "./types"; +import { CodeInfo, ContractInfo, CosmosSdkAccount, CosmosSdkTx, Model } from "./types"; interface NodeInfo { readonly network: string; } @@ -92,7 +92,7 @@ export declare class RestClient { blocksLatest(): Promise; blocks(height: number): Promise; /** returns the amino-encoding of the transaction performed by the server */ - encodeTx(stdTx: StdTx): Promise; + encodeTx(tx: CosmosSdkTx): Promise; authAccounts(address: string, height?: string): Promise; txs(query: string): Promise; txsById(id: string): Promise; From 331702638b8fcd240d0eceb391b51a861ffe45aa Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 12 Feb 2020 09:46:58 +0100 Subject: [PATCH 2/3] Add CosmWasmClient.getIdentifier --- packages/sdk/src/cosmwasmclient.spec.ts | 9 +++++++++ packages/sdk/src/cosmwasmclient.ts | 12 ++++++++++++ packages/sdk/types/cosmwasmclient.d.ts | 6 +++++- 3 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/sdk/src/cosmwasmclient.spec.ts b/packages/sdk/src/cosmwasmclient.spec.ts index 27ff42e3..80a5b9a2 100644 --- a/packages/sdk/src/cosmwasmclient.spec.ts +++ b/packages/sdk/src/cosmwasmclient.spec.ts @@ -3,6 +3,7 @@ import { makeSignBytes, marshalTx } from "./encoding"; import { findAttribute } from "./logs"; import { Secp256k1Pen } from "./pen"; import { RestClient } from "./restclient"; +import cosmoshub from "./testdata/cosmoshub.json"; import { getRandomizedHackatom, makeRandomAddress } from "./testutils.spec"; import { Coin, MsgSend, StdFee } from "./types"; @@ -59,6 +60,14 @@ describe("CosmWasmClient", () => { }); }); + describe("getIdentifier", () => { + it("works", async () => { + pendingWithoutCosmos(); + const client = CosmWasmClient.makeReadOnly(httpUrl); + expect(await client.getIdentifier(cosmoshub.tx)).toEqual(cosmoshub.id); + }); + }); + describe("postTx", () => { it("works", async () => { pendingWithoutCosmos(); diff --git a/packages/sdk/src/cosmwasmclient.ts b/packages/sdk/src/cosmwasmclient.ts index f1c191e7..d0ff8a94 100644 --- a/packages/sdk/src/cosmwasmclient.ts +++ b/packages/sdk/src/cosmwasmclient.ts @@ -1,3 +1,4 @@ +import { Sha256 } from "@iov/crypto"; import { Encoding } from "@iov/encoding"; import { makeSignBytes, marshalTx } from "./encoding"; @@ -5,6 +6,7 @@ import { findAttribute, Log, parseLogs } from "./logs"; import { RestClient } from "./restclient"; import { Coin, + CosmosSdkTx, MsgExecuteContract, MsgInstantiateContract, MsgStoreCode, @@ -106,6 +108,16 @@ export class CosmWasmClient { return response.node_info.network; } + /** + * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) + */ + public async getIdentifier(tx: CosmosSdkTx): Promise { + // We consult the REST API because we don't have a local amino encoder + const bytes = await this.restClient.encodeTx(tx); + const hash = new Sha256(bytes).digest(); + return Encoding.toHex(hash).toUpperCase(); + } + /** * Returns account number and sequence. * diff --git a/packages/sdk/types/cosmwasmclient.d.ts b/packages/sdk/types/cosmwasmclient.d.ts index bee7e6a2..4fae10bd 100644 --- a/packages/sdk/types/cosmwasmclient.d.ts +++ b/packages/sdk/types/cosmwasmclient.d.ts @@ -1,5 +1,5 @@ import { Log } from "./logs"; -import { Coin, StdSignature } from "./types"; +import { Coin, CosmosSdkTx, StdSignature } from "./types"; export interface SigningCallback { (signBytes: Uint8Array): Promise; } @@ -25,6 +25,10 @@ export declare class CosmWasmClient { private get signCallback(); private constructor(); chainId(): Promise; + /** + * Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID) + */ + getIdentifier(tx: CosmosSdkTx): Promise; /** * Returns account number and sequence. * From e66aa14d6dae80245ef04172c72dcc9a3180d5f2 Mon Sep 17 00:00:00 2001 From: Simon Warta Date: Wed, 12 Feb 2020 09:54:40 +0100 Subject: [PATCH 3/3] Use CosmWasmClient.getIdentifier --- packages/bcp/src/cosmwasmconnection.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/bcp/src/cosmwasmconnection.ts b/packages/bcp/src/cosmwasmconnection.ts index a44be650..1f8affbf 100644 --- a/packages/bcp/src/cosmwasmconnection.ts +++ b/packages/bcp/src/cosmwasmconnection.ts @@ -29,7 +29,6 @@ import { TransactionState, UnsignedTransaction, } from "@iov/bcp"; -import { Sha256 } from "@iov/crypto"; import { Encoding, Uint53 } from "@iov/encoding"; import { DefaultValueProducer, ValueAndUpdates } from "@iov/stream"; import BN from "bn.js"; @@ -43,7 +42,7 @@ import { decodeAmount, parseTxsResponse } from "./decode"; import { buildSignedTx } from "./encode"; import { accountToNonce, BankToken, Erc20Token } from "./types"; -const { fromAscii, toHex } = Encoding; +const { fromAscii } = Encoding; interface ChainData { readonly chainId: ChainId; @@ -163,10 +162,8 @@ export class CosmWasmConnection implements BlockchainConnection { */ public async identifier(signed: SignedTransaction): Promise { const tx = buildSignedTx(signed, this.bankTokens, this.erc20Tokens); - // tslint:disable-next-line: deprecation - const bytes = await this.restClient.encodeTx(tx); - const hash = new Sha256(bytes).digest(); - return toHex(hash).toUpperCase() as TransactionId; + const id = await this.cosmWasmClient.getIdentifier(tx); + return id as TransactionId; } public async getAccount(query: AccountQuery): Promise {