From 91aff9bad3352a6df524f6e9549ae50011063858 Mon Sep 17 00:00:00 2001 From: cdc-Hitesh Date: Tue, 22 Jun 2021 16:16:18 +0530 Subject: [PATCH] #284: MsgSubmitMisbehaviour support --- lib/src/core/cro.ts | 2 + lib/src/cosmos/v1beta1/types/typeurls.ts | 1 + .../transaction/common/constants/typeurl.ts | 1 + .../ibc/core/MsgSubmitMisbehaviour.spec.ts | 125 ++++++++++++++++++ .../msg/ibc/core/MsgSubmitMisbehaviour.ts | 75 +++++++++++ lib/src/transaction/msg/ow.types.ts | 5 + 6 files changed, 209 insertions(+) create mode 100644 lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.spec.ts create mode 100644 lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.ts diff --git a/lib/src/core/cro.ts b/lib/src/core/cro.ts index 38e63289..97f4c706 100644 --- a/lib/src/core/cro.ts +++ b/lib/src/core/cro.ts @@ -33,6 +33,7 @@ import { msgTransferIBC } from '../transaction/msg/ibc/applications/MsgTransfer' import { msgCreateClientIBC } from '../transaction/msg/ibc/core/MsgCreateClient'; import { msgUpdateClientIBC } from '../transaction/msg/ibc/core/MsgUpdateClient'; import { msgUpgradeClientIBC } from '../transaction/msg/ibc/core/MsgUpgradeClient'; +import { msgSubmitMisbehaviourIBC } from '../transaction/msg/ibc/core/MsgSubmitMisbehaviour'; export const CroSDK = function (configs: InitConfigurations) { ow(configs, 'configs', owCroSDKInitParams); @@ -83,6 +84,7 @@ export const CroSDK = function (configs: InitConfigurations) { MsgCreateClient: msgCreateClientIBC(configs), MsgUpdateClient: msgUpdateClientIBC(configs), MsgUpgradeClient: msgUpgradeClientIBC(configs), + MsgSubmitMisbehaviour: msgSubmitMisbehaviourIBC(configs), }, Options: configs, }; diff --git a/lib/src/cosmos/v1beta1/types/typeurls.ts b/lib/src/cosmos/v1beta1/types/typeurls.ts index 79c65719..a1c26abf 100644 --- a/lib/src/cosmos/v1beta1/types/typeurls.ts +++ b/lib/src/cosmos/v1beta1/types/typeurls.ts @@ -35,6 +35,7 @@ export const typeUrlMappings: { '/ibc.core.client.v1.MsgCreateClient': ibc.core.client.v1.MsgCreateClient, '/ibc.core.client.v1.MsgUpdateClient': ibc.core.client.v1.MsgUpdateClient, '/ibc.core.client.v1.MsgUpgradeClient': ibc.core.client.v1.MsgUpgradeClient, + '/ibc.core.client.v1.MsgSubmitMisbehaviour': ibc.core.client.v1.MsgSubmitMisbehaviour, }; export interface GeneratedType { diff --git a/lib/src/transaction/common/constants/typeurl.ts b/lib/src/transaction/common/constants/typeurl.ts index 3d43407f..79b740b2 100644 --- a/lib/src/transaction/common/constants/typeurl.ts +++ b/lib/src/transaction/common/constants/typeurl.ts @@ -37,5 +37,6 @@ export const COSMOS_MSG_TYPEURL = { MsgCreateClient: '/ibc.core.client.v1.MsgCreateClient', MsgUpdateClient: '/ibc.core.client.v1.MsgUpdateClient', MsgUpgradeClient: '/ibc.core.client.v1.MsgUpgradeClient', + MsgSubmitMisbehaviour: '/ibc.core.client.v1.MsgSubmitMisbehaviour', }, }; diff --git a/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.spec.ts b/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.spec.ts new file mode 100644 index 00000000..941494e4 --- /dev/null +++ b/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.spec.ts @@ -0,0 +1,125 @@ +import 'mocha'; +import { expect } from 'chai'; +import Big from 'big.js'; + +import { fuzzyDescribe } from '../../../../test/mocha-fuzzy/suite'; +import { Msg } from '../../../../cosmos/v1beta1/types/msg'; +import { Secp256k1KeyPair } from '../../../../keypair/secp256k1'; +import { Bytes } from '../../../../utils/bytes/bytes'; +import { CroSDK } from '../../../../core/cro'; +import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; +import { google } from '../../../../cosmos/v1beta1/codec'; + +const cro = CroSDK({ + network: { + defaultNodeUrl: '', + chainId: 'testnet-croeseid-1', + addressPrefix: 'tcro', + validatorAddressPrefix: 'tcrocncl', + validatorPubKeyPrefix: 'tcrocnclconspub', + coin: { + baseDenom: 'basetcro', + croDenom: 'tcro', + }, + bip44Path: { + coinType: 1, + account: 0, + }, + rpcUrl: '', + }, +}); + +describe('Testing MsgSubmitMisbehaviour', function () { + fuzzyDescribe('should throw Error when options is invalid', function (fuzzy) { + const anyValidOptions = { + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + }; + + const testRunner = fuzzy(fuzzy.ObjArg(anyValidOptions)); + + testRunner(function (options) { + if (options.valid) { + return; + } + expect(() => new cro.ibc.MsgSubmitMisbehaviour(options.value)).to.throw( + 'Expected `options` to be of type `object`', + ); + }); + }); + + it('Test MsgSubmitMisbehaviour conversion', function () { + const MsgSubmitMisbehaviour = new cro.ibc.MsgSubmitMisbehaviour({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + }); + + const rawMsg: Msg = { + typeUrl: COSMOS_MSG_TYPEURL.ibc.MsgSubmitMisbehaviour, + value: { + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + misbehaviour: undefined, + }, + }; + + expect(MsgSubmitMisbehaviour.toRawMsg()).to.deep.eq(rawMsg); + }); + + it('Test appendTxBody MsgSubmitMisbehaviour Tx signing', function () { + const anyKeyPair = Secp256k1KeyPair.fromPrivKey( + Bytes.fromHexString('66633d18513bec30dd11a209f1ceb1787aa9e2069d5d47e590174dc9665102b3'), + ); + + const MsgSubmitMisbehaviour = new cro.ibc.MsgSubmitMisbehaviour({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + misbehaviour: google.protobuf.Any.create({ + type_url: '/some.valid.type.url', + value: new Uint8Array([1, 2, 35, 5]), + }), + clientId: 'clientId', + }); + + const anySigner = { + publicKey: anyKeyPair.getPubKey(), + accountNumber: new Big(0), + accountSequence: new Big(2), + }; + + const rawTx = new cro.RawTransaction(); + + const signableTx = rawTx.appendMessage(MsgSubmitMisbehaviour).addSigner(anySigner).toSignable(); + + const signedTx = signableTx.setSignature(0, anyKeyPair.sign(signableTx.toSignDocumentHash(0))).toSigned(); + + const signedTxHex = signedTx.encode().toHexString(); + expect(signedTxHex).to.be.eql( + '0a85010a82010a292f6962632e636f72652e636c69656e742e76312e4d73675375626d69744d69736265686176696f757212550a08636c69656e744964121c0a142f736f6d652e76616c69642e747970652e75726c1204010223051a2b7463726f313573667570643236737036716633376c6c3571367875663333306b37646639746e767271687412580a500a460a1f2f636f736d6f732e63727970746f2e736563703235366b312e5075624b657912230a2103fd0d560b6c4aa1ca16721d039a192867c3457e19dad553edb98e7ba88b159c2712040a0208011802120410c09a0c1a406b03e8c6860b1ba2f02af6187606eb40bac88bccfd7f54c5bf1993a9e2607da96e84f7b7dc14b8d111403ae62c27a5b9001848ef814b29da9b6b08424030e272', + ); + }); + + it('Should validate MsgSubmitMisbehaviour provided addresses with network config', function () { + const params1 = { + signer: 'cosmos1vw4ucaeagtduv5ep4sa95e3aqzqpsk5meda08c', + misbehaviour: google.protobuf.Any.create({ + type_url: '/some.valid.type.url', + value: new Uint8Array([1, 2, 35, 5]), + }), + clientId: 'clientId', + }; + + expect(() => new cro.ibc.MsgSubmitMisbehaviour(params1)).to.throw( + 'Provided `signer` does not match network selected', + ); + }); + + it('Should throw on getting toRawAminoMsg()', function () { + const MsgSubmitMisbehaviour = new cro.ibc.MsgSubmitMisbehaviour({ + signer: 'tcro15sfupd26sp6qf37ll5q6xuf330k7df9tnvrqht', + clientId: 'clientId', + }); + + expect(() => MsgSubmitMisbehaviour.toRawAminoMsg()).to.throw( + 'IBC Module not supported under amino encoding scheme', + ); + }); +}); diff --git a/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.ts b/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.ts new file mode 100644 index 00000000..0b8b68f8 --- /dev/null +++ b/lib/src/transaction/msg/ibc/core/MsgSubmitMisbehaviour.ts @@ -0,0 +1,75 @@ +import ow from 'ow'; +import { google } from '../../../../cosmos/v1beta1/codec/generated/codecimpl'; +import { InitConfigurations } from '../../../../core/cro'; +import { CosmosMsg } from '../../cosmosMsg'; +import { Msg } from '../../../../cosmos/v1beta1/types/msg'; +import { COSMOS_MSG_TYPEURL } from '../../../common/constants/typeurl'; +import { validateAddress, AddressType } from '../../../../utils/address'; +import { owMsgSubmitMisbehaviourOptions } from '../../ow.types'; +import * as legacyAmino from '../../../../cosmos/amino'; + +export const msgSubmitMisbehaviourIBC = function (config: InitConfigurations) { + return class MsgSubmitMisbehaviour implements CosmosMsg { + /** MsgSubmitMisbehaviour clientId. */ + public clientId: string; + + /** MsgSubmitMisbehaviour misbehaviour. */ + public misbehaviour?: google.protobuf.IAny | null; + + /** MsgSubmitMisbehaviour signer. */ + public signer: string; + + /** + * Constructor to create a new IBC.MsgSubmitMisbehaviour + * @param {MsgSubmitMisbehaviourOptions} options + * @returns {MsgSubmitMisbehaviour} + * @throws {Error} when options is invalid + */ + constructor(options: MsgSubmitMisbehaviourOptions) { + ow(options, 'options', owMsgSubmitMisbehaviourOptions); + this.clientId = options.clientId; + this.misbehaviour = options.misbehaviour; + this.signer = options.signer; + this.validateAddresses(); + } + + /** + * Returns the raw Msg representation of Ibc.MsgSubmitMisbehaviour + * @returns {Msg} + */ + toRawMsg(): Msg { + return { + typeUrl: COSMOS_MSG_TYPEURL.ibc.MsgSubmitMisbehaviour, + value: { + clientId: this.clientId, + misbehaviour: this.misbehaviour, + signer: this.signer, + }, + }; + } + + // eslint-disable-next-line class-methods-use-this + toRawAminoMsg(): legacyAmino.Msg { + throw new Error('IBC Module not supported under amino encoding scheme'); + } + + validateAddresses() { + // TODO: Can `signer` be from non-CRO network + if ( + !validateAddress({ + address: this.signer, + network: config.network, + type: AddressType.USER, + }) + ) { + throw new TypeError('Provided `signer` does not match network selected'); + } + } + }; +}; + +export type MsgSubmitMisbehaviourOptions = { + clientId: string; + misbehaviour?: google.protobuf.IAny | null; + signer: string; +}; diff --git a/lib/src/transaction/msg/ow.types.ts b/lib/src/transaction/msg/ow.types.ts index e76a1df7..ed9d41e9 100644 --- a/lib/src/transaction/msg/ow.types.ts +++ b/lib/src/transaction/msg/ow.types.ts @@ -226,3 +226,8 @@ export const owMsgUpgradeClientOptions = owStrictObject().exactShape({ proofUpgradeConsensusState: ow.uint8Array, signer: ow.string, }); +export const owMsgSubmitMisbehaviourOptions = owStrictObject().exactShape({ + clientId: ow.string, + misbehaviour: ow.optional.any(owGoogleProtoAnyOptional(), ow.optional.null), + signer: ow.string, +});