cli: refactor ibc and counter into own binaries
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/basecoin/plugins/counter"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
wire "github.com/tendermint/go-wire"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
var (
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
CounterPluginFlag = cli.BoolFlag{
|
||||
Name: "counter-plugin",
|
||||
Usage: "Enable the counter plugin",
|
||||
}
|
||||
)
|
||||
|
||||
func init() {
|
||||
RegisterTxPlugin(CounterTxCmd)
|
||||
RegisterStartPlugin(CounterPluginFlag,
|
||||
func() types.Plugin { return counter.New("counter") })
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
@@ -1,216 +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")
|
||||
|
||||
DirFlag = cli.StringFlag{
|
||||
Name: "dir",
|
||||
Value: ".",
|
||||
Usage: "Root directory",
|
||||
}
|
||||
|
||||
InProcTMFlag = cli.BoolFlag{
|
||||
Name: "in-proc",
|
||||
Usage: "Run Tendermint in-process with the App",
|
||||
}
|
||||
|
||||
IbcPluginFlag = cli.BoolFlag{
|
||||
Name: "ibc-plugin",
|
||||
Usage: "Enable the ibc plugin",
|
||||
}
|
||||
)
|
||||
|
||||
// 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.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",
|
||||
}
|
||||
)
|
||||
|
||||
// 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: "",
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
)
|
||||
|
||||
// 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: "",
|
||||
}
|
||||
)
|
||||
@@ -1,251 +0,0 @@
|
||||
package commands
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
var (
|
||||
IbcCmd = cli.Command{
|
||||
Name: "ibc",
|
||||
Usage: "Send a transaction to the interblockchain (ibc) plugin",
|
||||
Flags: []cli.Flag{
|
||||
NodeFlag,
|
||||
ChainIDFlag,
|
||||
|
||||
FromFlag,
|
||||
|
||||
AmountFlag,
|
||||
CoinFlag,
|
||||
GasFlag,
|
||||
FeeFlag,
|
||||
SeqFlag,
|
||||
|
||||
NameFlag,
|
||||
DataFlag,
|
||||
},
|
||||
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,
|
||||
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,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
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 := []byte(wire.BinaryBytes(struct {
|
||||
ibc.IBCTx `json:"unwrap"`
|
||||
}{ibcTx}))
|
||||
name := "IBC"
|
||||
|
||||
return AppTx(parent, name, data)
|
||||
}
|
||||
|
||||
func cmdIBCUpdateTx(c *cli.Context) error {
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
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 := []byte(wire.BinaryBytes(struct {
|
||||
ibc.IBCTx `json:"unwrap"`
|
||||
}{ibcTx}))
|
||||
name := "IBC"
|
||||
|
||||
return AppTx(c.Parent(), name, data)
|
||||
}
|
||||
|
||||
func cmdIBCPacketCreateTx(c *cli.Context) error {
|
||||
fromChain, toChain := c.String("from"), c.String("to")
|
||||
packetType := c.String("type")
|
||||
|
||||
payloadBytes, err := hex.DecodeString(StripHex(c.String("payload")))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Payload (%v) is invalid hex: %v", c.String("payload"), err))
|
||||
}
|
||||
|
||||
sequence, err := getIBCSequence(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ibcTx := ibc.IBCPacketCreateTx{
|
||||
Packet: ibc.Packet{
|
||||
SrcChainID: fromChain,
|
||||
DstChainID: toChain,
|
||||
Sequence: sequence,
|
||||
Type: packetType,
|
||||
Payload: payloadBytes,
|
||||
},
|
||||
}
|
||||
|
||||
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
|
||||
|
||||
data := []byte(wire.BinaryBytes(struct {
|
||||
ibc.IBCTx `json:"unwrap"`
|
||||
}{ibcTx}))
|
||||
|
||||
return AppTx(c.Parent().Parent(), "IBC", data)
|
||||
}
|
||||
|
||||
func cmdIBCPacketPostTx(c *cli.Context) error {
|
||||
fromChain, fromHeight := c.String("from"), c.Int("height")
|
||||
|
||||
packetBytes, err := hex.DecodeString(StripHex(c.String("packet")))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Packet (%v) is invalid hex: %v", c.String("packet"), 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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
if err := wire.ReadBinaryBytes(proofBytes, &proof); err != nil {
|
||||
return errors.New(cmn.Fmt("Error unmarshalling proof: %v", err))
|
||||
}
|
||||
|
||||
ibcTx := ibc.IBCPacketPostTx{
|
||||
FromChainID: fromChain,
|
||||
FromChainHeight: uint64(fromHeight),
|
||||
Packet: packet,
|
||||
Proof: proof,
|
||||
}
|
||||
|
||||
fmt.Println("IBCTx:", string(wire.JSONBytes(ibcTx)))
|
||||
|
||||
data := []byte(wire.BinaryBytes(struct {
|
||||
ibc.IBCTx `json:"unwrap"`
|
||||
}{ibcTx}))
|
||||
|
||||
return AppTx(c.Parent().Parent(), "IBC", data)
|
||||
}
|
||||
|
||||
func getIBCSequence(c *cli.Context) (uint64, error) {
|
||||
if c.IsSet("sequence") {
|
||||
return uint64(c.Int("sequence")), nil
|
||||
}
|
||||
|
||||
// TODO: get sequence
|
||||
return 0, nil
|
||||
}
|
||||
@@ -1,213 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
cmn "github.com/tendermint/go-common"
|
||||
"github.com/tendermint/go-merkle"
|
||||
"github.com/tendermint/go-wire"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
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,
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
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(nextBlock.Header),
|
||||
Commit: wire.BinaryBytes(nextBlock.LastCommit),
|
||||
},
|
||||
BlockJSON{
|
||||
Header: nextBlock.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"`
|
||||
}
|
||||
|
||||
func cmdVerify(c *cli.Context) error {
|
||||
keyString, valueString := c.String("key"), c.String("value")
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
value := []byte(valueString)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
root, err := hex.DecodeString(StripHex(c.String("root")))
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Root (%v) is invalid hex: %v", c.String("root"), 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))
|
||||
}
|
||||
|
||||
proof, err := merkle.ReadProof(proofBytes)
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("Error unmarshalling proof: %v", err))
|
||||
}
|
||||
|
||||
if proof.Verify(key, value, root) {
|
||||
fmt.Println("OK")
|
||||
} else {
|
||||
return errors.New("Proof does not verify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tendermint/abci/server"
|
||||
cmn "github.com/tendermint/go-common"
|
||||
cfg "github.com/tendermint/go-config"
|
||||
//logger "github.com/tendermint/go-logger"
|
||||
eyes "github.com/tendermint/merkleeyes/client"
|
||||
|
||||
tmcfg "github.com/tendermint/tendermint/config/tendermint"
|
||||
"github.com/tendermint/tendermint/node"
|
||||
"github.com/tendermint/tendermint/proxy"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/tendermint/basecoin/app"
|
||||
"github.com/tendermint/basecoin/plugins/ibc"
|
||||
"github.com/tendermint/basecoin/types"
|
||||
)
|
||||
|
||||
var config cfg.Config
|
||||
|
||||
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,
|
||||
DirFlag,
|
||||
InProcTMFlag,
|
||||
ChainIDFlag,
|
||||
IbcPluginFlag,
|
||||
},
|
||||
}
|
||||
|
||||
type plugin struct {
|
||||
name string
|
||||
init func() types.Plugin
|
||||
}
|
||||
|
||||
var plugins = []plugin{}
|
||||
|
||||
// RegisterStartPlugin is used to add another
|
||||
func RegisterStartPlugin(flag cli.BoolFlag, init func() types.Plugin) {
|
||||
StartCmd.Flags = append(StartCmd.Flags, flag)
|
||||
plugins = append(plugins, plugin{name: flag.GetName(), init: init})
|
||||
}
|
||||
|
||||
func cmdStart(c *cli.Context) error {
|
||||
|
||||
// Connect to MerkleEyes
|
||||
var eyesCli *eyes.Client
|
||||
if c.String("eyes") == "local" {
|
||||
eyesCli = eyes.NewLocalClient(path.Join(c.String("dir"), "merkleeyes.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
|
||||
basecoinApp := app.NewBasecoin(eyesCli)
|
||||
if c.Bool("ibc-plugin") {
|
||||
basecoinApp.RegisterPlugin(ibc.New())
|
||||
}
|
||||
|
||||
// loop through all registered plugins and enable if desired
|
||||
for _, p := range plugins {
|
||||
if c.Bool(p.name) {
|
||||
basecoinApp.RegisterPlugin(p.init())
|
||||
}
|
||||
}
|
||||
|
||||
// If genesis file exists, set key-value options
|
||||
genesisFile := path.Join(c.String("dir"), "genesis.json")
|
||||
if _, err := os.Stat(genesisFile); err == nil {
|
||||
err := basecoinApp.LoadGenesis(genesisFile)
|
||||
if err != nil {
|
||||
return errors.New(cmn.Fmt("%+v", err))
|
||||
}
|
||||
}
|
||||
|
||||
if c.Bool("in-proc") {
|
||||
startTendermint(c, basecoinApp)
|
||||
} else {
|
||||
startBasecoinABCI(c, basecoinApp)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func startBasecoinABCI(c *cli.Context, basecoinApp *app.Basecoin) error {
|
||||
// Start the ABCI listener
|
||||
svr, err := server.NewServer(c.String("address"), "socket", basecoinApp)
|
||||
if err != nil {
|
||||
return errors.New("create listener: " + err.Error())
|
||||
}
|
||||
// Wait forever
|
||||
cmn.TrapSignal(func() {
|
||||
// Cleanup
|
||||
svr.Stop()
|
||||
})
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func startTendermint(c *cli.Context, basecoinApp *app.Basecoin) {
|
||||
// Get configuration
|
||||
config = tmcfg.GetConfig("")
|
||||
// logger.SetLogLevel("notice") //config.GetString("log_level"))
|
||||
|
||||
// parseFlags(config, args[1:]) // Command line overrides
|
||||
|
||||
// Create & start tendermint node
|
||||
privValidatorFile := config.GetString("priv_validator_file")
|
||||
privValidator := tmtypes.LoadOrGenPrivValidator(privValidatorFile)
|
||||
n := node.NewNode(config, privValidator, proxy.NewLocalClientCreator(basecoinApp))
|
||||
|
||||
n.Start()
|
||||
|
||||
// Wait forever
|
||||
cmn.TrapSignal(func() {
|
||||
// Cleanup
|
||||
n.Stop()
|
||||
})
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
|
||||
"github.com/tendermint/basecoin/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"
|
||||
)
|
||||
|
||||
var (
|
||||
SendTxCmd = cli.Command{
|
||||
Name: "sendtx",
|
||||
Usage: "Broadcast a basecoin SendTx",
|
||||
ArgsUsage: "",
|
||||
Action: func(c *cli.Context) error {
|
||||
return cmdSendTx(c)
|
||||
},
|
||||
Flags: []cli.Flag{
|
||||
NodeFlag,
|
||||
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{
|
||||
NodeFlag,
|
||||
ChainIDFlag,
|
||||
|
||||
FromFlag,
|
||||
|
||||
AmountFlag,
|
||||
CoinFlag,
|
||||
GasFlag,
|
||||
FeeFlag,
|
||||
SeqFlag,
|
||||
|
||||
NameFlag,
|
||||
DataFlag,
|
||||
},
|
||||
// Subcommands are dynamically registered with plugins as needed
|
||||
Subcommands: []cli.Command{},
|
||||
}
|
||||
)
|
||||
|
||||
// RegisterTxPlugin is used to add another subcommand and create a custom
|
||||
// apptx encoding. Look at counter.go for an example
|
||||
func RegisterTxPlugin(cmd cli.Command) {
|
||||
AppTxCmd.Subcommands = append(AppTxCmd.Subcommands, cmd)
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
// convert destination address to bytes
|
||||
to, err := hex.DecodeString(StripHex(toHex))
|
||||
if err != nil {
|
||||
return errors.New("To address is invalid hex: " + err.Error())
|
||||
}
|
||||
|
||||
// load the priv validator
|
||||
// XXX: this is overkill for now, we need a keys solution
|
||||
privVal := tmtypes.LoadPrivValidator(fromFile)
|
||||
|
||||
// get the sequence number for the tx
|
||||
sequence, err := getSeq(c, privVal.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// craft the tx
|
||||
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},
|
||||
}
|
||||
|
||||
// sign that puppy
|
||||
signBytes := tx.SignBytes(chainID)
|
||||
tx.Inputs[0].Signature = privVal.Sign(signBytes)
|
||||
|
||||
fmt.Println("Signed SendTx:")
|
||||
fmt.Println(string(wire.JSONBytes(tx)))
|
||||
|
||||
// broadcast the transaction to tendermint
|
||||
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")
|
||||
|
||||
privVal := tmtypes.LoadPrivValidator(fromFile)
|
||||
|
||||
sequence, err := getSeq(c, privVal.Address)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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("Signed AppTx:")
|
||||
fmt.Println(string(wire.JSONBytes(tx)))
|
||||
|
||||
res, err := broadcastTx(c, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Response: %X\n", res)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// broadcast the transaction to tendermint
|
||||
func broadcastTx(c *cli.Context, tx types.Tx) ([]byte, error) {
|
||||
tmResult := new(ctypes.TMResult)
|
||||
tmAddr := c.String("node")
|
||||
clientURI := client.NewClientURI(tmAddr)
|
||||
|
||||
// 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 := clientURI.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, 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
|
||||
}
|
||||
tmAddr := c.String("node")
|
||||
acc, err := getAcc(tmAddr, address)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return acc.Sequence + 1, nil
|
||||
}
|
||||
|
||||
func newOutput(to []byte, coin string, amount int64) types.TxOutput {
|
||||
return types.TxOutput{
|
||||
Address: to,
|
||||
Coins: types.Coins{
|
||||
types.Coin{
|
||||
Denom: coin,
|
||||
Amount: amount,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,94 +0,0 @@
|
||||
package commands
|
||||
|
||||
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"
|
||||
func isHex(s string) bool {
|
||||
if len(s) > 2 && s[:2] == "0x" {
|
||||
_, err := hex.DecodeString(s[2:])
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func StripHex(s string) string {
|
||||
if isHex(s) {
|
||||
return s[2:]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func Query(tmAddr string, key []byte) (*abci.ResponseQuery, error) {
|
||||
clientURI := client.NewClientURI(tmAddr)
|
||||
tmResult := new(ctypes.TMResult)
|
||||
|
||||
params := map[string]interface{}{
|
||||
"path": "/key",
|
||||
"data": key,
|
||||
"prove": true,
|
||||
}
|
||||
_, err := clientURI.Call("abci_query", params, tmResult)
|
||||
if err != nil {
|
||||
return nil, errors.New(cmn.Fmt("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 &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 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",
|
||||
accountBytes, err.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
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/tendermint/basecoin/cmd/basecoin/commands"
|
||||
"github.com/tendermint/basecoin/cmd/commands"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@@ -14,12 +14,10 @@ func main() {
|
||||
app.Version = "0.1.0"
|
||||
app.Commands = []cli.Command{
|
||||
commands.StartCmd,
|
||||
commands.SendTxCmd,
|
||||
commands.AppTxCmd,
|
||||
commands.IbcCmd,
|
||||
commands.TxCmd,
|
||||
commands.QueryCmd,
|
||||
commands.VerifyCmd,
|
||||
commands.BlockCmd,
|
||||
commands.VerifyCmd, // TODO: move to merkleeyes?
|
||||
commands.BlockCmd, // TODO: move to adam?
|
||||
commands.AccountCmd,
|
||||
}
|
||||
app.Run(os.Args)
|
||||
|
||||
Reference in New Issue
Block a user