Merge pull request #10 from confio/error-on-failed-tx

Error on failed tx
This commit is contained in:
Ethan Frey 2020-01-23 15:47:06 +01:00 committed by GitHub
commit ae1534896d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 20 additions and 30 deletions

View File

@ -24,6 +24,7 @@
"docs": "shx rm -rf docs && typedoc --options typedoc.js", "docs": "shx rm -rf docs && typedoc --options typedoc.js",
"format": "prettier --write --loglevel warn \"./src/**/*.ts\"", "format": "prettier --write --loglevel warn \"./src/**/*.ts\"",
"lint": "eslint --max-warnings 0 \"**/*.{js,ts}\" && tslint -t verbose --project .", "lint": "eslint --max-warnings 0 \"**/*.{js,ts}\" && tslint -t verbose --project .",
"autolint": "eslint --max-warnings 0 \"**/*.{js,ts}\" --fix",
"move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts", "move-types": "shx rm -rf ./types/* && shx mv build/types/* ./types && rm -rf ./types/testdata && shx rm -f ./types/*.spec.d.ts",
"format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"", "format-types": "prettier --write --loglevel warn \"./types/**/*.d.ts\"",
"build": "shx rm -rf ./build && tsc && yarn move-types && yarn format-types", "build": "shx rm -rf ./build && tsc && yarn move-types && yarn format-types",

View File

@ -18,7 +18,7 @@ import { Sha256 } from "@iov/crypto";
import { Encoding } from "@iov/encoding"; import { Encoding } from "@iov/encoding";
import { marshalTx, unmarshalTx } from "@tendermint/amino-js"; import { marshalTx, unmarshalTx } from "@tendermint/amino-js";
import { isValidAddress, pubkeyToAddress, CosmosBech32Prefix } from "./address"; import { CosmosBech32Prefix, isValidAddress, pubkeyToAddress } from "./address";
import { Caip5 } from "./caip5"; import { Caip5 } from "./caip5";
import { parseTx } from "./decode"; import { parseTx } from "./decode";
import { buildSignedTx, buildUnsignedTx } from "./encode"; import { buildSignedTx, buildUnsignedTx } from "./encode";
@ -91,7 +91,6 @@ export class CosmosCodec implements TxCodec {
throw new Error("Nonce is required"); throw new Error("Nonce is required");
} }
const parsed = unmarshalTx(bytes); const parsed = unmarshalTx(bytes);
// TODO: this needs access to token list
return parseTx(parsed, chainId, nonce, this.tokens); return parseTx(parsed, chainId, nonce, this.tokens);
} }

View File

@ -14,9 +14,9 @@ import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding"; import { Encoding } from "@iov/encoding";
import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol"; import { HdPaths, Secp256k1HdWallet, UserProfile } from "@iov/keycontrol";
import { cosmosCodec, CosmosCodec } from "./cosmoscodec";
import { CosmosConnection } from "./cosmosconnection";
import { CosmosBech32Prefix } from "./address"; import { CosmosBech32Prefix } from "./address";
import { CosmosCodec, cosmosCodec } from "./cosmoscodec";
import { CosmosConnection } from "./cosmosconnection";
import { TokenInfos } from "./types"; import { TokenInfos } from "./types";
const { fromBase64, toHex } = Encoding; const { fromBase64, toHex } = Encoding;
@ -197,11 +197,9 @@ describe("CosmosConnection", () => {
const nonce = await connection.getNonce({ address: faucetAddress }); const nonce = await connection.getNonce({ address: faucetAddress });
// TODO: we need to use custom codecs everywhere // TODO: we need to use custom codecs everywhere
const codec = new CosmosCodec(defaultPrefix, defaultTokens); const codec = new CosmosCodec(defaultPrefix, defaultTokens);
console.log("nonce:", nonce);
const signed = await profile.signTransaction(faucet, unsigned, codec, nonce); const signed = await profile.signTransaction(faucet, unsigned, codec, nonce);
const postableBytes = codec.bytesToPost(signed); const postableBytes = codec.bytesToPost(signed);
const response = await connection.postTx(postableBytes); const response = await connection.postTx(postableBytes);
console.log(response);
const { transactionId } = response; const { transactionId } = response;
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info)); const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
expect(blockInfo.state).toEqual(TransactionState.Succeeded); expect(blockInfo.state).toEqual(TransactionState.Succeeded);
@ -263,7 +261,6 @@ describe("CosmosConnection", () => {
const signed = await profile.signTransaction(faucet, unsigned, codec, nonce); const signed = await profile.signTransaction(faucet, unsigned, codec, nonce);
const postableBytes = codec.bytesToPost(signed); const postableBytes = codec.bytesToPost(signed);
const response = await connection.postTx(postableBytes); const response = await connection.postTx(postableBytes);
console.log(response);
const { transactionId } = response; const { transactionId } = response;
const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info)); const blockInfo = await response.blockInfo.waitFor(info => !isBlockInfoPending(info));
expect(blockInfo.state).toEqual(TransactionState.Succeeded); expect(blockInfo.state).toEqual(TransactionState.Succeeded);

View File

@ -89,14 +89,13 @@ export class CosmosConnection implements BlockchainConnection {
private readonly restClient: RestClient; private readonly restClient: RestClient;
private readonly chainData: ChainData; private readonly chainData: ChainData;
private readonly primaryToken: Token;
// TODO: deprecate this???
private readonly supportedTokens: readonly Token[];
private readonly _prefix: CosmosBech32Prefix; private readonly _prefix: CosmosBech32Prefix;
private readonly tokenInfo: TokenInfos; private readonly tokenInfo: TokenInfos;
// these are derived from arguments (cached for use in multiple functions)
private readonly primaryToken: Token;
private readonly supportedTokens: readonly Token[];
private get prefix(): CosmosBech32Prefix { private get prefix(): CosmosBech32Prefix {
return this._prefix; return this._prefix;
} }
@ -214,8 +213,10 @@ export class CosmosConnection implements BlockchainConnection {
} }
public async postTx(tx: PostableBytes): Promise<PostTxResponse> { public async postTx(tx: PostableBytes): Promise<PostTxResponse> {
// TODO: we need to check errors here... bad chain-id breaks this const { code, txhash, raw_log } = await this.restClient.postTx(tx);
const { txhash, raw_log } = await this.restClient.postTx(tx); if (code !== 0) {
throw new Error(raw_log);
}
const transactionId = txhash as TransactionId; const transactionId = txhash as TransactionId;
const firstEvent: BlockInfo = { state: TransactionState.Pending }; const firstEvent: BlockInfo = { state: TransactionState.Pending };
let blockInfoInterval: NodeJS.Timeout; let blockInfoInterval: NodeJS.Timeout;

View File

@ -1,8 +1,8 @@
import { ChainConnector, ChainId } from "@iov/bcp"; import { ChainConnector, ChainId } from "@iov/bcp";
import { CosmosBech32Prefix } from "./address";
import { cosmosCodec } from "./cosmoscodec"; import { cosmosCodec } from "./cosmoscodec";
import { CosmosConnection } from "./cosmosconnection"; import { CosmosConnection } from "./cosmosconnection";
import { CosmosBech32Prefix } from "./address";
import { TokenInfos } from "./types"; import { TokenInfos } from "./types";
/** /**

View File

@ -12,7 +12,6 @@ import {
SendTransaction, SendTransaction,
SignatureBytes, SignatureBytes,
SignedTransaction, SignedTransaction,
TokenTicker,
TransactionId, TransactionId,
UnsignedTransaction, UnsignedTransaction,
} from "@iov/bcp"; } from "@iov/bcp";
@ -20,12 +19,10 @@ import { Encoding } from "@iov/encoding";
import amino from "@tendermint/amino-js"; import amino from "@tendermint/amino-js";
import { TxsResponse } from "./restclient"; import { TxsResponse } from "./restclient";
import { isAminoStdTx, TokenInfos, coinToAmount } from "./types"; import { coinToAmount, isAminoStdTx, TokenInfos } from "./types";
const { fromBase64 } = Encoding; const { fromBase64 } = Encoding;
const atom = "ATOM" as TokenTicker;
export function decodePubkey(pubkey: amino.PubKey): PubkeyBundle { export function decodePubkey(pubkey: amino.PubKey): PubkeyBundle {
return { return {
algo: Algorithm.Secp256k1, algo: Algorithm.Secp256k1,
@ -45,9 +42,6 @@ export function decodeFullSignature(signature: amino.StdSignature, nonce: number
}; };
} }
// TODO: this needs access to token list - we need something more like amountToCoin and coinToAmount here
// and wire that info all the way from both connection and codec.
// TODO: return null vs throw exception for undefined??? // TODO: return null vs throw exception for undefined???
export const decodeAmount = (tokens: TokenInfos) => (coin: amino.Coin): Amount => { export const decodeAmount = (tokens: TokenInfos) => (coin: amino.Coin): Amount => {
return coinToAmount(tokens, coin); return coinToAmount(tokens, coin);
@ -69,7 +63,6 @@ export function parseMsg(msg: amino.Msg, chainId: ChainId, tokens: TokenInfos):
chainId: chainId, chainId: chainId,
sender: msgValue.from_address as Address, sender: msgValue.from_address as Address,
recipient: msgValue.to_address as Address, recipient: msgValue.to_address as Address,
// TODO: this needs access to token list
amount: decodeAmount(tokens)(msgValue.amount[0]), amount: decodeAmount(tokens)(msgValue.amount[0]),
}; };
} }
@ -94,9 +87,7 @@ export function parseTx(tx: amino.Tx, chainId: ChainId, nonce: Nonce, tokens: To
} }
const [primarySignature] = txValue.signatures.map(signature => decodeFullSignature(signature, nonce)); const [primarySignature] = txValue.signatures.map(signature => decodeFullSignature(signature, nonce));
// TODO: this needs access to token list
const msg = parseMsg(txValue.msg[0], chainId, tokens); const msg = parseMsg(txValue.msg[0], chainId, tokens);
// TODO: this needs access to token list
const fee = parseFee(txValue.fee, tokens); const fee = parseFee(txValue.fee, tokens);
const transaction = { const transaction = {

View File

@ -13,7 +13,7 @@ import { Secp256k1 } from "@iov/crypto";
import { Encoding } from "@iov/encoding"; import { Encoding } from "@iov/encoding";
import amino from "@tendermint/amino-js"; import amino from "@tendermint/amino-js";
import { AminoTx, TokenInfos, amountToCoin } from "./types"; import { AminoTx, amountToCoin, TokenInfos } from "./types";
const { toBase64 } = Encoding; const { toBase64 } = Encoding;

View File

@ -16,7 +16,7 @@ export interface TokenInfo extends Token {
export type TokenInfos = ReadonlyArray<TokenInfo>; export type TokenInfos = ReadonlyArray<TokenInfo>;
// TODO: alias amino types // TODO: return null vs throw exception for undefined???
export function amountToCoin(lookup: ReadonlyArray<TokenInfo>, amount: Amount): amino.Coin { export function amountToCoin(lookup: ReadonlyArray<TokenInfo>, amount: Amount): amino.Coin {
const match = lookup.find(({ tokenTicker }) => tokenTicker === amount.tokenTicker); const match = lookup.find(({ tokenTicker }) => tokenTicker === amount.tokenTicker);
if (!match) { if (!match) {
@ -28,6 +28,7 @@ export function amountToCoin(lookup: ReadonlyArray<TokenInfo>, amount: Amount):
}; };
} }
// TODO: return null vs throw exception for undefined???
export function coinToAmount(tokens: TokenInfos, coin: amino.Coin): Amount { export function coinToAmount(tokens: TokenInfos, coin: amino.Coin): Amount {
const match = tokens.find(({ denom }) => denom === coin.denom); const match = tokens.find(({ denom }) => denom === coin.denom);
if (!match) { if (!match) {

View File

@ -27,10 +27,10 @@ export declare class CosmosConnection implements BlockchainConnection {
private static initialize; private static initialize;
private readonly restClient; private readonly restClient;
private readonly chainData; private readonly chainData;
private readonly primaryToken;
private readonly supportedTokens;
private readonly _prefix; private readonly _prefix;
private readonly tokenInfo; private readonly tokenInfo;
private readonly primaryToken;
private readonly supportedTokens;
private get prefix(); private get prefix();
private constructor(); private constructor();
disconnect(): void; disconnect(): void;

View File

@ -1,6 +1,6 @@
import { ChainConnector, ChainId } from "@iov/bcp"; import { ChainConnector, ChainId } from "@iov/bcp";
import { CosmosConnection } from "./cosmosconnection";
import { CosmosBech32Prefix } from "./address"; import { CosmosBech32Prefix } from "./address";
import { CosmosConnection } from "./cosmosconnection";
import { TokenInfos } from "./types"; import { TokenInfos } from "./types";
/** /**
* A helper to connect to a cosmos-based chain at a given url * A helper to connect to a cosmos-based chain at a given url