added cli cobra

rebaseFixes

int

removed ExitOnErr

int

int

int

int

int

added uint64 to RegisterFlags
This commit is contained in:
rigelrozanski 2017-03-09 02:19:07 -05:00 committed by Ethan Buchman
parent c6e348e01b
commit fb3fd1b425
20 changed files with 716 additions and 726 deletions

View File

@ -4,17 +4,18 @@ import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/cmd/commands"
"github.com/tendermint/basecoin/version"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "basecoin"
app.Usage = "basecoin [command] [args...]"
app.Version = version.Version
app.Commands = []cli.Command{
var RootCmd = &cobra.Command{
Use: "basecoin",
Short: "A cryptocurrency framework in Golang based on Tendermint-Core",
}
RootCmd.AddCommand(
commands.InitCmd,
commands.StartCmd,
commands.TxCmd,
@ -24,9 +25,10 @@ func main() {
commands.BlockCmd,
commands.AccountCmd,
commands.UnsafeResetAllCmd,
}
err := app.Run(os.Args)
if err != nil {
commands.VersionCmd,
)
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}

View File

@ -1,119 +0,0 @@
package commands
import (
"github.com/urfave/cli"
)
// start flags
var (
AddrFlag = cli.StringFlag{
Name: "address",
Value: "tcp://0.0.0.0:46658",
Usage: "Listen address",
}
EyesFlag = cli.StringFlag{
Name: "eyes",
Value: "local",
Usage: "MerkleEyes address, or 'local' for embedded",
}
// TODO: move to config file
// eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
WithoutTendermintFlag = cli.BoolFlag{
Name: "without-tendermint",
Usage: "Run the Basecoin app without Tendermint",
}
)
// tx flags
var (
NodeFlag = cli.StringFlag{
Name: "node",
Value: "tcp://localhost:46657",
Usage: "Tendermint RPC address",
}
ToFlag = cli.StringFlag{
Name: "to",
Value: "",
Usage: "Destination address for the transaction",
}
AmountFlag = cli.StringFlag{
Name: "amount",
Value: "",
Usage: "Coins to send in transaction of the format <amt><coin>,<amt2><coin2>,... (eg: 1btc,2gold,5silver)",
}
FromFlag = cli.StringFlag{
Name: "from",
Value: "key.json",
Usage: "Path to a private key to sign the transaction",
}
SeqFlag = cli.IntFlag{
Name: "sequence",
Value: 0,
Usage: "Sequence number for the account",
}
GasFlag = cli.IntFlag{
Name: "gas",
Value: 0,
Usage: "The amount of gas for the transaction",
}
FeeFlag = cli.StringFlag{
Name: "fee",
Value: "",
Usage: "Coins for the transaction fee of the format <amt><coin>",
}
DataFlag = cli.StringFlag{
Name: "data",
Value: "",
Usage: "Data to send with the transaction",
}
NameFlag = cli.StringFlag{
Name: "name",
Value: "",
Usage: "Plugin to send the transaction to",
}
ChainIDFlag = cli.StringFlag{
Name: "chain_id",
Value: "test_chain_id",
Usage: "ID of the chain for replay protection",
}
)
// proof flags
var (
ProofFlag = cli.StringFlag{
Name: "proof",
Usage: "hex-encoded IAVL proof",
Value: "",
}
KeyFlag = cli.StringFlag{
Name: "key",
Usage: "key to the IAVL tree",
Value: "",
}
ValueFlag = cli.StringFlag{
Name: "value",
Usage: "value in the IAVL tree",
Value: "",
}
RootFlag = cli.StringFlag{
Name: "root",
Usage: "root hash of the IAVL tree",
Value: "",
}
)

View File

@ -2,11 +2,10 @@ package commands
import (
"encoding/hex"
"errors"
"fmt"
"io/ioutil"
"github.com/urfave/cli"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/plugins/ibc"
@ -21,172 +20,110 @@ func NewIBCPlugin() *ibc.IBCPlugin {
return ibc.New()
}
//---------------------------------------------------------------------
// ibc flags
//commands
var (
IbcChainIDFlag = cli.StringFlag{
Name: "chain_id",
Usage: "ChainID for the new blockchain",
Value: "",
IBCTxCmd = &cobra.Command{
Use: "ibc",
Short: "An IBC transaction, for InterBlockchain Communication",
}
IbcGenesisFlag = cli.StringFlag{
Name: "genesis",
Usage: "Genesis file for the new blockchain",
Value: "",
IBCRegisterTxCmd = &cobra.Command{
Use: "register",
Short: "Register a blockchain via IBC",
Run: ibcRegisterTxCmd,
}
IbcHeaderFlag = cli.StringFlag{
Name: "header",
Usage: "Block header for an ibc update",
Value: "",
IBCUpdateTxCmd = &cobra.Command{
Use: "update",
Short: "Update the latest state of a blockchain via IBC",
Run: ibcUpdateTxCmd,
}
IbcCommitFlag = cli.StringFlag{
Name: "commit",
Usage: "Block commit for an ibc update",
Value: "",
IBCPacketTxCmd = &cobra.Command{
Use: "packet",
Short: "Send a new packet via IBC",
}
IbcFromFlag = cli.StringFlag{
Name: "from",
Usage: "Source ChainID",
Value: "",
IBCPacketCreateTxCmd = &cobra.Command{
Use: "create",
Short: "Create an egress IBC packet",
Run: ibcPacketCreateTxCmd,
}
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: "",
}
IbcSequenceFlag = cli.IntFlag{
Name: "sequence",
Usage: "sequence number for IBC packet",
Value: 0,
}
IbcHeightFlag = cli.IntFlag{
Name: "height",
Usage: "Height the packet became egress in source chain",
Value: 0,
IBCPacketPostTxCmd = &cobra.Command{
Use: "post",
Short: "Deliver an IBC packet to another chain",
Run: ibcPacketPostTxCmd,
}
)
//---------------------------------------------------------------------
// ibc commands
//flags
var (
IbcTxCmd = cli.Command{
Name: "ibc",
Usage: "an IBC transaction, for InterBlockchain Communication",
Flags: TxFlags,
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",
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,
IbcSequenceFlag,
},
}
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{
IbcFromFlag,
IbcHeightFlag,
IbcPacketFlag,
IbcProofFlag,
},
}
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 cmdIBCRegisterTx(c *cli.Context) error {
chainID := c.String("chain_id")
genesisFile := c.String("genesis")
parent := c.Parent()
func ibcRegisterTxCmd(cmd *cobra.Command, args []string) {
chainID := ibcChainIDFlag
genesisFile := ibcGenesisFlag
genesisBytes, err := ioutil.ReadFile(genesisFile)
if err != nil {
return errors.New(cmn.Fmt("Error reading genesis file %v: %v", genesisFile, err))
cmn.Exit(fmt.Sprintf("Error reading genesis file %v: %+v\n", genesisFile, err))
}
ibcTx := ibc.IBCRegisterChainTx{
@ -203,27 +140,31 @@ func cmdIBCRegisterTx(c *cli.Context) error {
}{ibcTx}))
name := "IBC"
return AppTx(parent, name, data)
AppTx(name, data)
}
func cmdIBCUpdateTx(c *cli.Context) error {
headerBytes, err := hex.DecodeString(StripHex(c.String("header")))
func ibcUpdateTxCmd(cmd *cobra.Command, args []string) {
headerBytes, err := hex.DecodeString(StripHex(ibcHeaderFlag))
if err != nil {
return errors.New(cmn.Fmt("Header (%v) is invalid hex: %v", c.String("header"), err))
cmn.Exit(fmt.Sprintf("Header (%v) is invalid hex: %+v\n", ibcHeaderFlag, err))
}
commitBytes, err := hex.DecodeString(StripHex(c.String("commit")))
commitBytes, err := hex.DecodeString(StripHex(ibcCommitFlag))
if err != nil {
return errors.New(cmn.Fmt("Commit (%v) is invalid hex: %v", c.String("commit"), err))
cmn.Exit(fmt.Sprintf("Commit (%v) is invalid hex: %+v\n", ibcCommitFlag, err))
}
header := new(tmtypes.Header)
commit := new(tmtypes.Commit)
if err := wire.ReadBinaryBytes(headerBytes, &header); err != nil {
return errors.New(cmn.Fmt("Error unmarshalling header: %v", err))
err = wire.ReadBinaryBytes(headerBytes, &header)
if err != nil {
cmn.Exit(fmt.Sprintf("Error unmarshalling header: %+v\n", err))
}
if err := wire.ReadBinaryBytes(commitBytes, &commit); err != nil {
return errors.New(cmn.Fmt("Error unmarshalling commit: %v", err))
err = wire.ReadBinaryBytes(commitBytes, &commit)
if err != nil {
cmn.Exit(fmt.Sprintf("Error unmarshalling commit: %+v\n", err))
}
ibcTx := ibc.IBCUpdateChainTx{
@ -238,21 +179,21 @@ func cmdIBCUpdateTx(c *cli.Context) error {
}{ibcTx}))
name := "IBC"
return AppTx(c.Parent(), name, data)
AppTx(name, data)
}
func cmdIBCPacketCreateTx(c *cli.Context) error {
fromChain, toChain := c.String("from"), c.String("to")
packetType := c.String("type")
func ibcPacketCreateTxCmd(cmd *cobra.Command, args []string) {
fromChain, toChain := ibcFromFlag, ibcToFlag
packetType := ibcTypeFlag
payloadBytes, err := hex.DecodeString(StripHex(c.String("payload")))
payloadBytes, err := hex.DecodeString(StripHex(ibcPayloadFlag))
if err != nil {
return errors.New(cmn.Fmt("Payload (%v) is invalid hex: %v", c.String("payload"), err))
cmn.Exit(fmt.Sprintf("Payload (%v) is invalid hex: %+v\n", ibcPayloadFlag, err))
}
sequence, err := getIBCSequence(c)
sequence, err := ibcSequenceCmd()
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
ibcTx := ibc.IBCPacketCreateTx{
@ -271,29 +212,33 @@ func cmdIBCPacketCreateTx(c *cli.Context) error {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
return AppTx(c.Parent().Parent(), "IBC", data)
AppTx("IBC", data)
}
func cmdIBCPacketPostTx(c *cli.Context) error {
fromChain, fromHeight := c.String("from"), c.Int("height")
func ibcPacketPostTxCmd(cmd *cobra.Command, args []string) {
fromChain, fromHeight := ibcFromFlag, ibcHeightFlag
packetBytes, err := hex.DecodeString(StripHex(c.String("packet")))
packetBytes, err := hex.DecodeString(StripHex(ibcPacketFlag))
if err != nil {
return errors.New(cmn.Fmt("Packet (%v) is invalid hex: %v", c.String("packet"), err))
cmn.Exit(fmt.Sprintf("Packet (%v) is invalid hex: %+v\n", ibcPacketFlag, err))
}
proofBytes, err := hex.DecodeString(StripHex(c.String("proof")))
proofBytes, err := hex.DecodeString(StripHex(ibcProofFlag))
if err != nil {
return errors.New(cmn.Fmt("Proof (%v) is invalid hex: %v", c.String("proof"), err))
cmn.Exit(fmt.Sprintf("Proof (%v) is invalid hex: %+v\n", ibcProofFlag, err))
}
var packet ibc.Packet
proof := new(merkle.IAVLProof)
if err := wire.ReadBinaryBytes(packetBytes, &packet); err != nil {
return errors.New(cmn.Fmt("Error unmarshalling packet: %v", err))
err = wire.ReadBinaryBytes(packetBytes, &packet)
if err != nil {
cmn.Exit(fmt.Sprintf("Error unmarshalling packet: %+v\n", err))
}
if err := wire.ReadBinaryBytes(proofBytes, &proof); err != nil {
return errors.New(cmn.Fmt("Error unmarshalling proof: %v", err))
err = wire.ReadBinaryBytes(proofBytes, &proof)
if err != nil {
cmn.Exit(fmt.Sprintf("Error unmarshalling proof: %+v\n", err))
}
ibcTx := ibc.IBCPacketPostTx{
@ -309,12 +254,12 @@ func cmdIBCPacketPostTx(c *cli.Context) error {
ibc.IBCTx `json:"unwrap"`
}{ibcTx}))
return AppTx(c.Parent().Parent(), "IBC", data)
AppTx("IBC", data)
}
func getIBCSequence(c *cli.Context) (uint64, error) {
if c.IsSet("sequence") {
return uint64(c.Int("sequence")), nil
func ibcSequenceCmd() (uint64, error) {
if ibcSequenceFlag >= 0 {
return uint64(ibcSequenceFlag), nil
}
// TODO: get sequence

View File

@ -1,27 +1,38 @@
package commands
import (
"fmt"
"io/ioutil"
"path"
"github.com/urfave/cli"
"github.com/spf13/cobra"
cmn "github.com/tendermint/go-common"
)
var InitCmd = cli.Command{
Name: "init",
Usage: "Initialize a basecoin blockchain",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdInit(c)
},
Flags: []cli.Flag{
ChainIDFlag,
},
}
//commands
var (
InitCmd = &cobra.Command{
Use: "init",
Short: "Initialize a basecoin blockchain",
Run: initCmd,
}
)
func cmdInit(c *cli.Context) error {
//flags
//var chainIDFlag string
//func init() {
//
// //register flags
// flags := []Flag2Register{
// {&chainIDFlag, "chain_id", "test_chain_id", "ID of the chain for replay protection"},
// }
// RegisterFlags(InitCmd, flags)
//
//}
func initCmd(cmd *cobra.Command, args []string) {
rootDir := BasecoinRoot("")
cmn.EnsureDir(rootDir, 0777)
@ -32,22 +43,27 @@ func cmdInit(c *cli.Context) error {
key1File := path.Join(rootDir, "key.json")
key2File := path.Join(rootDir, "key2.json")
if err := ioutil.WriteFile(genesisFile, []byte(genesisJSON), 0644); err != nil {
return err
err := ioutil.WriteFile(genesisFile, []byte(genesisJSON), 0644)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
if err := ioutil.WriteFile(privValFile, []byte(privValJSON), 0400); err != nil {
return err
err = ioutil.WriteFile(privValFile, []byte(privValJSON), 0400)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
if err := ioutil.WriteFile(key1File, []byte(key1JSON), 0400); err != nil {
return err
err = ioutil.WriteFile(key1File, []byte(key1JSON), 0400)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
if err := ioutil.WriteFile(key2File, []byte(key2JSON), 0400); err != nil {
return err
err = ioutil.WriteFile(key2File, []byte(key2JSON), 0400)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
log.Notice("Initialized Basecoin", "genesis", genesisFile, "key", key1File)
return nil
}
const privValJSON = `{

View File

@ -8,38 +8,38 @@ import (
"path"
"strings"
"github.com/urfave/cli"
"github.com/spf13/cobra"
cmn "github.com/tendermint/go-common"
"github.com/tendermint/go-crypto"
)
//commands
var (
KeyCmd = cli.Command{
Name: "key",
Usage: "Manage keys",
ArgsUsage: "",
Subcommands: []cli.Command{NewKeyCmd},
KeyCmd = &cobra.Command{
Use: "key",
Short: "Manage keys",
}
NewKeyCmd = cli.Command{
Name: "new",
Usage: "Create a new private key",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdNewKey(c)
},
NewKeyCmd = &cobra.Command{
Use: "new",
Short: "Create a new private key",
Run: newKeyCmd,
}
)
func cmdNewKey(c *cli.Context) error {
func newKeyCmd(cmd *cobra.Command, args []string) {
key := genKey()
keyJSON, err := json.MarshalIndent(key, "", "\t")
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
fmt.Println(string(keyJSON))
return nil
}
func init() {
//register commands
KeyCmd.AddCommand(NewKeyCmd)
}
//---------------------------------------------
@ -88,12 +88,14 @@ func LoadKey(keyFile string) *Key {
filePath := path.Join(BasecoinRoot(""), keyFile)
keyJSONBytes, err := ioutil.ReadFile(filePath)
if err != nil {
cmn.Exit(err.Error())
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
key := new(Key)
err = json.Unmarshal(keyJSONBytes, key)
if err != nil {
cmn.Exit(cmn.Fmt("Error reading key from %v: %v\n", filePath, err))
cmn.Exit(fmt.Sprintf("Error reading key from %v: %v\n", filePath, err))
}
return key
}

View File

@ -0,0 +1,41 @@
package commands
import (
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/types"
)
type plugin struct {
name string
newPlugin func() types.Plugin
}
var plugins = []plugin{}
// RegisterStartPlugin is used to enable a plugin
func RegisterStartPlugin(name string, newPlugin func() types.Plugin) {
plugins = append(plugins, plugin{name: name, newPlugin: newPlugin})
}
// Register a subcommand of QueryCmd for plugin specific query functionality
func RegisterQuerySubcommand(cmd *cobra.Command) {
QueryCmd.AddCommand(cmd)
}
// Register a subcommand of TxCmd to craft transactions for plugins
func RegisterTxSubcommand(cmd *cobra.Command) {
TxCmd.AddCommand(cmd)
}
//Returns a version command based on version input
func QuickVersionCmd(version string) *cobra.Command {
return &cobra.Command{
Use: "version",
Short: "Show version info",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version)
},
}
}

View File

@ -2,11 +2,10 @@ package commands
import (
"encoding/hex"
"errors"
"fmt"
"strconv"
"github.com/urfave/cli"
"github.com/spf13/cobra"
cmn "github.com/tendermint/go-common"
"github.com/tendermint/go-merkle"
@ -14,85 +13,85 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
)
//commands
var (
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,
},
QueryCmd = &cobra.Command{
Use: "query [key]",
Short: "Query the merkle tree",
Run: queryCmd,
}
AccountCmd = cli.Command{
Name: "account",
Usage: "Get details of an account",
ArgsUsage: "<address>",
Action: func(c *cli.Context) error {
return cmdAccount(c)
},
Flags: []cli.Flag{
NodeFlag,
},
AccountCmd = &cobra.Command{
Use: "account [address]",
Short: "Get details of an account",
Run: accountCmd,
}
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,
},
BlockCmd = &cobra.Command{
Use: "block [height]",
Short: "Get the header and commit of a block",
Run: blockCmd,
}
VerifyCmd = cli.Command{
Name: "verify",
Usage: "Verify the IAVL proof",
Action: func(c *cli.Context) error {
return cmdVerify(c)
},
Flags: []cli.Flag{
ProofFlag,
KeyFlag,
ValueFlag,
RootFlag,
},
VerifyCmd = &cobra.Command{
Use: "verify",
Short: "Verify the IAVL proof",
Run: verifyCmd,
}
)
// Register a subcommand of QueryCmd for plugin specific query functionality
func RegisterQuerySubcommand(cmd cli.Command) {
QueryCmd.Subcommands = append(QueryCmd.Subcommands, cmd)
//flags
var (
nodeFlag string
proofFlag string
keyFlag string
valueFlag string
rootFlag string
)
func init() {
commonFlags := []Flag2Register{
{&nodeFlag, "node", "tcp://localhost:46657", "Tendermint RPC address"},
}
verifyFlags := []Flag2Register{
{&proofFlag, "proof", "", "hex-encoded IAVL proof"},
{&keyFlag, "key", "", "key to the IAVL tree"},
{&valueFlag, "value", "", "value in the IAVL tree"},
{&rootFlag, "root", "", "root hash of the IAVL tree"},
}
RegisterFlags(QueryCmd, commonFlags)
RegisterFlags(AccountCmd, commonFlags)
RegisterFlags(BlockCmd, commonFlags)
RegisterFlags(VerifyCmd, verifyFlags)
}
func cmdQuery(c *cli.Context) error {
if len(c.Args()) != 1 {
return errors.New("query command requires an argument ([key])")
func queryCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmn.Exit("query command requires an argument ([key])")
}
keyString := c.Args()[0]
keyString := 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))
cmn.Exit(fmt.Sprintf("Query key (%v) is invalid hex: %+v\n", keyString, err))
}
}
resp, err := Query(c.String("node"), key)
resp, err := Query(nodeFlag, key)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("Query returns error: %+v\n", 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))
cmn.Exit(fmt.Sprintf("Query for key (%v) returned non-zero code (%v): %v", keyString, resp.Code, resp.Log))
}
val := resp.Value
@ -104,43 +103,44 @@ func cmdQuery(c *cli.Context) error {
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])")
func accountCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmn.Exit("account command requires an argument ([address])")
}
addrHex := StripHex(c.Args()[0])
addrHex := StripHex(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))
cmn.Exit(fmt.Sprintf("Account address (%v) is invalid hex: %+v\n", addrHex, err))
}
acc, err := getAcc(c.String("node"), addr)
acc, err := getAcc(nodeFlag, addr)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", 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))
func blockCmd(cmd *cobra.Command, args []string) {
if len(args) != 1 {
cmn.Exit("block command requires an argument ([height])")
}
header, commit, err := getHeaderAndCommit(c, height)
heightString := args[0]
height, err := strconv.Atoi(heightString)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("Height must be an int, got %v: %+v\n", heightString, err))
}
header, commit, err := getHeaderAndCommit(nodeFlag, height)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
fmt.Println(string(wire.JSONBytes(struct {
@ -156,8 +156,6 @@ func cmdBlock(c *cli.Context) error {
Commit: commit,
},
})))
return nil
}
type BlockHex struct {
@ -170,15 +168,16 @@ type BlockJSON struct {
Commit *tmtypes.Commit `json:"commit"`
}
func cmdVerify(c *cli.Context) error {
keyString, valueString := c.String("key"), c.String("value")
func verifyCmd(cmd *cobra.Command, args []string) {
keyString, valueString := keyFlag, valueFlag
var err error
key := []byte(keyString)
if isHex(keyString) {
key, err = hex.DecodeString(StripHex(keyString))
if err != nil {
return errors.New(cmn.Fmt("Key (%v) is invalid hex: %v", keyString, err))
cmn.Exit(fmt.Sprintf("Key (%v) is invalid hex: %+v\n", keyString, err))
}
}
@ -186,29 +185,25 @@ func cmdVerify(c *cli.Context) error {
if isHex(valueString) {
value, err = hex.DecodeString(StripHex(valueString))
if err != nil {
return errors.New(cmn.Fmt("Value (%v) is invalid hex: %v", valueString, err))
cmn.Exit(fmt.Sprintf("Value (%v) is invalid hex: %+v\n", valueString, err))
}
}
root, err := hex.DecodeString(StripHex(c.String("root")))
root, err := hex.DecodeString(StripHex(rootFlag))
if err != nil {
return errors.New(cmn.Fmt("Root (%v) is invalid hex: %v", c.String("root"), err))
cmn.Exit(fmt.Sprintf("Root (%v) is invalid hex: %+v\n", rootFlag, err))
}
proofBytes, err := hex.DecodeString(StripHex(c.String("proof")))
if err != nil {
return errors.New(cmn.Fmt("Proof (%v) is invalid hex: %v", c.String("proof"), err))
}
proofBytes, err := hex.DecodeString(StripHex(proofFlag))
proof, err := merkle.ReadProof(proofBytes)
if err != nil {
return errors.New(cmn.Fmt("Error unmarshalling proof: %v", err))
cmn.Exit(fmt.Sprintf("Error unmarshalling proof: %+v\n", err))
}
if proof.Verify(key, value, root) {
fmt.Println("OK")
} else {
return errors.New("Proof does not verify")
cmn.Exit(fmt.Sprintf("Proof does not verify"))
}
return nil
}

View File

@ -1,47 +1,24 @@
package commands
import (
"os"
"path"
"github.com/urfave/cli"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/cmd/tendermint/commands"
tmcfg "github.com/tendermint/tendermint/config/tendermint"
types "github.com/tendermint/tendermint/types"
)
var UnsafeResetAllCmd = cli.Command{
Name: "unsafe_reset_all",
Usage: "Reset all blockchain data",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdUnsafeResetAll(c)
},
var UnsafeResetAllCmd = &cobra.Command{
Use: "unsafe_reset_all",
Short: "Reset all blockchain data",
Run: unsafeResetAllCmd,
}
func cmdUnsafeResetAll(c *cli.Context) error {
func unsafeResetAllCmd(cmd *cobra.Command, args []string) {
basecoinDir := BasecoinRoot("")
tmDir := path.Join(basecoinDir)
tmConfig := tmcfg.GetConfig(tmDir)
// Get and Reset PrivValidator
var privValidator *types.PrivValidator
privValidatorFile := tmConfig.GetString("priv_validator_file")
if _, err := os.Stat(privValidatorFile); err == nil {
privValidator = types.LoadPrivValidator(privValidatorFile)
privValidator.Reset()
log.Notice("Reset PrivValidator", "file", privValidatorFile)
} else {
privValidator = types.GenPrivValidator()
privValidator.SetFile(privValidatorFile)
privValidator.Save()
log.Notice("Generated PrivValidator", "file", privValidatorFile)
}
// Remove all tendermint data
tmDataDir := tmConfig.GetString("db_dir")
os.RemoveAll(tmDataDir)
log.Notice("Removed all data", "dir", tmDataDir)
return nil
commands.ResetAll(tmConfig, log)
}

View File

@ -1,12 +1,11 @@
package commands
import (
"errors"
"fmt"
"os"
"path"
"github.com/urfave/cli"
"github.com/spf13/cobra"
"github.com/tendermint/abci/server"
cmn "github.com/tendermint/go-common"
@ -18,50 +17,51 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/types"
)
var StartCmd = &cobra.Command{
Use: "start",
Short: "Start basecoin",
Run: startCmd,
}
//flags
var (
addrFlag string
eyesFlag string
dirFlag string
withoutTendermintFlag bool
)
// TODO: move to config file
const EyesCacheSize = 10000
var StartCmd = cli.Command{
Name: "start",
Usage: "Start basecoin",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdStart(c)
},
Flags: []cli.Flag{
AddrFlag,
EyesFlag,
WithoutTendermintFlag,
ChainIDFlag,
},
func init() {
flags := []Flag2Register{
{&addrFlag, "address", "tcp://0.0.0.0:46658", "Listen address"},
{&eyesFlag, "eyes", "local", "MerkleEyes address, or 'local' for embedded"},
{&dirFlag, "dir", ".", "Root directory"},
{&withoutTendermintFlag, "without-tendermint", false, "Run Tendermint in-process with the App"},
}
RegisterFlags(StartCmd, flags)
// TODO: move to config file
// eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
}
type plugin struct {
name string
newPlugin func() types.Plugin
}
var plugins = []plugin{}
// RegisterStartPlugin is used to enable a plugin
func RegisterStartPlugin(name string, newPlugin func() types.Plugin) {
plugins = append(plugins, plugin{name: name, newPlugin: newPlugin})
}
func cmdStart(c *cli.Context) error {
func startCmd(cmd *cobra.Command, args []string) {
basecoinDir := BasecoinRoot("")
// Connect to MerkleEyes
var eyesCli *eyes.Client
if c.String("eyes") == "local" {
if eyesFlag == "local" {
eyesCli = eyes.NewLocalClient(path.Join(basecoinDir, "data", "merkleeyes.db"), EyesCacheSize)
} else {
var err error
eyesCli, err = eyes.NewClient(c.String("eyes"))
eyesCli, err = eyes.NewClient(eyesFlag)
if err != nil {
return errors.New("connect to MerkleEyes: " + err.Error())
cmn.Exit(fmt.Sprintf("Error connecting to MerkleEyes: %+v\n", err))
}
}
@ -84,7 +84,7 @@ func cmdStart(c *cli.Context) error {
if _, err := os.Stat(genesisFile); err == nil {
err := basecoinApp.LoadGenesis(genesisFile)
if err != nil {
return errors.New(cmn.Fmt("%+v", err))
cmn.Exit(fmt.Sprintf("Error in LoadGenesis: %+v\n", err))
}
} else {
fmt.Printf("No genesis file at %s, skipping...\n", genesisFile)
@ -92,40 +92,37 @@ func cmdStart(c *cli.Context) error {
}
chainID := basecoinApp.GetState().GetChainID()
if c.Bool("without-tendermint") {
if withoutTendermintFlag {
log.Notice("Starting Basecoin without Tendermint", "chain_id", chainID)
// run just the abci app/server
return startBasecoinABCI(c, basecoinApp)
startBasecoinABCI(basecoinApp)
} else {
log.Notice("Starting Basecoin with Tendermint", "chain_id", chainID)
// start the app with tendermint in-process
return startTendermint(basecoinDir, basecoinApp)
startTendermint(basecoinDir, basecoinApp)
}
return nil
}
func startBasecoinABCI(c *cli.Context, basecoinApp *app.Basecoin) error {
func startBasecoinABCI(basecoinApp *app.Basecoin) {
// Start the ABCI listener
svr, err := server.NewServer(c.String("address"), "socket", basecoinApp)
svr, err := server.NewServer(addrFlag, "socket", basecoinApp)
if err != nil {
return errors.New("create listener: " + err.Error())
cmn.Exit(fmt.Sprintf("Error creating listener: %+v\n", err))
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
svr.Stop()
})
return nil
}
func startTendermint(dir string, basecoinApp *app.Basecoin) error {
func startTendermint(dir string, basecoinApp *app.Basecoin) {
// Get configuration
tmConfig := tmcfg.GetConfig(dir)
// logger.SetLogLevel("notice") //config.GetString("log_level"))
// parseFlags(config, args[1:]) // Command line overrides
// Create & start tendermint node
@ -135,7 +132,7 @@ func startTendermint(dir string, basecoinApp *app.Basecoin) error {
_, err := n.Start()
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
// Wait forever
@ -143,6 +140,4 @@ func startTendermint(dir string, basecoinApp *app.Basecoin) error {
// Cleanup
n.Stop()
})
return nil
}

View File

@ -2,10 +2,10 @@ package commands
import (
"encoding/hex"
"errors"
"fmt"
"github.com/urfave/cli"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/types"
crypto "github.com/tendermint/go-crypto"
@ -16,211 +16,215 @@ import (
ctypes "github.com/tendermint/tendermint/rpc/core/types"
)
var TxFlags = []cli.Flag{
NodeFlag,
ChainIDFlag,
FromFlag,
AmountFlag,
GasFlag,
FeeFlag,
SeqFlag,
}
//commands
var (
TxCmd = cli.Command{
Name: "tx",
Usage: "Create, sign, and broadcast a transaction",
ArgsUsage: "",
Subcommands: []cli.Command{
SendTxCmd,
AppTxCmd,
IbcTxCmd,
},
TxCmd = &cobra.Command{
Use: "tx",
Short: "Create, sign, and broadcast a transaction",
}
SendTxCmd = cli.Command{
Name: "send",
Usage: "a SendTx transaction, for sending tokens around",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdSendTx(c)
},
Flags: append(TxFlags, ToFlag),
SendTxCmd = &cobra.Command{
Use: "send",
Short: "A SendTx transaction, for sending tokens around",
Run: sendTxCmd,
}
AppTxCmd = cli.Command{
Name: "app",
Usage: "an AppTx transaction, for sending raw data to plugins",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdAppTx(c)
},
Flags: append(TxFlags, NameFlag, DataFlag),
// Subcommands are dynamically registered with plugins as needed
Subcommands: []cli.Command{},
AppTxCmd = &cobra.Command{
Use: "app",
Short: "An AppTx transaction, for sending raw data to plugins",
Run: appTxCmd,
}
)
// Register a subcommand of TxCmd to craft transactions for plugins
func RegisterTxSubcommand(cmd cli.Command) {
TxCmd.Subcommands = append(TxCmd.Subcommands, cmd)
//flags
var (
txNodeFlag string
toFlag string
amountFlag string
fromFlag string
seqFlag int
gasFlag int
feeFlag string
dataFlag string
nameFlag string
chainIDFlag string
)
func init() {
// register flags
cmdTxFlags := []Flag2Register{
{&txNodeFlag, "node", "tcp://localhost:46657", "Tendermint RPC address"},
{&chainIDFlag, "chain_id", "test_chain_id", "ID of the chain for replay protection"},
{&fromFlag, "from", "key.json", "Path to a private key to sign the transaction"},
{&amountFlag, "amount", "", "Coins to send in transaction of the format <amt><coin>,<amt2><coin2>,... (eg: 1btc,2gold,5silver},"},
{&gasFlag, "gas", 0, "The amount of gas for the transaction"},
{&feeFlag, "fee", "", "Coins for the transaction fee of the format <amt><coin>"},
{&seqFlag, "sequence", -1, "Sequence number for the account (-1 to autocalculate},"},
}
sendTxFlags := []Flag2Register{
{&toFlag, "to", "", "Destination address for the transaction"},
}
appTxFlags := []Flag2Register{
{&nameFlag, "name", "", "Plugin to send the transaction to"},
{&dataFlag, "data", "", "Data to send with the transaction"},
}
RegisterPersistentFlags(TxCmd, cmdTxFlags)
RegisterFlags(SendTxCmd, sendTxFlags)
RegisterFlags(AppTxCmd, appTxFlags)
//register commands
TxCmd.AddCommand(SendTxCmd, AppTxCmd)
}
func cmdSendTx(c *cli.Context) error {
toHex := c.String("to")
fromFile := c.String("from")
amount := c.String("amount")
gas := int64(c.Int("gas"))
fee := c.String("fee")
chainID := c.String("chain_id")
func sendTxCmd(cmd *cobra.Command, args []string) {
// convert destination address to bytes
to, err := hex.DecodeString(StripHex(toHex))
to, err := hex.DecodeString(StripHex(toFlag))
if err != nil {
return errors.New("To address is invalid hex: " + err.Error())
cmn.Exit(fmt.Sprintf("To address is invalid hex: %+v\n", err))
}
// load the priv key
privKey := LoadKey(fromFile)
privKey := LoadKey(fromFlag)
// get the sequence number for the tx
sequence, err := getSeq(c, privKey.Address[:])
sequence, err := getSeq(privKey.Address[:])
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
//parse the fee and amounts into coin types
feeCoin, err := types.ParseCoin(fee)
feeCoin, err := types.ParseCoin(feeFlag)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
amountCoins, err := types.ParseCoins(amount)
amountCoins, err := types.ParseCoins(amountFlag)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
// craft the tx
input := types.NewTxInput(privKey.PubKey, amountCoins, sequence)
output := newOutput(to, amountCoins)
tx := &types.SendTx{
Gas: gas,
Gas: int64(gasFlag),
Fee: feeCoin,
Inputs: []types.TxInput{input},
Outputs: []types.TxOutput{output},
}
// sign that puppy
signBytes := tx.SignBytes(chainID)
signBytes := tx.SignBytes(chainIDFlag)
tx.Inputs[0].Signature = crypto.SignatureS{privKey.Sign(signBytes)}
fmt.Println("Signed SendTx:")
fmt.Println(string(wire.JSONBytes(tx)))
// broadcast the transaction to tendermint
data, log, err := broadcastTx(c, tx)
data, log, err := broadcastTx(tx)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
fmt.Printf("Response: %X ; %s\n", data, log)
return nil
}
func cmdAppTx(c *cli.Context) error {
func appTxCmd(cmd *cobra.Command, args []string) {
// convert data to bytes
dataString := c.String("data")
data := []byte(dataString)
if isHex(dataString) {
data, _ = hex.DecodeString(dataString)
data := []byte(dataFlag)
if isHex(dataFlag) {
data, _ = hex.DecodeString(dataFlag)
}
name := c.String("name")
return AppTx(c, name, data)
name := nameFlag
AppTx(name, data)
}
func AppTx(c *cli.Context, name string, data []byte) error {
fromFile := c.String("from")
amount := c.String("amount")
fee := c.String("fee")
gas := int64(c.Int("gas"))
chainID := c.String("chain_id")
func AppTx(name string, data []byte) {
privKey := LoadKey(fromFile)
privKey := LoadKey(fromFlag)
sequence, err := getSeq(c, privKey.Address[:])
sequence, err := getSeq(privKey.Address[:])
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
//parse the fee and amounts into coin types
feeCoin, err := types.ParseCoin(fee)
feeCoin, err := types.ParseCoin(feeFlag)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
amountCoins, err := types.ParseCoins(amount)
amountCoins, err := types.ParseCoins(amountFlag)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
input := types.NewTxInput(privKey.PubKey, amountCoins, sequence)
tx := &types.AppTx{
Gas: gas,
Gas: int64(gasFlag),
Fee: feeCoin,
Name: name,
Input: input,
Data: data,
}
tx.Input.Signature = crypto.SignatureS{privKey.Sign(tx.SignBytes(chainID))}
tx.Input.Signature = crypto.SignatureS{privKey.Sign(tx.SignBytes(chainIDFlag))}
fmt.Println("Signed AppTx:")
fmt.Println(string(wire.JSONBytes(tx)))
data, log, err := broadcastTx(c, tx)
data, log, err := broadcastTx(tx)
if err != nil {
return err
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
fmt.Printf("Response: %X ; %s\n", data, log)
return nil
}
// broadcast the transaction to tendermint
func broadcastTx(c *cli.Context, tx types.Tx) ([]byte, string, error) {
func broadcastTx(tx types.Tx) ([]byte, string, error) {
tmResult := new(ctypes.TMResult)
tmAddr := c.String("node")
uriClient := client.NewURIClient(tmAddr)
uriClient := client.NewURIClient(txNodeFlag)
// Don't you hate having to do this?
// How many times have I lost an hour over this trick?!
txBytes := []byte(wire.BinaryBytes(struct {
types.Tx `json:"unwrap"`
}{tx}))
_, err := uriClient.Call("broadcast_tx_commit", map[string]interface{}{"tx": txBytes}, tmResult)
if err != nil {
return nil, "", errors.New(cmn.Fmt("Error on broadcast tx: %v", err))
}
res := (*tmResult).(*ctypes.ResultBroadcastTxCommit)
// if it fails check, we don't even get a delivertx back!
if !res.CheckTx.Code.IsOK() {
r := res.CheckTx
return nil, "", errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log))
}
if !res.DeliverTx.Code.IsOK() {
r := res.DeliverTx
return nil, "", errors.New(cmn.Fmt("BroadcastTxCommit got non-zero exit code: %v. %X; %s", r.Code, r.Data, r.Log))
}
return res.DeliverTx.Data, res.DeliverTx.Log, nil
}
// if the sequence flag is set, return it;
// else, fetch the account by querying the app and return the sequence number
func getSeq(c *cli.Context, address []byte) (int, error) {
if c.IsSet("sequence") {
return c.Int("sequence"), nil
func getSeq(address []byte) (int, error) {
if seqFlag >= 0 {
return seqFlag, nil
}
tmAddr := c.String("node")
acc, err := getAcc(tmAddr, address)
acc, err := getAcc(txNodeFlag, address)
if err != nil {
return 0, err
}
@ -232,5 +236,4 @@ func newOutput(to []byte, amount types.Coins) types.TxOutput {
Address: to,
Coins: amount,
}
}

View File

@ -2,16 +2,17 @@ package commands
import (
"encoding/hex"
"errors"
"fmt"
"os"
"github.com/urfave/cli"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
"github.com/tendermint/basecoin/state"
"github.com/tendermint/basecoin/types"
abci "github.com/tendermint/abci/types"
cmn "github.com/tendermint/go-common"
client "github.com/tendermint/go-rpc/client"
wire "github.com/tendermint/go-wire"
ctypes "github.com/tendermint/tendermint/rpc/core/types"
@ -28,6 +29,60 @@ func BasecoinRoot(rootDir string) string {
return rootDir
}
type Flag2Register struct {
Pointer interface{}
Use string
Value interface{}
Desc string
}
//register flag utils
func RegisterFlags(c *cobra.Command, flags []Flag2Register) {
registerFlags(c, flags, false)
}
func RegisterPersistentFlags(c *cobra.Command, flags []Flag2Register) {
registerFlags(c, flags, true)
}
func registerFlags(c *cobra.Command, flags []Flag2Register, persistent bool) {
var flagset *pflag.FlagSet
if persistent {
flagset = c.PersistentFlags()
} else {
flagset = c.Flags()
}
for _, f := range flags {
ok := false
switch f.Value.(type) {
case string:
if _, ok = f.Pointer.(*string); ok {
flagset.StringVar(f.Pointer.(*string), f.Use, f.Value.(string), f.Desc)
}
case int:
if _, ok = f.Pointer.(*int); ok {
flagset.IntVar(f.Pointer.(*int), f.Use, f.Value.(int), f.Desc)
}
case uint64:
if _, ok = f.Pointer.(*uint64); ok {
flagset.Uint64Var(f.Pointer.(*uint64), f.Use, f.Value.(uint64), f.Desc)
}
case bool:
if _, ok = f.Pointer.(*bool); ok {
flagset.BoolVar(f.Pointer.(*bool), f.Use, f.Value.(bool), f.Desc)
}
}
if !ok {
panic("improper use of RegisterFlags")
}
}
}
// Returns true for non-empty hex-string prefixed with "0x"
func isHex(s string) bool {
if len(s) > 2 && s[:2] == "0x" {
@ -58,11 +113,11 @@ func Query(tmAddr string, key []byte) (*abci.ResponseQuery, error) {
}
_, err := uriClient.Call("abci_query", params, tmResult)
if err != nil {
return nil, errors.New(cmn.Fmt("Error calling /abci_query: %v", err))
return nil, errors.New(fmt.Sprintf("Error calling /abci_query: %v", err))
}
res := (*tmResult).(*ctypes.ResultABCIQuery)
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))
return nil, errors.New(fmt.Sprintf("Query got non-zero exit code: %v. %s", res.Response.Code, res.Response.Log))
}
return &res.Response, nil
}
@ -79,28 +134,27 @@ func getAcc(tmAddr string, address []byte) (*types.Account, error) {
accountBytes := response.Value
if len(accountBytes) == 0 {
return nil, errors.New(cmn.Fmt("Account bytes are empty for address: %X ", address))
return nil, errors.New(fmt.Sprintf("Account bytes are empty for address: %X ", address))
}
var acc *types.Account
err = wire.ReadBinaryBytes(accountBytes, &acc)
if err != nil {
return nil, errors.New(cmn.Fmt("Error reading account %X error: %v",
return nil, errors.New(fmt.Sprintf("Error reading account %X error: %v",
accountBytes, err.Error()))
}
return acc, nil
}
func getHeaderAndCommit(c *cli.Context, height int) (*tmtypes.Header, *tmtypes.Commit, error) {
func getHeaderAndCommit(tmAddr string, height int) (*tmtypes.Header, *tmtypes.Commit, error) {
tmResult := new(ctypes.TMResult)
tmAddr := c.String("node")
uriClient := client.NewURIClient(tmAddr)
method := "commit"
_, err := uriClient.Call(method, map[string]interface{}{"height": height}, tmResult)
if err != nil {
return nil, nil, errors.New(cmn.Fmt("Error on %s: %v", method, err))
return nil, nil, errors.New(fmt.Sprintf("Error on %s: %v", method, err))
}
resCommit := (*tmResult).(*ctypes.ResultCommit)
header := resCommit.Header

17
cmd/commands/version.go Normal file
View File

@ -0,0 +1,17 @@
package commands
import (
"fmt"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/version"
)
var VersionCmd = &cobra.Command{
Use: "version",
Short: "Show version info",
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(version.Version)
},
}

View File

@ -3,46 +3,47 @@ package main
import (
"fmt"
"github.com/spf13/cobra"
wire "github.com/tendermint/go-wire"
"github.com/urfave/cli"
"github.com/tendermint/basecoin/cmd/commands"
"github.com/tendermint/basecoin/plugins/counter"
"github.com/tendermint/basecoin/types"
cmn "github.com/tendermint/go-common"
)
//commands
var CounterTxCmd = &cobra.Command{
Use: "counter",
Short: "Create, sign, and broadcast a transaction to the counter plugin",
Run: counterTxCmd,
}
//flags
var (
validFlag bool
countFeeFlag string
)
func init() {
CounterTxCmd.Flags().BoolVar(&validFlag, "valid", false, "Set valid field in CounterTx")
CounterTxCmd.Flags().StringVar(&countFeeFlag, "countfee", "", "Coins for the counter fee of the format <amt><coin>")
commands.RegisterTxSubcommand(CounterTxCmd)
commands.RegisterStartPlugin("counter", func() types.Plugin { return counter.New() })
}
var (
ValidFlag = cli.BoolFlag{
Name: "valid",
Usage: "Set valid field in CounterTx",
}
func counterTxCmd(cmd *cobra.Command, args []string) {
CounterTxCmd = cli.Command{
Name: "counter",
Usage: "Create, sign, and broadcast a transaction to the counter plugin",
Action: func(c *cli.Context) error {
return cmdCounterTx(c)
},
Flags: append(commands.TxFlags, ValidFlag),
countFee, err := commands.ParseCoins(countFeeFlag)
if err != nil {
cmn.Exit(fmt.Sprintf("%+v\n", err))
}
)
func cmdCounterTx(c *cli.Context) error {
valid := c.Bool("valid")
counterTx := counter.CounterTx{
Valid: valid,
Fee: types.Coins{
{
Denom: c.String("coin"),
Amount: int64(c.Int("fee")),
},
},
Valid: validFlag,
Fee: countFee,
}
fmt.Println("CounterTx:", string(wire.JSONBytes(counterTx)))
@ -50,5 +51,5 @@ func cmdCounterTx(c *cli.Context) error {
data := wire.BinaryBytes(counterTx)
name := "counter"
return commands.AppTx(c, name, data)
commands.AppTx(name, data)
}

View File

@ -1,23 +1,34 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/cmd/commands"
"github.com/urfave/cli"
)
func main() {
app := cli.NewApp()
app.Name = "counter"
app.Usage = "counter [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
var RootCmd = &cobra.Command{
Use: "counter",
Short: "demo plugin for basecoin",
}
RootCmd.AddCommand(
commands.StartCmd,
commands.TxCmd,
commands.KeyCmd,
commands.QueryCmd,
commands.KeyCmd,
commands.VerifyCmd,
commands.BlockCmd,
commands.AccountCmd,
commands.QuickVersionCmd("0.1.0"),
)
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
app.Run(os.Args)
}

View File

@ -103,14 +103,14 @@ sleep 3
echo "... registering chain1 on chain2"
echo ""
# register chain1 on chain2
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --chain_id $CHAIN_ID1 --genesis ./data/chain1/genesis.json
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 register --ibc_chain_id $CHAIN_ID1 --genesis ./data/chain1/genesis.json
echo ""
echo "... creating egress packet on chain1"
echo ""
# create a packet on chain1 destined for chain2
PAYLOAD="DEADBEEF" #TODO
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload $PAYLOAD --sequence 1
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS1 packet create --ibc_from $CHAIN_ID1 --to $CHAIN_ID2 --type coin --payload $PAYLOAD --ibc_sequence 1
echo ""
echo "... querying for packet data"
@ -162,7 +162,7 @@ echo ""
echo "... posting packet from chain1 on chain2"
echo ""
# post the packet from chain1 to chain2
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF
basecoin tx ibc --amount 10mycoin $CHAIN_FLAGS2 packet post --ibc_from $CHAIN_ID1 --height $HEIGHT --packet 0x$PACKET --proof 0x$PROOF
echo ""
echo "... checking if the packet is present on chain2"

View File

@ -25,18 +25,30 @@ The `main.go` is very simple and does not need to be changed:
```golang
func main() {
app := cli.NewApp()
app.Name = "example-plugin"
app.Usage = "example-plugin [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
//Initialize example-plugin root command
var RootCmd = &cobra.Command{
Use: "example-plugin",
Short: "example-plugin usage description",
}
//Add the default basecoin commands to the root command
RootCmd.AddCommand(
commands.InitCmd,
commands.StartCmd,
commands.TxCmd,
commands.KeyCmd,
commands.QueryCmd,
commands.KeyCmd,
commands.VerifyCmd,
commands.BlockCmd,
commands.AccountCmd,
commands.UnsafeResetAllCmd,
)
//Run the root command
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
app.Run(os.Args)
}
```
@ -49,19 +61,40 @@ This is where the `cmd.go` comes in.
### cmd.go
First, we register the plugin:
First we define the new command and associated flag variables
```golang
var (
//CLI Flags
validFlag bool
//CLI Plugin Commands
ExamplePluginTxCmd = &cobra.Command{
Use: "example",
Short: "Create, sign, and broadcast a transaction to the example plugin",
Run: examplePluginTxCmd,
}
)
```
Next we register the plugin:
```golang
func init() {
//Set the Plugin Flags
ExamplePluginTxCmd.Flags().BoolVar(&validFlag, "valid", false, "Set this to make transaction valid")
//Register a plugin specific CLI command as a subcommand of the tx command
commands.RegisterTxSubcommand(ExamplePluginTxCmd)
//Register the example with basecoin at start
commands.RegisterStartPlugin("example-plugin", func() types.Plugin { return NewExamplePlugin() })
}
```
This creates a new subcommand under `tx` (defined below),
and ensures the plugin is activated when we start the app.
Now we actually define the new command:
```golang
var (

View File

@ -1,16 +1,32 @@
package main
import (
"github.com/spf13/cobra"
wire "github.com/tendermint/go-wire"
"github.com/urfave/cli"
"github.com/tendermint/basecoin/cmd/commands"
"github.com/tendermint/basecoin/types"
)
var (
//CLI Flags
validFlag bool
//CLI Plugin Commands
ExamplePluginTxCmd = &cobra.Command{
Use: "example",
Short: "Create, sign, and broadcast a transaction to the example plugin",
Run: examplePluginTxCmd,
}
)
//Called during CLI initialization
func init() {
//Set the Plugin Flags
ExamplePluginTxCmd.Flags().BoolVar(&validFlag, "valid", false, "Set this to make transaction valid")
//Register a plugin specific CLI command as a subcommand of the tx command
commands.RegisterTxSubcommand(ExamplePluginTxCmd)
@ -18,32 +34,12 @@ func init() {
commands.RegisterStartPlugin("example-plugin", func() types.Plugin { return NewExamplePlugin() })
}
var (
//CLI Flags
ExampleFlag = cli.BoolFlag{
Name: "valid",
Usage: "Set this to make the transaction valid",
}
//CLI Plugin Commands
ExamplePluginTxCmd = cli.Command{
Name: "example",
Usage: "Create, sign, and broadcast a transaction to the example plugin",
Action: func(c *cli.Context) error {
return cmdExamplePluginTx(c)
},
Flags: append(commands.TxFlags, ExampleFlag),
}
)
//Send a transaction
func cmdExamplePluginTx(c *cli.Context) error {
//Retrieve any flag results
exampleFlag := c.Bool("valid")
func examplePluginTxCmd(cmd *cobra.Command, args []string) {
// Create a transaction using the flag.
// The tx passes on custom information to the plugin
exampleTx := ExamplePluginTx{exampleFlag}
exampleTx := ExamplePluginTx{validFlag}
// The tx is passed to the plugin in the form of
// a byte array. This is achieved by serializing the object using go-wire.
@ -62,5 +58,5 @@ func cmdExamplePluginTx(c *cli.Context) error {
// - Once deserialized, the tx is passed to `state.ExecTx` (state/execution.go)
// - If the tx passes various checks, the `tx.Data` is forwarded as `txBytes` to `plugin.RunTx` (docs/guide/src/example-plugin/plugin.go)
// - Finally, it deserialized back to the ExamplePluginTx
return commands.AppTx(c, "example-plugin", exampleTxBytes)
commands.AppTx("example-plugin", exampleTxBytes)
}

View File

@ -1,24 +1,38 @@
package main
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/basecoin/cmd/commands"
"github.com/urfave/cli"
)
func main() {
//Initialize an instance of basecoin with default basecoin commands
app := cli.NewApp()
app.Name = "example-plugin"
app.Usage = "example-plugin [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
//Initialize example-plugin root command
var RootCmd = &cobra.Command{
Use: "example-plugin",
Short: "example-plugin usage description",
}
//Add the default basecoin commands to the root command
RootCmd.AddCommand(
commands.InitCmd,
commands.StartCmd,
commands.TxCmd,
commands.KeyCmd,
commands.QueryCmd,
commands.KeyCmd,
commands.VerifyCmd,
commands.BlockCmd,
commands.AccountCmd,
commands.UnsafeResetAllCmd,
)
//Run the root command
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
}
app.Run(os.Args)
}

27
glide.lock generated
View File

@ -1,5 +1,5 @@
hash: c023dbd97e1ea0a525e33738f03afd6be61f997f1c2592a5d9928fdcecc71361
updated: 2017-04-21T17:38:13.194966906+02:00
hash: 57732245af8acdb6bc7f20b36e2e0329b60570797ac47353edee108129b1b600
updated: 2017-04-13T18:07:44.07521907-04:00
imports:
- name: github.com/btcsuite/btcd
version: 583684b21bfbde9b5fc4403916fd7c807feb0289
@ -19,6 +19,8 @@ imports:
version: 553a641470496b2327abcac10b36396bd98e45c9
- name: github.com/gorilla/websocket
version: 3ab3a8b8831546bd18fd182c20687ca853b2bb13
- name: github.com/inconshreveable/mousetrap
version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
- name: github.com/jmhodges/levigo
version: c42d9e0ca023e2198120196f842701bb4c55d7b9
- name: github.com/mattn/go-colorable
@ -26,7 +28,11 @@ imports:
- name: github.com/mattn/go-isatty
version: 57fdcb988a5c543893cc61bce354a6e24ab70022
- name: github.com/pkg/errors
version: bfd5150e4e41705ded2129ec33379de1cb90b513
version: 645ef00459ed84a119197bfb8d8205042c6df63d
- name: github.com/spf13/cobra
version: fcd0c5a1df88f5d6784cb4feead962c3f3d0b66c
- name: github.com/spf13/pflag
version: 9ff6c6923cfffbcd502984b8e0c80539a94968b7
- name: github.com/syndtr/goleveldb
version: 3c5717caf1475fd25964109a0fc640bd150fce43
subpackages:
@ -43,7 +49,7 @@ imports:
- leveldb/table
- leveldb/util
- name: github.com/tendermint/abci
version: 56e13d87f4e3ec1ea756957d6b23caa6ebcf0998
version: af792eac777de757cd496349a5f6b5313738fcbc
subpackages:
- client
- example/dummy
@ -59,11 +65,11 @@ imports:
- name: github.com/tendermint/go-clist
version: 3baa390bbaf7634251c42ad69a8682e7e3990552
- name: github.com/tendermint/go-common
version: f9e3db037330c8a8d61d3966de8473eaf01154fa
version: dcb015dff6c7af21e65c8e2f3b450df19d38c777
- name: github.com/tendermint/go-config
version: 620dcbbd7d587cf3599dedbf329b64311b0c307a
- name: github.com/tendermint/go-crypto
version: 0ca2c6fdb0706001ca4c4b9b80c9f428e8cf39da
version: 3f47cfac5fcd9e0f1727c7db980b3559913b3e3a
- name: github.com/tendermint/go-data
version: e7fcc6d081ec8518912fcdc103188275f83a3ee5
- name: github.com/tendermint/go-db
@ -83,13 +89,13 @@ imports:
subpackages:
- upnp
- name: github.com/tendermint/go-rpc
version: 9d18cbe74e66f875afa36d2fa3be280e4a2dc9e6
version: fcea0cda21f64889be00a0f4b6d13266b1a76ee7
subpackages:
- client
- server
- types
- name: github.com/tendermint/go-wire
version: c1c9a57ab8038448ddea1714c0698f8051e5748c
version: f530b7af7a8b06e612c2063bff6ace49060a085e
- name: github.com/tendermint/log15
version: ae0f3d6450da9eac7074b439c8e1c3cabf0d5ce6
subpackages:
@ -100,9 +106,10 @@ imports:
- app
- client
- name: github.com/tendermint/tendermint
version: 7cf773e2d37b2b5a08bc94fb125cfd346b834824
version: 022a5509181a19f78995a3dd9bba470333fe2d63
subpackages:
- blockchain
- cmd/tendermint/commands
- config/tendermint
- consensus
- mempool
@ -117,8 +124,6 @@ imports:
- state/txindex/null
- types
- version
- name: github.com/urfave/cli
version: 0bdeddeeb0f650497d603c4ad7b20cfe685682f6
- name: golang.org/x/crypto
version: 728b753d0135da6801d45a38e6f43ff55779c5c2
subpackages:

View File

@ -1,22 +1,24 @@
package: github.com/tendermint/basecoin
import:
- package: github.com/tendermint/go-common
version: develop
version: master
- package: github.com/tendermint/go-crypto
version: develop
version: master
- package: github.com/tendermint/go-events
version: develop
version: master
- package: github.com/tendermint/go-logger
version: develop
version: master
- package: github.com/tendermint/go-data
version: master
- package: github.com/tendermint/go-rpc
version: develop
version: master
- package: github.com/tendermint/go-wire
version: develop
version: master
- package: github.com/tendermint/merkleeyes
version: develop
version: master
- package: github.com/tendermint/tendermint
version: develop
version: cli_change
- package: github.com/tendermint/abci
version: develop
version: master
- package: github.com/gorilla/websocket
version: v1.1.0