This commit is contained in:
Ethan Buchman 2017-01-28 21:12:58 -05:00
parent 0b583ec97b
commit 665b39e330
3 changed files with 305 additions and 45 deletions

View File

@ -1,55 +1,160 @@
package main
import (
"flag"
"os"
"github.com/tendermint/abci/server"
"github.com/tendermint/basecoin/app"
cmn "github.com/tendermint/go-common"
eyes "github.com/tendermint/merkleeyes/client"
"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 (
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",
}
)
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")
eyesDBNamePtr := flag.String("eyes-db-name", "local.db", "MerkleEyes db name, for embedded")
eyesCacheSizePtr := flag.Int("eyes-cache-size", 10000, "MerkleEyes db cache size, for embedded")
genFilePath := flag.String("genesis", "", "Genesis file, if any")
flag.Parse()
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,
},
},
// Connect to MerkleEyes
var eyesCli *eyes.Client
if *eyesPtr == "local" {
eyesCli = eyes.NewLocalClient(*eyesDBNamePtr, *eyesCacheSizePtr)
} else {
var err error
eyesCli, err = eyes.NewClient(*eyesPtr)
if err != nil {
cmn.Exit("connect to MerkleEyes: " + err.Error())
}
{
Name: "sendtx",
Usage: "Broadcast a basecoin SendTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdSendTx(c)
},
Flags: []cli.Flag{
toFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
},
},
{
Name: "apptx",
Usage: "Broadcast a basecoin AppTx",
ArgsUsage: "",
Action: func(c *cli.Context) error {
return cmdAppTx(c)
},
Flags: []cli.Flag{
nameFlag,
fromFlag,
amountFlag,
coinFlag,
gasFlag,
feeFlag,
dataFlag,
},
},
}
// Create Basecoin app
app := app.NewBasecoin(eyesCli)
// 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()
})
app.Run(os.Args)
}

54
cmd/basecoin/start.go Normal file
View File

@ -0,0 +1,54 @@
package main
import (
"errors"
"github.com/urfave/cli"
"github.com/tendermint/abci/server"
"github.com/tendermint/basecoin/app"
cmn "github.com/tendermint/go-common"
eyes "github.com/tendermint/merkleeyes/client"
)
const EyesCacheSize = 10000
func cmdStart(c *cli.Context) error {
// Connect to MerkleEyes
var eyesCli *eyes.Client
if c.String("eyes") == "local" {
eyesCli = eyes.NewLocalClient(c.String("eyes-db"), EyesCacheSize)
} else {
var err error
eyesCli, err = eyes.NewClient(c.String("eyes"))
if err != nil {
return errors.New("connect to MerkleEyes: " + err.Error())
}
}
// Create Basecoin app
app := app.NewBasecoin(eyesCli)
// If genesis file was specified, set key-value options
if c.String("genesis") != "" {
err := app.LoadGenesis(c.String("genesis"))
if err != nil {
return errors.New(cmn.Fmt("%+v", err))
}
}
// Start the listener
svr, err := server.NewServer(c.String("address"), "socket", app)
if err != nil {
return errors.New("create listener: " + err.Error())
}
// Wait forever
cmn.TrapSignal(func() {
// Cleanup
svr.Stop()
})
return nil
}

101
cmd/basecoin/tx.go Normal file
View File

@ -0,0 +1,101 @@
package main
import (
"encoding/hex"
"errors"
"fmt"
"github.com/urfave/cli"
"github.com/tendermint/basecoin/types"
cmn "github.com/tendermint/go-common"
"github.com/tendermint/go-wire"
tmtypes "github.com/tendermint/tendermint/types"
)
func cmdSendTx(c *cli.Context) error {
toHex := c.String("to")
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")
to, err := hex.DecodeString(toHex)
if err != nil {
return errors.New("To address is invalid hex: " + err.Error())
}
privVal := tmtypes.LoadPrivValidator(fromFile)
sequence := getSeq(c)
input := types.NewTxInput(privVal.PubKey, types.Coins{types.Coin{coin, amount}}, sequence)
output := newOutput(to, coin, amount)
tx := types.SendTx{
Gas: int64(gas),
Fee: types.Coin{coin, fee},
Inputs: []types.TxInput{input},
Outputs: []types.TxOutput{output},
}
tx.Inputs[0].Signature = privVal.Sign(tx.SignBytes(chainID))
fmt.Println(string(wire.JSONBytes(tx)))
return nil
}
func cmdAppTx(c *cli.Context) error {
name := c.String("name")
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")
data := []byte(dataString)
if cmn.IsHex(dataString) {
data, _ = hex.DecodeString(dataString)
}
privVal := tmtypes.LoadPrivValidator(fromFile)
sequence := getSeq(c)
input := types.NewTxInput(privVal.PubKey, types.Coins{types.Coin{coin, amount}}, sequence)
tx := types.AppTx{
Gas: int64(gas),
Fee: types.Coin{coin, fee},
Name: name,
Input: input,
Data: data,
}
tx.Input.Signature = privVal.Sign(tx.SignBytes(chainID))
fmt.Println(string(wire.JSONBytes(tx)))
return nil
}
func getSeq(c *cli.Context) int {
if c.IsSet("sequence") {
return c.Int("sequence")
}
// TODO: get from query
return 0
}
func newOutput(to []byte, coin string, amount int64) types.TxOutput {
return types.TxOutput{
Address: to,
Coins: types.Coins{
types.Coin{
Denom: coin,
Amount: amount,
},
},
}
}