cosmos-sdk/cmd/commands/ibc.go

268 lines
6.4 KiB
Go

package commands
import (
"encoding/hex"
"fmt"
"io/ioutil"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/plugins/ibc"
"github.com/tendermint/merkleeyes/iavl"
"github.com/tendermint/go-wire"
tmtypes "github.com/tendermint/tendermint/types"
)
// returns a new IBC plugin to be registered with Basecoin
func NewIBCPlugin() *ibc.IBCPlugin {
return ibc.New()
}
//commands
var (
IBCTxCmd = &cobra.Command{
Use: "ibc",
Short: "An IBC transaction, for InterBlockchain Communication",
}
IBCRegisterTxCmd = &cobra.Command{
Use: "register",
Short: "Register a blockchain via IBC",
RunE: ibcRegisterTxCmd,
}
IBCUpdateTxCmd = &cobra.Command{
Use: "update",
Short: "Update the latest state of a blockchain via IBC",
RunE: ibcUpdateTxCmd,
}
IBCPacketTxCmd = &cobra.Command{
Use: "packet",
Short: "Send a new packet via IBC",
}
IBCPacketCreateTxCmd = &cobra.Command{
Use: "create",
Short: "Create an egress IBC packet",
RunE: ibcPacketCreateTxCmd,
}
IBCPacketPostTxCmd = &cobra.Command{
Use: "post",
Short: "Deliver an IBC packet to another chain",
RunE: ibcPacketPostTxCmd,
}
)
//flags
var (
ibcChainIDFlag string
ibcGenesisFlag string
ibcHeaderFlag string
ibcCommitFlag string
ibcFromFlag string
ibcToFlag string
ibcTypeFlag string
ibcPayloadFlag string
ibcPacketFlag string
ibcProofFlag string
ibcSequenceFlag int
ibcHeightFlag int
)
func init() {
// register flags
registerFlags := []Flag2Register{
{&ibcChainIDFlag, "ibc_chain_id", "", "ChainID for the new blockchain"},
{&ibcGenesisFlag, "genesis", "", "Genesis file for the new blockchain"},
}
updateFlags := []Flag2Register{
{&ibcHeaderFlag, "header", "", "Block header for an ibc update"},
{&ibcCommitFlag, "commit", "", "Block commit for an ibc update"},
}
fromFlagReg := Flag2Register{&ibcFromFlag, "ibc_from", "", "Source ChainID"}
packetCreateFlags := []Flag2Register{
fromFlagReg,
{&ibcToFlag, "to", "", "Destination ChainID"},
{&ibcTypeFlag, "type", "", "IBC packet type (eg. coin)"},
{&ibcPayloadFlag, "payload", "", "IBC packet payload"},
{&ibcSequenceFlag, "ibc_sequence", -1, "sequence number for IBC packet"},
}
packetPostFlags := []Flag2Register{
fromFlagReg,
{&ibcHeightFlag, "height", 0, "Height the packet became egress in source chain"},
{&ibcPacketFlag, "packet", "", "hex-encoded IBC packet"},
{&ibcProofFlag, "proof", "", "hex-encoded proof of IBC packet from source chain"},
}
RegisterFlags(IBCRegisterTxCmd, registerFlags)
RegisterFlags(IBCUpdateTxCmd, updateFlags)
RegisterFlags(IBCPacketCreateTxCmd, packetCreateFlags)
RegisterFlags(IBCPacketPostTxCmd, packetPostFlags)
//register commands
IBCTxCmd.AddCommand(IBCRegisterTxCmd, IBCUpdateTxCmd, IBCPacketTxCmd)
IBCPacketTxCmd.AddCommand(IBCPacketCreateTxCmd, IBCPacketPostTxCmd)
RegisterTxSubcommand(IBCTxCmd)
}
//---------------------------------------------------------------------
// ibc command implementations
func ibcRegisterTxCmd(cmd *cobra.Command, args []string) error {
chainID := ibcChainIDFlag
genesisFile := ibcGenesisFlag
genesisBytes, err := ioutil.ReadFile(genesisFile)
if err != nil {
return errors.Errorf("Error reading genesis file %v: %v\n", genesisFile, err)
}
ibcTx := ibc.IBCRegisterChainTx{
ibc.BlockchainGenesis{
ChainID: chainID,
Genesis: string(genesisBytes),
},
}
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
data := []byte(wire.BinaryBytes(struct {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
name := "IBC"
return AppTx(name, data)
}
func ibcUpdateTxCmd(cmd *cobra.Command, args []string) error {
headerBytes, err := hex.DecodeString(StripHex(ibcHeaderFlag))
if err != nil {
return errors.Errorf("Header (%v) is invalid hex: %v\n", ibcHeaderFlag, err)
}
commitBytes, err := hex.DecodeString(StripHex(ibcCommitFlag))
if err != nil {
return errors.Errorf("Commit (%v) is invalid hex: %v\n", ibcCommitFlag, err)
}
header := new(tmtypes.Header)
commit := new(tmtypes.Commit)
err = wire.ReadBinaryBytes(headerBytes, &header)
if err != nil {
return errors.Errorf("Error unmarshalling header: %v\n", err)
}
err = wire.ReadBinaryBytes(commitBytes, &commit)
if err != nil {
return errors.Errorf("Error unmarshalling commit: %v\n", err)
}
ibcTx := ibc.IBCUpdateChainTx{
Header: *header,
Commit: *commit,
}
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
data := []byte(wire.BinaryBytes(struct {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
name := "IBC"
return AppTx(name, data)
}
func ibcPacketCreateTxCmd(cmd *cobra.Command, args []string) error {
fromChain, toChain := ibcFromFlag, ibcToFlag
packetType := ibcTypeFlag
payloadBytes, err := hex.DecodeString(StripHex(ibcPayloadFlag))
if err != nil {
return errors.Errorf("Payload (%v) is invalid hex: %v\n", ibcPayloadFlag, err)
}
sequence, err := ibcSequenceCmd()
if err != nil {
return err
}
ibcTx := ibc.IBCPacketCreateTx{
Packet: ibc.Packet{
SrcChainID: fromChain,
DstChainID: toChain,
Sequence: sequence,
Type: packetType,
Payload: payloadBytes,
},
}
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
data := []byte(wire.BinaryBytes(struct {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
return AppTx("IBC", data)
}
func ibcPacketPostTxCmd(cmd *cobra.Command, args []string) error {
fromChain, fromHeight := ibcFromFlag, ibcHeightFlag
packetBytes, err := hex.DecodeString(StripHex(ibcPacketFlag))
if err != nil {
return errors.Errorf("Packet (%v) is invalid hex: %v\n", ibcPacketFlag, err)
}
proofBytes, err := hex.DecodeString(StripHex(ibcProofFlag))
if err != nil {
return errors.Errorf("Proof (%v) is invalid hex: %v\n", ibcProofFlag, err)
}
var packet ibc.Packet
proof := new(merkle.IAVLProof)
err = wire.ReadBinaryBytes(packetBytes, &packet)
if err != nil {
return errors.Errorf("Error unmarshalling packet: %v\n", err)
}
err = wire.ReadBinaryBytes(proofBytes, &proof)
if err != nil {
return errors.Errorf("Error unmarshalling proof: %v\n", err)
}
ibcTx := ibc.IBCPacketPostTx{
FromChainID: fromChain,
FromChainHeight: uint64(fromHeight),
Packet: packet,
Proof: proof,
}
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
data := []byte(wire.BinaryBytes(struct {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
return AppTx("IBC", data)
}
func ibcSequenceCmd() (uint64, error) {
if ibcSequenceFlag >= 0 {
return uint64(ibcSequenceFlag), nil
}
// TODO: get sequence
return 0, nil
}