Generic 02-client cli cmds, removes light client specific ones (#8259)

* remove old light client cli cmds and replace with generic ones housed in client

* remove print and add client cli getter cmds

* use any as arguments

* revert back to single pub key

* fix tests

* typo

* remove todo

* add upgrade cli cmd cc @AdityaSripal

* register upgrade cmd
This commit is contained in:
colin axnér 2021-01-08 14:00:07 +01:00 committed by GitHub
parent 2e8f5e52bd
commit 0df0626604
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 290 additions and 534 deletions

View File

@ -25,8 +25,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth/legacy/legacytx"
bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil"
"github.com/cosmos/cosmos-sdk/x/bank/types"
ibcclientcli "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/client/cli"
ibccli "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/client/cli"
ibcsolomachinecli "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/client/cli"
)
type IntegrationTestSuite struct {
@ -480,10 +480,20 @@ func (s *IntegrationTestSuite) testQueryIBCTx(txRes sdk.TxResponse, cmd *cobra.C
func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
val := s.network.Validators[0]
// Write client state json to temp file, used for an IBC message.
// Generated by printing the result of cdc.MarshalIntefaceJSON on
// a solo machine client state
clientStateJSON := testutil.WriteToNewTempFile(
s.T(),
`{"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false}`,
)
// Write consensus json to temp file, used for an IBC message.
// Generated by printing the result of cdc.MarshalIntefaceJSON on
// a solo machine consensus state
consensusJSON := testutil.WriteToNewTempFile(
s.T(),
`{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`,
`{"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`,
)
testCases := []struct {
@ -509,10 +519,10 @@ func (s *IntegrationTestSuite) TestLegacyRestErrMessages() {
},
{
"Successful IBC message",
ibcsolomachinecli.NewCreateClientCmd(),
ibcclientcli.NewCreateClientCmd(),
[]string{
"1", // dummy sequence
consensusJSON.Name(), // path to consensus json,
clientStateJSON.Name(), // path to client state json
consensusJSON.Name(), // path to consensus json,
fmt.Sprintf("--%s=true", flags.FlagSkipConfirmation),
fmt.Sprintf("--%s=%s", flags.FlagBroadcastMode, flags.BroadcastBlock),
fmt.Sprintf("--%s=%s", flags.FlagFees, sdk.NewCoins(sdk.NewCoin(s.cfg.BondDenom, sdk.NewInt(10))).String()),

View File

@ -29,3 +29,23 @@ func GetQueryCmd() *cobra.Command {
return queryCmd
}
// NewTxCmd returns the command to create and handle IBC clients
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.SubModuleName,
Short: "IBC client transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
NewCreateClientCmd(),
NewUpdateClientCmd(),
NewSubmitMisbehaviourCmd(),
NewUpgradeClientCmd(),
)
return txCmd
}

View File

@ -193,12 +193,11 @@ func GetCmdQueryHeader() *cobra.Command {
if err != nil {
return err
}
header, height, err := utils.QueryTendermintHeader(clientCtx)
header, _, err := utils.QueryTendermintHeader(clientCtx)
if err != nil {
return err
}
clientCtx = clientCtx.WithHeight(height)
return clientCtx.PrintProto(&header)
},
}
@ -222,12 +221,11 @@ func GetCmdNodeConsensusState() *cobra.Command {
if err != nil {
return err
}
state, height, err := utils.QueryNodeConsensusState(clientCtx)
state, _, err := utils.QueryNodeConsensusState(clientCtx)
if err != nil {
return err
}
clientCtx = clientCtx.WithHeight(height)
return clientCtx.PrintProto(state)
},
}

View File

@ -0,0 +1,246 @@
package cli
import (
"fmt"
"io/ioutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
)
// NewCreateClientCmd defines the command to create a new IBC light client.
func NewCreateClientCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create [path/to/client_state.json] [path/to/consensus_state.json]",
Short: "create new IBC client",
Long: `create a new IBC client with the specified client state and consensus state
- ClientState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false}
- ConsensusState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`,
Example: fmt.Sprintf("%s tx ibc %s create [path/to/client_state.json] [path/to/consensus_state.json] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
// attempt to unmarshal client state argument
var clientState exported.ClientState
clientContentOrFileName := args[0]
if err := cdc.UnmarshalInterfaceJSON([]byte(clientContentOrFileName), &clientState); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(clientContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for client state were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, &clientState); err != nil {
return errors.Wrap(err, "error unmarshalling client state file")
}
}
// attempt to unmarshal consensus state argument
var consensusState exported.ConsensusState
consensusContentOrFileName := args[1]
if err := cdc.UnmarshalInterfaceJSON([]byte(consensusContentOrFileName), &consensusState); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(consensusContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, &consensusState); err != nil {
return errors.Wrap(err, "error unmarshalling consensus state file")
}
}
msg, err := types.NewMsgCreateClient(clientState, consensusState, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewUpdateClientCmd defines the command to update an IBC client.
func NewUpdateClientCmd() *cobra.Command {
return &cobra.Command{
Use: "update [client-id] [path/to/header.json]",
Short: "update existing client with a header",
Long: "update existing client with a header",
Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
clientID := args[0]
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
var header exported.Header
headerContentOrFileName := args[1]
if err := cdc.UnmarshalInterfaceJSON([]byte(headerContentOrFileName), &header); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(headerContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for header were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, &header); err != nil {
return errors.Wrap(err, "error unmarshalling header file")
}
}
msg, err := types.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
}
// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent
// future updates.
func NewSubmitMisbehaviourCmd() *cobra.Command {
return &cobra.Command{
Use: "misbehaviour [path/to/misbehaviour.json]",
Short: "submit a client misbehaviour",
Long: "submit a client misbehaviour to prevent future updates",
Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
var misbehaviour exported.Misbehaviour
misbehaviourContentOrFileName := args[0]
if err := cdc.UnmarshalInterfaceJSON([]byte(misbehaviourContentOrFileName), &misbehaviour); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(misbehaviourContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for misbehaviour were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, misbehaviour); err != nil {
return errors.Wrap(err, "error unmarshalling misbehaviour file")
}
}
msg, err := types.NewMsgSubmitMisbehaviour(misbehaviour.GetClientID(), misbehaviour, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
}
// NewUpgradeClientCmd defines the command to upgrade an IBC light client.
func NewUpgradeClientCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "upgrade [client-identifier] [path/to/client_state.json] [path/to/consensus_state.json] [upgrade-client-proof] [upgrade-consensus-state-proof]",
Short: "upgrade an IBC client",
Long: `upgrade the IBC client associated with the provided client identifier while providing proof committed by the counterparty chain to the new client and consensus states
- ClientState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ClientState","sequence":"1","frozen_sequence":"0","consensus_state":{"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"},"allow_update_after_proposal":false}
- ConsensusState JSON example: {"@type":"/ibc.lightclients.solomachine.v1.ConsensusState","public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"AtK50+5pJOoaa04qqAqrnyAqsYrwrR/INnA6UPIaYZlp"},"diversifier":"testing","timestamp":"10"}`,
Example: fmt.Sprintf("%s tx ibc %s upgrade [client-identifier] [path/to/client_state.json] [path/to/consensus_state.json] [client-state-proof] [consensus-state-proof] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
clientID := args[0]
// attempt to unmarshal client state argument
var clientState exported.ClientState
clientContentOrFileName := args[1]
if err := cdc.UnmarshalInterfaceJSON([]byte(clientContentOrFileName), &clientState); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(clientContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for client state were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, &clientState); err != nil {
return errors.Wrap(err, "error unmarshalling client state file")
}
}
// attempt to unmarshal consensus state argument
var consensusState exported.ConsensusState
consensusContentOrFileName := args[2]
if err := cdc.UnmarshalInterfaceJSON([]byte(consensusContentOrFileName), &consensusState); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(consensusContentOrFileName)
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided")
}
if err := cdc.UnmarshalInterfaceJSON(contents, &consensusState); err != nil {
return errors.Wrap(err, "error unmarshalling consensus state file")
}
}
proofUpgradeClient := []byte(args[3])
proofUpgradeConsensus := []byte(args[4])
msg, err := types.NewMsgUpgradeClient(clientID, clientState, consensusState, proofUpgradeClient, proofUpgradeConsensus, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -18,6 +18,11 @@ func GetQueryCmd() *cobra.Command {
return cli.GetQueryCmd()
}
// GetTxCmd returns the root tx command for 02-client.
func GetTxCmd() *cobra.Command {
return cli.NewTxCmd()
}
// RegisterQueryService registers the gRPC query service for IBC client.
func RegisterQueryService(server grpc.Server, queryServer types.QueryServer) {
types.RegisterQueryServer(server, queryServer)

View File

@ -8,8 +8,6 @@ import (
connection "github.com/cosmos/cosmos-sdk/x/ibc/core/03-connection"
channel "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel"
host "github.com/cosmos/cosmos-sdk/x/ibc/core/24-host"
solomachine "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine"
tendermint "github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint"
)
// GetTxCmd returns the transaction commands for this module
@ -23,8 +21,7 @@ func GetTxCmd() *cobra.Command {
}
ibcTxCmd.AddCommand(
solomachine.GetTxCmd(),
tendermint.GetTxCmd(),
ibcclient.GetTxCmd(),
connection.GetTxCmd(),
channel.GetTxCmd(),
)

View File

@ -1,27 +0,0 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types"
)
// NewTxCmd returns a root CLI command handler for all solo machine transaction commands.
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.SubModuleName,
Short: "Solo Machine transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
NewCreateClientCmd(),
NewUpdateClientCmd(),
NewSubmitMisbehaviourCmd(),
)
return txCmd
}

View File

@ -1,169 +0,0 @@
package cli
import (
"fmt"
"io/ioutil"
"strconv"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types"
)
const (
flagAllowUpdateAfterProposal = "allow_update_after_proposal"
)
// NewCreateClientCmd defines the command to create a new solo machine client.
func NewCreateClientCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create [sequence] [path/to/consensus_state.json]",
Short: "create new solo machine client",
Long: `create a new solo machine client with the specified identifier and public key
- ConsensusState json example: {"public_key":{"@type":"/cosmos.crypto.secp256k1.PubKey","key":"A/3SXL2ONYaOkxpdR5P8tHTlSlPv1AwQwSFxKRee5JQW"},"diversifier":"diversifier","timestamp":"10"}`,
Example: fmt.Sprintf("%s tx ibc %s create [sequence] [path/to/consensus_state] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
sequence, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
// attempt to unmarshal consensus state argument
consensusState := &types.ConsensusState{}
if err := cdc.UnmarshalJSON([]byte(args[1]), consensusState); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[1])
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for consensus state were provided")
}
if err := cdc.UnmarshalJSON(contents, consensusState); err != nil {
return errors.Wrap(err, "error unmarshalling consensus state file")
}
}
allowUpdateAfterProposal, _ := cmd.Flags().GetBool(flagAllowUpdateAfterProposal)
clientState := types.NewClientState(sequence, consensusState, allowUpdateAfterProposal)
msg, err := clienttypes.NewMsgCreateClient(clientState, consensusState, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().Bool(flagAllowUpdateAfterProposal, false, "allow governance proposal to update client")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewUpdateClientCmd defines the command to update a solo machine client.
func NewUpdateClientCmd() *cobra.Command {
return &cobra.Command{
Use: "update [client-id] [path/to/header.json]",
Short: "update existing client with a header",
Long: "update existing client with a solo machine header",
Example: fmt.Sprintf("%s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
clientID := args[0]
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
header := &types.Header{}
if err := cdc.UnmarshalJSON([]byte(args[1]), header); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[1])
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for header were provided")
}
if err := cdc.UnmarshalJSON(contents, header); err != nil {
return errors.Wrap(err, "error unmarshalling header file")
}
}
msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
}
// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to prevent
// future updates.
func NewSubmitMisbehaviourCmd() *cobra.Command {
return &cobra.Command{
Use: "misbehaviour [path/to/misbehaviour.json]",
Short: "submit a client misbehaviour",
Long: "submit a client misbehaviour to prevent future updates",
Example: fmt.Sprintf("%s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
m := &types.Misbehaviour{}
if err := cdc.UnmarshalJSON([]byte(args[0]), m); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[0])
if err != nil {
return errors.Wrap(err, "neither JSON input nor path to .json file for misbehaviour were provided")
}
if err := cdc.UnmarshalJSON(contents, m); err != nil {
return errors.Wrap(err, "error unmarshalling misbehaviour file")
}
}
msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
}

View File

@ -1,9 +1,6 @@
package solomachine
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/06-solomachine/types"
)
@ -11,8 +8,3 @@ import (
func Name() string {
return types.SubModuleName
}
// GetTxCmd returns the root tx command for the solo machine client.
func GetTxCmd() *cobra.Command {
return cli.NewTxCmd()
}

View File

@ -9,9 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
)
var (
_ exported.Misbehaviour = (*Misbehaviour)(nil)
)
var _ exported.Misbehaviour = &Misbehaviour{}
// ClientType is a Solo Machine light client.
func (misbehaviour Misbehaviour) ClientType() string {

View File

@ -1,25 +0,0 @@
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)
// NewTxCmd returns a root CLI command handler for all x/ibc/light-clients/07-tendermint transaction commands.
func NewTxCmd() *cobra.Command {
txCmd := &cobra.Command{
Use: types.SubModuleName,
Short: "Tendermint client transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
}
txCmd.AddCommand(
NewCreateClientCmd(),
NewUpdateClientCmd(),
NewSubmitMisbehaviourCmd(),
)
return txCmd
}

View File

@ -1,281 +0,0 @@
package cli
import (
"fmt"
"io/ioutil"
"strconv"
"strings"
"time"
ics23 "github.com/confio/ics23/go"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/light"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/version"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/23-commitment/types"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)
const (
flagTrustLevel = "trust-level"
flagProofSpecs = "proof-specs"
flagUpgradePath = "upgrade-path"
flagAllowUpdateAfterExpiry = "allow_update_after_expiry"
flagAllowUpdateAfterMisbehaviour = "allow_update_after_misbehaviour"
)
// NewCreateClientCmd defines the command to create a new IBC Client as defined
// in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create
func NewCreateClientCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift]",
Short: "create new tendermint client",
Long: `Create a new tendermint IBC client.
- 'trust-level' flag can be a fraction (eg: '1/3') or 'default'
- 'proof-specs' flag can be JSON input, a path to a .json file or 'default'
- 'upgrade-path' flag is a string specifying the upgrade path for this chain where a future upgraded client will be stored. The path is a comma-separated list representing the keys in order of the keyPath to the committed upgraded client.
e.g. 'upgrade/upgradedClient'`,
Example: fmt.Sprintf("%s tx ibc %s create [path/to/consensus_state.json] [trusting_period] [unbonding_period] [max_clock_drift] --trust-level default --consensus-params [path/to/consensus-params.json] --proof-specs [path/to/proof-specs.json] --upgrade-path upgrade/upgradedClient --from node0 --home ../node0/<app>cli --chain-id $CID", version.AppName, types.SubModuleName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
legacyAmino := codec.NewLegacyAmino()
var header *types.Header
if err := cdc.UnmarshalJSON([]byte(args[0]), header); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[0])
if err != nil {
return errors.New("neither JSON input nor path to .json file were provided for consensus header")
}
if err := cdc.UnmarshalJSON(contents, header); err != nil {
return errors.Wrap(err, "error unmarshalling consensus header file")
}
}
var (
trustLevel types.Fraction
specs []*ics23.ProofSpec
)
lvl, _ := cmd.Flags().GetString(flagTrustLevel)
if lvl == "default" {
trustLevel = types.NewFractionFromTm(light.DefaultTrustLevel)
} else {
trustLevel, err = parseFraction(lvl)
if err != nil {
return err
}
}
trustingPeriod, err := time.ParseDuration(args[1])
if err != nil {
return err
}
ubdPeriod, err := time.ParseDuration(args[2])
if err != nil {
return err
}
maxClockDrift, err := time.ParseDuration(args[3])
if err != nil {
return err
}
spc, _ := cmd.Flags().GetString(flagProofSpecs)
if spc == "default" {
specs = commitmenttypes.GetSDKSpecs()
// TODO migrate to use JSONMarshaler (implement MarshalJSONArray
// or wrap lists of proto.Message in some other message)
} else if err := legacyAmino.UnmarshalJSON([]byte(spc), &specs); err != nil {
// check for file path if JSON input not provided
contents, err := ioutil.ReadFile(spc)
if err != nil {
return errors.New("neither JSON input nor path to .json file was provided for proof specs flag")
}
// TODO migrate to use JSONMarshaler (implement MarshalJSONArray
// or wrap lists of proto.Message in some other message)
if err := legacyAmino.UnmarshalJSON(contents, &specs); err != nil {
return errors.Wrap(err, "error unmarshalling proof specs file")
}
}
allowUpdateAfterExpiry, _ := cmd.Flags().GetBool(flagAllowUpdateAfterExpiry)
allowUpdateAfterMisbehaviour, _ := cmd.Flags().GetBool(flagAllowUpdateAfterMisbehaviour)
upgradePathStr, _ := cmd.Flags().GetString(flagUpgradePath)
upgradePath := strings.Split(upgradePathStr, ",")
// validate header
if err := header.ValidateBasic(); err != nil {
return err
}
height := header.GetHeight().(clienttypes.Height)
clientState := types.NewClientState(
header.GetHeader().GetChainID(), trustLevel, trustingPeriod, ubdPeriod, maxClockDrift,
height, specs, upgradePath, allowUpdateAfterExpiry, allowUpdateAfterMisbehaviour,
)
consensusState := header.ConsensusState()
msg, err := clienttypes.NewMsgCreateClient(
clientState, consensusState, clientCtx.GetFromAddress(),
)
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(flagTrustLevel, "default", "light client trust level fraction for header updates")
cmd.Flags().String(flagProofSpecs, "default", "proof specs format to be used for verification")
cmd.Flags().Bool(flagAllowUpdateAfterExpiry, false, "allow governance proposal to update client after expiry")
cmd.Flags().Bool(flagAllowUpdateAfterMisbehaviour, false, "allow governance proposal to update client after misbehaviour")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewUpdateClientCmd defines the command to update a client as defined in
// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#update
func NewUpdateClientCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update [client-id] [path/to/header.json]",
Short: "update existing client with a header",
Long: "update existing tendermint client with a tendermint header",
Example: fmt.Sprintf(
"$ %s tx ibc %s update [client-id] [path/to/header.json] --from node0 --home ../node0/<app>cli --chain-id $CID",
version.AppName, types.SubModuleName,
),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
clientID := args[0]
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
var header *types.Header
if err := cdc.UnmarshalJSON([]byte(args[1]), header); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[1])
if err != nil {
return errors.New("neither JSON input nor path to .json file were provided")
}
if err := cdc.UnmarshalJSON(contents, header); err != nil {
return errors.Wrap(err, "error unmarshalling header file")
}
}
msg, err := clienttypes.NewMsgUpdateClient(clientID, header, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// NewSubmitMisbehaviourCmd defines the command to submit a misbehaviour to invalidate
// previous state roots and prevent future updates as defined in
// https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#misbehaviour
func NewSubmitMisbehaviourCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "misbehaviour [path/to/misbehaviour.json]",
Short: "submit a client misbehaviour",
Long: "submit a client misbehaviour to invalidate to invalidate previous state roots and prevent future updates",
Example: fmt.Sprintf(
"$ %s tx ibc %s misbehaviour [path/to/misbehaviour.json] --from node0 --home ../node0/<app>cli --chain-id $CID",
version.AppName, types.SubModuleName,
),
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
cdc := codec.NewProtoCodec(clientCtx.InterfaceRegistry)
var m *types.Misbehaviour
if err := cdc.UnmarshalJSON([]byte(args[0]), m); err != nil {
// check for file path if JSON input is not provided
contents, err := ioutil.ReadFile(args[0])
if err != nil {
return errors.New("neither JSON input nor path to .json file were provided")
}
if err := cdc.UnmarshalJSON(contents, m); err != nil {
return errors.Wrap(err, "error unmarshalling misbehaviour file")
}
}
msg, err := clienttypes.NewMsgSubmitMisbehaviour(m.ClientId, m, clientCtx.GetFromAddress())
if err != nil {
return err
}
if err := msg.ValidateBasic(); err != nil {
return err
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
func parseFraction(fraction string) (types.Fraction, error) {
fr := strings.Split(fraction, "/")
if len(fr) != 2 || fr[0] == fraction {
return types.Fraction{}, fmt.Errorf("fraction must have format 'numerator/denominator' got %s", fraction)
}
numerator, err := strconv.ParseUint(fr[0], 10, 64)
if err != nil {
return types.Fraction{}, fmt.Errorf("invalid trust-level numerator: %w", err)
}
denominator, err := strconv.ParseUint(fr[1], 10, 64)
if err != nil {
return types.Fraction{}, fmt.Errorf("invalid trust-level denominator: %w", err)
}
return types.Fraction{
Numerator: numerator,
Denominator: denominator,
}, nil
}

View File

@ -1,9 +1,6 @@
package tendermint
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/client/cli"
"github.com/cosmos/cosmos-sdk/x/ibc/light-clients/07-tendermint/types"
)
@ -11,8 +8,3 @@ import (
func Name() string {
return types.SubModuleName
}
// GetTxCmd returns the root tx command for the IBC client
func GetTxCmd() *cobra.Command {
return cli.NewTxCmd()
}