cosmos-sdk/x/ibc/03-connection/client/cli/tx.go

266 lines
7.9 KiB
Go

package cli
import (
"bufio"
"fmt"
"strings"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/client/utils"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
)
// Connection Handshake flags
const (
FlagNode1 = "node1"
FlagNode2 = "node2"
FlagFrom1 = "from1"
FlagFrom2 = "from2"
FlagChainID2 = "chain-id2"
)
// GetCmdConnectionOpenInit defines the command to initialize a connection on
// chain A with a given counterparty chain B
func GetCmdConnectionOpenInit(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: strings.TrimSpace(`open-init [connection-id] [client-id] [counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]`),
Short: "initialize connection on chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B:
Example:
$ %s tx ibc connection open-init [connection-id] [client-id] \
[counterparty-connection-id] [counterparty-client-id] \
[path/to/counterparty_prefix.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
clientCtx := client.NewContextWithInput(inBuf).WithCodec(cdc)
connectionID := args[0]
clientID := args[1]
counterpartyConnectionID := args[2]
counterpartyClientID := args[3]
counterpartyPrefix, err := utils.ParsePrefix(clientCtx.Codec, args[4])
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenInit(
connectionID, clientID, counterpartyConnectionID, counterpartyClientID,
counterpartyPrefix, clientCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenTry defines the command to relay a try open a connection on
// chain B
func GetCmdConnectionOpenTry(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: strings.TrimSpace(`open-try [connection-id] [client-id]
[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json]
[counterparty-versions] [path/to/proof_init.json] [path/to/proof_consensus.json]`),
Short: "initiate connection handshake between two chains",
Long: strings.TrimSpace(
fmt.Sprintf(`initialize a connection on chain A with a given counterparty chain B:
Example:
$ %s tx ibc connection open-try connection-id] [client-id] \
[counterparty-connection-id] [counterparty-client-id] [path/to/counterparty_prefix.json] \
[counterparty-versions] [path/to/proof_init.json] [path/tp/proof_consensus.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(8),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
clientCtx := client.NewContextWithInput(inBuf).
WithCodec(cdc).
WithHeight(viper.GetInt64(flags.FlagHeight))
connectionID := args[0]
clientID := args[1]
counterpartyConnectionID := args[2]
counterpartyClientID := args[3]
counterpartyPrefix, err := utils.ParsePrefix(clientCtx.Codec, args[4])
if err != nil {
return err
}
// TODO: parse strings?
counterpartyVersions := args[5]
proofInit, err := utils.ParseProof(clientCtx.Codec, args[6])
if err != nil {
return err
}
proofConsensus, err := utils.ParseProof(clientCtx.Codec, args[7])
if err != nil {
return err
}
proofHeight := uint64(clientCtx.Height)
consensusHeight, err := lastHeight(clientCtx)
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenTry(
connectionID, clientID, counterpartyConnectionID, counterpartyClientID,
counterpartyPrefix, []string{counterpartyVersions}, proofInit, proofConsensus, proofHeight,
consensusHeight, clientCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenAck defines the command to relay the acceptance of a
// connection open attempt from chain B to chain A
func GetCmdConnectionOpenAck(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-ack [connection-id] [path/to/proof_try.json] [path/to/proof_consensus.json] [version]",
Short: "relay the acceptance of a connection open attempt from chain B to chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`relay the acceptance of a connection open attempt from chain B to chain A:
Example:
$ %s tx ibc connection open-ack [connection-id] [path/to/proof_try.json] [path/to/proof_consensus.json] [version]
`, version.ClientName),
),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
clientCtx := client.NewContextWithInput(inBuf).WithCodec(cdc)
connectionID := args[0]
proofTry, err := utils.ParseProof(clientCtx.Codec, args[1])
if err != nil {
return err
}
proofConsensus, err := utils.ParseProof(clientCtx.Codec, args[2])
if err != nil {
return err
}
proofHeight := uint64(clientCtx.Height)
consensusHeight, err := lastHeight(clientCtx)
if err != nil {
return err
}
version := args[3]
msg := types.NewMsgConnectionOpenAck(
connectionID, proofTry, proofConsensus, proofHeight,
consensusHeight, version, clientCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// GetCmdConnectionOpenConfirm defines the command to initialize a connection on
// chain A with a given counterparty chain B
func GetCmdConnectionOpenConfirm(storeKey string, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "open-confirm [connection-id] [path/to/proof_ack.json]",
Short: "confirm to chain B that connection is open on chain A",
Long: strings.TrimSpace(
fmt.Sprintf(`confirm to chain B that connection is open on chain A:
Example:
$ %s tx ibc connection open-confirm [connection-id] [path/to/proof_ack.json]
`, version.ClientName),
),
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
txBldr := authtypes.NewTxBuilderFromCLI(inBuf).WithTxEncoder(authclient.GetTxEncoder(cdc))
clientCtx := client.NewContextWithInput(inBuf).
WithCodec(cdc).
WithHeight(viper.GetInt64(flags.FlagHeight))
connectionID := args[0]
proofAck, err := utils.ParseProof(clientCtx.Codec, args[1])
if err != nil {
return err
}
proofHeight := uint64(clientCtx.Height)
if err != nil {
return err
}
msg := types.NewMsgConnectionOpenConfirm(
connectionID, proofAck, proofHeight, clientCtx.GetFromAddress(),
)
if err := msg.ValidateBasic(); err != nil {
return err
}
return authclient.GenerateOrBroadcastMsgs(clientCtx, txBldr, []sdk.Msg{msg})
},
}
return cmd
}
// lastHeight util function to get the consensus height from the node
func lastHeight(clientCtx client.Context) (uint64, error) {
node, err := clientCtx.GetNode()
if err != nil {
return 0, err
}
info, err := node.ABCIInfo()
if err != nil {
return 0, err
}
return uint64(info.Response.LastBlockHeight), nil
}