Add more efficient getHeight implementation
This commit is contained in:
parent
e7f60e9abd
commit
a08b07f320
@ -4,7 +4,7 @@ import { Bech32, Encoding } from "@iov/encoding";
|
||||
import { assert, sleep } from "@iov/utils";
|
||||
import { ReadonlyDate } from "readonly-date";
|
||||
|
||||
import { Code, CosmWasmClient } from "./cosmwasmclient";
|
||||
import { Code, CosmWasmClient, PrivateCosmWasmClient } from "./cosmwasmclient";
|
||||
import { makeSignBytes } from "./encoding";
|
||||
import { findAttribute } from "./logs";
|
||||
import { Secp256k1Pen } from "./pen";
|
||||
@ -57,14 +57,42 @@ describe("CosmWasmClient", () => {
|
||||
});
|
||||
|
||||
describe("getHeight", () => {
|
||||
it("works", async () => {
|
||||
it("gets height via last block", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
const openedClient = (client as unknown) as PrivateCosmWasmClient;
|
||||
const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough();
|
||||
|
||||
const height1 = await client.getHeight();
|
||||
expect(height1).toBeGreaterThan(0);
|
||||
await sleep(1_000);
|
||||
const height2 = await client.getHeight();
|
||||
expect(height2).toEqual(height1 + 1);
|
||||
|
||||
expect(blockLatestSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it("gets height via authAccount once an address is known", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const client = new CosmWasmClient(wasmdEndpoint);
|
||||
|
||||
const openedClient = (client as unknown) as PrivateCosmWasmClient;
|
||||
const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough();
|
||||
const authAccountsSpy = spyOn(openedClient.restClient, "authAccounts").and.callThrough();
|
||||
|
||||
const height1 = await client.getHeight();
|
||||
expect(height1).toBeGreaterThan(0);
|
||||
|
||||
await client.getCodes(); // warm up the client
|
||||
|
||||
const height2 = await client.getHeight();
|
||||
expect(height2).toBeGreaterThan(0);
|
||||
await sleep(1_000);
|
||||
const height3 = await client.getHeight();
|
||||
expect(height3).toEqual(height2 + 1);
|
||||
|
||||
expect(blockLatestSpy).toHaveBeenCalledTimes(1);
|
||||
expect(authAccountsSpy).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@ -137,8 +137,15 @@ export interface Block {
|
||||
readonly txs: ReadonlyArray<Uint8Array>;
|
||||
}
|
||||
|
||||
/** Use for testing only */
|
||||
export interface PrivateCosmWasmClient {
|
||||
readonly restClient: RestClient;
|
||||
}
|
||||
|
||||
export class CosmWasmClient {
|
||||
protected readonly restClient: RestClient;
|
||||
/** Any address the chain considers valid (valid bech32 with proper prefix) */
|
||||
protected anyValidAddress: string | undefined;
|
||||
|
||||
public constructor(url: string, broadcastMode = BroadcastMode.Block) {
|
||||
this.restClient = new RestClient(url, broadcastMode);
|
||||
@ -150,10 +157,15 @@ export class CosmWasmClient {
|
||||
}
|
||||
|
||||
public async getHeight(): Promise<number> {
|
||||
// Note: this gets inefficient when blocks contain a lot of transactions since it
|
||||
// requires downloading and deserializing all transactions in the block.
|
||||
const latest = await this.restClient.blocksLatest();
|
||||
return parseInt(latest.block.header.height, 10);
|
||||
if (this.anyValidAddress) {
|
||||
const { height } = await this.restClient.authAccounts(this.anyValidAddress);
|
||||
return parseInt(height, 10);
|
||||
} else {
|
||||
// Note: this gets inefficient when blocks contain a lot of transactions since it
|
||||
// requires downloading and deserializing all transactions in the block.
|
||||
const latest = await this.restClient.blocksLatest();
|
||||
return parseInt(latest.block.header.height, 10);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -189,15 +201,18 @@ export class CosmWasmClient {
|
||||
public async getAccount(address: string): Promise<Account | undefined> {
|
||||
const account = await this.restClient.authAccounts(address);
|
||||
const value = account.result.value;
|
||||
return value.address === ""
|
||||
? undefined
|
||||
: {
|
||||
address: value.address,
|
||||
balance: value.coins,
|
||||
pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined,
|
||||
accountNumber: value.account_number,
|
||||
sequence: value.sequence,
|
||||
};
|
||||
if (value.address === "") {
|
||||
return undefined;
|
||||
} else {
|
||||
this.anyValidAddress = value.address;
|
||||
return {
|
||||
address: value.address,
|
||||
balance: value.coins,
|
||||
pubkey: value.public_key ? decodeBech32Pubkey(value.public_key) : undefined,
|
||||
accountNumber: value.account_number,
|
||||
sequence: value.sequence,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -283,13 +298,16 @@ export class CosmWasmClient {
|
||||
public async getCodes(): Promise<readonly Code[]> {
|
||||
const result = await this.restClient.listCodeInfo();
|
||||
return result.map(
|
||||
(entry): Code => ({
|
||||
id: entry.id,
|
||||
creator: entry.creator,
|
||||
checksum: Encoding.toHex(Encoding.fromHex(entry.data_hash)),
|
||||
source: entry.source || undefined,
|
||||
builder: entry.builder || undefined,
|
||||
}),
|
||||
(entry): Code => {
|
||||
this.anyValidAddress = entry.creator;
|
||||
return {
|
||||
id: entry.id,
|
||||
creator: entry.creator,
|
||||
checksum: Encoding.toHex(Encoding.fromHex(entry.data_hash)),
|
||||
source: entry.source || undefined,
|
||||
builder: entry.builder || undefined,
|
||||
};
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -2,6 +2,7 @@ import { Sha256 } from "@iov/crypto";
|
||||
import { Encoding } from "@iov/encoding";
|
||||
import { assert } from "@iov/utils";
|
||||
|
||||
import { PrivateCosmWasmClient } from "./cosmwasmclient";
|
||||
import { Secp256k1Pen } from "./pen";
|
||||
import { RestClient } from "./restclient";
|
||||
import { SigningCosmWasmClient, UploadMeta } from "./signingcosmwasmclient";
|
||||
@ -31,6 +32,24 @@ describe("SigningCosmWasmClient", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getHeight", () => {
|
||||
it("always uses authAccount implementation", async () => {
|
||||
pendingWithoutWasmd();
|
||||
const pen = await Secp256k1Pen.fromMnemonic(faucet.mnemonic);
|
||||
const client = new SigningCosmWasmClient(httpUrl, faucet.address, signBytes => pen.sign(signBytes));
|
||||
|
||||
const openedClient = (client as unknown) as PrivateCosmWasmClient;
|
||||
const blockLatestSpy = spyOn(openedClient.restClient, "blocksLatest").and.callThrough();
|
||||
const authAccountsSpy = spyOn(openedClient.restClient, "authAccounts").and.callThrough();
|
||||
|
||||
const height = await client.getHeight();
|
||||
expect(height).toBeGreaterThan(0);
|
||||
|
||||
expect(blockLatestSpy).toHaveBeenCalledTimes(0);
|
||||
expect(authAccountsSpy).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("upload", () => {
|
||||
it("works", async () => {
|
||||
pendingWithoutWasmd();
|
||||
|
||||
@ -111,6 +111,8 @@ export class SigningCosmWasmClient extends CosmWasmClient {
|
||||
broadcastMode = BroadcastMode.Block,
|
||||
) {
|
||||
super(url, broadcastMode);
|
||||
this.anyValidAddress = senderAddress;
|
||||
|
||||
this.senderAddress = senderAddress;
|
||||
this.signCallback = signCallback;
|
||||
this.fees = { ...defaultFees, ...(customFees || {}) };
|
||||
|
||||
6
packages/sdk/types/cosmwasmclient.d.ts
vendored
6
packages/sdk/types/cosmwasmclient.d.ts
vendored
@ -103,8 +103,14 @@ export interface Block {
|
||||
/** Array of raw transactions */
|
||||
readonly txs: ReadonlyArray<Uint8Array>;
|
||||
}
|
||||
/** Use for testing only */
|
||||
export interface PrivateCosmWasmClient {
|
||||
readonly restClient: RestClient;
|
||||
}
|
||||
export declare class CosmWasmClient {
|
||||
protected readonly restClient: RestClient;
|
||||
/** Any address the chain considers valid (valid bech32 with proper prefix) */
|
||||
protected anyValidAddress: string | undefined;
|
||||
constructor(url: string, broadcastMode?: BroadcastMode);
|
||||
chainId(): Promise<string>;
|
||||
getHeight(): Promise<number>;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user