cmd: ibc
This commit is contained in:
parent
b5e3a11347
commit
90d0b53a2f
|
@ -1,31 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tendermint/go-wire"
|
||||
)
|
||||
|
||||
func cmdAccount(c *cli.Context) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return errors.New("account command requires an argument ([address])")
|
||||
}
|
||||
addrHex := stripHex(c.Args()[0])
|
||||
|
||||
// convert destination address to bytes
|
||||
addr, err := hex.DecodeString(addrHex)
|
||||
if err != nil {
|
||||
return errors.New("Account address is invalid hex: " + err.Error())
|
||||
}
|
||||
|
||||
acc, err := getAcc(c.String("tendermint"), addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(wire.JSONBytes(acc)))
|
||||
return nil
|
||||
}
|
|
@ -31,7 +31,7 @@ var (
|
|||
return cmdSendTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
tmAddrFlag,
|
||||
nodeFlag,
|
||||
chainIDFlag,
|
||||
|
||||
fromFlag,
|
||||
|
@ -54,7 +54,7 @@ var (
|
|||
return cmdAppTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
tmAddrFlag,
|
||||
nodeFlag,
|
||||
chainIDFlag,
|
||||
|
||||
fromFlag,
|
||||
|
@ -84,15 +84,114 @@ var (
|
|||
},
|
||||
}
|
||||
|
||||
ibcCmd = cli.Command{
|
||||
Name: "ibc",
|
||||
Usage: "Send a transaction to the interblockchain (ibc) plugin",
|
||||
Flags: []cli.Flag{
|
||||
nodeFlag,
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
ibcRegisterTxCmd,
|
||||
ibcUpdateTxCmd,
|
||||
ibcPacketTxCmd,
|
||||
},
|
||||
}
|
||||
|
||||
ibcRegisterTxCmd = cli.Command{
|
||||
Name: "register",
|
||||
Usage: "Register a blockchain via IBC",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdIBCRegisterTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
ibcChainIDFlag,
|
||||
ibcGenesisFlag,
|
||||
},
|
||||
}
|
||||
|
||||
ibcUpdateTxCmd = cli.Command{
|
||||
Name: "update",
|
||||
Usage: "Update the latest state of a blockchain via IBC",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdIBCUpdateTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
ibcHeaderFlag,
|
||||
ibcCommitFlag,
|
||||
},
|
||||
}
|
||||
|
||||
ibcPacketTxCmd = cli.Command{
|
||||
Name: "packet",
|
||||
Usage: "Send a new packet via IBC",
|
||||
Flags: []cli.Flag{
|
||||
//
|
||||
},
|
||||
Subcommands: []cli.Command{
|
||||
ibcPacketCreateTx,
|
||||
ibcPacketPostTx,
|
||||
},
|
||||
}
|
||||
|
||||
ibcPacketCreateTx = cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create an egress IBC packet",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdIBCPacketCreateTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
ibcFromFlag,
|
||||
ibcToFlag,
|
||||
ibcTypeFlag,
|
||||
ibcPayloadFlag,
|
||||
},
|
||||
}
|
||||
|
||||
ibcPacketPostTx = cli.Command{
|
||||
Name: "post",
|
||||
Usage: "Deliver an IBC packet to another chain",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdIBCPacketPostTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
ibcPacketFlag,
|
||||
ibcProofFlag,
|
||||
},
|
||||
}
|
||||
|
||||
queryCmd = cli.Command{
|
||||
Name: "query",
|
||||
Usage: "Query the merkle tree",
|
||||
ArgsUsage: "<key>",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdQuery(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
nodeFlag,
|
||||
},
|
||||
}
|
||||
|
||||
accountCmd = cli.Command{
|
||||
Name: "account",
|
||||
Usage: "Get details of an account",
|
||||
ArgsUsage: "[address]",
|
||||
ArgsUsage: "<address>",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdAccount(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
tmAddrFlag,
|
||||
nodeFlag,
|
||||
},
|
||||
}
|
||||
|
||||
blockCmd = cli.Command{
|
||||
Name: "block",
|
||||
Usage: "Get the header and commit of a block",
|
||||
ArgsUsage: "<height>",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdBlock(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
nodeFlag,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -48,8 +48,8 @@ var (
|
|||
// tx flags
|
||||
|
||||
var (
|
||||
tmAddrFlag = cli.StringFlag{
|
||||
Name: "tendermint",
|
||||
nodeFlag = cli.StringFlag{
|
||||
Name: "node",
|
||||
Value: "tcp://localhost:46657",
|
||||
Usage: "Tendermint RPC address",
|
||||
}
|
||||
|
@ -119,3 +119,66 @@ var (
|
|||
Usage: "Set valid field in CounterTx",
|
||||
}
|
||||
)
|
||||
|
||||
// ibc flags
|
||||
var (
|
||||
ibcChainIDFlag = cli.StringFlag{
|
||||
Name: "chain_id",
|
||||
Usage: "ChainID for the new blockchain",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcGenesisFlag = cli.StringFlag{
|
||||
Name: "genesis",
|
||||
Usage: "Genesis file for the new blockchain",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcHeaderFlag = cli.StringFlag{
|
||||
Name: "header",
|
||||
Usage: "Block header for an ibc update",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcCommitFlag = cli.StringFlag{
|
||||
Name: "commit",
|
||||
Usage: "Block commit for an ibc update",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcFromFlag = cli.StringFlag{
|
||||
Name: "from",
|
||||
Usage: "Source ChainID",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcToFlag = cli.StringFlag{
|
||||
Name: "to",
|
||||
Usage: "Destination ChainID",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcTypeFlag = cli.StringFlag{
|
||||
Name: "type",
|
||||
Usage: "IBC packet type (eg. coin)",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcPayloadFlag = cli.StringFlag{
|
||||
Name: "payload",
|
||||
Usage: "IBC packet payload",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcPacketFlag = cli.StringFlag{
|
||||
Name: "packet",
|
||||
Usage: "hex-encoded IBC packet",
|
||||
Value: "",
|
||||
}
|
||||
|
||||
ibcProofFlag = cli.StringFlag{
|
||||
Name: "proof",
|
||||
Usage: "hex-encoded proof of IBC packet from source chain",
|
||||
Value: "",
|
||||
}
|
||||
)
|
||||
|
|
|
@ -0,0 +1,114 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tendermint/basecoin/plugins/ibc"
|
||||
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-merkle"
|
||||
"github.com/tendermint/go-wire"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func cmdIBCRegisterTx(c *cli.Context) error {
|
||||
chainID := c.String("chain_id")
|
||||
genesisFile := c.String("genesis")
|
||||
parent := c.Parent()
|
||||
|
||||
genesisBytes, err := ioutil.ReadFile(genesisFile)
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Error reading genesis file %v: %v", genesisFile, err))
|
||||
}
|
||||
|
||||
ibcTx := ibc.IBCRegisterChainTx{
|
||||
ibc.BlockchainGenesis{
|
||||
ChainID: chainID,
|
||||
Genesis: string(genesisBytes),
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
|
||||
|
||||
data := wire.BinaryBytes(ibcTx)
|
||||
name := "ibc"
|
||||
|
||||
return appTx(parent, name, data)
|
||||
}
|
||||
|
||||
func cmdIBCUpdateTx(c *cli.Context) error {
|
||||
parent := c.Parent()
|
||||
|
||||
headerBytes, err := hex.DecodeString(stripHex(c.String("header")))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Header (%v) is invalid hex: %v", c.String("header"), err))
|
||||
}
|
||||
commitBytes, err := hex.DecodeString(stripHex(c.String("commit")))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Commit (%v) is invalid hex: %v", c.String("commit"), err))
|
||||
}
|
||||
|
||||
var header tmtypes.Header
|
||||
var commit tmtypes.Commit
|
||||
|
||||
if err := wire.ReadBinaryBytes(headerBytes, &header); err != nil {
|
||||
return errors.New(cmn.Fmt("Error unmarshalling header: %v", err))
|
||||
}
|
||||
if err := wire.ReadBinaryBytes(commitBytes, &commit); err != nil {
|
||||
return errors.New(cmn.Fmt("Error unmarshalling commit: %v", err))
|
||||
}
|
||||
|
||||
ibcTx := ibc.IBCUpdateChainTx{
|
||||
Header: header,
|
||||
Commit: commit,
|
||||
}
|
||||
|
||||
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
|
||||
|
||||
data := wire.BinaryBytes(ibcTx)
|
||||
name := "ibc"
|
||||
|
||||
return appTx(parent, name, data)
|
||||
}
|
||||
|
||||
func cmdIBCPacketCreateTx(c *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdIBCPacketPostTx(c *cli.Context) error {
|
||||
parent := c.Parent()
|
||||
|
||||
var fromChain string
|
||||
var fromHeight uint64
|
||||
var proof merkle.IAVLProof
|
||||
|
||||
var srcChain, dstChain string
|
||||
var sequence uint64
|
||||
var packetType string
|
||||
var payload []byte
|
||||
|
||||
ibcTx := ibc.IBCPacketTx{
|
||||
FromChainID: fromChain,
|
||||
FromChainHeight: fromHeight,
|
||||
Packet: ibc.Packet{
|
||||
SrcChainID: srcChain,
|
||||
DstChainID: dstChain,
|
||||
Sequence: sequence,
|
||||
Type: packetType,
|
||||
Payload: payload,
|
||||
},
|
||||
Proof: proof,
|
||||
}
|
||||
|
||||
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
|
||||
|
||||
data := wire.BinaryBytes(ibcTx)
|
||||
name := "ibc"
|
||||
|
||||
return appTx(parent, name, data)
|
||||
}
|
|
@ -15,6 +15,9 @@ func main() {
|
|||
startCmd,
|
||||
sendTxCmd,
|
||||
appTxCmd,
|
||||
ibcCmd,
|
||||
queryCmd,
|
||||
blockCmd,
|
||||
accountCmd,
|
||||
}
|
||||
app.Run(os.Args)
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-wire"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
func cmdQuery(c *cli.Context) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return errors.New("query command requires an argument ([key])")
|
||||
}
|
||||
keyString := c.Args()[0]
|
||||
key := []byte(keyString)
|
||||
if isHex(keyString) {
|
||||
// convert key to bytes
|
||||
var err error
|
||||
key, err = hex.DecodeString(stripHex(keyString))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Query key (%v) is invalid hex: %v", keyString, err))
|
||||
}
|
||||
}
|
||||
|
||||
resp, err := query(c.String("node"), key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !resp.Code.IsOK() {
|
||||
return errors.New(cmn.Fmt("Query for key (%v) returned non-zero code (%v): %v", keyString, resp.Code, resp.Log))
|
||||
}
|
||||
|
||||
val := resp.Value
|
||||
proof := resp.Proof
|
||||
height := resp.Height
|
||||
|
||||
fmt.Println(string(wire.JSONBytes(struct {
|
||||
Value []byte `json:"value"`
|
||||
Proof []byte `json:"proof"`
|
||||
Height uint64 `json:"height"`
|
||||
}{val, proof, height})))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdAccount(c *cli.Context) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return errors.New("account command requires an argument ([address])")
|
||||
}
|
||||
addrHex := stripHex(c.Args()[0])
|
||||
|
||||
// convert destination address to bytes
|
||||
addr, err := hex.DecodeString(addrHex)
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Account address (%v) is invalid hex: %v", addrHex, err))
|
||||
}
|
||||
|
||||
acc, err := getAcc(c.String("node"), addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(wire.JSONBytes(acc)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func cmdBlock(c *cli.Context) error {
|
||||
if len(c.Args()) != 1 {
|
||||
return errors.New("block command requires an argument ([height])")
|
||||
}
|
||||
heightString := c.Args()[0]
|
||||
height, err := strconv.Atoi(heightString)
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Height must be an int, got %v: %v", heightString, err))
|
||||
}
|
||||
|
||||
block, err := getBlock(c, height)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nextBlock, err := getBlock(c, height+1)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println(string(wire.JSONBytes(struct {
|
||||
Hex BlockHex `json:"hex"`
|
||||
JSON BlockJSON `json:"json"`
|
||||
}{
|
||||
BlockHex{
|
||||
Header: wire.BinaryBytes(block.Header),
|
||||
Commit: wire.BinaryBytes(nextBlock.LastCommit),
|
||||
},
|
||||
BlockJSON{
|
||||
Header: block.Header,
|
||||
Commit: nextBlock.LastCommit,
|
||||
},
|
||||
})))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type BlockHex struct {
|
||||
Header []byte `json:"header"`
|
||||
Commit []byte `json:"commit"`
|
||||
}
|
||||
|
||||
type BlockJSON struct {
|
||||
Header *tmtypes.Header `json:"header"`
|
||||
Commit *tmtypes.Commit `json:"commit"`
|
||||
}
|
|
@ -136,7 +136,7 @@ func cmdCounterTx(c *cli.Context) error {
|
|||
// broadcast the transaction to tendermint
|
||||
func broadcastTx(c *cli.Context, tx types.Tx) error {
|
||||
tmResult := new(ctypes.TMResult)
|
||||
tmAddr := c.String("tendermint")
|
||||
tmAddr := c.String("node")
|
||||
clientURI := client.NewClientURI(tmAddr)
|
||||
|
||||
// Don't you hate having to do this?
|
||||
|
@ -161,7 +161,7 @@ func getSeq(c *cli.Context, address []byte) (int, error) {
|
|||
if c.IsSet("sequence") {
|
||||
return c.Int("sequence"), nil
|
||||
}
|
||||
tmAddr := c.String("tendermint")
|
||||
tmAddr := c.String("node")
|
||||
acc, err := getAcc(tmAddr, address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
|
@ -4,12 +4,16 @@ import (
|
|||
"encoding/hex"
|
||||
"errors"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tendermint/basecoin/types"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/go-common"
|
||||
client "github.com/tendermint/go-rpc/client"
|
||||
"github.com/tendermint/go-wire"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// Returns true for non-empty hex-string prefixed with "0x"
|
||||
|
@ -31,15 +35,14 @@ func stripHex(s string) string {
|
|||
return s
|
||||
}
|
||||
|
||||
// fetch the account by querying the app
|
||||
func getAcc(tmAddr string, address []byte) (*types.Account, error) {
|
||||
func query(tmAddr string, key []byte) (*abci.ResponseQuery, error) {
|
||||
clientURI := client.NewClientURI(tmAddr)
|
||||
tmResult := new(ctypes.TMResult)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"path": "/key",
|
||||
"data": append([]byte("base/a/"), address...),
|
||||
"prove": false,
|
||||
"data": key,
|
||||
"prove": true,
|
||||
}
|
||||
_, err := clientURI.Call("abci_query", params, tmResult)
|
||||
if err != nil {
|
||||
|
@ -49,11 +52,24 @@ func getAcc(tmAddr string, address []byte) (*types.Account, error) {
|
|||
if !res.Response.Code.IsOK() {
|
||||
return nil, errors.New(cmn.Fmt("Query got non-zero exit code: %v. %s", res.Response.Code, res.Response.Log))
|
||||
}
|
||||
accountBytes := res.Response.Value
|
||||
return &res.Response, nil
|
||||
}
|
||||
|
||||
// fetch the account by querying the app
|
||||
func getAcc(tmAddr string, address []byte) (*types.Account, error) {
|
||||
|
||||
key := append([]byte("base/a/"), address...)
|
||||
response, err := query(tmAddr, key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
accountBytes := response.Value
|
||||
|
||||
if len(accountBytes) == 0 {
|
||||
return nil, errors.New(cmn.Fmt("Account bytes are empty from query for address %X", address))
|
||||
return nil, errors.New(cmn.Fmt("Account bytes are empty for address: %X ", address))
|
||||
}
|
||||
|
||||
var acc *types.Account
|
||||
err = wire.ReadBinaryBytes(accountBytes, &acc)
|
||||
if err != nil {
|
||||
|
@ -63,3 +79,16 @@ func getAcc(tmAddr string, address []byte) (*types.Account, error) {
|
|||
|
||||
return acc, nil
|
||||
}
|
||||
|
||||
func getBlock(c *cli.Context, height int) (*tmtypes.Block, error) {
|
||||
tmResult := new(ctypes.TMResult)
|
||||
tmAddr := c.String("node")
|
||||
clientURI := client.NewClientURI(tmAddr)
|
||||
|
||||
_, err := clientURI.Call("block", map[string]interface{}{"height": height}, tmResult)
|
||||
if err != nil {
|
||||
return nil, errors.New(cmn.Fmt("Error on broadcast tx: %v", err))
|
||||
}
|
||||
res := (*tmResult).(*ctypes.ResultBlock)
|
||||
return res.Block, nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue