Add roles wrapper/tx/query command to basecoin
This commit is contained in:
parent
737e3740dd
commit
911dd1423e
10
app/app.go
10
app/app.go
|
@ -16,6 +16,7 @@ import (
|
||||||
"github.com/tendermint/basecoin/modules/coin"
|
"github.com/tendermint/basecoin/modules/coin"
|
||||||
"github.com/tendermint/basecoin/modules/fee"
|
"github.com/tendermint/basecoin/modules/fee"
|
||||||
"github.com/tendermint/basecoin/modules/nonce"
|
"github.com/tendermint/basecoin/modules/nonce"
|
||||||
|
"github.com/tendermint/basecoin/modules/roles"
|
||||||
"github.com/tendermint/basecoin/stack"
|
"github.com/tendermint/basecoin/stack"
|
||||||
sm "github.com/tendermint/basecoin/state"
|
sm "github.com/tendermint/basecoin/state"
|
||||||
"github.com/tendermint/basecoin/version"
|
"github.com/tendermint/basecoin/version"
|
||||||
|
@ -56,14 +57,19 @@ func NewBasecoin(handler basecoin.Handler, eyesCli *eyes.Client, logger log.Logg
|
||||||
// DefaultHandler - placeholder to just handle sendtx
|
// DefaultHandler - placeholder to just handle sendtx
|
||||||
func DefaultHandler(feeDenom string) basecoin.Handler {
|
func DefaultHandler(feeDenom string) basecoin.Handler {
|
||||||
// use the default stack
|
// use the default stack
|
||||||
h := coin.NewHandler()
|
c := coin.NewHandler()
|
||||||
d := stack.NewDispatcher(stack.WrapHandler(h))
|
r := roles.NewHandler()
|
||||||
|
d := stack.NewDispatcher(
|
||||||
|
stack.WrapHandler(c),
|
||||||
|
stack.WrapHandler(r),
|
||||||
|
)
|
||||||
return stack.New(
|
return stack.New(
|
||||||
base.Logger{},
|
base.Logger{},
|
||||||
stack.Recovery{},
|
stack.Recovery{},
|
||||||
auth.Signatures{},
|
auth.Signatures{},
|
||||||
base.Chain{},
|
base.Chain{},
|
||||||
nonce.ReplayCheck{},
|
nonce.ReplayCheck{},
|
||||||
|
roles.NewMiddleware(),
|
||||||
fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank),
|
fee.NewSimpleFeeMiddleware(coin.Coin{feeDenom, 0}, fee.Bank),
|
||||||
).Use(d)
|
).Use(d)
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,11 +83,11 @@ func GetCertifier() (*certifiers.InquiringCertifier, error) {
|
||||||
return cert, nil
|
return cert, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseAddress parses an address of form:
|
// ParseActor parses an address of form:
|
||||||
// [<chain>:][<app>:]<hex address>
|
// [<chain>:][<app>:]<hex address>
|
||||||
// into a basecoin.Actor.
|
// into a basecoin.Actor.
|
||||||
// If app is not specified or "", then assume auth.NameSigs
|
// If app is not specified or "", then assume auth.NameSigs
|
||||||
func ParseAddress(input string) (res basecoin.Actor, err error) {
|
func ParseActor(input string) (res basecoin.Actor, err error) {
|
||||||
chain, app := "", auth.NameSigs
|
chain, app := "", auth.NameSigs
|
||||||
input = strings.TrimSpace(input)
|
input = strings.TrimSpace(input)
|
||||||
spl := strings.SplitN(input, ":", 3)
|
spl := strings.SplitN(input, ":", 3)
|
||||||
|
@ -114,3 +114,17 @@ func ParseAddress(input string) (res basecoin.Actor, err error) {
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ParseActors takes a comma-separated list of actors and parses them into
|
||||||
|
// a slice
|
||||||
|
func ParseActors(key string) (signers []basecoin.Actor, err error) {
|
||||||
|
var act basecoin.Actor
|
||||||
|
for _, k := range strings.Split(key, ",") {
|
||||||
|
act, err = ParseActor(k)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
signers = append(signers, act)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -52,6 +52,37 @@ func GetSignerAct() (res basecoin.Actor) {
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DoTx is a helper function for the lazy :)
|
||||||
|
//
|
||||||
|
// It uses only public functions and goes through the standard sequence of
|
||||||
|
// wrapping the tx with middleware layers, signing it, either preparing it,
|
||||||
|
// or posting it and displaying the result.
|
||||||
|
//
|
||||||
|
// If you want a non-standard flow, just call the various functions directly.
|
||||||
|
// eg. if you already set the middleware layers in your code, or want to
|
||||||
|
// output in another format.
|
||||||
|
func DoTx(tx basecoin.Tx) (err error) {
|
||||||
|
tx, err = Middleware.Wrap(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = SignTx(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bres, err := PrepareOrPostTx(tx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if bres == nil {
|
||||||
|
return nil // successful prep, nothing left to do
|
||||||
|
}
|
||||||
|
return OutputTx(bres) // print response of the post
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// SignTx will validate the tx, and signs it if it is wrapping a Signable.
|
// SignTx will validate the tx, and signs it if it is wrapping a Signable.
|
||||||
// Modifies tx in place, and returns an error if it should sign but couldn't
|
// Modifies tx in place, and returns an error if it should sign but couldn't
|
||||||
func SignTx(tx basecoin.Tx) error {
|
func SignTx(tx basecoin.Tx) error {
|
||||||
|
|
|
@ -22,6 +22,7 @@ import (
|
||||||
coincmd "github.com/tendermint/basecoin/modules/coin/commands"
|
coincmd "github.com/tendermint/basecoin/modules/coin/commands"
|
||||||
feecmd "github.com/tendermint/basecoin/modules/fee/commands"
|
feecmd "github.com/tendermint/basecoin/modules/fee/commands"
|
||||||
noncecmd "github.com/tendermint/basecoin/modules/nonce/commands"
|
noncecmd "github.com/tendermint/basecoin/modules/nonce/commands"
|
||||||
|
rolecmd "github.com/tendermint/basecoin/modules/roles/commands"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BaseCli - main basecoin client command
|
// BaseCli - main basecoin client command
|
||||||
|
@ -61,6 +62,7 @@ func main() {
|
||||||
// set up the middleware
|
// set up the middleware
|
||||||
txcmd.Middleware = txcmd.Wrappers{
|
txcmd.Middleware = txcmd.Wrappers{
|
||||||
feecmd.FeeWrapper{},
|
feecmd.FeeWrapper{},
|
||||||
|
rolecmd.RoleWrapper{},
|
||||||
noncecmd.NonceWrapper{},
|
noncecmd.NonceWrapper{},
|
||||||
basecmd.ChainWrapper{},
|
basecmd.ChainWrapper{},
|
||||||
authcmd.SigWrapper{},
|
authcmd.SigWrapper{},
|
||||||
|
|
|
@ -33,32 +33,12 @@ func init() {
|
||||||
fs.Bool(FlagValid, false, "Is count valid?")
|
fs.Bool(FlagValid, false, "Is count valid?")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: counterTx is very similar to the sendtx one,
|
|
||||||
// maybe we can pull out some common patterns?
|
|
||||||
func counterTx(cmd *cobra.Command, args []string) error {
|
func counterTx(cmd *cobra.Command, args []string) error {
|
||||||
tx, err := readCounterTxFlags()
|
tx, err := readCounterTxFlags()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return txcmd.DoTx(tx)
|
||||||
tx, err = txcmd.Middleware.Wrap(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = txcmd.SignTx(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bres, err := txcmd.PrepareOrPostTx(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bres == nil {
|
|
||||||
return nil // successful prep, nothing left to do
|
|
||||||
}
|
|
||||||
return txcmd.OutputTx(bres) // print response of the post
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readCounterTxFlags() (tx basecoin.Tx, err error) {
|
func readCounterTxFlags() (tx basecoin.Tx, err error) {
|
||||||
|
|
|
@ -37,31 +37,12 @@ func sendTxCmd(cmd *cobra.Command, args []string) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
return txcmd.DoTx(tx)
|
||||||
tx, err = txcmd.Middleware.Wrap(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = txcmd.SignTx(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise, post it and display response
|
|
||||||
bres, err := txcmd.PrepareOrPostTx(tx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if bres == nil {
|
|
||||||
return nil // successful prep, nothing left to do
|
|
||||||
}
|
|
||||||
return txcmd.OutputTx(bres) // print response of the post
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func readSendTxFlags() (tx basecoin.Tx, err error) {
|
func readSendTxFlags() (tx basecoin.Tx, err error) {
|
||||||
// parse to address
|
// parse to address
|
||||||
toAddr, err := commands.ParseAddress(viper.GetString(FlagTo))
|
toAddr, err := commands.ParseActor(viper.GetString(FlagTo))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx, err
|
return tx, err
|
||||||
}
|
}
|
||||||
|
@ -94,5 +75,5 @@ func readFromAddr() (basecoin.Actor, error) {
|
||||||
if from == "" {
|
if from == "" {
|
||||||
return txcmd.GetSignerAct(), nil
|
return txcmd.GetSignerAct(), nil
|
||||||
}
|
}
|
||||||
return commands.ParseAddress(from)
|
return commands.ParseActor(from)
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,5 +55,5 @@ func readPayer() (basecoin.Actor, error) {
|
||||||
if payer == "" {
|
if payer == "" {
|
||||||
return txcmd.GetSignerAct(), nil
|
return txcmd.GetSignerAct(), nil
|
||||||
}
|
}
|
||||||
return commands.ParseAddress(payer)
|
return commands.ParseActor(payer)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
lc "github.com/tendermint/light-client"
|
lc "github.com/tendermint/light-client"
|
||||||
|
|
||||||
"github.com/tendermint/basecoin"
|
"github.com/tendermint/basecoin"
|
||||||
lcmd "github.com/tendermint/basecoin/client/commands"
|
"github.com/tendermint/basecoin/client/commands"
|
||||||
proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
|
proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
|
||||||
"github.com/tendermint/basecoin/modules/nonce"
|
"github.com/tendermint/basecoin/modules/nonce"
|
||||||
"github.com/tendermint/basecoin/stack"
|
"github.com/tendermint/basecoin/stack"
|
||||||
|
@ -19,7 +19,7 @@ import (
|
||||||
var NonceQueryCmd = &cobra.Command{
|
var NonceQueryCmd = &cobra.Command{
|
||||||
Use: "nonce [address]",
|
Use: "nonce [address]",
|
||||||
Short: "Get details of a nonce sequence number, with proof",
|
Short: "Get details of a nonce sequence number, with proof",
|
||||||
RunE: lcmd.RequireInit(nonceQueryCmd),
|
RunE: commands.RequireInit(nonceQueryCmd),
|
||||||
}
|
}
|
||||||
|
|
||||||
func nonceQueryCmd(cmd *cobra.Command, args []string) error {
|
func nonceQueryCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
@ -28,7 +28,7 @@ func nonceQueryCmd(cmd *cobra.Command, args []string) error {
|
||||||
}
|
}
|
||||||
addr := strings.Join(args, ",")
|
addr := strings.Join(args, ",")
|
||||||
|
|
||||||
signers, err := parseActors(addr)
|
signers, err := commands.ParseActors(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@ package commands
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
"github.com/spf13/pflag"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
|
@ -54,19 +53,7 @@ func readNonceKey() ([]basecoin.Actor, error) {
|
||||||
if nonce == "" {
|
if nonce == "" {
|
||||||
return []basecoin.Actor{txcmd.GetSignerAct()}, nil
|
return []basecoin.Actor{txcmd.GetSignerAct()}, nil
|
||||||
}
|
}
|
||||||
return parseActors(nonce)
|
return commands.ParseActors(nonce)
|
||||||
}
|
|
||||||
|
|
||||||
func parseActors(key string) (signers []basecoin.Actor, err error) {
|
|
||||||
var act basecoin.Actor
|
|
||||||
for _, k := range strings.Split(key, ",") {
|
|
||||||
act, err = commands.ParseAddress(k)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
signers = append(signers, act)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// read the sequence from the flag or query for it if flag is -1
|
// read the sequence from the flag or query for it if flag is -1
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
|
lcmd "github.com/tendermint/basecoin/client/commands"
|
||||||
|
proofcmd "github.com/tendermint/basecoin/client/commands/proofs"
|
||||||
|
"github.com/tendermint/basecoin/modules/roles"
|
||||||
|
"github.com/tendermint/basecoin/stack"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoleQueryCmd - command to query a role
|
||||||
|
var RoleQueryCmd = &cobra.Command{
|
||||||
|
Use: "role [name]",
|
||||||
|
Short: "Get details of a role, with proof",
|
||||||
|
RunE: lcmd.RequireInit(roleQueryCmd),
|
||||||
|
}
|
||||||
|
|
||||||
|
func roleQueryCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("Missing required argument [name]")
|
||||||
|
} else if len(args) > 1 {
|
||||||
|
return errors.New("Command only supports one name")
|
||||||
|
}
|
||||||
|
|
||||||
|
role, err := parseRole(args[0])
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var res roles.Role
|
||||||
|
key := stack.PrefixedKey(roles.NameRole, role)
|
||||||
|
proof, err := proofcmd.GetAndParseAppProof(key, &res)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return proofcmd.OutputProof(res, proof.BlockHeight())
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
"github.com/tendermint/basecoin/client/commands"
|
||||||
|
txcmd "github.com/tendermint/basecoin/client/commands/txs"
|
||||||
|
"github.com/tendermint/basecoin/modules/roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
// CreateRoleTxCmd is CLI command to send tokens between basecoin accounts
|
||||||
|
var CreateRoleTxCmd = &cobra.Command{
|
||||||
|
Use: "send",
|
||||||
|
Short: "send tokens from one account to another",
|
||||||
|
RunE: commands.RequireInit(createRoleTxCmd),
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint
|
||||||
|
const (
|
||||||
|
FlagRole = "role"
|
||||||
|
FlagMembers = "members"
|
||||||
|
FlagMinSigs = "min-sigs"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
flags := CreateRoleTxCmd.Flags()
|
||||||
|
flags.String(FlagRole, "", "Name of the role to create")
|
||||||
|
flags.String(FlagMembers, "", "Set of comma-separated addresses for this role")
|
||||||
|
flags.Int(FlagMinSigs, 0, "Minimum number of signatures needed to assume this role")
|
||||||
|
}
|
||||||
|
|
||||||
|
// createRoleTxCmd is an example of how to make a tx
|
||||||
|
func createRoleTxCmd(cmd *cobra.Command, args []string) error {
|
||||||
|
tx, err := readCreateRoleTxFlags()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return txcmd.DoTx(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func readCreateRoleTxFlags() (tx basecoin.Tx, err error) {
|
||||||
|
role, err := parseRole(viper.GetString(FlagRole))
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
|
||||||
|
sigs := viper.GetInt(FlagMinSigs)
|
||||||
|
if sigs < 1 {
|
||||||
|
return tx, errors.Errorf("--%s must be at least 1", FlagMinSigs)
|
||||||
|
}
|
||||||
|
|
||||||
|
signers, err := commands.ParseActors(viper.GetString(FlagMembers))
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
if len(signers) == 0 {
|
||||||
|
return tx, errors.New("must specify at least one member")
|
||||||
|
}
|
||||||
|
|
||||||
|
tx = roles.NewCreateRoleTx(role, uint32(sigs), signers)
|
||||||
|
return tx, nil
|
||||||
|
}
|
|
@ -0,0 +1,48 @@
|
||||||
|
package commands
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"github.com/spf13/viper"
|
||||||
|
|
||||||
|
"github.com/tendermint/basecoin"
|
||||||
|
txcmd "github.com/tendermint/basecoin/client/commands/txs"
|
||||||
|
"github.com/tendermint/basecoin/modules/roles"
|
||||||
|
)
|
||||||
|
|
||||||
|
// nolint
|
||||||
|
const (
|
||||||
|
FlagAssumeRole = "assume-role"
|
||||||
|
)
|
||||||
|
|
||||||
|
// RoleWrapper wraps a tx with 0, 1, or more roles
|
||||||
|
type RoleWrapper struct{}
|
||||||
|
|
||||||
|
var _ txcmd.Wrapper = RoleWrapper{}
|
||||||
|
|
||||||
|
// Wrap grabs the sequence number from the flag and wraps
|
||||||
|
// the tx with this nonce. Grabs the permission from the signer,
|
||||||
|
// as we still only support single sig on the cli
|
||||||
|
func (RoleWrapper) Wrap(tx basecoin.Tx) (basecoin.Tx, error) {
|
||||||
|
assume := viper.GetStringSlice(FlagAssumeRole)
|
||||||
|
|
||||||
|
// we wrap from inside-out, so we must wrap them in the reverse order,
|
||||||
|
// so they are applied in the order the user intended
|
||||||
|
for i := len(assume) - 1; i >= 0; i-- {
|
||||||
|
r, err := parseRole(assume[i])
|
||||||
|
if err != nil {
|
||||||
|
return tx, err
|
||||||
|
}
|
||||||
|
tx = roles.NewAssumeRoleTx(r, tx)
|
||||||
|
}
|
||||||
|
return tx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register adds the sequence flags to the cli
|
||||||
|
func (RoleWrapper) Register(fs *pflag.FlagSet) {
|
||||||
|
fs.StringSlice(FlagAssumeRole, nil, "Roles to assume (can use multiple times)")
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse role turns the string->byte... todo: support hex?
|
||||||
|
func parseRole(role string) ([]byte, error) {
|
||||||
|
return []byte(role), nil
|
||||||
|
}
|
Loading…
Reference in New Issue