cmd: counter tx

This commit is contained in:
Ethan Buchman 2017-01-29 15:32:38 -08:00
parent 1fea9501d1
commit f811502826
8 changed files with 275 additions and 238 deletions

View File

@ -1,6 +1,7 @@
package app
import (
"fmt"
"strings"
abci "github.com/tendermint/abci/types"
@ -102,6 +103,8 @@ func (app *Basecoin) CheckTx(txBytes []byte) (res abci.Result) {
return abci.ErrBaseEncodingError.AppendLog("Tx size exceeds maximum")
}
fmt.Printf("%X\n", txBytes)
// Decode tx
var tx types.Tx
err := wire.ReadBinaryBytes(txBytes, &tx)

98
cmd/basecoin/cmd.go Normal file
View File

@ -0,0 +1,98 @@
package main
import (
"github.com/urfave/cli"
)
var (
startCmd = cli.Command{
Name: "start",
Usage: "Start basecoin",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdStart(c)
},
Flags: []cli.Flag{
addrFlag,
eyesFlag,
eyesDBFlag,
genesisFlag,
inProcTMFlag,
chainIDFlag,
pluginFlag,
},
}
sendTxCmd = cli.Command{
Name: "sendtx",
Usage: "Broadcast a basecoin SendTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdSendTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
chainIDFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
seqFlag,
toFlag,
},
}
appTxCmd = cli.Command{
Name: "apptx",
Usage: "Broadcast a basecoin AppTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdAppTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
chainIDFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
seqFlag,
nameFlag,
dataFlag,
},
Subcommands: []cli.Command{
counterTxCmd,
},
}
counterTxCmd = cli.Command{
Name: "counter",
Usage: "Craft a transaction to the counter plugin",
Action: func(c *cli.Context) error {
return cmdCounterTx(c)
},
Flags: []cli.Flag{
validFlag,
},
}
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{
tmAddrFlag,
},
}
)

121
cmd/basecoin/flags.go Normal file
View File

@ -0,0 +1,121 @@
package main
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",
}
eyesDBFlag = cli.StringFlag{
Name: "eyes-db",
Value: "merkleeyes.db",
Usage: "MerkleEyes db name for embedded",
}
// TODO: move to config file
// eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
genesisFlag = cli.StringFlag{
Name: "genesis",
Value: "",
Usage: "Path to genesis file, if it exists",
}
inProcTMFlag = cli.BoolFlag{
Name: "in-proc",
Usage: "Run Tendermint in-process with the App",
}
pluginFlag = cli.StringFlag{
Name: "plugin",
Value: "counter", // load the counter by default
Usage: "Plugin to enable",
}
)
// tx flags
var (
tmAddrFlag = cli.StringFlag{
Name: "tendermint",
Value: "tcp://localhost:46657",
Usage: "Tendermint RPC address",
}
toFlag = cli.StringFlag{
Name: "to",
Value: "",
Usage: "Destination address for the transaction",
}
amountFlag = cli.IntFlag{
Name: "amount",
Value: 0,
Usage: "Amount of coins to send in the transaction",
}
fromFlag = cli.StringFlag{
Name: "from",
Value: "priv_validator.json",
Usage: "Path to a private key to sign the transaction",
}
seqFlag = cli.IntFlag{
Name: "sequence",
Value: 0,
Usage: "Sequence number for the account",
}
coinFlag = cli.StringFlag{
Name: "coin",
Value: "blank",
Usage: "Specify a coin denomination",
}
gasFlag = cli.IntFlag{
Name: "gas",
Value: 0,
Usage: "The amount of gas for the transaction",
}
feeFlag = cli.IntFlag{
Name: "fee",
Value: 0,
Usage: "The transaction fee",
}
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",
}
validFlag = cli.BoolFlag{
Name: "valid",
Usage: "Set valid field in CounterTx",
}
)

View File

@ -6,185 +6,16 @@ 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",
}
eyesDBFlag = cli.StringFlag{
Name: "eyes-db",
Value: "merkleeyes.db",
Usage: "MerkleEyes db name for embedded",
}
// TODO: move to config file
// eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
genesisFlag = cli.StringFlag{
Name: "genesis",
Value: "",
Usage: "Path to genesis file, if it exists",
}
inProcTMFlag = cli.BoolFlag{
Name: "in-proc",
Usage: "Run Tendermint in-process with the App",
}
)
// tx flags
var (
tmAddrFlag = cli.StringFlag{
Name: "tendermint",
Value: "tcp://localhost:46657",
Usage: "Tendermint RPC address",
}
toFlag = cli.StringFlag{
Name: "to",
Value: "",
Usage: "Destination address for the transaction",
}
amountFlag = cli.IntFlag{
Name: "amount",
Value: 0,
Usage: "Amount of coins to send in the transaction",
}
fromFlag = cli.StringFlag{
Name: "from",
Value: "priv_validator.json",
Usage: "Path to a private key to sign the transaction",
}
seqFlag = cli.IntFlag{
Name: "sequence",
Value: 0,
Usage: "Sequence number for the account",
}
coinFlag = cli.StringFlag{
Name: "coin",
Value: "blank",
Usage: "Specify a coin denomination",
}
gasFlag = cli.IntFlag{
Name: "gas",
Value: 0,
Usage: "The amount of gas for the transaction",
}
feeFlag = cli.IntFlag{
Name: "fee",
Value: 0,
Usage: "The transaction fee",
}
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",
}
)
func main() {
app := cli.NewApp()
app.Name = "basecoin"
app.Usage = "basecoin [command] [args...]"
app.Version = "0.1.0"
app.Commands = []cli.Command{
{
Name: "start",
Usage: "Start basecoin",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdStart(c)
},
Flags: []cli.Flag{
addrFlag,
eyesFlag,
eyesDBFlag,
genesisFlag,
inProcTMFlag,
chainIDFlag,
},
},
{
Name: "sendtx",
Usage: "Broadcast a basecoin SendTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdSendTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
toFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
chainIDFlag,
seqFlag,
},
},
{
Name: "apptx",
Usage: "Broadcast a basecoin AppTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdAppTx(c)
},
Flags: []cli.Flag{
tmAddrFlag,
nameFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
dataFlag,
seqFlag,
},
},
{
Name: "account",
Usage: "Get details of an account",
ArgsUsage: "[address]",
Action: func(c *cli.Context) error {
return cmdAccount(c)
},
Flags: []cli.Flag{
tmAddrFlag,
},
},
startCmd,
sendTxCmd,
appTxCmd,
accountCmd,
}
app.Run(os.Args)
}

View File

@ -17,6 +17,7 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/plugins/counter"
)
var config cfg.Config
@ -40,6 +41,15 @@ func cmdStart(c *cli.Context) error {
// Create Basecoin app
basecoinApp := app.NewBasecoin(eyesCli)
switch c.String("plugin") {
case "counter":
basecoinApp.RegisterPlugin(counter.New("counter"))
case "":
// no plugins to register
default:
return errors.New(cmn.Fmt("Unknown plugin: %v", c.String("plugin")))
}
// If genesis file was specified, set key-value options
if c.String("genesis") != "" {
err := basecoinApp.LoadGenesis(c.String("genesis"))

View File

@ -7,7 +7,9 @@ import (
"github.com/urfave/cli"
"github.com/tendermint/basecoin/plugins/counter"
"github.com/tendermint/basecoin/types"
cmn "github.com/tendermint/go-common"
client "github.com/tendermint/go-rpc/client"
"github.com/tendermint/go-wire"
@ -60,24 +62,26 @@ func cmdSendTx(c *cli.Context) error {
if err := broadcastTx(c, tx); err != nil {
return err
}
return nil
}
func cmdAppTx(c *cli.Context) error {
// convert data to bytes
dataString := c.String("data")
data := []byte(dataString)
if isHex(dataString) {
data, _ = hex.DecodeString(dataString)
}
name := c.String("name")
return appTx(c, name, data)
}
func appTx(c *cli.Context, name string, data []byte) error {
fromFile := c.String("from")
amount := int64(c.Int("amount"))
coin := c.String("coin")
gas, fee := c.Int("gas"), int64(c.Int("fee"))
chainID := c.String("chain_id")
dataString := c.String("data")
// convert data to bytes
data := []byte(dataString)
if isHex(dataString) {
data, _ = hex.DecodeString(dataString)
}
privVal := tmtypes.LoadPrivValidator(fromFile)
@ -107,16 +111,39 @@ func cmdAppTx(c *cli.Context) error {
return nil
}
func cmdCounterTx(c *cli.Context) error {
valid := c.Bool("valid")
parent := c.Parent()
counterTx := counter.CounterTx{
Valid: valid,
Fee: types.Coins{
{
Denom: parent.String("coin"),
Amount: int64(parent.Int("fee")),
},
},
}
fmt.Println("CounterTx:", string(wire.JSONBytes(counterTx)))
data := wire.BinaryBytes(counterTx)
name := "counter"
return appTx(parent, name, data)
}
// broadcast the transaction to tendermint
func broadcastTx(c *cli.Context, tx types.Tx) error {
tmResult := new(ctypes.TMResult)
tmAddr := c.String("tendermint")
clientURI := client.NewClientURI(tmAddr)
/*txBytes := []byte(wire.JSONBytes(struct {
// 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}))*/
txBytes := wire.BinaryBytes(tx)
}{tx}))
_, err := clientURI.Call("broadcast_tx_sync", map[string]interface{}{"tx": txBytes}, tmResult)
if err != nil {
return errors.New(cmn.Fmt("Error on broadcast tx: %v", err))

View File

@ -1,53 +0,0 @@
package main
import (
"flag"
"github.com/tendermint/abci/server"
"github.com/tendermint/basecoin/app"
"github.com/tendermint/basecoin/plugins/counter"
cmn "github.com/tendermint/go-common"
eyes "github.com/tendermint/merkleeyes/client"
)
func main() {
addrPtr := flag.String("address", "tcp://0.0.0.0:46658", "Listen address")
eyesPtr := flag.String("eyes", "local", "MerkleEyes address, or 'local' for embedded")
genFilePath := flag.String("genesis", "", "Genesis file, if any")
flag.Parse()
// Connect to MerkleEyes
eyesCli, err := eyes.NewClient(*eyesPtr)
if err != nil {
cmn.Exit("connect to MerkleEyes: " + err.Error())
}
// Create Basecoin app
app := app.NewBasecoin(eyesCli)
// add plugins
// TODO: add some more, like the cool voting app
counter := counter.New("counter")
app.RegisterPlugin(counter)
// If genesis file was specified, set key-value options
if *genFilePath != "" {
err := app.LoadGenesis(*genFilePath)
if err != nil {
cmn.Exit(cmn.Fmt("%+v", err))
}
}
// Start the listener
svr, err := server.NewServer(*addrPtr, "socket", app)
if err != nil {
cmn.Exit("create listener: " + err.Error())
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
svr.Stop()
})
}

View File

@ -47,7 +47,7 @@ func (cp *CounterPlugin) RunTx(store types.KVStore, ctx types.CallContext, txByt
var tx CounterTx
err := wire.ReadBinaryBytes(txBytes, &tx)
if err != nil {
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error())
return abci.ErrBaseEncodingError.AppendLog("Error decoding tx: " + err.Error()).PrependLog("CounterTx Error: ")
}
// Validate tx