move Bond/UnbondCoins to transact

working

...
This commit is contained in:
Ethan Buchman 2018-03-16 21:36:16 +01:00 committed by rigelrozanski
parent af6c1a3f02
commit 865b116837
6 changed files with 228 additions and 212 deletions

View File

@ -5,7 +5,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
flag "github.com/spf13/pflag" flag "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -13,8 +12,8 @@ import (
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/examples/basecoin/app" "github.com/cosmos/cosmos-sdk/client/builder"
coin "github.com/cosmos/cosmos-sdk/x/bank" // XXX fix "github.com/cosmos/cosmos-sdk/wire" // XXX fix
"github.com/cosmos/cosmos-sdk/x/stake" "github.com/cosmos/cosmos-sdk/x/stake"
) )
@ -26,88 +25,39 @@ func PrefixedKey(app string, key []byte) []byte {
//nolint //nolint
var ( var (
CmdQueryCandidates = &cobra.Command{ fsValAddr = flag.NewFlagSet("", flag.ContinueOnError)
Use: "candidates", fsDelAddr = flag.NewFlagSet("", flag.ContinueOnError)
Short: "Query for the set of validator-candidates pubkeys", FlagValidatorAddr = "address"
RunE: cmdQueryCandidates, FlagDelegatorAddr = "delegator-address"
}
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"
) )
func init() { func init() {
//Add Flags //Add Flags
fsPk := flag.NewFlagSet("", flag.ContinueOnError) fsValAddr.String(FlagValidatorAddr, "", "Address of the validator/candidate")
fsPk.String(FlagPubKey, "", "PubKey of the validator-candidate") fsDelAddr.String(FlagDelegatorAddr, "", "Delegator hex address")
fsAddr := flag.NewFlagSet("", flag.ContinueOnError)
fsAddr.String(FlagDelegatorAddress, "", "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 // create command to query for all candidates
func makeQuery(key, storeName string) (res []byte, err error) { func GetCmdQueryCandidates(cdc *wire.Codec, storeName string) *cobra.Command {
cmd := &cobra.Command{
path := fmt.Sprintf("/%s/key", a.storeName) Use: "candidates",
Short: "Query for the set of validator-candidates pubkeys",
uri := viper.GetString(client.FlagNode) RunE: func(cmd *cobra.Command, args []string) error {
if uri == "" {
return res, errors.New("Must define which node to query with --node")
}
node := client.GetNode(uri)
opts := rpcclient.ABCIQueryOptions{
Height: viper.GetInt64(client.FlagHeight),
Trusted: viper.GetBool(client.FlagTrustNode),
}
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
}
func cmdQueryCandidates(cmd *cobra.Command, args []string) error {
var pks []crypto.PubKey var pks []crypto.PubKey
prove := !viper.GetBool(client.FlagTrustNode) prove := !viper.GetBool(client.FlagTrustNode)
key := PrefixedKey(stake.Name(), stake.CandidatesPubKeysKey) key := PrefixedKey(stake.Name, stake.CandidatesAddrKey)
res, err := makeQuery(key, "gaia-store-name") // XXX move gaia store name out of here res, err := builder.Query(key, storeName)
if err != nil { if err != nil {
return err return err
} }
// parse out the candidates // parse out the candidates
candidates := new(stake.Candidates) candidates := new(stake.Candidates)
cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module err = cdc.UnmarshalJSON(res, candidates)
err = cdc.UnmarshalBinary(res, candidates)
if err != nil { if err != nil {
return err return err
} }
@ -119,23 +69,35 @@ func cmdQueryCandidates(cmd *cobra.Command, args []string) error {
return nil return nil
// TODO output with proofs / machine parseable etc. // TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsDelAddr)
return cmd
} }
func cmdQueryCandidate(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 candidate stake.Candidate addr, err := GetAddress(viper.GetString(FlagValidatorAddr))
pk, err := GetPubKey(viper.GetString(FlagPubKey))
if err != nil { if err != nil {
return err return err
} }
prove := !viper.GetBool(client.FlagTrustNode) prove := !viper.GetBool(client.FlagTrustNode)
key := PrefixedKey(stake.Name(), stake.GetCandidateKey(pk)) key := PrefixedKey(stake.Name, stake.GetCandidateKey(addr))
res, err := builder.Query(key, storeName)
if err != nil {
return err
}
// parse out the candidate // parse out the candidate
candidate := new(stake.Candidate) candidate := new(stake.Candidate)
cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module
err = cdc.UnmarshalBinary(res, candidate) err = cdc.UnmarshalBinary(res, candidate)
if err != nil { if err != nil {
return err return err
@ -148,28 +110,41 @@ func cmdQueryCandidate(cmd *cobra.Command, args []string) error {
return nil return nil
// TODO output with proofs / machine parseable etc. // TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsValAddr)
return cmd
} }
func cmdQueryDelegatorBond(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 {
pk, err := GetPubKey(viper.GetString(FlagPubKey)) addr, err := GetAddress(viper.GetString(FlagValidatorAddr))
if err != nil { if err != nil {
return err return err
} }
bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddress)) bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr))
if err != nil { if err != nil {
return err return err
} }
delegator := crypto.Address(bz) delegator := crypto.Address(bz)
delegator = coin.ChainAddr(delegator)
prove := !viper.GetBool(client.FlagTrustNode) prove := !viper.GetBool(client.FlagTrustNode)
key := PrefixedKey(stake.Name(), stake.GetDelegatorBondKey(delegator, pk)) key := PrefixedKey(stake.Name, stake.GetDelegatorBondKey(delegator, addr, cdc))
res, err := builder.Query(key, storeName)
if err != nil {
return err
}
// parse out the bond // parse out the bond
var bond stake.DelegatorBond var bond stake.DelegatorBond
cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module
err = cdc.UnmarshalBinary(res, bond) err = cdc.UnmarshalBinary(res, bond)
if err != nil { if err != nil {
return err return err
@ -182,23 +157,37 @@ func cmdQueryDelegatorBond(cmd *cobra.Command, args []string) error {
return nil return nil
// TODO output with proofs / machine parseable etc. // TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsValAddr)
cmd.Flags().AddFlagSet(fsDelAddr)
return cmd
} }
func cmdQueryDelegatorCandidates(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 {
bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddress)) bz, err := hex.DecodeString(viper.GetString(FlagDelegatorAddr))
if err != nil { if err != nil {
return err return err
} }
delegator := crypto.Address(bz) delegator := crypto.Address(bz)
delegator = coin.ChainAddr(delegator)
prove := !viper.GetBool(client.FlagTrustNode) prove := !viper.GetBool(client.FlagTrustNode)
key := PrefixedKey(stake.Name(), stake.GetDelegatorBondsKey(delegator)) key := PrefixedKey(stake.Name, stake.GetDelegatorBondsKey(delegator, cdc))
res, err := builder.Query(key, storeName)
if err != nil {
return err
}
// parse out the candidates list // parse out the candidates list
var candidates []crypto.PubKey var candidates []crypto.PubKey
cdc := app.MakeTxCodec() // XXX create custom Tx for Staking Module
err = cdc.UnmarshalBinary(res, candidates) err = cdc.UnmarshalBinary(res, candidates)
if err != nil { if err != nil {
return err return err
@ -211,4 +200,8 @@ func cmdQueryDelegatorCandidates(cmd *cobra.Command, args []string) error {
return nil return nil
// TODO output with proofs / machine parseable etc. // TODO output with proofs / machine parseable etc.
},
}
cmd.Flags().AddFlagSet(fsDelAddr)
return cmd
} }

View File

@ -18,6 +18,7 @@ import (
// nolint // nolint
const ( const (
FlagAddress = "address"
FlagPubKey = "pubkey" FlagPubKey = "pubkey"
FlagAmount = "amount" FlagAmount = "amount"
FlagShares = "shares" FlagShares = "shares"
@ -91,6 +92,11 @@ func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error {
return err return err
} }
addr, err := GetAddress(viper.GetString(FlagAddress))
if err != nil {
return err
}
pk, err := GetPubKey(viper.GetString(FlagPubKey)) pk, err := GetPubKey(viper.GetString(FlagPubKey))
if err != nil { if err != nil {
return err return err
@ -107,13 +113,13 @@ func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error {
Details: viper.GetString(FlagDetails), Details: viper.GetString(FlagDetails),
} }
tx := stake.NewMsgDeclareCandidacy(amount, pk, description) tx := stake.NewMsgDeclareCandidacy(addr, pk, amount, description)
return doTx(tx) return doTx(tx)
} }
func cmdEditCandidacy(cmd *cobra.Command, args []string) error { func cmdEditCandidacy(cmd *cobra.Command, args []string) error {
pk, err := GetPubKey(viper.GetString(FlagPubKey)) addr, err := GetAddress(viper.GetString(FlagAddress))
if err != nil { if err != nil {
return err return err
} }
@ -125,7 +131,7 @@ func cmdEditCandidacy(cmd *cobra.Command, args []string) error {
Details: viper.GetString(FlagDetails), Details: viper.GetString(FlagDetails),
} }
tx := stake.NewMsgEditCandidacy(pk, description) tx := stake.NewMsgEditCandidacy(addr, description)
return doTx(tx) return doTx(tx)
} }
@ -135,12 +141,12 @@ func cmdDelegate(cmd *cobra.Command, args []string) error {
return err return err
} }
pk, err := GetPubKey(viper.GetString(FlagPubKey)) addr, err := GetAddress(viper.GetString(FlagAddress))
if err != nil { if err != nil {
return err return err
} }
tx := stake.NewMsgDelegate(amount, pk) tx := stake.NewMsgDelegate(addr, amount)
return doTx(tx) 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 { if err != nil {
return err return err
} }
tx := stake.NewMsgUnbond(sharesStr, pk) tx := stake.NewMsgUnbond(addr, sharesStr)
return doTx(tx) return doTx(tx)
} }
//______________________________________________________________________________________
// GetPubKey - create the pubkey from a pubkey string // GetPubKey - create the pubkey from a pubkey string
func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) { func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) {
@ -193,7 +201,19 @@ func GetPubKey(pubKeyStr string) (pk crypto.PubKey, err error) {
return 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 // XXX consolidate to client
func doTx(tx []byte) { func doTx(tx []byte) {

View File

@ -249,7 +249,7 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s
} }
// Account new shares, save // Account new shares, save
err := bond.BondCoins(candidate, tx.Bond, tr) err := tr.BondCoins(bond, candidate, tx.Bond)
if err != nil { if err != nil {
return err return err
} }
@ -259,6 +259,37 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s
return nil 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 { func (tr transact) unbond(tx MsgUnbond) sdk.Error {
// check if bond has any shares in it unbond // check if bond has any shares in it unbond

View File

@ -17,7 +17,7 @@ import (
func initAccounts(n int, amount int64) ([]sdk.Address, map[string]int64) { func initAccounts(n int, amount int64) ([]sdk.Address, map[string]int64) {
accStore := map[string]int64{} accStore := map[string]int64{}
senders := newActors(n) senders := newAddrs(n)
for _, sender := range senders { for _, sender := range senders {
accStore[string(sender.Address)] = amount accStore[string(sender.Address)] = amount
} }
@ -49,9 +49,9 @@ func newMsgUnbond(shares string, pubKey crypto.PubKey) MsgUnbond {
func paramsNoInflation() Params { func paramsNoInflation() Params {
return Params{ return Params{
InflationRateChange: sdk.Zero, InflationRateChange: sdk.ZeroRat,
InflationMax: sdk.Zero, InflationMax: sdk.ZeroRat,
InflationMin: sdk.Zero, InflationMin: sdk.ZeroRat,
GoalBonded: sdk.New(67, 100), GoalBonded: sdk.New(67, 100),
MaxVals: 100, MaxVals: 100,
BondDenom: "fermion", BondDenom: "fermion",

View File

@ -8,6 +8,9 @@ import (
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
) )
// name to idetify transaction types
var Name = "stake"
//Verify interface at compile time //Verify interface at compile time
var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{} var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{}
@ -25,7 +28,7 @@ func NewMsgAddr(address sdk.Address) MsgAddr {
} }
// nolint // 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) Get(key interface{}) (value interface{}) { return nil }
func (msg MsgAddr) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} } func (msg MsgAddr) GetSigners() []sdk.Address { return []sdk.Address{msg.Address} }
func (msg MsgAddr) String() string { func (msg MsgAddr) String() string {
@ -50,7 +53,7 @@ type MsgDeclareCandidacy struct {
PubKey crypto.PubKey `json:"pubkey"` 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{ return MsgDeclareCandidacy{
MsgAddr: NewMsgAddr(address), MsgAddr: NewMsgAddr(address),
Description: description, Description: description,
@ -167,10 +170,10 @@ type MsgUnbond struct {
Shares string `json:"shares"` Shares string `json:"shares"`
} }
func NewMsgUnbond(bond sdk.Coin, address sdk.Address) MsgDelegate { func NewMsgUnbond(address sdk.Address, shares string) MsgUnbond {
return MsgDelegate{ return MsgUnbond{
MsgAddr: NewMsgAddr(address), MsgAddr: NewMsgAddr(address),
Bond: bond, // Shares: shares, Shares: shares,
} }
} }

View File

@ -260,34 +260,3 @@ type DelegatorBond struct {
Address sdk.Address `json:"pub_key"` Address sdk.Address `json:"pub_key"`
Shares sdk.Rat `json:"shares"` 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
}