diff --git a/packages/tendermint-rpc/src/inthelpers.ts b/packages/tendermint-rpc/src/inthelpers.ts new file mode 100644 index 00000000..0219da53 --- /dev/null +++ b/packages/tendermint-rpc/src/inthelpers.ts @@ -0,0 +1,20 @@ +import { Int53 } from "@cosmjs/math"; + +/** + * Takes an integer value from the Tendermint RPC API and + * returns it as number. + * + * Only works within the safe integer range. + */ +export function apiToSmallInt(input: string | number): number { + const asInt = typeof input === "number" ? new Int53(input) : Int53.fromString(input); + return asInt.toNumber(); +} + +/** + * Takes an integer in the safe integer range and returns + * a string representation to be used in the Tendermint RPC API. + */ +export function smallIntToApi(num: number): string { + return new Int53(num).toString(); +} diff --git a/packages/tendermint-rpc/src/tendermint34/adaptor/requests.ts b/packages/tendermint-rpc/src/tendermint34/adaptor/requests.ts index 1dc95947..ae2bd709 100644 --- a/packages/tendermint-rpc/src/tendermint34/adaptor/requests.ts +++ b/packages/tendermint-rpc/src/tendermint34/adaptor/requests.ts @@ -2,8 +2,9 @@ import { toBase64, toHex } from "@cosmjs/encoding"; import { JsonRpcRequest } from "@cosmjs/json-rpc"; +import { smallIntToApi } from "../../inthelpers"; import { createJsonRpcRequest } from "../../jsonrpc"; -import { assertNotEmpty, Integer, may } from "../encodings"; +import { assertNotEmpty, may } from "../encodings"; import * as requests from "../requests"; interface HeightParam { @@ -14,7 +15,7 @@ interface RpcHeightParam { } function encodeHeightParam(param: HeightParam): RpcHeightParam { return { - height: may(Integer.encode, param.height), + height: may(smallIntToApi, param.height), }; } @@ -25,8 +26,8 @@ interface RpcBlockchainRequestParams { function encodeBlockchainRequestParams(param: requests.BlockchainRequestParams): RpcBlockchainRequestParams { return { - minHeight: may(Integer.encode, param.minHeight), - maxHeight: may(Integer.encode, param.maxHeight), + minHeight: may(smallIntToApi, param.minHeight), + maxHeight: may(smallIntToApi, param.maxHeight), }; } @@ -39,8 +40,8 @@ interface RpcBlockSearchParams { function encodeBlockSearchParams(params: requests.BlockSearchParams): RpcBlockSearchParams { return { query: params.query, - page: may(Integer.encode, params.page), - per_page: may(Integer.encode, params.per_page), + page: may(smallIntToApi, params.page), + per_page: may(smallIntToApi, params.per_page), order_by: params.order_by, }; } @@ -57,7 +58,7 @@ function encodeAbciQueryParams(params: requests.AbciQueryParams): RpcAbciQueryPa return { path: assertNotEmpty(params.path), data: toHex(params.data), - height: may(Integer.encode, params.height), + height: may(smallIntToApi, params.height), prove: params.prove, }; } @@ -95,8 +96,8 @@ function encodeTxSearchParams(params: requests.TxSearchParams): RpcTxSearchParam return { query: params.query, prove: params.prove, - page: may(Integer.encode, params.page), - per_page: may(Integer.encode, params.per_page), + page: may(smallIntToApi, params.page), + per_page: may(smallIntToApi, params.per_page), order_by: params.order_by, }; } @@ -108,9 +109,9 @@ interface RpcValidatorsParams { } function encodeValidatorsParams(params: requests.ValidatorsParams): RpcValidatorsParams { return { - height: may(Integer.encode, params.height), - page: may(Integer.encode, params.page), - per_page: may(Integer.encode, params.per_page), + height: may(smallIntToApi, params.height), + page: may(smallIntToApi, params.page), + per_page: may(smallIntToApi, params.per_page), }; } diff --git a/packages/tendermint-rpc/src/tendermint34/adaptor/responses.ts b/packages/tendermint-rpc/src/tendermint34/adaptor/responses.ts index 1a44a10e..3457bdd2 100644 --- a/packages/tendermint-rpc/src/tendermint34/adaptor/responses.ts +++ b/packages/tendermint-rpc/src/tendermint34/adaptor/responses.ts @@ -4,6 +4,7 @@ import { JsonRpcSuccessResponse } from "@cosmjs/json-rpc"; import { assert } from "@cosmjs/utils"; import { DateWithNanoseconds, fromRfc3339WithNanoseconds } from "../../dates"; +import { apiToSmallInt } from "../../inthelpers"; import { SubscriptionEvent } from "../../rpcclients"; import { BlockIdFlag, CommitSignature, ValidatorPubkey } from "../../types"; import { @@ -15,7 +16,6 @@ import { assertSet, assertString, dictionaryToStringMap, - Integer, may, } from "../encodings"; import { hashTx } from "../hasher"; @@ -35,7 +35,7 @@ interface RpcAbciInfoResponse { function decodeAbciInfo(data: RpcAbciInfoResponse): responses.AbciInfoResponse { return { data: data.data, - lastBlockHeight: may(Integer.parse, data.last_block_height), + lastBlockHeight: may(apiToSmallInt, data.last_block_height), lastBlockAppHash: may(fromBase64, data.last_block_app_hash), }; } @@ -96,10 +96,10 @@ function decodeAbciQuery(data: RpcAbciQueryResponse): responses.AbciQueryRespons key: fromBase64(assertString(data.key ?? "")), value: fromBase64(assertString(data.value ?? "")), proof: may(decodeQueryProof, data.proofOps), - height: may(Integer.parse, data.height), - code: may(Integer.parse, data.code), + height: may(apiToSmallInt, data.height), + code: may(apiToSmallInt, data.code), codespace: assertString(data.codespace ?? ""), - index: may(Integer.parse, data.index), + index: may(apiToSmallInt, data.index), log: data.log, info: assertString(data.info ?? ""), }; @@ -153,13 +153,13 @@ interface RpcTxData { function decodeTxData(data: RpcTxData): responses.TxData { return { - code: Integer.parse(assertNumber(data.code ?? 0)), + code: apiToSmallInt(assertNumber(data.code ?? 0)), codeSpace: data.codespace, log: data.log, data: may(fromBase64, data.data), events: data.events ? decodeEvents(data.events) : [], - gasWanted: Integer.parse(data.gas_wanted ?? "0"), - gasUsed: Integer.parse(data.gas_used ?? "0"), + gasWanted: apiToSmallInt(data.gas_wanted ?? "0"), + gasUsed: apiToSmallInt(data.gas_used ?? "0"), }; } @@ -221,8 +221,8 @@ interface RpcBlockParams { */ function decodeBlockParams(data: RpcBlockParams): responses.BlockParams { return { - maxBytes: Integer.parse(assertNotEmpty(data.max_bytes)), - maxGas: Integer.parse(assertNotEmpty(data.max_gas)), + maxBytes: apiToSmallInt(assertNotEmpty(data.max_bytes)), + maxGas: apiToSmallInt(assertNotEmpty(data.max_gas)), }; } @@ -233,8 +233,8 @@ interface RpcEvidenceParams { function decodeEvidenceParams(data: RpcEvidenceParams): responses.EvidenceParams { return { - maxAgeNumBlocks: Integer.parse(assertNotEmpty(data.max_age_num_blocks)), - maxAgeDuration: Integer.parse(assertNotEmpty(data.max_age_duration)), + maxAgeNumBlocks: apiToSmallInt(assertNotEmpty(data.max_age_num_blocks)), + maxAgeDuration: apiToSmallInt(assertNotEmpty(data.max_age_duration)), }; } @@ -279,7 +279,7 @@ interface RpcValidatorUpdate { export function decodeValidatorUpdate(data: RpcValidatorUpdate): responses.ValidatorUpdate { return { pubkey: decodePubkey(assertObject(data.pub_key)), - votingPower: Integer.parse(data.power ?? 0), + votingPower: apiToSmallInt(data.power ?? 0), }; } @@ -294,7 +294,7 @@ interface RpcBlockResultsResponse { function decodeBlockResults(data: RpcBlockResultsResponse): responses.BlockResultsResponse { return { - height: Integer.parse(assertNotEmpty(data.height)), + height: apiToSmallInt(assertNotEmpty(data.height)), results: (data.txs_results || []).map(decodeTxData), validatorUpdates: (data.validator_updates || []).map(decodeValidatorUpdate), consensusUpdates: may(decodeConsensusParams, data.consensus_param_updates), @@ -330,8 +330,8 @@ interface RpcBlockVersion { function decodeBlockVersion(data: RpcBlockVersion): responses.Version { return { - block: Integer.parse(data.block), - app: Integer.parse(data.app ?? 0), + block: apiToSmallInt(data.block), + app: apiToSmallInt(data.app ?? 0), }; } @@ -369,7 +369,7 @@ function decodeHeader(data: RpcHeader): responses.Header { return { version: decodeBlockVersion(data.version), chainId: assertNotEmpty(data.chain_id), - height: Integer.parse(assertNotEmpty(data.height)), + height: apiToSmallInt(assertNotEmpty(data.height)), time: fromRfc3339WithNanoseconds(assertNotEmpty(data.time)), // When there is no last block ID (i.e. this block's height is 1), we get an empty structure like this: @@ -400,9 +400,9 @@ interface RpcBlockMeta { function decodeBlockMeta(data: RpcBlockMeta): responses.BlockMeta { return { blockId: decodeBlockId(data.block_id), - blockSize: Integer.parse(assertNotEmpty(data.block_size)), + blockSize: apiToSmallInt(assertNotEmpty(data.block_size)), header: decodeHeader(data.header), - numTxs: Integer.parse(assertNotEmpty(data.num_txs)), + numTxs: apiToSmallInt(assertNotEmpty(data.num_txs)), }; } @@ -413,7 +413,7 @@ interface RpcBlockchainResponse { function decodeBlockchain(data: RpcBlockchainResponse): responses.BlockchainResponse { return { - lastHeight: Integer.parse(assertNotEmpty(data.last_height)), + lastHeight: apiToSmallInt(assertNotEmpty(data.last_height)), blockMetas: assertArray(data.block_metas).map(decodeBlockMeta), }; } @@ -440,7 +440,7 @@ interface RpcBroadcastTxCommitResponse { function decodeBroadcastTxCommit(data: RpcBroadcastTxCommitResponse): responses.BroadcastTxCommitResponse { return { - height: Integer.parse(data.height), + height: apiToSmallInt(data.height), hash: fromHex(assertNotEmpty(data.hash)), checkTx: decodeTxData(assertObject(data.check_tx)), deliverTx: may(decodeTxData, data.deliver_tx), @@ -494,8 +494,8 @@ interface RpcCommit { function decodeCommit(data: RpcCommit): responses.Commit { return { blockId: decodeBlockId(assertObject(data.block_id)), - height: Integer.parse(assertNotEmpty(data.height)), - round: Integer.parse(data.round), + height: apiToSmallInt(assertNotEmpty(data.height)), + round: apiToSmallInt(data.round), signatures: assertArray(data.signatures).map(decodeCommitSignature), }; } @@ -528,7 +528,7 @@ export function decodeValidatorGenesis(data: RpcValidatorGenesis): responses.Val return { address: fromHex(assertNotEmpty(data.address)), pubkey: decodePubkey(assertObject(data.pub_key)), - votingPower: Integer.parse(assertNotEmpty(data.power)), + votingPower: apiToSmallInt(assertNotEmpty(data.power)), }; } @@ -571,9 +571,9 @@ interface RpcValidatorInfo { export function decodeValidatorInfo(data: RpcValidatorInfo): responses.Validator { return { pubkey: decodePubkey(assertObject(data.pub_key)), - votingPower: Integer.parse(assertNotEmpty(data.voting_power)), + votingPower: apiToSmallInt(assertNotEmpty(data.voting_power)), address: fromHex(assertNotEmpty(data.address)), - proposerPriority: data.proposer_priority ? Integer.parse(data.proposer_priority) : undefined, + proposerPriority: data.proposer_priority ? apiToSmallInt(data.proposer_priority) : undefined, }; } @@ -611,9 +611,9 @@ function decodeNodeInfo(data: RpcNodeInfo): responses.NodeInfo { moniker: assertNotEmpty(data.moniker), other: dictionaryToStringMap(data.other), protocolVersion: { - app: Integer.parse(assertNotEmpty(data.protocol_version.app)), - block: Integer.parse(assertNotEmpty(data.protocol_version.block)), - p2p: Integer.parse(assertNotEmpty(data.protocol_version.p2p)), + app: apiToSmallInt(assertNotEmpty(data.protocol_version.app)), + block: apiToSmallInt(assertNotEmpty(data.protocol_version.block)), + p2p: apiToSmallInt(assertNotEmpty(data.protocol_version.p2p)), }, }; } @@ -633,7 +633,7 @@ function decodeSyncInfo(data: RpcSyncInfo): responses.SyncInfo { latestBlockHash: fromHex(assertNotEmpty(data.latest_block_hash)), latestAppHash: fromHex(assertNotEmpty(data.latest_app_hash)), latestBlockTime: fromRfc3339WithNanoseconds(assertNotEmpty(data.latest_block_time)), - latestBlockHeight: Integer.parse(assertNotEmpty(data.latest_block_height)), + latestBlockHeight: apiToSmallInt(assertNotEmpty(data.latest_block_height)), catchingUp: assertBoolean(data.catching_up), }; } @@ -685,8 +685,8 @@ function decodeTxProof(data: RpcTxProof): responses.TxProof { data: fromBase64(assertNotEmpty(data.data)), rootHash: fromHex(assertNotEmpty(data.root_hash)), proof: { - total: Integer.parse(assertNotEmpty(data.proof.total)), - index: Integer.parse(assertNotEmpty(data.proof.index)), + total: apiToSmallInt(assertNotEmpty(data.proof.total)), + index: apiToSmallInt(assertNotEmpty(data.proof.index)), leafHash: fromBase64(assertNotEmpty(data.proof.leaf_hash)), aunts: assertArray(data.proof.aunts).map(fromBase64), }, @@ -708,8 +708,8 @@ function decodeTxResponse(data: RpcTxResponse): responses.TxResponse { return { tx: fromBase64(assertNotEmpty(data.tx)), result: decodeTxData(assertObject(data.tx_result)), - height: Integer.parse(assertNotEmpty(data.height)), - index: Integer.parse(assertNumber(data.index)), + height: apiToSmallInt(assertNotEmpty(data.height)), + index: apiToSmallInt(assertNumber(data.index)), hash: fromHex(assertNotEmpty(data.hash)), proof: may(decodeTxProof, data.proof), }; @@ -722,7 +722,7 @@ interface RpcTxSearchResponse { function decodeTxSearch(data: RpcTxSearchResponse): responses.TxSearchResponse { return { - totalCount: Integer.parse(assertNotEmpty(data.total_count)), + totalCount: apiToSmallInt(assertNotEmpty(data.total_count)), txs: assertArray(data.txs).map(decodeTxResponse), }; } @@ -742,8 +742,8 @@ function decodeTxEvent(data: RpcTxEvent): responses.TxEvent { tx: tx, hash: hashTx(tx), result: decodeTxData(data.result), - height: Integer.parse(assertNotEmpty(data.height)), - index: may(Integer.parse, data.index), + height: apiToSmallInt(assertNotEmpty(data.height)), + index: may(apiToSmallInt, data.index), }; } @@ -756,10 +756,10 @@ interface RpcValidatorsResponse { function decodeValidators(data: RpcValidatorsResponse): responses.ValidatorsResponse { return { - blockHeight: Integer.parse(assertNotEmpty(data.block_height)), + blockHeight: apiToSmallInt(assertNotEmpty(data.block_height)), validators: assertArray(data.validators).map(decodeValidatorInfo), - count: Integer.parse(assertNotEmpty(data.count)), - total: Integer.parse(assertNotEmpty(data.total)), + count: apiToSmallInt(assertNotEmpty(data.count)), + total: apiToSmallInt(assertNotEmpty(data.total)), }; } @@ -813,7 +813,7 @@ interface RpcBlockSearchResponse { function decodeBlockSearch(data: RpcBlockSearchResponse): responses.BlockSearchResponse { return { - totalCount: Integer.parse(assertNotEmpty(data.total_count)), + totalCount: apiToSmallInt(assertNotEmpty(data.total_count)), blocks: assertArray(data.blocks).map(decodeBlockResponse), }; } @@ -825,8 +825,8 @@ interface RpcNumUnconfirmedTxsResponse { function decodeNumUnconfirmedTxs(data: RpcNumUnconfirmedTxsResponse): responses.NumUnconfirmedTxsResponse { return { - total: Integer.parse(assertNotEmpty(data.total)), - totalBytes: Integer.parse(assertNotEmpty(data.total_bytes)), + total: apiToSmallInt(assertNotEmpty(data.total)), + totalBytes: apiToSmallInt(assertNotEmpty(data.total_bytes)), }; } diff --git a/packages/tendermint-rpc/src/tendermint34/encodings.ts b/packages/tendermint-rpc/src/tendermint34/encodings.ts index b4b1b32f..037b5068 100644 --- a/packages/tendermint-rpc/src/tendermint34/encodings.ts +++ b/packages/tendermint-rpc/src/tendermint34/encodings.ts @@ -1,5 +1,4 @@ import { toUtf8 } from "@cosmjs/encoding"; -import { Int53 } from "@cosmjs/math"; import { ReadonlyDateWithNanoseconds } from "../dates"; import { BlockId, Version } from "./responses"; @@ -140,17 +139,6 @@ export function dictionaryToStringMap(obj: Record): Map): Map