2017-01-30 06:16:51 -08:00
|
|
|
package commands
|
2017-01-29 13:34:48 -08:00
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2017-03-08 23:19:07 -08:00
|
|
|
"fmt"
|
2017-01-29 13:34:48 -08:00
|
|
|
|
2017-03-08 23:19:07 -08:00
|
|
|
"github.com/pkg/errors"
|
|
|
|
"github.com/spf13/cobra"
|
|
|
|
"github.com/spf13/pflag"
|
2017-01-29 18:41:37 -08:00
|
|
|
|
2017-04-27 17:09:12 -07:00
|
|
|
abci "github.com/tendermint/abci/types"
|
|
|
|
wire "github.com/tendermint/go-wire"
|
|
|
|
|
2017-02-09 18:48:42 -08:00
|
|
|
"github.com/tendermint/basecoin/state"
|
2017-01-29 13:34:48 -08:00
|
|
|
"github.com/tendermint/basecoin/types"
|
|
|
|
|
2017-05-13 17:37:37 -07:00
|
|
|
client "github.com/tendermint/tendermint/rpc/client"
|
2017-01-29 18:41:37 -08:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
2017-01-29 13:34:48 -08:00
|
|
|
)
|
|
|
|
|
2017-04-17 18:28:03 -07:00
|
|
|
//Quickly registering flags can be quickly achieved through using the utility functions
|
|
|
|
//RegisterFlags, and RegisterPersistentFlags. Ex:
|
|
|
|
// flags := []Flag2Register{
|
|
|
|
// {&myStringFlag, "mystringflag", "foobar", "description of what this flag does"},
|
|
|
|
// {&myBoolFlag, "myboolflag", false, "description of what this flag does"},
|
|
|
|
// {&myInt64Flag, "myintflag", 333, "description of what this flag does"},
|
|
|
|
// }
|
|
|
|
// RegisterFlags(MyCobraCmd, flags)
|
2017-03-08 23:19:07 -08:00
|
|
|
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")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-29 13:34:48 -08:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2017-01-30 08:16:00 -08:00
|
|
|
func StripHex(s string) string {
|
2017-01-29 13:34:48 -08:00
|
|
|
if isHex(s) {
|
|
|
|
return s[2:]
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2017-05-12 11:29:13 -07:00
|
|
|
func Query(tmAddr string, key []byte) (*abci.ResultQuery, error) {
|
|
|
|
httpClient := client.NewHTTP(tmAddr, "/websocket")
|
|
|
|
res, err := httpClient.ABCIQuery("/key", key, true)
|
2017-01-29 13:34:48 -08:00
|
|
|
if err != nil {
|
2017-04-15 09:07:27 -07:00
|
|
|
return nil, errors.Errorf("Error calling /abci_query: %v", err)
|
2017-01-29 13:34:48 -08:00
|
|
|
}
|
2017-05-12 11:29:13 -07:00
|
|
|
if !res.Code.IsOK() {
|
|
|
|
return nil, errors.Errorf("Query got non-zero exit code: %v. %s", res.Code, res.Log)
|
2017-01-29 13:34:48 -08:00
|
|
|
}
|
2017-05-12 11:29:13 -07:00
|
|
|
return res.ResultQuery, nil
|
2017-01-29 18:41:37 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
// fetch the account by querying the app
|
|
|
|
func getAcc(tmAddr string, address []byte) (*types.Account, error) {
|
|
|
|
|
2017-02-09 18:48:42 -08:00
|
|
|
key := state.AccountKey(address)
|
2017-01-31 06:33:34 -08:00
|
|
|
response, err := Query(tmAddr, key)
|
2017-01-29 18:41:37 -08:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
accountBytes := response.Value
|
2017-01-29 13:34:48 -08:00
|
|
|
|
|
|
|
if len(accountBytes) == 0 {
|
2017-04-15 09:07:27 -07:00
|
|
|
return nil, fmt.Errorf("Account bytes are empty for address: %X ", address) //never stack trace
|
2017-01-29 13:34:48 -08:00
|
|
|
}
|
2017-01-29 18:41:37 -08:00
|
|
|
|
2017-01-29 13:34:48 -08:00
|
|
|
var acc *types.Account
|
|
|
|
err = wire.ReadBinaryBytes(accountBytes, &acc)
|
|
|
|
if err != nil {
|
2017-04-15 09:07:27 -07:00
|
|
|
return nil, errors.Errorf("Error reading account %X error: %v",
|
|
|
|
accountBytes, err.Error())
|
2017-01-29 13:34:48 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return acc, nil
|
|
|
|
}
|
2017-01-29 18:41:37 -08:00
|
|
|
|
2017-03-08 23:19:07 -08:00
|
|
|
func getHeaderAndCommit(tmAddr string, height int) (*tmtypes.Header, *tmtypes.Commit, error) {
|
2017-05-12 11:29:13 -07:00
|
|
|
httpClient := client.NewHTTP(tmAddr, "/websocket")
|
|
|
|
res, err := httpClient.Commit(height)
|
2017-01-29 18:41:37 -08:00
|
|
|
if err != nil {
|
2017-05-12 11:29:13 -07:00
|
|
|
return nil, nil, errors.Errorf("Error on commit: %v", err)
|
2017-01-29 18:41:37 -08:00
|
|
|
}
|
2017-05-12 11:29:13 -07:00
|
|
|
header := res.Header
|
|
|
|
commit := res.Commit
|
2017-02-13 20:22:31 -08:00
|
|
|
|
|
|
|
return header, commit, nil
|
2017-01-29 18:41:37 -08:00
|
|
|
}
|