Make lastBlockId and lastCommit optional
This commit is contained in:
parent
69a47c0065
commit
2701acf37e
@ -12,6 +12,12 @@ and this project adheres to
|
||||
`Tendermint34Client.blockSearchAll` were added to allow searching blocks in
|
||||
Tendermint 0.34.9+ backends.
|
||||
|
||||
### Changes
|
||||
|
||||
- @cosmjs/tendermint-rpc: Make `tendermint34.Header.lastBlockId` and
|
||||
`tendermint34.Block.lastCommit` optional to better handle the case of height 1
|
||||
where there is no previous block.
|
||||
|
||||
## [0.25.3] - 2021-05-18
|
||||
|
||||
### Fixed
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import { iavlSpec, ics23, tendermintSpec, verifyExistence, verifyNonExistence } from "@confio/ics23";
|
||||
import { toAscii, toHex } from "@cosmjs/encoding";
|
||||
import { firstEvent } from "@cosmjs/stream";
|
||||
import { Header, NewBlockHeaderEvent, ProofOp, Tendermint34Client } from "@cosmjs/tendermint-rpc";
|
||||
import { tendermint34, Tendermint34Client } from "@cosmjs/tendermint-rpc";
|
||||
import { arrayContentEquals, assert, assertDefined, isNonNullObject, sleep } from "@cosmjs/utils";
|
||||
import { Stream } from "xstream";
|
||||
|
||||
@ -10,7 +10,7 @@ import { ProofOps } from "../codec/tendermint/crypto/proof";
|
||||
|
||||
type QueryExtensionSetup<P> = (base: QueryClient) => P;
|
||||
|
||||
function checkAndParseOp(op: ProofOp, kind: string, key: Uint8Array): ics23.CommitmentProof {
|
||||
function checkAndParseOp(op: tendermint34.ProofOp, kind: string, key: Uint8Array): ics23.CommitmentProof {
|
||||
if (op.type !== kind) {
|
||||
throw new Error(`Op expected to be ${kind}, got "${op.type}`);
|
||||
}
|
||||
@ -587,15 +587,15 @@ export class QueryClient {
|
||||
|
||||
// this must return the header for height+1
|
||||
// throws an error if height is 0 or undefined
|
||||
private async getNextHeader(height?: number): Promise<Header> {
|
||||
private async getNextHeader(height?: number): Promise<tendermint34.Header> {
|
||||
assertDefined(height);
|
||||
if (height === 0) {
|
||||
throw new Error("Query returned height 0, cannot prove it");
|
||||
}
|
||||
|
||||
const searchHeight = height + 1;
|
||||
let nextHeader: Header | undefined;
|
||||
let headersSubscription: Stream<NewBlockHeaderEvent> | undefined;
|
||||
let nextHeader: tendermint34.Header | undefined;
|
||||
let headersSubscription: Stream<tendermint34.NewBlockHeaderEvent> | undefined;
|
||||
try {
|
||||
headersSubscription = this.tmClient.subscribeNewBlockHeader();
|
||||
} catch {
|
||||
|
||||
@ -284,10 +284,10 @@ interface RpcBlockId {
|
||||
|
||||
function decodeBlockId(data: RpcBlockId): responses.BlockId {
|
||||
return {
|
||||
hash: fromHex(data.hash),
|
||||
hash: fromHex(assertNotEmpty(data.hash)),
|
||||
parts: {
|
||||
total: data.parts.total,
|
||||
hash: fromHex(data.parts.hash),
|
||||
total: assertNotEmpty(data.parts.total),
|
||||
hash: fromHex(assertNotEmpty(data.parts.hash)),
|
||||
},
|
||||
};
|
||||
}
|
||||
@ -341,7 +341,9 @@ function decodeHeader(data: RpcHeader): responses.Header {
|
||||
height: Integer.parse(assertNotEmpty(data.height)),
|
||||
time: fromRfc3339WithNanoseconds(assertNotEmpty(data.time)),
|
||||
|
||||
lastBlockId: decodeBlockId(data.last_block_id),
|
||||
// When there is no last block ID (i.e. this block's height is 1), we get an empty structure like this:
|
||||
// { hash: '', parts: { total: 0, hash: '' } }
|
||||
lastBlockId: data.last_block_id.hash ? decodeBlockId(data.last_block_id) : null,
|
||||
|
||||
lastCommitHash: fromHex(assertNotEmpty(data.last_commit_hash)),
|
||||
dataHash: fromHex(assertSet(data.data_hash)),
|
||||
@ -765,7 +767,9 @@ interface RpcBlock {
|
||||
function decodeBlock(data: RpcBlock): responses.Block {
|
||||
return {
|
||||
header: decodeHeader(assertObject(data.header)),
|
||||
lastCommit: decodeCommit(assertObject(data.last_commit)),
|
||||
// For the block at height 1, last commit is not set. This is represented in an empty object like this:
|
||||
// { height: '0', round: 0, block_id: { hash: '', parts: [Object] }, signatures: [] }
|
||||
lastCommit: data.last_commit.block_id.hash ? decodeCommit(assertObject(data.last_commit)) : null,
|
||||
txs: data.data.txs ? assertArray(data.data.txs).map(fromBase64) : [],
|
||||
evidence: data.evidence && may(decodeEvidences, data.evidence.evidence),
|
||||
};
|
||||
|
||||
@ -46,6 +46,12 @@ function hashTree(hashes: readonly Uint8Array[]): Uint8Array {
|
||||
}
|
||||
|
||||
export function hashBlock(header: Header): Uint8Array {
|
||||
if (!header.lastBlockId) {
|
||||
throw new Error(
|
||||
"Hashing a block header with no last block ID (i.e. header at height 1) is not supported. If you need this, contributions are welcome. Please add documentation and test vectors for this case.",
|
||||
);
|
||||
}
|
||||
|
||||
const encodedFields: readonly Uint8Array[] = [
|
||||
encodeVersion(header.version),
|
||||
encodeString(header.chainId),
|
||||
|
||||
@ -217,7 +217,10 @@ export interface BlockId {
|
||||
|
||||
export interface Block {
|
||||
readonly header: Header;
|
||||
readonly lastCommit: Commit;
|
||||
/**
|
||||
* For the block at height 1, last commit is not set.
|
||||
*/
|
||||
readonly lastCommit: Commit | null;
|
||||
readonly txs: readonly Uint8Array[];
|
||||
readonly evidence?: readonly Evidence[];
|
||||
}
|
||||
@ -269,8 +272,10 @@ export interface Header {
|
||||
readonly height: number;
|
||||
readonly time: ReadonlyDateWithNanoseconds;
|
||||
|
||||
// prev block info
|
||||
readonly lastBlockId: BlockId;
|
||||
/**
|
||||
* Block ID of the previous block. This can be `null` when the currect block is height 1.
|
||||
*/
|
||||
readonly lastBlockId: BlockId | null;
|
||||
|
||||
// hashes of block data
|
||||
readonly lastCommitHash: Uint8Array;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user