Merge pull request #581 from cosmos/579-search-by-id

Separate .searchTx and .getTx methods
This commit is contained in:
mergify[bot] 2020-12-15 15:04:04 +00:00 committed by GitHub
commit 9b7878bad1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 81 additions and 186 deletions

View File

@ -6,12 +6,16 @@
@cosmjs/launchpad instead.
- @cosmjs/cosmwasm: Export `JsonObject`, `ChangeAdminResult` and `WasmData`
types as well as `isValidBuilder` and `parseWasmData` functions.
- @cosmjs/cosmwasm: Add `CosmWasmClient.getTx` method for searching by ID and
remove such functionality from `CosmWasmClient.searchTx`.
- @cosmjs/cosmwasm-stargate: Add new package for CosmWasm Stargate support.
- @cosmjs/launchpad: Add `Secp256k1Wallet` to manage a single raw secp256k1
keypair.
- @cosmjs/launchpad: `OfflineSigner` types `sign` method renamed `signAmino`
and `SignResponse` type renamed `AminoSignResponse`.
- @cosmjs/launchpad: `Secp256k1HdWallet.sign` method renamed `signAmino`.
- @cosmjs/launchpad: Add `CosmosClient.getTx` method for searching by ID and
remove such functionality from `CosmosClient.searchTx`.
- @cosmjs/launchpad-ledger: `LedgerSigner.sign` method renamed `signAmino`.
- @cosmjs/proto-signing: Add new package for handling transaction signing with
protobuf encoding.

View File

@ -50,7 +50,6 @@ export async function main(originalArgs: readonly string[]): Promise<void> {
"CosmWasmClient",
"GetSequenceResult",
"SearchByHeightQuery",
"SearchByIdQuery",
"SearchBySentFromOrToQuery",
"SearchByTagsQuery",
"SearchTxQuery",

View File

@ -5,7 +5,6 @@ import {
Block,
Coin,
isSearchByHeightQuery,
isSearchByIdQuery,
isSearchBySentFromOrToQuery,
isSearchByTagsQuery,
SearchTxFilter,
@ -126,6 +125,11 @@ export class CosmWasmClient {
return balance ? coinFromProto(balance) : null;
}
public async getTx(id: string): Promise<IndexedTx | null> {
const results = await this.txsQuery(`tx.hash='${id}'`);
return results[0] ?? null;
}
public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise<readonly IndexedTx[]> {
const minHeight = filter.minHeight || 0;
const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER;
@ -134,9 +138,7 @@ export class CosmWasmClient {
let txs: readonly IndexedTx[];
if (isSearchByIdQuery(query)) {
txs = await this.txsQuery(`tx.hash='${query.id}'`);
} else if (isSearchByHeightQuery(query)) {
if (isSearchByHeightQuery(query)) {
txs =
query.height >= minHeight && query.height <= maxHeight
? await this.txsQuery(`tx.height=${query.height}`)

View File

@ -495,8 +495,9 @@ describe("SigningCosmWasmClient", () => {
await sleep(1000);
const searchResult = await client.searchTx({ id: result.transactionHash });
const tx = Tx.decode(searchResult[0].tx);
const searchResult = await client.getTx(result.transactionHash);
assert(searchResult, "Must find transaction");
const tx = Tx.decode(searchResult.tx);
// From ModifyingDirectSecp256k1HdWallet
expect(tx.body!.memo).toEqual("This was modified");
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));
@ -571,8 +572,9 @@ describe("SigningCosmWasmClient", () => {
await sleep(1000);
const searchResult = await client.searchTx({ id: result.transactionHash });
const tx = Tx.decode(searchResult[0].tx);
const searchResult = await client.getTx(result.transactionHash);
assert(searchResult, "Must find transaction");
const tx = Tx.decode(searchResult.tx);
// From ModifyingSecp256k1HdWallet
expect(tx.body!.memo).toEqual("This was modified");
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));

View File

@ -29,6 +29,7 @@ export declare class CosmWasmClient {
getSequence(address: string): Promise<SequenceResponse | null>;
getBlock(height?: number): Promise<Block>;
getBalance(address: string, searchDenom: string): Promise<Coin | null>;
getTx(id: string): Promise<IndexedTx | null>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
disconnect(): void;
broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse>;

View File

@ -44,7 +44,7 @@ interface TestTxExecute {
readonly tx: WrappedStdTx;
}
describe("CosmWasmClient.searchTx", () => {
describe("CosmWasmClient.getTx and .searchTx", () => {
let sendSuccessful: TestTxSend | undefined;
let sendSelfSuccessful: TestTxSend | undefined;
let sendUnsuccessful: TestTxSend | undefined;
@ -147,15 +147,14 @@ describe("CosmWasmClient.searchTx", () => {
}
});
describe("with SearchByIdQuery", () => {
it("can search successful tx by ID", async () => {
describe("getTx", () => {
it("can get successful tx by ID", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.searchTx({ id: sendSuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendSuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
@ -165,14 +164,13 @@ describe("CosmWasmClient.searchTx", () => {
);
});
it("can search unsuccessful tx by ID", async () => {
it("can get unsuccessful tx by ID", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendUnsuccessful, "value must be set in beforeAll()");
const client = new CosmWasmClient(launchpad.endpoint);
const result = await client.searchTx({ id: sendUnsuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendUnsuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendUnsuccessful.height,
hash: sendUnsuccessful.hash,
@ -182,41 +180,13 @@ describe("CosmWasmClient.searchTx", () => {
);
});
it("can search by ID (non existent)", async () => {
it("can get by ID (non existent)", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
const client = new CosmWasmClient(launchpad.endpoint);
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
const result = await client.searchTx({ id: nonExistentId });
expect(result.length).toEqual(0);
});
it("can search by ID and filter by minHeight", async () => {
pendingWithoutLaunchpad();
pendingWithoutErc20();
assert(sendSuccessful);
const client = new CosmWasmClient(launchpad.endpoint);
const query = { id: sendSuccessful.hash };
{
const result = await client.searchTx(query, { minHeight: 0 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 });
expect(result.length).toEqual(0);
}
const result = await client.getTx(nonExistentId);
expect(result).toBeNull();
});
});

View File

@ -54,15 +54,7 @@ export interface SearchByTagsQuery {
readonly tags: ReadonlyArray<{ readonly key: string; readonly value: string }>;
}
export type SearchTxQuery =
| SearchByIdQuery
| SearchByHeightQuery
| SearchBySentFromOrToQuery
| SearchByTagsQuery;
function isSearchByIdQuery(query: SearchTxQuery): query is SearchByIdQuery {
return (query as SearchByIdQuery).id !== undefined;
}
export type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery;
function isSearchByHeightQuery(query: SearchTxQuery): query is SearchByHeightQuery {
return (query as SearchByHeightQuery).height !== undefined;
@ -264,6 +256,11 @@ export class CosmWasmClient {
};
}
public async getTx(id: string): Promise<IndexedTx | null> {
const results = await this.txsQuery(`tx.hash=${id}`);
return results[0] ?? null;
}
public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise<readonly IndexedTx[]> {
const minHeight = filter.minHeight || 0;
const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER;
@ -275,9 +272,7 @@ export class CosmWasmClient {
}
let txs: readonly IndexedTx[];
if (isSearchByIdQuery(query)) {
txs = await this.txsQuery(`tx.hash=${query.id}`);
} else if (isSearchByHeightQuery(query)) {
if (isSearchByHeightQuery(query)) {
// optional optimization to avoid network request
if (query.height < minHeight || query.height > maxHeight) {
txs = [];

View File

@ -14,7 +14,6 @@ export {
CosmWasmClient,
GetSequenceResult,
SearchByHeightQuery,
SearchByIdQuery,
SearchBySentFromOrToQuery,
SearchByTagsQuery,
SearchTxQuery,

View File

@ -42,11 +42,7 @@ export interface SearchByTagsQuery {
readonly value: string;
}>;
}
export declare type SearchTxQuery =
| SearchByIdQuery
| SearchByHeightQuery
| SearchBySentFromOrToQuery
| SearchByTagsQuery;
export declare type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery;
export interface SearchTxFilter {
readonly minHeight?: number;
readonly maxHeight?: number;
@ -148,6 +144,7 @@ export declare class CosmWasmClient {
* @param height The height of the block. If undefined, the latest height is used.
*/
getBlock(height?: number): Promise<Block>;
getTx(id: string): Promise<IndexedTx | null>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
broadcastTx(tx: StdTx): Promise<BroadcastTxResult>;
getCodes(): Promise<readonly Code[]>;

View File

@ -13,7 +13,6 @@ export {
CosmWasmClient,
GetSequenceResult,
SearchByHeightQuery,
SearchByIdQuery,
SearchBySentFromOrToQuery,
SearchByTagsQuery,
SearchTxQuery,

View File

@ -26,7 +26,7 @@ interface TestTxSend {
readonly tx: WrappedStdTx;
}
describe("CosmosClient.searchTx", () => {
describe("CosmosClient.getTx and .searchTx", () => {
let sendUnsuccessful: TestTxSend | undefined;
let sendSuccessful: TestTxSend | undefined;
@ -91,14 +91,13 @@ describe("CosmosClient.searchTx", () => {
}
});
describe("with SearchByIdQuery", () => {
it("can search successful tx by ID", async () => {
describe("getTx", () => {
it("can get successful tx by ID", async () => {
pendingWithoutLaunchpad();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = new CosmosClient(launchpad.endpoint);
const result = await client.searchTx({ id: sendSuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendSuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
@ -108,13 +107,12 @@ describe("CosmosClient.searchTx", () => {
);
});
it("can search unsuccessful tx by ID", async () => {
it("can get unsuccessful tx by ID", async () => {
pendingWithoutLaunchpad();
assert(sendUnsuccessful, "value must be set in beforeAll()");
const client = new CosmosClient(launchpad.endpoint);
const result = await client.searchTx({ id: sendUnsuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendUnsuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendUnsuccessful.height,
hash: sendUnsuccessful.hash,
@ -124,39 +122,12 @@ describe("CosmosClient.searchTx", () => {
);
});
it("can search by ID (non existent)", async () => {
it("can get by ID (non existent)", async () => {
pendingWithoutLaunchpad();
const client = new CosmosClient(launchpad.endpoint);
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
const result = await client.searchTx({ id: nonExistentId });
expect(result.length).toEqual(0);
});
it("can search by ID and filter by minHeight", async () => {
pendingWithoutLaunchpad();
assert(sendSuccessful);
const client = new CosmosClient(launchpad.endpoint);
const query = { id: sendSuccessful.hash };
{
const result = await client.searchTx(query, { minHeight: 0 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 });
expect(result.length).toEqual(0);
}
const result = await client.getTx(nonExistentId);
expect(result).toBeNull();
});
});

View File

@ -66,10 +66,6 @@ export function assertIsBroadcastTxSuccess(result: BroadcastTxResult): asserts r
}
}
export interface SearchByIdQuery {
readonly id: string;
}
export interface SearchByHeightQuery {
readonly height: number;
}
@ -86,15 +82,7 @@ export interface SearchByTagsQuery {
readonly tags: ReadonlyArray<{ readonly key: string; readonly value: string }>;
}
export type SearchTxQuery =
| SearchByIdQuery
| SearchByHeightQuery
| SearchBySentFromOrToQuery
| SearchByTagsQuery;
export function isSearchByIdQuery(query: SearchTxQuery): query is SearchByIdQuery {
return (query as SearchByIdQuery).id !== undefined;
}
export type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery;
export function isSearchByHeightQuery(query: SearchTxQuery): query is SearchByHeightQuery {
return (query as SearchByHeightQuery).height !== undefined;
@ -269,6 +257,11 @@ export class CosmosClient {
};
}
public async getTx(id: string): Promise<IndexedTx | null> {
const results = await this.txsQuery(`tx.hash=${id}`);
return results[0] ?? null;
}
public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise<readonly IndexedTx[]> {
const minHeight = filter.minHeight || 0;
const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER;
@ -280,9 +273,7 @@ export class CosmosClient {
}
let txs: readonly IndexedTx[];
if (isSearchByIdQuery(query)) {
txs = await this.txsQuery(`tx.hash=${query.id}`);
} else if (isSearchByHeightQuery(query)) {
if (isSearchByHeightQuery(query)) {
// optional optimization to avoid network request
if (query.height < minHeight || query.height > maxHeight) {
txs = [];

View File

@ -18,13 +18,11 @@ export {
BroadcastTxResult,
BroadcastTxSuccess,
SearchByHeightQuery,
SearchByIdQuery,
SearchBySentFromOrToQuery,
SearchByTagsQuery,
SearchTxQuery,
SearchTxFilter,
isSearchByHeightQuery,
isSearchByIdQuery,
isSearchBySentFromOrToQuery,
isSearchByTagsQuery,
} from "./cosmosclient";

View File

@ -38,9 +38,6 @@ export declare function isBroadcastTxSuccess(result: BroadcastTxResult): result
export declare function assertIsBroadcastTxSuccess(
result: BroadcastTxResult,
): asserts result is BroadcastTxSuccess;
export interface SearchByIdQuery {
readonly id: string;
}
export interface SearchByHeightQuery {
readonly height: number;
}
@ -57,12 +54,7 @@ export interface SearchByTagsQuery {
readonly value: string;
}>;
}
export declare type SearchTxQuery =
| SearchByIdQuery
| SearchByHeightQuery
| SearchBySentFromOrToQuery
| SearchByTagsQuery;
export declare function isSearchByIdQuery(query: SearchTxQuery): query is SearchByIdQuery;
export declare type SearchTxQuery = SearchByHeightQuery | SearchBySentFromOrToQuery | SearchByTagsQuery;
export declare function isSearchByHeightQuery(query: SearchTxQuery): query is SearchByHeightQuery;
export declare function isSearchBySentFromOrToQuery(query: SearchTxQuery): query is SearchBySentFromOrToQuery;
export declare function isSearchByTagsQuery(query: SearchTxQuery): query is SearchByTagsQuery;
@ -144,6 +136,7 @@ export declare class CosmosClient {
* @param height The height of the block. If undefined, the latest height is used.
*/
getBlock(height?: number): Promise<Block>;
getTx(id: string): Promise<IndexedTx | null>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
broadcastTx(tx: StdTx): Promise<BroadcastTxResult>;
private txsQuery;

View File

@ -16,13 +16,11 @@ export {
BroadcastTxResult,
BroadcastTxSuccess,
SearchByHeightQuery,
SearchByIdQuery,
SearchBySentFromOrToQuery,
SearchByTagsQuery,
SearchTxQuery,
SearchTxFilter,
isSearchByHeightQuery,
isSearchByIdQuery,
isSearchBySentFromOrToQuery,
isSearchByTagsQuery,
} from "./cosmosclient";

View File

@ -201,8 +201,9 @@ describe("SigningStargateClient", () => {
await sleep(1000);
const searchResult = await client.searchTx({ id: result.transactionHash });
const tx = Tx.decode(searchResult[0].tx);
const searchResult = await client.getTx(result.transactionHash);
assert(searchResult, "Must find transaction");
const tx = Tx.decode(searchResult.tx);
// From ModifyingDirectSecp256k1HdWallet
expect(tx.body!.memo).toEqual("This was modified");
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));
@ -277,8 +278,9 @@ describe("SigningStargateClient", () => {
await sleep(1000);
const searchResult = await client.searchTx({ id: result.transactionHash });
const tx = Tx.decode(searchResult[0].tx);
const searchResult = await client.getTx(result.transactionHash);
assert(searchResult, "Must find transaction");
const tx = Tx.decode(searchResult.tx);
// From ModifyingSecp256k1HdWallet
expect(tx.body!.memo).toEqual("This was modified");
expect({ ...tx.authInfo!.fee!.amount![0] }).toEqual(coin(3000, "ucosm"));

View File

@ -95,7 +95,7 @@ async function sendTokens(
};
}
describe("StargateClient.searchTx", () => {
describe("StargateClient.getTx and .searchTx", () => {
const registry = new Registry();
let sendUnsuccessful: TestTxSend | undefined;
@ -147,14 +147,13 @@ describe("StargateClient.searchTx", () => {
}
});
describe("with SearchByIdQuery", () => {
it("can search successful tx by ID", async () => {
describe("getTx", () => {
it("can get successful tx by ID", async () => {
pendingWithoutSimapp();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = await StargateClient.connect(simapp.tendermintUrl);
const result = await client.searchTx({ id: sendSuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendSuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendSuccessful.height,
hash: sendSuccessful.hash,
@ -164,13 +163,12 @@ describe("StargateClient.searchTx", () => {
);
});
it("can search unsuccessful tx by ID", async () => {
it("can get unsuccessful tx by ID", async () => {
pendingWithoutSimapp();
assert(sendUnsuccessful, "value must be set in beforeAll()");
const client = await StargateClient.connect(simapp.tendermintUrl);
const result = await client.searchTx({ id: sendUnsuccessful.hash });
expect(result.length).toEqual(1);
expect(result[0]).toEqual(
const result = await client.getTx(sendUnsuccessful.hash);
expect(result).toEqual(
jasmine.objectContaining({
height: sendUnsuccessful.height,
hash: sendUnsuccessful.hash,
@ -180,39 +178,12 @@ describe("StargateClient.searchTx", () => {
);
});
it("can search by ID (non existent)", async () => {
it("can get by ID (non existent)", async () => {
pendingWithoutSimapp();
const client = await StargateClient.connect(simapp.tendermintUrl);
const nonExistentId = "0000000000000000000000000000000000000000000000000000000000000000";
const result = await client.searchTx({ id: nonExistentId });
expect(result.length).toEqual(0);
});
it("can search by ID and filter by minHeight", async () => {
pendingWithoutSimapp();
assert(sendSuccessful, "value must be set in beforeAll()");
const client = await StargateClient.connect(simapp.tendermintUrl);
const query = { id: sendSuccessful.hash };
{
const result = await client.searchTx(query, { minHeight: 0 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height - 1 });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height });
expect(result.length).toEqual(1);
}
{
const result = await client.searchTx(query, { minHeight: sendSuccessful.height + 1 });
expect(result.length).toEqual(0);
}
const result = await client.getTx(nonExistentId);
expect(result).toBeNull();
});
});

View File

@ -4,7 +4,6 @@ import {
Block,
Coin,
isSearchByHeightQuery,
isSearchByIdQuery,
isSearchBySentFromOrToQuery,
isSearchByTagsQuery,
PubKey,
@ -207,6 +206,11 @@ export class StargateClient {
return balances.map(coinFromProto);
}
public async getTx(id: string): Promise<IndexedTx | null> {
const results = await this.txsQuery(`tx.hash='${id}'`);
return results[0] ?? null;
}
public async searchTx(query: SearchTxQuery, filter: SearchTxFilter = {}): Promise<readonly IndexedTx[]> {
const minHeight = filter.minHeight || 0;
const maxHeight = filter.maxHeight || Number.MAX_SAFE_INTEGER;
@ -219,9 +223,7 @@ export class StargateClient {
let txs: readonly IndexedTx[];
if (isSearchByIdQuery(query)) {
txs = await this.txsQuery(`tx.hash='${query.id}'`);
} else if (isSearchByHeightQuery(query)) {
if (isSearchByHeightQuery(query)) {
txs =
query.height >= minHeight && query.height <= maxHeight
? await this.txsQuery(`tx.height=${query.height}`)

View File

@ -72,6 +72,7 @@ export declare class StargateClient {
* proofs from such a method.
*/
getAllBalancesUnverified(address: string): Promise<readonly Coin[]>;
getTx(id: string): Promise<IndexedTx | null>;
searchTx(query: SearchTxQuery, filter?: SearchTxFilter): Promise<readonly IndexedTx[]>;
disconnect(): void;
broadcastTx(tx: Uint8Array): Promise<BroadcastTxResponse>;