From 865b1168379b1d03e6377009174e0708183c83da Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Fri, 16 Mar 2018 21:36:16 +0100 Subject: [PATCH] move Bond/UnbondCoins to transact working ... --- x/stake/commands/query.go | 313 +++++++++++++++++++------------------- x/stake/commands/tx.go | 42 +++-- x/stake/handler.go | 33 +++- x/stake/handler_test.go | 8 +- x/stake/tx.go | 13 +- x/stake/types.go | 31 ---- 6 files changed, 228 insertions(+), 212 deletions(-) diff --git a/x/stake/commands/query.go b/x/stake/commands/query.go index 46fc029526..6523cc75b8 100644 --- a/x/stake/commands/query.go +++ b/x/stake/commands/query.go @@ -5,7 +5,6 @@ import ( "encoding/json" "fmt" - "github.com/pkg/errors" "github.com/spf13/cobra" flag "github.com/spf13/pflag" "github.com/spf13/viper" @@ -13,8 +12,8 @@ import ( crypto "github.com/tendermint/go-crypto" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/examples/basecoin/app" - coin "github.com/cosmos/cosmos-sdk/x/bank" // XXX fix + "github.com/cosmos/cosmos-sdk/client/builder" + "github.com/cosmos/cosmos-sdk/wire" // XXX fix "github.com/cosmos/cosmos-sdk/x/stake" ) @@ -26,189 +25,183 @@ func PrefixedKey(app string, key []byte) []byte { //nolint var ( - CmdQueryCandidates = &cobra.Command{ - Use: "candidates", - Short: "Query for the set of validator-candidates pubkeys", - RunE: cmdQueryCandidates, - } - - CmdQueryCandidate = &cobra.Command{ - Use: "candidate", - Short: "Query a validator-candidate account", - RunE: cmdQueryCandidate, - } - - CmdQueryDelegatorBond = &cobra.Command{ - Use: "delegator-bond", - Short: "Query a delegators bond based on address and candidate pubkey", - RunE: cmdQueryDelegatorBond, - } - - CmdQueryDelegatorCandidates = &cobra.Command{ - Use: "delegator-candidates", - RunE: cmdQueryDelegatorCandidates, - Short: "Query all delegators candidates' pubkeys based on address", - } - - FlagDelegatorAddress = "delegator-address" + fsValAddr = flag.NewFlagSet("", flag.ContinueOnError) + fsDelAddr = flag.NewFlagSet("", flag.ContinueOnError) + FlagValidatorAddr = "address" + FlagDelegatorAddr = "delegator-address" ) func init() { //Add Flags - fsPk := flag.NewFlagSet("", flag.ContinueOnError) - fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate") - fsAddr := flag.NewFlagSet("", flag.ContinueOnError) - fsAddr.String(FlagDelegatorAddress, "", "Delegator Hex Address") + fsValAddr.String(FlagValidatorAddr, "", "Address of the validator/candidate") + fsDelAddr.String(FlagDelegatorAddr, "", "Delegator hex address") - CmdQueryCandidate.Flags().AddFlagSet(fsPk) - CmdQueryDelegatorBond.Flags().AddFlagSet(fsPk) - CmdQueryDelegatorBond.Flags().AddFlagSet(fsAddr) - CmdQueryDelegatorCandidates.Flags().AddFlagSet(fsAddr) } -// XXX move to common directory in client helpers -func makeQuery(key, storeName string) (res []byte, err error) { +// create command to query for all candidates +func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command { + cmd := &cobra.Command{ + Use: "candidates", + Short: "Query for the set of validator-candidates pubkeys", + RunE: func(cmd *cobra.Command, args []string) error { - path := fmt.Sprintf("/%s/key", a.storeName) + var pks []crypto.PubKey - uri := viper.GetString(client.FlagNode) - if uri == "" { - return res, errors.New("Must define which node to query with --node") - } - node := client.GetNode(uri) + prove := !viper.GetBool(client.FlagTrustNode) + key := PrefixedKey(stake.Name, stake.CandidatesAddrKey) - opts := rpcclient.ABCIQueryOptions{ - Height: viper.GetInt64(client.FlagHeight), - Trusted: viper.GetBool(client.FlagTrustNode), + res, err := builder.Query(key, storeName) + if err != nil { + return err + } + + // parse out the candidates + candidates := new(stake.Candidates) + err = cdc.UnmarshalJSON(res, candidates) + if err != nil { + return err + } + output, err := json.MarshalIndent(candidates, "", " ") + if err != nil { + return err + } + fmt.Println(string(output)) + return nil + + // TODO output with proofs / machine parseable etc. + }, } - result, err := node.ABCIQueryWithOptions(path, key, opts) - if err != nil { - return res, err - } - resp := result.Response - if resp.Code != uint32(0) { - return res, errors.Errorf("Query failed: (%d) %s", resp.Code, resp.Log) - } - return resp.val, nil + + cmd.Flags().AddFlagSet(fsDelAddr) + return cmd } -func cmdQueryCandidates(cmd *cobra.Command, args []string) error { +// get the command to query a candidate +func GetCmdQueryCandidate(cdc *wire.Codec, storeName string) *cobra.Command { + cmd := &cobra.Command{ + Use: "candidate", + Short: "Query a validator-candidate account", + RunE: func(cmd *cobra.Command, args []string) error { - var pks []crypto.PubKey + addr, err := GetAddress(viper.GetString(FlagValidatorAddr)) + if err != nil { + return err + } - prove := !viper.GetBool(client.FlagTrustNode) - key := PrefixedKey(stake.Name(), stake.CandidatesPubKeysKey) + prove := !viper.GetBool(client.FlagTrustNode) + key := PrefixedKey(stake.Name, stake.GetCandidateKey(addr)) - res, err := makeQuery(key, "gaia-store-name") // XXX move gaia store name out of here - if err != nil { - return err + res, err := builder.Query(key, storeName) + if err != nil { + return err + } + + // parse out the candidate + candidate := new(stake.Candidate) + err = cdc.UnmarshalBinary(res, candidate) + if err != nil { + return err + } + output, err := json.MarshalIndent(candidate, "", " ") + if err != nil { + return err + } + fmt.Println(string(output)) + return nil + + // TODO output with proofs / machine parseable etc. + }, } - // parse out the candidates - candidates := new(stake.Candidates) - cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module - err = cdc.UnmarshalBinary(res, candidates) - if err != nil { - return err - } - output, err := json.MarshalIndent(candidates, "", " ") - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - - // TODO output with proofs / machine parseable etc. + cmd.Flags().AddFlagSet(fsValAddr) + return cmd } -func cmdQueryCandidate(cmd *cobra.Command, args []string) error { +// get the command to query a single delegator bond +func GetCmdQueryDelegatorBond(cdc *wire.Codec, storeName string) *cobra.Command { + cmd := &cobra.Command{ + Use: "delegator-bond", + Short: "Query a delegators bond based on address and candidate pubkey", + RunE: func(cmd *cobra.Command, args []string) error { - var candidate stake.Candidate + addr, err := GetAddress(viper.GetString(FlagValidatorAddr)) + if err != nil { + return err + } - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err + bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr)) + if err != nil { + return err + } + delegator := crypto.Address(bz) + + prove := !viper.GetBool(client.FlagTrustNode) + key := PrefixedKey(stake.Name, stake.GetDelegatorBondKey(delegator, addr, cdc)) + + res, err := builder.Query(key, storeName) + if err != nil { + return err + } + + // parse out the bond + var bond stake.DelegatorBond + err = cdc.UnmarshalBinary(res, bond) + if err != nil { + return err + } + output, err := json.MarshalIndent(bond, "", " ") + if err != nil { + return err + } + fmt.Println(string(output)) + return nil + + // TODO output with proofs / machine parseable etc. + }, } - prove := !viper.GetBool(client.FlagTrustNode) - key := PrefixedKey(stake.Name(), stake.GetCandidateKey(pk)) - - // parse out the candidate - candidate := new(stake.Candidate) - cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module - err = cdc.UnmarshalBinary(res, candidate) - if err != nil { - return err - } - output, err := json.MarshalIndent(candidate, "", " ") - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - - // TODO output with proofs / machine parseable etc. + cmd.Flags().AddFlagSet(fsValAddr) + cmd.Flags().AddFlagSet(fsDelAddr) + return cmd } -func cmdQueryDelegatorBond(cmd *cobra.Command, args []string) error { +// get the command to query all the candidates bonded to a delegator +func GetCmdQueryDelegatorBonds(cdc *wire.Codec, storeName string) *cobra.Command { + cmd := &cobra.Command{ + Use: "delegator-candidates", + Short: "Query all delegators candidates' pubkeys based on address", + RunE: func(cmd *cobra.Command, args []string) error { - pk, err := GetPubKey(viper.GetString(FlagPubKey)) - if err != nil { - return err + bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr)) + if err != nil { + return err + } + delegator := crypto.Address(bz) + + prove := !viper.GetBool(client.FlagTrustNode) + key := PrefixedKey(stake.Name, stake.GetDelegatorBondsKey(delegator, cdc)) + + res, err := builder.Query(key, storeName) + if err != nil { + return err + } + + // parse out the candidates list + var candidates []crypto.PubKey + err = cdc.UnmarshalBinary(res, candidates) + if err != nil { + return err + } + output, err := json.MarshalIndent(candidates, "", " ") + if err != nil { + return err + } + fmt.Println(string(output)) + return nil + + // TODO output with proofs / machine parseable etc. + }, } - - bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddress)) - if err != nil { - return err - } - delegator := crypto.Address(bz) - delegator = coin.ChainAddr(delegator) - - prove := !viper.GetBool(client.FlagTrustNode) - key := PrefixedKey(stake.Name(), stake.GetDelegatorBondKey(delegator, pk)) - - // parse out the bond - var bond stake.DelegatorBond - cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module - err = cdc.UnmarshalBinary(res, bond) - if err != nil { - return err - } - output, err := json.MarshalIndent(bond, "", " ") - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - - // TODO output with proofs / machine parseable etc. -} - -func cmdQueryDelegatorCandidates(cmd *cobra.Command, args []string) error { - - bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddress)) - if err != nil { - return err - } - delegator := crypto.Address(bz) - delegator = coin.ChainAddr(delegator) - - prove := !viper.GetBool(client.FlagTrustNode) - key := PrefixedKey(stake.Name(), stake.GetDelegatorBondsKey(delegator)) - - // parse out the candidates list - var candidates []crypto.PubKey - cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module - err = cdc.UnmarshalBinary(res, candidates) - if err != nil { - return err - } - output, err := json.MarshalIndent(candidates, "", " ") - if err != nil { - return err - } - fmt.Println(string(output)) - return nil - - // TODO output with proofs / machine parseable etc. + cmd.Flags().AddFlagSet(fsDelAddr) + return cmd } diff --git a/x/stake/commands/tx.go b/x/stake/commands/tx.go index c264dfd80a..de3e4c848c 100644 --- a/x/stake/commands/tx.go +++ b/x/stake/commands/tx.go @@ -18,9 +18,10 @@ import ( // nolint const ( - FlagPubKey = "pubkey" - FlagAmount = "amount" - FlagShares = "shares" + FlagAddress = "address" + FlagPubKey = "pubkey" + FlagAmount = "amount" + FlagShares = "shares" FlagMoniker = "moniker" FlagIdentity = "keybase-sig" @@ -91,6 +92,11 @@ func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error { return err } + addr, err := GetAddress(viper.GetString(FlagAddress)) + if err != nil { + return err + } + pk, err := GetPubKey(viper.GetString(FlagPubKey)) if err != nil { return err @@ -107,13 +113,13 @@ func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error { Details: viper.GetString(FlagDetails), } - tx := stake.NewMsgDeclareCandidacy(amount, pk, description) + tx := stake.NewMsgDeclareCandidacy(addr, pk, amount, description) return doTx(tx) } func cmdEditCandidacy(cmd *cobra.Command, args []string) error { - pk, err := GetPubKey(viper.GetString(FlagPubKey)) + addr, err := GetAddress(viper.GetString(FlagAddress)) if err != nil { return err } @@ -125,7 +131,7 @@ func cmdEditCandidacy(cmd *cobra.Command, args []string) error { Details: viper.GetString(FlagDetails), } - tx := stake.NewMsgEditCandidacy(pk, description) + tx := stake.NewMsgEditCandidacy(addr, description) return doTx(tx) } @@ -135,12 +141,12 @@ func cmdDelegate(cmd *cobra.Command, args []string) error { return err } - pk, err := GetPubKey(viper.GetString(FlagPubKey)) + addr, err := GetAddress(viper.GetString(FlagAddress)) if err != nil { return err } - tx := stake.NewMsgDelegate(amount, pk) + tx := stake.NewMsgDelegate(addr, amount) return doTx(tx) } @@ -162,15 +168,17 @@ func cmdUnbond(cmd *cobra.Command, args []string) error { } } - pk, err := GetPubKey(viper.GetString(FlagPubKey)) + addr, err := GetAddress(viper.GetString(FlagAddress)) if err != nil { return err } - tx := stake.NewMsgUnbond(sharesStr, pk) + tx := stake.NewMsgUnbond(addr, sharesStr) return doTx(tx) } +//______________________________________________________________________________________ + // GetPubKey - create the pubkey from a pubkey string func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) { @@ -193,7 +201,19 @@ func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) { return } -//-------------------------------------------------------------------- +// GetPubKey - create an Address from a pubkey string +func GetAddress(Address string) (addr sdk.Address, err error) { + if len(Address) == 0 { + return addr, errors.New("must use provide address") + } + bz, err := hex.DecodeString(addr) + if err != nil { + return nil, err + } + return sdk.Address(bz), nil +} + +//______________________________________________________________________________________ // XXX consolidate to client func doTx(tx []byte) { diff --git a/x/stake/handler.go b/x/stake/handler.go index d13881864f..402d3e2f18 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -249,7 +249,7 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s } // Account new shares, save - err := bond.BondCoins(candidate, tx.Bond, tr) + err := tr.BondCoins(bond, candidate, tx.Bond) if err != nil { return err } @@ -259,6 +259,37 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s return nil } +// Perform all the actions required to bond tokens to a delegator bond from their account +func (tr *transact) BondCoins(bond *DelegatorBond, candidate *Candidate, tokens sdk.Coin) sdk.Error { + + _, err := tr.coinKeeper.SubtractCoins(tr.ctx, candidate.Address, sdk.Coins{tokens}) + if err != nil { + return err + } + newShares := candidate.addTokens(tokens.Amount, tr.gs) + bond.Shares = bond.Shares.Add(newShares) + return nil +} + +// Perform all the actions required to bond tokens to a delegator bond from their account +func (tr *transact) UnbondCoins(bond *DelegatorBond, candidate *Candidate, shares sdk.Rat) sdk.Error { + + // subtract bond tokens from delegator bond + if bond.Shares.LT(shares) { + return sdk.ErrInsufficientFunds("") // TODO + } + bond.Shares = bond.Shares.Sub(shares) + + returnAmount := candidate.removeShares(shares, tr.gs) + returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}} + + _, err := tr.coinKeeper.AddCoins(tr.ctx, candidate.Address, returnCoins) + if err != nil { + return err + } + return nil +} + func (tr transact) unbond(tx MsgUnbond) sdk.Error { // check if bond has any shares in it unbond diff --git a/x/stake/handler_test.go b/x/stake/handler_test.go index 4e5a1ee4ca..0c26f8a242 100644 --- a/x/stake/handler_test.go +++ b/x/stake/handler_test.go @@ -17,7 +17,7 @@ import ( func initAccounts(n int, amount int64) ([]sdk.Address, map[string]int64) { accStore := map[string]int64{} - senders := newActors(n) + senders := newAddrs(n) for _, sender := range senders { accStore[string(sender.Address)] = amount } @@ -49,9 +49,9 @@ func newMsgUnbond(shares string, pubKey crypto.PubKey) MsgUnbond { func paramsNoInflation() Params { return Params{ - InflationRateChange: sdk.Zero, - InflationMax: sdk.Zero, - InflationMin: sdk.Zero, + InflationRateChange: sdk.ZeroRat, + InflationMax: sdk.ZeroRat, + InflationMin: sdk.ZeroRat, GoalBonded: sdk.New(67, 100), MaxVals: 100, BondDenom: "fermion", diff --git a/x/stake/tx.go b/x/stake/tx.go index 5cc3de6d39..7104b92a8b 100644 --- a/x/stake/tx.go +++ b/x/stake/tx.go @@ -8,6 +8,9 @@ import ( crypto "github.com/tendermint/go-crypto" ) +// name to idetify transaction types +var Name = "stake" + //Verify interface at compile time var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{} @@ -25,7 +28,7 @@ func NewMsgAddr(address sdk.Address) MsgAddr { } // nolint -func (msg MsgAddr) Type() string { return "stake" } +func (msg MsgAddr) Type() string { return Name } func (msg MsgAddr) Get(key interface{}) (value interface{}) { return nil } func (msg MsgAddr) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} } func (msg MsgAddr) String() string { @@ -50,7 +53,7 @@ type MsgDeclareCandidacy struct { PubKey crypto.PubKey `json:"pubkey"` } -func NewMsgDeclareCandidacy(bond sdk.Coin, address sdk.Address, pubkey crypto.PubKey, description Description) MsgDeclareCandidacy { +func NewMsgDeclareCandidacy(address sdk.Address, pubkey crypto.PubKey, bond sdk.Coin, description Description) MsgDeclareCandidacy { return MsgDeclareCandidacy{ MsgAddr: NewMsgAddr(address), Description: description, @@ -167,10 +170,10 @@ type MsgUnbond struct { Shares string `json:"shares"` } -func NewMsgUnbond(bond sdk.Coin, address sdk.Address) MsgDelegate { - return MsgDelegate{ +func NewMsgUnbond(address sdk.Address, shares string) MsgUnbond { + return MsgUnbond{ MsgAddr: NewMsgAddr(address), - Bond: bond, // Shares: shares, + Shares: shares, } } diff --git a/x/stake/types.go b/x/stake/types.go index 698c7813d8..2ffc58ede1 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -260,34 +260,3 @@ type DelegatorBond struct { Address sdk.Address `json:"pub_key"` Shares sdk.Rat `json:"shares"` } - -// Perform all the actions required to bond tokens to a delegator bond from their account -func (bond *DelegatorBond) BondCoins(candidate *Candidate, tokens sdk.Coin, tr transact) sdk.Error { - - _, err := tr.coinKeeper.SubtractCoins(tr.ctx, candidate.Address, sdk.Coins{tokens}) - if err != nil { - return err - } - newShares := candidate.addTokens(tokens.Amount, tr.gs) - bond.Shares = bond.Shares.Add(newShares) - return nil -} - -// Perform all the actions required to bond tokens to a delegator bond from their account -func (bond *DelegatorBond) UnbondCoins(candidate *Candidate, shares int64, tr transact) sdk.Error { - - // subtract bond tokens from delegator bond - if bond.Shares.LT(shares) { - return sdk.ErrInsufficientFunds("") // TODO - } - bond.Shares = bond.Shares.Sub(shares) - - returnAmount := candidate.removeShares(shares, tr.gs) - returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}} - - _, err := tr.coinKeeper.AddCoins(tr.ctx, candidate.Address, returnCoins) - if err != nil { - return err - } - return nil -}