Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: block results validator update decoder #1162

Merged
merged 2 commits into from
Jun 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ and this project adheres to
- @cosmjs/stargate: Let `calculateFee` handle fee amounts that exceed the safe
integer range.

### Fixed

- @cosmjs/tendermint-rpc: Fix block results validator update decoder. ([#1151])

[#1151]: https://github.com/cosmos/cosmjs/issues/1151

## [0.28.4] - 2022-04-15

### Added
Expand Down
77 changes: 77 additions & 0 deletions packages/tendermint-rpc/src/tendermint34/adaptor/responses.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/* eslint-disable @typescript-eslint/naming-convention */
import { fromBase64, fromHex } from "@cosmjs/encoding";

import { decodeValidatorGenesis, decodeValidatorInfo, decodeValidatorUpdate } from "./responses";

describe("Adaptor Responses", () => {
describe("decodeValidatorGenesis", () => {
it("works for genesis format", () => {
// from https://raw.githubusercontent.com/cosmos/mainnet/master/genesis.json
const validator = decodeValidatorGenesis({
address: "A03DC128D38DB0BC5F18AE1872F1CB2E1FD41157",
name: "真本聪&IOSG",
power: "169980",
pub_key: {
type: "tendermint/PubKeyEd25519",
value: "2BX6Zuj8RmdJAkD1BAg6KB0v04liyM7jBdwOGIb9F9Q=",
},
});
expect(validator).toEqual({
address: fromHex("A03DC128D38DB0BC5F18AE1872F1CB2E1FD41157"),
votingPower: 169980,
pubkey: {
algorithm: "ed25519",
data: fromBase64("2BX6Zuj8RmdJAkD1BAg6KB0v04liyM7jBdwOGIb9F9Q="),
},
});
});
});

describe("decodeValidatorUpdate", () => {
it("works for block results format", () => {
// from https://rpc.cosmos.network/block_results?height=10539773
const update = decodeValidatorUpdate({
pub_key: {
Sum: {
type: "tendermint.crypto.PublicKey_Ed25519",
value: {
ed25519: "0kNlxBMpm+5WtfHIG1xsWatOXTKPLtmSqn3EiEIDZeI=",
},
},
},
power: "11418237",
});
expect(update).toEqual({
pubkey: {
algorithm: "ed25519",
data: fromBase64("0kNlxBMpm+5WtfHIG1xsWatOXTKPLtmSqn3EiEIDZeI="),
},
votingPower: 11418237,
});
});
});

describe("decodeValidatorInfo", () => {
it("works for validators format", () => {
// from https://rpc.cosmos.network/validators?height=10601034
const info = decodeValidatorInfo({
address: "AC2D56057CD84765E6FBE318979093E8E44AA18F",
pub_key: {
type: "tendermint/PubKeyEd25519",
value: "0kNlxBMpm+5WtfHIG1xsWatOXTKPLtmSqn3EiEIDZeI=",
},
voting_power: "11228980",
proposer_priority: "62870960",
});
expect(info).toEqual({
address: fromHex("AC2D56057CD84765E6FBE318979093E8E44AA18F"),
pubkey: {
algorithm: "ed25519",
data: fromBase64("0kNlxBMpm+5WtfHIG1xsWatOXTKPLtmSqn3EiEIDZeI="),
},
votingPower: 11228980,
proposerPriority: 62870960,
});
});
});
});
101 changes: 59 additions & 42 deletions packages/tendermint-rpc/src/tendermint34/adaptor/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,49 +148,51 @@ function decodeTxData(data: RpcTxData): responses.TxData {
};
}

// yes, a different format for status and dump consensus state
interface RpcPubkey {
readonly type: string;
/** base64 encoded */
readonly value: string;
}
type RpcPubkey =
| {
readonly type: string;
/** base64 encoded */
readonly value: string;
}
| {
// See: https://github.com/cosmos/cosmjs/issues/1142
readonly Sum: {
readonly type: string;
readonly value: {
/** base64 encoded */
[algorithm: string]: string;
};
};
};

function decodePubkey(data: RpcPubkey): ValidatorPubkey {
switch (data.type) {
// go-amino special code
case "tendermint/PubKeyEd25519":
return {
algorithm: "ed25519",
data: fromBase64(assertNotEmpty(data.value)),
};
case "tendermint/PubKeySecp256k1":
return {
algorithm: "secp256k1",
data: fromBase64(assertNotEmpty(data.value)),
};
default:
throw new Error(`unknown pubkey type: ${data.type}`);
if ("Sum" in data) {
// we don't need to check type because we're checking algorithm
const [[algorithm, value]] = Object.entries(data.Sum.value);
assert(algorithm === "ed25519" || algorithm === "secp256k1", `unknown pubkey type: ${algorithm}`);
return {
algorithm,
data: fromBase64(assertNotEmpty(value)),
};
} else {
switch (data.type) {
// go-amino special code
case "tendermint/PubKeyEd25519":
return {
algorithm: "ed25519",
data: fromBase64(assertNotEmpty(data.value)),
};
case "tendermint/PubKeySecp256k1":
return {
algorithm: "secp256k1",
data: fromBase64(assertNotEmpty(data.value)),
};
default:
throw new Error(`unknown pubkey type: ${data.type}`);
}
}
}

// for evidence, block results, etc.
interface RpcValidatorUpdate {
/** hex encoded */
readonly address: string;
readonly pub_key: RpcPubkey;
readonly voting_power: string;
readonly proposer_priority: string;
}

function decodeValidatorUpdate(data: RpcValidatorUpdate): responses.Validator {
return {
pubkey: decodePubkey(assertObject(data.pub_key)),
votingPower: Integer.parse(assertNotEmpty(data.voting_power)),
address: fromHex(assertNotEmpty(data.address)),
proposerPriority: Integer.parse(data.proposer_priority),
};
}

interface RpcBlockParams {
readonly max_bytes: string;
readonly max_gas: string;
Expand Down Expand Up @@ -252,6 +254,19 @@ function decodeConsensusParams(data: RpcConsensusParams): responses.ConsensusPar
};
}

// for block results
interface RpcValidatorUpdate {
readonly pub_key: RpcPubkey;
readonly power: string;
}

export function decodeValidatorUpdate(data: RpcValidatorUpdate): responses.ValidatorUpdate {
return {
pubkey: decodePubkey(assertObject(data.pub_key)),
votingPower: Integer.parse(assertNotEmpty(data.power)),
};
}

interface RpcBlockResultsResponse {
readonly height: string;
readonly txs_results: readonly RpcTxData[] | null;
Expand Down Expand Up @@ -493,7 +508,7 @@ interface RpcValidatorGenesis {
readonly name?: string;
}

function decodeValidatorGenesis(data: RpcValidatorGenesis): responses.Validator {
export function decodeValidatorGenesis(data: RpcValidatorGenesis): responses.Validator {
return {
address: fromHex(assertNotEmpty(data.address)),
pubkey: decodePubkey(assertObject(data.pub_key)),
Expand Down Expand Up @@ -534,13 +549,15 @@ interface RpcValidatorInfo {
readonly address: string;
readonly pub_key: RpcPubkey;
readonly voting_power: string;
readonly proposer_priority?: string;
}

function decodeValidatorInfo(data: RpcValidatorInfo): responses.Validator {
export function decodeValidatorInfo(data: RpcValidatorInfo): responses.Validator {
return {
pubkey: decodePubkey(assertObject(data.pub_key)),
votingPower: Integer.parse(assertNotEmpty(data.voting_power)),
address: fromHex(assertNotEmpty(data.address)),
proposerPriority: data.proposer_priority ? Integer.parse(data.proposer_priority) : undefined,
};
}

Expand Down Expand Up @@ -716,15 +733,15 @@ function decodeTxEvent(data: RpcTxEvent): responses.TxEvent {

interface RpcValidatorsResponse {
readonly block_height: string;
readonly validators: readonly RpcValidatorUpdate[];
readonly validators: readonly RpcValidatorInfo[];
readonly count: string;
readonly total: string;
}

function decodeValidators(data: RpcValidatorsResponse): responses.ValidatorsResponse {
return {
blockHeight: Integer.parse(assertNotEmpty(data.block_height)),
validators: assertArray(data.validators).map(decodeValidatorUpdate),
validators: assertArray(data.validators).map(decodeValidatorInfo),
count: Integer.parse(assertNotEmpty(data.count)),
total: Integer.parse(assertNotEmpty(data.total)),
};
Expand Down
7 changes: 6 additions & 1 deletion packages/tendermint-rpc/src/tendermint34/responses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export interface BlockResponse {
export interface BlockResultsResponse {
readonly height: number;
readonly results: readonly TxData[];
readonly validatorUpdates: readonly Validator[];
readonly validatorUpdates: readonly ValidatorUpdate[];
readonly consensusUpdates?: ConsensusParams;
readonly beginBlockEvents: readonly Event[];
readonly endBlockEvents: readonly Event[];
Expand Down Expand Up @@ -351,6 +351,11 @@ export interface Validator {
readonly proposerPriority?: number;
}

export interface ValidatorUpdate {
readonly pubkey: ValidatorPubkey;
readonly votingPower: number;
}

export interface ConsensusParams {
readonly block: BlockParams;
readonly evidence: EvidenceParams;
Expand Down