fix: block results validator update decoder (#1162)

* fix: block results validator update decoder

* Test decofing results

Co-authored-by: blorgon1 <102304575+blorgon1@users.noreply.github.com>
This commit is contained in:
Simon Warta 2022-06-08 14:33:49 +02:00 committed by GitHub
commit 79473bb308
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 148 additions and 43 deletions

View File

@ -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

View File

@ -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,
});
});
});
});

View File

@ -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;
@ -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;
@ -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)),
@ -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,
};
}
@ -716,7 +733,7 @@ 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;
}
@ -724,7 +741,7 @@ interface RpcValidatorsResponse {
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)),
};

View File

@ -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[];
@ -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;