Merge pull request #82 from confio/encodeTx-improvements

Add CosmWasmClient.getIdentifier
This commit is contained in:
Simon Warta 2020-02-12 14:11:44 +01:00 committed by GitHub
commit 737d5570b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 51 additions and 30 deletions

View File

@ -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);
});
});

View File

@ -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,
@ -35,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";
@ -46,9 +39,10 @@ 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;
const { fromAscii } = Encoding;
interface ChainData {
readonly chainId: ChainId;
@ -162,12 +156,14 @@ export class CosmWasmConnection implements BlockchainConnection {
return this.supportedTokens;
}
public async identifier(signed: PostableBytes): Promise<TransactionId> {
const tx = unmarshalTx(signed);
// tslint:disable-next-line: deprecation
const bytes = await this.restClient.encodeTx(tx);
const hash = new Sha256(bytes).digest();
return toHex(hash).toUpperCase() as TransactionId;
/**
* 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<TransactionId> {
const tx = buildSignedTx(signed, this.bankTokens, this.erc20Tokens);
const id = await this.cosmWasmClient.getIdentifier(tx);
return id as TransactionId;
}
public async getAccount(query: AccountQuery): Promise<Account | undefined> {

View File

@ -14,6 +14,7 @@ import {
PostableBytes,
PostTxResponse,
PubkeyQuery,
SignedTransaction,
Token,
TokenTicker,
TransactionId,
@ -58,7 +59,11 @@ export declare class CosmWasmConnection implements BlockchainConnection {
height(): Promise<number>;
getToken(searchTicker: TokenTicker): Promise<Token | undefined>;
getAllTokens(): Promise<readonly Token[]>;
identifier(signed: PostableBytes): Promise<TransactionId>;
/**
* 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<TransactionId>;
getAccount(query: AccountQuery): Promise<Account | undefined>;
watchAccount(_account: AccountQuery): Stream<Account | undefined>;
getNonce(query: AddressQuery | PubkeyQuery): Promise<Nonce>;

View File

@ -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();

View File

@ -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<string> {
// 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.
*

View File

@ -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));
});
});

View File

@ -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<Uint8Array> {
const tx = { type: "cosmos-sdk/StdTx", value: stdTx };
public async encodeTx(tx: CosmosSdkTx): Promise<Uint8Array> {
const responseData = await this.post("/txs/encode", tx);
if (!(responseData as any).tx) {
throw new Error("Unexpected response data format");

View File

@ -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<StdSignature>;
}
@ -25,6 +25,10 @@ export declare class CosmWasmClient {
private get signCallback();
private constructor();
chainId(): Promise<string>;
/**
* Returns a 32 byte upper-case hex transaction hash (typically used as the transaction ID)
*/
getIdentifier(tx: CosmosSdkTx): Promise<string>;
/**
* Returns account number and sequence.
*

View File

@ -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<BlocksResponse>;
blocks(height: number): Promise<BlocksResponse>;
/** returns the amino-encoding of the transaction performed by the server */
encodeTx(stdTx: StdTx): Promise<Uint8Array>;
encodeTx(tx: CosmosSdkTx): Promise<Uint8Array>;
authAccounts(address: string, height?: string): Promise<AuthAccountsResponse>;
txs(query: string): Promise<SearchTxsResponse>;
txsById(id: string): Promise<TxsResponse>;