This commit is contained in:
Ethan Buchman 2017-01-29 18:41:37 -08:00
parent b5e3a11347
commit 90d0b53a2f
8 changed files with 439 additions and 45 deletions

View File

@ -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
}

View File

@ -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,
},
}
)

View File

@ -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: "",
}
)

114
cmd/basecoin/ibc.go Normal file
View File

@ -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)
}

View File

@ -15,6 +15,9 @@ func main() {
startCmd,
sendTxCmd,
appTxCmd,
ibcCmd,
queryCmd,
blockCmd,
accountCmd,
}
app.Run(os.Args)

117
cmd/basecoin/query.go Normal file
View File

@ -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"`
}

View File

@ -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

View File

@ -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
}