refactor, staking uses addresses instead of pubkey
staking refactoring working working
This commit is contained in:
parent
292e156872
commit
dc8636390c
|
@ -50,7 +50,7 @@ type Params struct {
|
|||
ReserveTax rational.Rational // Tax collected on all fees
|
||||
|
||||
MaxVals uint16 // maximum number of validators
|
||||
AllowedBondDenom string // bondable coin denomination
|
||||
BondDenom string // bondable coin denomination
|
||||
|
||||
// gas costs for txs
|
||||
GasDeclareCandidacy int64
|
||||
|
|
|
@ -34,6 +34,15 @@ func (msg SetTrendMsg) String() string {
|
|||
return fmt.Sprintf("SetTrendMsg{Sender: %v, Cool: %v}", msg.Sender, msg.Cool)
|
||||
}
|
||||
|
||||
// Get the bytes for the message signer to sign on
|
||||
func (msg SetTrendMsg) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// Validate Basic is used to quickly disqualify obviously invalid messages quickly
|
||||
func (msg SetTrendMsg) ValidateBasic() sdk.Error {
|
||||
if len(msg.Sender) == 0 {
|
||||
|
@ -48,15 +57,6 @@ func (msg SetTrendMsg) ValidateBasic() sdk.Error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// Get the bytes for the message signer to sign on
|
||||
func (msg SetTrendMsg) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
//_______________________________________________________________________
|
||||
|
||||
// A message type to quiz how cool you are. these fields are can be entirely
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/big"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -57,7 +56,7 @@ func NewRat(Numerator int64, Denominator ...int64) Rat {
|
|||
}
|
||||
|
||||
//NewFromDecimal - create a rational from decimal string or integer string
|
||||
func NewRatFromDecimal(decimalStr string) (f Rat, err error) {
|
||||
func NewRatFromDecimal(decimalStr string) (f Rat, err Error) {
|
||||
|
||||
// first extract any negative symbol
|
||||
neg := false
|
||||
|
@ -73,23 +72,23 @@ func NewRatFromDecimal(decimalStr string) (f Rat, err error) {
|
|||
switch len(str) {
|
||||
case 1:
|
||||
if len(str[0]) == 0 {
|
||||
return f, errors.New("not a decimal string")
|
||||
return f, NewError(CodeUnknownRequest, "not a decimal string")
|
||||
}
|
||||
numStr = str[0]
|
||||
case 2:
|
||||
if len(str[0]) == 0 || len(str[1]) == 0 {
|
||||
return f, errors.New("not a decimal string")
|
||||
return f, NewError(CodeUnknownRequest, "not a decimal string")
|
||||
}
|
||||
numStr = str[0] + str[1]
|
||||
len := int64(len(str[1]))
|
||||
denom = new(big.Int).Exp(big.NewInt(10), big.NewInt(len), nil).Int64()
|
||||
default:
|
||||
return f, errors.New("not a decimal string")
|
||||
return f, NewError(CodeUnknownRequest, "not a decimal string")
|
||||
}
|
||||
|
||||
num, err := strconv.Atoi(numStr)
|
||||
if err != nil {
|
||||
return f, err
|
||||
num, errConv := strconv.Atoi(numStr)
|
||||
if errConv != nil {
|
||||
return f, NewError(CodeUnknownRequest, errConv.Error())
|
||||
}
|
||||
|
||||
if neg {
|
||||
|
|
|
@ -147,6 +147,7 @@ type StdSignMsg struct {
|
|||
// XXX: Alt
|
||||
}
|
||||
|
||||
// get message bytes
|
||||
func (msg StdSignMsg) Bytes() []byte {
|
||||
return StdSignBytes(msg.ChainID, msg.Sequences, msg.Fee, msg.Msg)
|
||||
}
|
||||
|
|
|
@ -107,7 +107,7 @@ func cmdDeclareCandidacy(cmd *cobra.Command, args []string) error {
|
|||
Details: viper.GetString(FlagDetails),
|
||||
}
|
||||
|
||||
tx := stake.NewTxDeclareCandidacy(amount, pk, description)
|
||||
tx := stake.NewMsgDeclareCandidacy(amount, pk, description)
|
||||
return doTx(tx)
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ func cmdEditCandidacy(cmd *cobra.Command, args []string) error {
|
|||
Details: viper.GetString(FlagDetails),
|
||||
}
|
||||
|
||||
tx := stake.NewTxEditCandidacy(pk, description)
|
||||
tx := stake.NewMsgEditCandidacy(pk, description)
|
||||
return doTx(tx)
|
||||
}
|
||||
|
||||
|
@ -140,7 +140,7 @@ func cmdDelegate(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
tx := stake.NewTxDelegate(amount, pk)
|
||||
tx := stake.NewMsgDelegate(amount, pk)
|
||||
return doTx(tx)
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ func cmdUnbond(cmd *cobra.Command, args []string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
tx := stake.NewTxUnbond(sharesStr, pk)
|
||||
tx := stake.NewMsgUnbond(sharesStr, pk)
|
||||
return doTx(tx)
|
||||
}
|
||||
|
||||
|
|
|
@ -43,46 +43,49 @@ func codeToDefaultMsg(code CodeType) string {
|
|||
//----------------------------------------
|
||||
// Error constructors
|
||||
|
||||
func ErrCandidateEmpty() error {
|
||||
func ErrCandidateEmpty() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Cannot bond to an empty candidate")
|
||||
}
|
||||
func ErrBadBondingDenom() error {
|
||||
func ErrBadBondingDenom() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Invalid coin denomination")
|
||||
}
|
||||
func ErrBadBondingAmount() error {
|
||||
func ErrBadBondingAmount() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Amount must be > 0")
|
||||
}
|
||||
func ErrNoBondingAcct() error {
|
||||
func ErrNoBondingAcct() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "No bond account for this (address, validator) pair")
|
||||
}
|
||||
func ErrCommissionNegative() error {
|
||||
func ErrCommissionNegative() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Commission must be positive")
|
||||
}
|
||||
func ErrCommissionHuge() error {
|
||||
func ErrCommissionHuge() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Commission cannot be more than 100%")
|
||||
}
|
||||
func ErrBadValidatorAddr() error {
|
||||
func ErrBadValidatorAddr() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Validator does not exist for that address")
|
||||
}
|
||||
func ErrCandidateExistsAddr() error {
|
||||
func ErrBadCandidateAddr() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Candidate does not exist for that address")
|
||||
}
|
||||
func ErrCandidateExistsAddr() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Candidate already exist, cannot re-declare candidacy")
|
||||
}
|
||||
func ErrMissingSignature() error {
|
||||
func ErrMissingSignature() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Missing signature")
|
||||
}
|
||||
func ErrBondNotNominated() error {
|
||||
func ErrBondNotNominated() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Cannot bond to non-nominated account")
|
||||
}
|
||||
func ErrNoCandidateForAddress() error {
|
||||
func ErrNoCandidateForAddress() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Validator does not exist for that address")
|
||||
}
|
||||
func ErrNoDelegatorForAddress() error {
|
||||
func ErrNoDelegatorForAddress() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Delegator does not contain validator bond")
|
||||
}
|
||||
func ErrInsufficientFunds() error {
|
||||
func ErrInsufficientFunds() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Insufficient bond shares")
|
||||
}
|
||||
func ErrBadRemoveValidator() error {
|
||||
func ErrBadRemoveValidator() sdk.Error {
|
||||
return newError(CodeInvalidValidator, "Error removing validator")
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
|
@ -9,28 +8,27 @@ import (
|
|||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
)
|
||||
|
||||
// separated for testing
|
||||
func InitState(ctx sdk.Context, mapper Mapper, key, value string) error {
|
||||
func InitState(ctx sdk.Context, mapper Mapper, key, value string) sdk.Error {
|
||||
|
||||
params := mapper.loadParams()
|
||||
switch key {
|
||||
case "allowed_bond_denom":
|
||||
params.AllowedBondDenom = value
|
||||
params.BondDenom = value
|
||||
case "max_vals", "gas_bond", "gas_unbond":
|
||||
|
||||
i, err := strconv.Atoi(value)
|
||||
if err != nil {
|
||||
return fmt.Errorf("input must be integer, Error: %v", err.Error())
|
||||
return sdk.ErrUnknownRequest(fmt.Sprintf("input must be integer, Error: %v", err.Error()))
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "max_vals":
|
||||
if i < 0 {
|
||||
return errors.New("cannot designate negative max validators")
|
||||
return sdk.ErrUnknownRequest("cannot designate negative max validators")
|
||||
}
|
||||
params.MaxVals = uint16(i)
|
||||
case "gas_bond":
|
||||
|
@ -53,112 +51,98 @@ func NewHandler(mapper Mapper, ck bank.CoinKeeper) sdk.Handler {
|
|||
|
||||
params := mapper.loadParams()
|
||||
|
||||
res := msg.ValidateBasic().Result()
|
||||
if res.Code != sdk.CodeOK {
|
||||
return res
|
||||
}
|
||||
sender, err := getTxSender(ctx)
|
||||
err := msg.ValidateBasic()
|
||||
if err != nil {
|
||||
return
|
||||
return err.Result() // TODO should also return gasUsed?
|
||||
}
|
||||
signers := msg.GetSigners()
|
||||
if len(signers) != 1 {
|
||||
return sdk.ErrUnauthorized("there can only be one signer for staking transaction").Result()
|
||||
}
|
||||
sender := signers[0]
|
||||
|
||||
transact := NewTransact(ctx, ck)
|
||||
transact := newTransact(ctx, sender, mapper, ck)
|
||||
|
||||
// Run the transaction
|
||||
switch _tx := tx.Unwrap().(type) {
|
||||
case TxDeclareCandidacy:
|
||||
switch msg := msg.(type) {
|
||||
case MsgDeclareCandidacy:
|
||||
res := transact.declareCandidacy(msg).Result()
|
||||
if !ctx.IsCheckTx() {
|
||||
res.GasUsed = params.GasDeclareCandidacy
|
||||
}
|
||||
return res, transact.declareCandidacy(_tx)
|
||||
case TxEditCandidacy:
|
||||
return res
|
||||
case MsgEditCandidacy:
|
||||
res := transact.editCandidacy(msg).Result()
|
||||
if !ctx.IsCheckTx() {
|
||||
res.GasUsed = params.GasEditCandidacy
|
||||
}
|
||||
return res, transact.editCandidacy(_tx)
|
||||
case TxDelegate:
|
||||
return res
|
||||
case MsgDelegate:
|
||||
res := transact.delegate(msg).Result()
|
||||
if !ctx.IsCheckTx() {
|
||||
res.GasUsed = params.GasDelegate
|
||||
}
|
||||
return res, transact.delegate(_tx)
|
||||
case TxUnbond:
|
||||
//context with hold account permissions
|
||||
return res
|
||||
case MsgUnbond:
|
||||
res := transact.unbond(msg).Result()
|
||||
if !ctx.IsCheckTx() {
|
||||
params := loadParams(store)
|
||||
res.GasUsed = params.GasUnbond
|
||||
}
|
||||
return res, transact.unbond(_tx)
|
||||
return res
|
||||
default:
|
||||
return sdk.ErrUnknownTxType(msgType)
|
||||
return sdk.ErrTxParse("invalid message parse in staking module").Result()
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// get the sender from the ctx and ensure it matches the tx pubkey
|
||||
func getTxSender(ctx sdk.Context) (sender crypto.Address, err error) {
|
||||
senders := ctx.GetPermissions("", auth.NameSigs)
|
||||
if len(senders) != 1 {
|
||||
return sender, ErrMissingSignature()
|
||||
}
|
||||
return senders[0], nil
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// common fields to all transactions
|
||||
type transact struct {
|
||||
ctx sdk.Context
|
||||
sender crypto.Address
|
||||
mapper Mapper
|
||||
coinKeeper bank.CoinKeeper
|
||||
params Params
|
||||
gs *GlobalState
|
||||
isCheckTx sdk.Context
|
||||
}
|
||||
|
||||
func newTransact(ctx sdk.Context, sender sdk.Address, mapper Mapper, ck bank.CoinKeeper) transact {
|
||||
return transact{
|
||||
ctx: ctx,
|
||||
sender: sender,
|
||||
mapper: mapper,
|
||||
coinKeeper: ck,
|
||||
params: mapper.loadParams(),
|
||||
gs: mapper.loadGlobalState(),
|
||||
isCheckTx: ctx.IsCheckTx(),
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
// helper functions
|
||||
// TODO move from deliver with new SDK should only be dependant on store to send coins in NEW SDK
|
||||
|
||||
// move a candidates asset pool from bonded to unbonded pool
|
||||
func (tr transact) bondedToUnbondedPool(candidate *Candidate) error {
|
||||
func (tr transact) bondedToUnbondedPool(candidate *Candidate) {
|
||||
|
||||
// replace bonded shares with unbonded shares
|
||||
tokens := tr.gs.removeSharesBonded(candidate.Assets)
|
||||
candidate.Assets = tr.gs.addTokensUnbonded(tokens)
|
||||
candidate.Status = Unbonded
|
||||
|
||||
return tr.transfer(tr.params.HoldBonded, tr.params.HoldUnbonded,
|
||||
sdk.Coins{{tr.params.AllowedBondDenom, tokens}})
|
||||
}
|
||||
|
||||
// move a candidates asset pool from unbonded to bonded pool
|
||||
func (tr transact) unbondedToBondedPool(candidate *Candidate) error {
|
||||
func (tr transact) unbondedToBondedPool(candidate *Candidate) {
|
||||
|
||||
// replace bonded shares with unbonded shares
|
||||
// replace unbonded shares with bonded shares
|
||||
tokens := tr.gs.removeSharesUnbonded(candidate.Assets)
|
||||
candidate.Assets = tr.gs.addTokensBonded(tokens)
|
||||
candidate.Status = Bonded
|
||||
|
||||
return tr.transfer(tr.params.HoldUnbonded, tr.params.HoldBonded,
|
||||
sdk.Coins{{tr.params.AllowedBondDenom, tokens}})
|
||||
}
|
||||
|
||||
// return an error if the bonds coins are incorrect
|
||||
func checkDenom(mapper Mapper, tx BondUpdate) error {
|
||||
if tx.Bond.Denom != mapper.loadParams().AllowedBondDenom {
|
||||
return fmt.Errorf("Invalid coin denomination")
|
||||
func checkDenom(mapper Mapper, bond sdk.Coin) sdk.Error {
|
||||
if bond.Denom != mapper.loadParams().BondDenom {
|
||||
return ErrBadBondingDenom()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -167,48 +151,42 @@ func checkDenom(mapper Mapper, tx BondUpdate) error {
|
|||
|
||||
// These functions assume everything has been authenticated,
|
||||
// now we just perform action and save
|
||||
func (tr transact) declareCandidacy(tx TxDeclareCandidacy) error {
|
||||
|
||||
func (tr transact) declareCandidacy(tx MsgDeclareCandidacy) sdk.Error {
|
||||
|
||||
// check to see if the pubkey or sender has been registered before
|
||||
if tr.mapper.loadCandidate(tx.PubKey) != nil {
|
||||
return fmt.Errorf("cannot bond to pubkey which is already declared candidacy"+
|
||||
" PubKey %v already registered with %v candidate address",
|
||||
candidate.PubKey, candidate.Owner)
|
||||
if tr.mapper.loadCandidate(tx.Address) != nil {
|
||||
return ErrCandidateExistsAddr()
|
||||
}
|
||||
err := checkDenom(tx.BondUpdate, tr.mapper)
|
||||
err := checkDenom(tr.mapper, tx.Bond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tr.IsCheckTx {
|
||||
if tr.ctx.IsCheckTx() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// create and save the empty candidate
|
||||
bond := tr.mapper.loadCandidate(tx.PubKey)
|
||||
if bond != nil {
|
||||
return ErrCandidateExistsAddr()
|
||||
}
|
||||
candidate := NewCandidate(tx.PubKey, tr.sender, tx.Description)
|
||||
tr.mapper.saveCandidate(candidate)
|
||||
|
||||
// move coins from the tr.sender account to a (self-bond) delegator account
|
||||
// the candidate account and global shares are updated within here
|
||||
txDelegate := TxDelegate{tx.BondUpdate}
|
||||
txDelegate := NewMsgDelegate(tx.Address, tx.Bond)
|
||||
return tr.delegateWithCandidate(txDelegate, candidate)
|
||||
}
|
||||
|
||||
func (tr transact) editCandidacy(tx TxEditCandidacy) error {
|
||||
func (tr transact) editCandidacy(tx MsgEditCandidacy) sdk.Error {
|
||||
|
||||
// candidate must already be registered
|
||||
if tr.mapper.loadCandidate(tx.PubKey) == nil { // does PubKey exist
|
||||
return fmt.Errorf("cannot delegate to non-existant PubKey %v", tx.PubKey)
|
||||
if tr.mapper.loadCandidate(tx.Address) == nil {
|
||||
return ErrBadCandidateAddr()
|
||||
}
|
||||
if tr.IsCheckTx {
|
||||
if tr.ctx.IsCheckTx() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the pubKey bond account
|
||||
candidate := tr.mapper.loadCandidate(tx.PubKey)
|
||||
candidate := tr.mapper.loadCandidate(tx.Address)
|
||||
if candidate == nil {
|
||||
return ErrBondNotNominated()
|
||||
}
|
||||
|
@ -234,28 +212,28 @@ func (tr transact) editCandidacy(tx TxEditCandidacy) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (tr transact) delegate(tx TxDelegate) error {
|
||||
func (tr transact) delegate(tx MsgDelegate) sdk.Error {
|
||||
|
||||
if tr.mapper.loadCandidate(tx.PubKey) == nil { // does PubKey exist
|
||||
return fmt.Errorf("cannot delegate to non-existant PubKey %v", tx.PubKey)
|
||||
if tr.mapper.loadCandidate(tx.Address) == nil { // does PubKey exist
|
||||
return ErrBadCandidateAddr()
|
||||
}
|
||||
err := checkDenom(tx.BondUpdate, tr.mapper)
|
||||
err := checkDenom(tr.mapper, tx.Bond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if tr.IsCheckTx {
|
||||
if tr.ctx.IsCheckTx() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Get the pubKey bond account
|
||||
candidate := tr.mapper.loadCandidate(tx.PubKey)
|
||||
candidate := tr.mapper.loadCandidate(tx.Address)
|
||||
if candidate == nil {
|
||||
return ErrBondNotNominated()
|
||||
}
|
||||
return tr.delegateWithCandidate(tx, candidate)
|
||||
}
|
||||
|
||||
func (tr transact) delegateWithCandidate(tx TxDelegate, candidate *Candidate) error {
|
||||
func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) sdk.Error {
|
||||
|
||||
if candidate.Status == Revoked { //candidate has been withdrawn
|
||||
return ErrBondNotNominated()
|
||||
|
@ -268,37 +246,33 @@ func (tr transact) delegateWithCandidate(tx TxDelegate, candidate *Candidate) er
|
|||
poolAccount = tr.params.HoldUnbonded
|
||||
}
|
||||
|
||||
// XXX refactor all steps like this into GlobalState.addBondedTokens()
|
||||
// Move coins from the delegator account to the bonded pool account
|
||||
err := tr.transfer(tr.sender, poolAccount, sdk.Coins{tx.Bond})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Get or create the delegator bond
|
||||
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.PubKey)
|
||||
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
|
||||
if bond == nil {
|
||||
bond = &DelegatorBond{
|
||||
PubKey: tx.PubKey,
|
||||
PubKey: tx.Address,
|
||||
Shares: sdk.ZeroRat,
|
||||
}
|
||||
}
|
||||
|
||||
// Account new shares, save
|
||||
bond.Shares = bond.Shares.Add(candidate.addTokens(tx.Bond.Amount, tr.gs))
|
||||
tr.mapper.saveCandidate(candidate)
|
||||
err := bond.BondTokens(candidate, tx.Bond, tr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tr.mapper.saveDelegatorBond(tr.sender, bond)
|
||||
tr.mapper.saveCandidate(candidate)
|
||||
tr.mapper.saveGlobalState(tr.gs)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tr transact) unbond(tx TxUnbond) error {
|
||||
func (tr transact) unbond(tx MsgUnbond) sdk.Error {
|
||||
|
||||
// check if bond has any shares in it unbond
|
||||
existingBond := tr.mapper.loadDelegatorBond(tr.sender, tx.PubKey)
|
||||
existingBond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
|
||||
sharesStr := viper.GetString(tx.Shares)
|
||||
if existingBond.Shares.LT(sdk.ZeroRat) { // bond shares < tx shares
|
||||
return errors.New("no shares in account to unbond")
|
||||
return ErrInsufficientFunds()
|
||||
}
|
||||
|
||||
// if shares set to special case Max then we're good
|
||||
|
@ -315,10 +289,12 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
bond.Shares, tx.Shares)
|
||||
}
|
||||
}
|
||||
// XXX end of old checkTx
|
||||
if tr.ctx.IsCheckTx() {
|
||||
return nil
|
||||
}
|
||||
|
||||
// get delegator bond
|
||||
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.PubKey)
|
||||
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
|
||||
if bond == nil {
|
||||
return ErrNoDelegatorForAddress()
|
||||
}
|
||||
|
@ -328,7 +304,6 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
if tx.Shares == "MAX" {
|
||||
shares = bond.Shares
|
||||
} else {
|
||||
var err error
|
||||
shares, err = sdk.NewRatFromDecimal(tx.Shares)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -342,7 +317,7 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
bond.Shares = bond.Shares.Sub(shares)
|
||||
|
||||
// get pubKey candidate
|
||||
candidate := tr.mapper.loadCandidate(tx.PubKey)
|
||||
candidate := tr.mapper.loadCandidate(tx.Address)
|
||||
if candidate == nil {
|
||||
return ErrNoCandidateForAddress()
|
||||
}
|
||||
|
@ -358,7 +333,7 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
}
|
||||
|
||||
// remove the bond
|
||||
tr.mapper.removeDelegatorBond(tr.sender, tx.PubKey)
|
||||
tr.mapper.removeDelegatorBond(tr.sender, tx.Address)
|
||||
} else {
|
||||
tr.mapper.saveDelegatorBond(tr.sender, bond)
|
||||
}
|
||||
|
@ -373,7 +348,7 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
|
||||
returnCoins := candidate.removeShares(shares, tr.gs)
|
||||
err := tr.transfer(poolAccount, tr.sender,
|
||||
sdk.Coins{{tr.params.AllowedBondDenom, returnCoins}})
|
||||
sdk.Coins{{tr.params.BondDenom, returnCoins}})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -383,10 +358,7 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
|
||||
// change the share types to unbonded if they were not already
|
||||
if candidate.Status == Bonded {
|
||||
err = tr.bondedToUnbondedPool(candidate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tr.bondedToUnbondedPool(candidate)
|
||||
}
|
||||
|
||||
// lastly update the status
|
||||
|
@ -395,7 +367,7 @@ func (tr transact) unbond(tx TxUnbond) error {
|
|||
|
||||
// deduct shares from the candidate and save
|
||||
if candidate.Liabilities.IsZero() {
|
||||
tr.mapper.removeCandidate(tx.PubKey)
|
||||
tr.mapper.removeCandidate(tx.Address)
|
||||
} else {
|
||||
tr.mapper.saveCandidate(candidate)
|
||||
}
|
||||
|
|
|
@ -24,25 +24,24 @@ func initAccounts(n int, amount int64) ([]sdk.Address, map[string]int64) {
|
|||
return senders, accStore
|
||||
}
|
||||
|
||||
func newTxDeclareCandidacy(amt int64, pubKey crypto.PubKey) TxDeclareCandidacy {
|
||||
return TxDeclareCandidacy{
|
||||
BondUpdate{
|
||||
PubKey: pubKey,
|
||||
Bond: coin.Coin{"fermion", amt},
|
||||
},
|
||||
func newTestMsgDeclareCandidacy(amt int64, pubKey crypto.PubKey, address sdk.Address) MsgDeclareCandidacy {
|
||||
return MsgDeclareCandidacy{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
PubKey: pubKey,
|
||||
Bond: coin.Coin{"fermion", amt},
|
||||
Description{},
|
||||
}
|
||||
}
|
||||
|
||||
func newTxDelegate(amt int64, pubKey crypto.PubKey) TxDelegate {
|
||||
return TxDelegate{BondUpdate{
|
||||
PubKey: pubKey,
|
||||
Bond: coin.Coin{"fermion", amt},
|
||||
}}
|
||||
func newTestMsgDelegate(amt int64, address sdk.Address) MsgDelegate {
|
||||
return MsgDelegate{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
Bond: coin.Coin{"fermion", amt},
|
||||
}
|
||||
}
|
||||
|
||||
func newTxUnbond(shares string, pubKey crypto.PubKey) TxUnbond {
|
||||
return TxUnbond{
|
||||
func newMsgUnbond(shares string, pubKey crypto.PubKey) MsgUnbond {
|
||||
return MsgUnbond{
|
||||
PubKey: pubKey,
|
||||
Shares: shares,
|
||||
}
|
||||
|
@ -50,14 +49,12 @@ func newTxUnbond(shares string, pubKey crypto.PubKey) TxUnbond {
|
|||
|
||||
func paramsNoInflation() Params {
|
||||
return Params{
|
||||
HoldBonded: sdk.NewActor(stakingModuleName, []byte("77777777777777777777777777777777")),
|
||||
HoldUnbonded: sdk.NewActor(stakingModuleName, []byte("88888888888888888888888888888888")),
|
||||
InflationRateChange: sdk.Zero,
|
||||
InflationMax: sdk.Zero,
|
||||
InflationMin: sdk.Zero,
|
||||
GoalBonded: sdk.New(67, 100),
|
||||
MaxVals: 100,
|
||||
AllowedBondDenom: "fermion",
|
||||
BondDenom: "fermion",
|
||||
GasDeclareCandidacy: 20,
|
||||
GasEditCandidacy: 20,
|
||||
GasDelegate: 20,
|
||||
|
@ -72,7 +69,7 @@ func newTestTransact(t, sender sdk.Address, isCheckTx bool) transact {
|
|||
newTransact(ctx, sender, mapper, coinKeeper)
|
||||
}
|
||||
|
||||
func TestDuplicatesTxDeclareCandidacy(t *testing.T) {
|
||||
func TestDuplicatesMsgDeclareCandidacy(t *testing.T) {
|
||||
senders, accStore := initAccounts(2, 1000) // for accounts
|
||||
|
||||
deliverer := newDeliver(t, senders[0], accStore)
|
||||
|
@ -81,9 +78,9 @@ func TestDuplicatesTxDeclareCandidacy(t *testing.T) {
|
|||
sender: senders[0],
|
||||
}
|
||||
|
||||
txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0])
|
||||
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
||||
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
assert.NoError(t, got, "expected no error on runTxDeclareCandidacy")
|
||||
assert.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
||||
|
||||
// one sender can bond to two different pubKeys
|
||||
txDeclareCandidacy.PubKey = pks[1]
|
||||
|
@ -97,21 +94,21 @@ func TestDuplicatesTxDeclareCandidacy(t *testing.T) {
|
|||
assert.NotNil(t, err, "expected error on checkTx")
|
||||
}
|
||||
|
||||
func TestIncrementsTxDelegate(t *testing.T) {
|
||||
func TestIncrementsMsgDelegate(t *testing.T) {
|
||||
initSender := int64(1000)
|
||||
senders, accStore := initAccounts(1, initSender) // for accounts
|
||||
deliverer := newDeliver(t, senders[0], accStore)
|
||||
|
||||
// first declare candidacy
|
||||
bondAmount := int64(10)
|
||||
txDeclareCandidacy := newTxDeclareCandidacy(bondAmount, pks[0])
|
||||
txDeclareCandidacy := newTestMsgDeclareCandidacy(bondAmount, pks[0])
|
||||
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
assert.NoError(t, got, "expected declare candidacy tx to be ok, got %v", got)
|
||||
expectedBond := bondAmount // 1 since we send 1 at the start of loop,
|
||||
|
||||
// just send the same txbond multiple times
|
||||
holder := deliverer.params.HoldUnbonded // XXX this should be HoldBonded, new SDK updates
|
||||
txDelegate := newTxDelegate(bondAmount, pks[0])
|
||||
txDelegate := newTestMsgDelegate(bondAmount, pks[0])
|
||||
for i := 0; i < 5; i++ {
|
||||
got := deliverer.delegate(txDelegate)
|
||||
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
||||
|
@ -129,7 +126,7 @@ func TestIncrementsTxDelegate(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestIncrementsTxUnbond(t *testing.T) {
|
||||
func TestIncrementsMsgUnbond(t *testing.T) {
|
||||
initSender := int64(0)
|
||||
senders, accStore := initAccounts(1, initSender) // for accounts
|
||||
deliverer := newDeliver(t, senders[0], accStore)
|
||||
|
@ -137,7 +134,7 @@ func TestIncrementsTxUnbond(t *testing.T) {
|
|||
// set initial bond
|
||||
initBond := int64(1000)
|
||||
accStore[string(deliverer.sender.Address)] = initBond
|
||||
got := deliverer.declareCandidacy(newTxDeclareCandidacy(initBond, pks[0]))
|
||||
got := deliverer.declareCandidacy(newTestMsgDeclareCandidacy(initBond, pks[0]))
|
||||
assert.NoError(t, got, "expected initial bond tx to be ok, got %v", got)
|
||||
|
||||
// just send the same txunbond multiple times
|
||||
|
@ -145,7 +142,7 @@ func TestIncrementsTxUnbond(t *testing.T) {
|
|||
|
||||
// XXX use decimals here
|
||||
unbondShares, unbondSharesStr := int64(10), "10"
|
||||
txUndelegate := newTxUnbond(unbondSharesStr, pks[0])
|
||||
txUndelegate := newMsgUnbond(unbondSharesStr, pks[0])
|
||||
nUnbonds := 5
|
||||
for i := 0; i < nUnbonds; i++ {
|
||||
got := deliverer.unbond(txUndelegate)
|
||||
|
@ -174,7 +171,7 @@ func TestIncrementsTxUnbond(t *testing.T) {
|
|||
}
|
||||
for _, c := range errorCases {
|
||||
unbondShares := strconv.Itoa(int(c))
|
||||
txUndelegate := newTxUnbond(unbondShares, pks[0])
|
||||
txUndelegate := newMsgUnbond(unbondShares, pks[0])
|
||||
got = deliverer.unbond(txUndelegate)
|
||||
assert.Error(t, got, "expected unbond tx to fail")
|
||||
}
|
||||
|
@ -182,17 +179,17 @@ func TestIncrementsTxUnbond(t *testing.T) {
|
|||
leftBonded := initBond - unbondShares*int64(nUnbonds)
|
||||
|
||||
// should be unable to unbond one more than we have
|
||||
txUndelegate = newTxUnbond(strconv.Itoa(int(leftBonded)+1), pks[0])
|
||||
txUndelegate = newMsgUnbond(strconv.Itoa(int(leftBonded)+1), pks[0])
|
||||
got = deliverer.unbond(txUndelegate)
|
||||
assert.Error(t, got, "expected unbond tx to fail")
|
||||
|
||||
// should be able to unbond just what we have
|
||||
txUndelegate = newTxUnbond(strconv.Itoa(int(leftBonded)), pks[0])
|
||||
txUndelegate = newMsgUnbond(strconv.Itoa(int(leftBonded)), pks[0])
|
||||
got = deliverer.unbond(txUndelegate)
|
||||
assert.NoError(t, got, "expected unbond tx to pass")
|
||||
}
|
||||
|
||||
func TestMultipleTxDeclareCandidacy(t *testing.T) {
|
||||
func TestMultipleMsgDeclareCandidacy(t *testing.T) {
|
||||
initSender := int64(1000)
|
||||
senders, accStore := initAccounts(3, initSender)
|
||||
pubKeys := []crypto.PubKey{pks[0], pks[1], pks[2]}
|
||||
|
@ -200,7 +197,7 @@ func TestMultipleTxDeclareCandidacy(t *testing.T) {
|
|||
|
||||
// bond them all
|
||||
for i, sender := range senders {
|
||||
txDeclareCandidacy := newTxDeclareCandidacy(10, pubKeys[i])
|
||||
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pubKeys[i])
|
||||
deliverer.sender = sender
|
||||
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
||||
|
@ -217,7 +214,7 @@ func TestMultipleTxDeclareCandidacy(t *testing.T) {
|
|||
// unbond them all
|
||||
for i, sender := range senders {
|
||||
candidatePre := loadCandidate(deliverer.store, pubKeys[i])
|
||||
txUndelegate := newTxUnbond("10", pubKeys[i])
|
||||
txUndelegate := newMsgUnbond("10", pubKeys[i])
|
||||
deliverer.sender = sender
|
||||
got := deliverer.unbond(txUndelegate)
|
||||
assert.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
||||
|
@ -233,19 +230,19 @@ func TestMultipleTxDeclareCandidacy(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMultipleTxDelegate(t *testing.T) {
|
||||
func TestMultipleMsgDelegate(t *testing.T) {
|
||||
accounts, accStore := initAccounts(3, 1000)
|
||||
sender, delegators := accounts[0], accounts[1:]
|
||||
deliverer := newDeliver(t, sender, accStore)
|
||||
|
||||
//first make a candidate
|
||||
txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0])
|
||||
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
||||
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
require.NoError(t, got, "expected tx to be ok, got %v", got)
|
||||
|
||||
// delegate multiple parties
|
||||
for i, delegator := range delegators {
|
||||
txDelegate := newTxDelegate(10, pks[0])
|
||||
txDelegate := newTestMsgDelegate(10, pks[0])
|
||||
deliverer.sender = delegator
|
||||
got := deliverer.delegate(txDelegate)
|
||||
require.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
||||
|
@ -257,7 +254,7 @@ func TestMultipleTxDelegate(t *testing.T) {
|
|||
|
||||
// unbond them all
|
||||
for i, delegator := range delegators {
|
||||
txUndelegate := newTxUnbond("10", pks[0])
|
||||
txUndelegate := newMsgUnbond("10", pks[0])
|
||||
deliverer.sender = delegator
|
||||
got := deliverer.unbond(txUndelegate)
|
||||
require.NoError(t, got, "expected tx %d to be ok, got %v", i, got)
|
||||
|
@ -274,21 +271,21 @@ func TestVoidCandidacy(t *testing.T) {
|
|||
deliverer := newDeliver(t, sender, accStore)
|
||||
|
||||
// create the candidate
|
||||
txDeclareCandidacy := newTxDeclareCandidacy(10, pks[0])
|
||||
txDeclareCandidacy := newTestMsgDeclareCandidacy(10, pks[0])
|
||||
got := deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
require.NoError(t, got, "expected no error on runTxDeclareCandidacy")
|
||||
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
||||
|
||||
// bond a delegator
|
||||
txDelegate := newTxDelegate(10, pks[0])
|
||||
txDelegate := newTestMsgDelegate(10, pks[0])
|
||||
deliverer.sender = delegator
|
||||
got = deliverer.delegate(txDelegate)
|
||||
require.NoError(t, got, "expected ok, got %v", got)
|
||||
|
||||
// unbond the candidates bond portion
|
||||
txUndelegate := newTxUnbond("10", pks[0])
|
||||
txUndelegate := newMsgUnbond("10", pks[0])
|
||||
deliverer.sender = sender
|
||||
got = deliverer.unbond(txUndelegate)
|
||||
require.NoError(t, got, "expected no error on runTxDeclareCandidacy")
|
||||
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
||||
|
||||
// test that this pubkey cannot yet be bonded too
|
||||
deliverer.sender = delegator
|
||||
|
@ -297,7 +294,7 @@ func TestVoidCandidacy(t *testing.T) {
|
|||
|
||||
// test that the delegator can still withdraw their bonds
|
||||
got = deliverer.unbond(txUndelegate)
|
||||
require.NoError(t, got, "expected no error on runTxDeclareCandidacy")
|
||||
require.NoError(t, got, "expected no error on runMsgDeclareCandidacy")
|
||||
|
||||
// verify that the pubkey can now be reused
|
||||
got = deliverer.declareCandidacy(txDeclareCandidacy)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
@ -10,9 +8,9 @@ import (
|
|||
//nolint
|
||||
var (
|
||||
// Keys for store prefixes
|
||||
CandidatesPubKeysKey = []byte{0x01} // key for all candidates' pubkeys
|
||||
ParamKey = []byte{0x02} // key for global parameters relating to staking
|
||||
GlobalStateKey = []byte{0x03} // key for global parameters relating to staking
|
||||
CandidatesAddrKey = []byte{0x01} // key for all candidates' addresses
|
||||
ParamKey = []byte{0x02} // key for global parameters relating to staking
|
||||
GlobalStateKey = []byte{0x03} // key for global parameters relating to staking
|
||||
|
||||
// Key prefixes
|
||||
CandidateKeyPrefix = []byte{0x04} // prefix for each key to a candidate
|
||||
|
@ -22,29 +20,29 @@ var (
|
|||
DelegatorBondsKeyPrefix = []byte{0x08} // prefix for each key to a delegator's bond
|
||||
)
|
||||
|
||||
// GetCandidateKey - get the key for the candidate with pubKey
|
||||
func GetCandidateKey(pubKey crypto.PubKey) []byte {
|
||||
return append(CandidateKeyPrefix, pubKey.Bytes()...)
|
||||
// GetCandidateKey - get the key for the candidate with address
|
||||
func GetCandidateKey(address sdk.Address) []byte {
|
||||
return append(CandidateKeyPrefix, address.Bytes()...)
|
||||
}
|
||||
|
||||
// GetValidatorKey - get the key for the validator used in the power-store
|
||||
func GetValidatorKey(pubKey crypto.PubKey, power sdk.Rational) []byte {
|
||||
b, _ := cdc.MarshalJSON(power) // TODO need to handle error here?
|
||||
return append(ValidatorKeyPrefix, append(b, pubKey.Bytes()...)...) // TODO does this need prefix if its in its own store
|
||||
func GetValidatorKey(address sdk.Address, power sdk.Rational) []byte {
|
||||
b, _ := cdc.MarshalJSON(power) // TODO need to handle error here?
|
||||
return append(ValidatorKeyPrefix, append(b, address.Bytes()...)...) // TODO does this need prefix if its in its own store
|
||||
}
|
||||
|
||||
// GetValidatorUpdatesKey - get the key for the validator used in the power-store
|
||||
func GetValidatorUpdatesKey(pubKey crypto.PubKey) []byte {
|
||||
return append(ValidatorUpdatesKeyPrefix, pubKey.Bytes()...) // TODO does this need prefix if its in its own store
|
||||
func GetValidatorUpdatesKey(address sdk.Address) []byte {
|
||||
return append(ValidatorUpdatesKeyPrefix, address.Bytes()...) // TODO does this need prefix if its in its own store
|
||||
}
|
||||
|
||||
// GetDelegatorBondKey - get the key for delegator bond with candidate
|
||||
func GetDelegatorBondKey(delegator crypto.Address, candidate crypto.PubKey) []byte {
|
||||
func GetDelegatorBondKey(delegator, candidate sdk.Address) []byte {
|
||||
return append(GetDelegatorBondKeyPrefix(delegator), candidate.Bytes()...)
|
||||
}
|
||||
|
||||
// GetDelegatorBondKeyPrefix - get the prefix for a delegator for all candidates
|
||||
func GetDelegatorBondKeyPrefix(delegator crypto.Address) []byte {
|
||||
func GetDelegatorBondKeyPrefix(delegator sdk.Address) []byte {
|
||||
res, err := cdc.MarshalJSON(&delegator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -53,7 +51,7 @@ func GetDelegatorBondKeyPrefix(delegator crypto.Address) []byte {
|
|||
}
|
||||
|
||||
// GetDelegatorBondsKey - get the key for list of all the delegator's bonds
|
||||
func GetDelegatorBondsKey(delegator crypto.Address) []byte {
|
||||
func GetDelegatorBondsKey(delegator sdk.Address) []byte {
|
||||
res, err := cdc.MarshalJSON(&delegator)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -69,20 +67,15 @@ type Mapper struct {
|
|||
cdc *wire.Codec
|
||||
}
|
||||
|
||||
func NewMapper(ctx sdk.Context, key sdk.StoreKey) Mapper {
|
||||
cdc := wire.NewCodec()
|
||||
cdc.RegisterInterface((*sdk.Rational)(nil), nil) // XXX make like crypto.RegisterWire()
|
||||
cdc.RegisterConcrete(sdk.Rat{}, "rat", nil)
|
||||
crypto.RegisterWire(cdc)
|
||||
|
||||
func NewMapper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey) Mapper {
|
||||
return StakeMapper{
|
||||
store: ctx.KVStore(m.key),
|
||||
cdc: cdc,
|
||||
}
|
||||
}
|
||||
|
||||
func (m Mapper) loadCandidate(pubKey crypto.PubKey) *Candidate {
|
||||
b := m.store.Get(GetCandidateKey(pubKey))
|
||||
func (m Mapper) loadCandidate(address sdk.Address) *Candidate {
|
||||
b := m.store.Get(GetCandidateKey(address))
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
|
@ -97,28 +90,28 @@ func (m Mapper) loadCandidate(pubKey crypto.PubKey) *Candidate {
|
|||
func (m Mapper) saveCandidate(candidate *Candidate) {
|
||||
|
||||
// XXX should only remove validator if we know candidate is a validator
|
||||
removeValidator(m.store, candidate.PubKey)
|
||||
validator := &Validator{candidate.PubKey, candidate.VotingPower}
|
||||
removeValidator(m.store, candidate.Address)
|
||||
validator := &Validator{candidate.Address, candidate.VotingPower}
|
||||
updateValidator(m.store, validator)
|
||||
|
||||
b, err := cdc.MarshalJSON(*candidate)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.store.Set(GetCandidateKey(candidate.PubKey), b)
|
||||
m.store.Set(GetCandidateKey(candidate.Address), b)
|
||||
}
|
||||
|
||||
func (m Mapper) removeCandidate(pubKey crypto.PubKey) {
|
||||
func (m Mapper) removeCandidate(address sdk.Address) {
|
||||
|
||||
// XXX should only remove validator if we know candidate is a validator
|
||||
removeValidator(m.store, pubKey)
|
||||
m.store.Delete(GetCandidateKey(pubKey))
|
||||
removeValidator(m.store, address)
|
||||
m.store.Delete(GetCandidateKey(address))
|
||||
}
|
||||
|
||||
//___________________________________________________________________________
|
||||
|
||||
//func loadValidator(m.store sdk.KVStore, pubKey crypto.PubKey, votingPower sdk.Rational) *Validator {
|
||||
//b := m.store.Get(GetValidatorKey(pubKey, votingPower))
|
||||
//func loadValidator(m.store sdk.KVStore, address sdk.Address, votingPower sdk.Rational) *Validator {
|
||||
//b := m.store.Get(GetValidatorKey(address, votingPower))
|
||||
//if b == nil {
|
||||
//return nil
|
||||
//}
|
||||
|
@ -140,25 +133,25 @@ func (m Mapper) updateValidator(validator *Validator) {
|
|||
}
|
||||
|
||||
// add to the validators to update list if necessary
|
||||
m.store.Set(GetValidatorUpdatesKey(validator.PubKey), b)
|
||||
m.store.Set(GetValidatorUpdatesKey(validator.Address), b)
|
||||
|
||||
// update the list ordered by voting power
|
||||
m.store.Set(GetValidatorKey(validator.PubKey, validator.VotingPower), b)
|
||||
m.store.Set(GetValidatorKey(validator.Address, validator.VotingPower), b)
|
||||
}
|
||||
|
||||
func (m Mapper) removeValidator(pubKey crypto.PubKey) {
|
||||
func (m Mapper) removeValidator(address sdk.Address) {
|
||||
|
||||
//add validator with zero power to the validator updates
|
||||
b, err := cdc.MarshalJSON(Validator{pubKey, sdk.ZeroRat})
|
||||
b, err := cdc.MarshalJSON(Validator{address, sdk.ZeroRat})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.store.Set(GetValidatorUpdatesKey(pubKey), b)
|
||||
m.store.Set(GetValidatorUpdatesKey(address), b)
|
||||
|
||||
// now actually delete from the validator set
|
||||
candidate := loadCandidate(m.store, pubKey)
|
||||
candidate := loadCandidate(m.store, address)
|
||||
if candidate != nil {
|
||||
m.store.Delete(GetValidatorKey(pubKey, candidate.VotingPower))
|
||||
m.store.Delete(GetValidatorKey(address, candidate.VotingPower))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -243,14 +236,14 @@ func (m Mapper) loadCandidates() (candidates Candidates) {
|
|||
//_____________________________________________________________________
|
||||
|
||||
// load the pubkeys of all candidates a delegator is delegated too
|
||||
func (m Mapper) loadDelegatorCandidates(delegator crypto.Address) (candidates []crypto.PubKey) {
|
||||
func (m Mapper) loadDelegatorCandidates(delegator sdk.Address) (candidateAddrs []sdk.Address) {
|
||||
|
||||
candidateBytes := m.store.Get(GetDelegatorBondsKey(delegator))
|
||||
if candidateBytes == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := cdc.UnmarshalJSON(candidateBytes, &candidates)
|
||||
err := cdc.UnmarshalJSON(candidateBytes, &candidateAddrs)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -259,8 +252,7 @@ func (m Mapper) loadDelegatorCandidates(delegator crypto.Address) (candidates []
|
|||
|
||||
//_____________________________________________________________________
|
||||
|
||||
func (m Mapper) loadDelegatorBond(delegator crypto.Address,
|
||||
candidate crypto.PubKey) *DelegatorBond {
|
||||
func (m Mapper) loadDelegatorBond(delegator, candidate sdk.Address) *DelegatorBond {
|
||||
|
||||
delegatorBytes := m.store.Get(GetDelegatorBondKey(delegator, candidate))
|
||||
if delegatorBytes == nil {
|
||||
|
@ -275,13 +267,13 @@ func (m Mapper) loadDelegatorBond(delegator crypto.Address,
|
|||
return bond
|
||||
}
|
||||
|
||||
func (m Mapper) saveDelegatorBond(delegator crypto.Address,
|
||||
func (m Mapper) saveDelegatorBond(delegator sdk.Address,
|
||||
bond *DelegatorBond) {
|
||||
|
||||
// if a new bond add to the list of bonds
|
||||
if loadDelegatorBond(m.store, delegator, bond.PubKey) == nil {
|
||||
if loadDelegatorBond(m.store, delegator, bond.Address) == nil {
|
||||
pks := loadDelegatorCandidates(m.store, delegator)
|
||||
pks = append(pks, (*bond).PubKey)
|
||||
pks = append(pks, (*bond).Address)
|
||||
b, err := cdc.MarshalJSON(pks)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
@ -294,11 +286,11 @@ func (m Mapper) saveDelegatorBond(delegator crypto.Address,
|
|||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
m.store.Set(GetDelegatorBondKey(delegator, bond.PubKey), b)
|
||||
m.store.Set(GetDelegatorBondKey(delegator, bond.Address), b)
|
||||
//updateDelegatorBonds(store, delegator)
|
||||
}
|
||||
|
||||
func (m Mapper) removeDelegatorBond(delegator crypto.Address, candidate crypto.PubKey) {
|
||||
func (m Mapper) removeDelegatorBond(delegator sdk.Address, candidate sdk.Address) {
|
||||
// TODO use list queries on multistore to remove iterations here!
|
||||
// first remove from the list of bonds
|
||||
pks := loadDelegatorCandidates(m.store, delegator)
|
||||
|
|
307
x/stake/tx.go
307
x/stake/tx.go
|
@ -1,52 +1,204 @@
|
|||
package stake
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
// Tx
|
||||
//--------------------------------------------------------------------------------
|
||||
|
||||
// register the tx type with its validation logic
|
||||
// make sure to use the name of the handler as the prefix in the tx type,
|
||||
// so it gets routed properly
|
||||
const (
|
||||
ByteTxDeclareCandidacy = 0x55
|
||||
ByteTxEditCandidacy = 0x56
|
||||
ByteTxDelegate = 0x57
|
||||
ByteTxUnbond = 0x58
|
||||
|
||||
TypeTxDeclareCandidacy = "staking/declareCandidacy"
|
||||
TypeTxEditCandidacy = "staking/editCandidacy"
|
||||
TypeTxDelegate = "staking/delegate"
|
||||
TypeTxUnbond = "staking/unbond"
|
||||
)
|
||||
|
||||
//func init() {
|
||||
//sdk.TxMapper.RegisterImplementation(TxDeclareCandidacy{}, TypeTxDeclareCandidacy, ByteTxDeclareCandidacy)
|
||||
//sdk.TxMapper.RegisterImplementation(TxEditCandidacy{}, TypeTxEditCandidacy, ByteTxEditCandidacy)
|
||||
//sdk.TxMapper.RegisterImplementation(TxDelegate{}, TypeTxDelegate, ByteTxDelegate)
|
||||
//sdk.TxMapper.RegisterImplementation(TxUnbond{}, TypeTxUnbond, ByteTxUnbond)
|
||||
//}
|
||||
|
||||
//Verify interface at compile time
|
||||
//var _, _, _, _ sdk.TxInner = &TxDeclareCandidacy{}, &TxEditCandidacy{}, &TxDelegate{}, &TxUnbond{}
|
||||
var _, _, _, _ sdk.Msg = &MsgDeclareCandidacy{}, &MsgEditCandidacy{}, &MsgDelegate{}, &MsgUnbond{}
|
||||
|
||||
// BondUpdate - struct for bonding or unbonding transactions
|
||||
type BondUpdate struct {
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
Bond sdk.Coin `json:"amount"`
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgAddr - struct for bonding or unbonding transactions
|
||||
type MsgAddr struct {
|
||||
Address sdk.Address `json:"address"`
|
||||
}
|
||||
|
||||
func NewMsgAddr(address sdk.Address) MsgAddr {
|
||||
return MsgAddr{
|
||||
Address: address,
|
||||
}
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (msg MsgAddr) Type() string { return "stake" }
|
||||
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 {
|
||||
return fmt.Sprintf("MsgAddr{Address: %v}", msg.Address)
|
||||
}
|
||||
|
||||
// ValidateBasic - Check for non-empty candidate, and valid coins
|
||||
func (tx BondUpdate) ValidateBasic() error {
|
||||
if tx.PubKey.Empty() {
|
||||
func (msg MsgAddr) ValidateBasic() sdk.Error {
|
||||
if msg.Address.Empty() {
|
||||
return errCandidateEmpty
|
||||
}
|
||||
coins := sdk.Coins{tx.Bond}
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgDeclareCandidacy - struct for unbonding transactions
|
||||
type MsgDeclareCandidacy struct {
|
||||
MsgAddr
|
||||
Description
|
||||
Bond sdk.Coin `json:"bond"`
|
||||
PubKey crypto.PubKey `json:"pubkey"`
|
||||
}
|
||||
|
||||
func NewMsgDeclareCandidacy(bond sdk.Coin, address sdk.Address, pubkey crypto.PubKey, description Description) MsgDeclareCandidacy {
|
||||
return MsgDeclareCandidacy{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
Description: description,
|
||||
Bond: bond,
|
||||
PubKey: PubKey,
|
||||
}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgDeclareCandidacy) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
|
||||
err := MsgAddr.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := validateCoin(msg.Bond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
empty := Description{}
|
||||
if msg.Description == empty {
|
||||
return fmt.Errorf("description must be included")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgEditCandidacy - struct for editing a candidate
|
||||
type MsgEditCandidacy struct {
|
||||
MsgAddr
|
||||
Description
|
||||
}
|
||||
|
||||
func NewMsgEditCandidacy(address sdk.Address, description Description) MsgEditCandidacy {
|
||||
return MsgEditCandidacy{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
Description: description,
|
||||
}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgEditCandidacy) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
|
||||
err := MsgAddr.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
empty := Description{}
|
||||
if msg.Description == empty {
|
||||
return fmt.Errorf("Transaction must include some information to modify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgDelegate - struct for bonding transactions
|
||||
type MsgDelegate struct {
|
||||
MsgAddr
|
||||
Bond sdk.Coin `json:"bond"`
|
||||
}
|
||||
|
||||
func NewMsgDelegate(address sdk.Address, bond sdk.Coin) MsgDelegate {
|
||||
return MsgDelegate{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
Bond: bond,
|
||||
}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgDelegate) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgDelegate) ValidateBasic() sdk.Error {
|
||||
err := MsgAddr.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err := validateCoin(msg.Bond)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
|
||||
// MsgUnbond - struct for unbonding transactions
|
||||
type MsgUnbond struct {
|
||||
MsgAddr
|
||||
Shares string `json:"shares"`
|
||||
}
|
||||
|
||||
func NewMsgUnbond(shares string, address sdk.Address) MsgDelegate {
|
||||
return MsgUnbond{
|
||||
MsgAddr: NewMsgAddr(address),
|
||||
Shares: shares,
|
||||
}
|
||||
}
|
||||
|
||||
// get the bytes for the message signer to sign on
|
||||
func (msg MsgUnbond) GetSignBytes() []byte {
|
||||
b, err := json.Marshal(msg)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
// quick validity check
|
||||
func (msg MsgUnbond) ValidateBasic() sdk.Error {
|
||||
err := MsgAddr.ValidateBasic()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if msg.Shares {
|
||||
return ErrCandidateEmpty()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
//______________________________________________________________________
|
||||
// helper
|
||||
|
||||
func validateCoin(coin coin.Coin) sdk.Error {
|
||||
coins := sdk.Coins{bond}
|
||||
if !sdk.IsValid() {
|
||||
return sdk.ErrInvalidCoins()
|
||||
}
|
||||
|
@ -55,92 +207,3 @@ func (tx BondUpdate) ValidateBasic() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxDeclareCandidacy - struct for unbonding transactions
|
||||
type TxDeclareCandidacy struct {
|
||||
BondUpdate
|
||||
Description
|
||||
}
|
||||
|
||||
// NewTxDeclareCandidacy - new TxDeclareCandidacy
|
||||
func NewTxDeclareCandidacy(bond sdk.Coin, pubKey crypto.PubKey, description Description) sdk.Tx {
|
||||
return TxDeclareCandidacy{
|
||||
BondUpdate{
|
||||
PubKey: pubKey,
|
||||
Bond: bond,
|
||||
},
|
||||
description,
|
||||
}.Wrap()
|
||||
}
|
||||
|
||||
// Wrap - Wrap a Tx as a Basecoin Tx
|
||||
func (tx TxDeclareCandidacy) Wrap() sdk.Tx { return sdk.Tx{tx} }
|
||||
|
||||
// TxEditCandidacy - struct for editing a candidate
|
||||
type TxEditCandidacy struct {
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
Description
|
||||
}
|
||||
|
||||
// NewTxEditCandidacy - new TxEditCandidacy
|
||||
func NewTxEditCandidacy(pubKey crypto.PubKey, description Description) sdk.Tx {
|
||||
return TxEditCandidacy{
|
||||
PubKey: pubKey,
|
||||
Description: description,
|
||||
}.Wrap()
|
||||
}
|
||||
|
||||
// Wrap - Wrap a Tx as a Basecoin Tx
|
||||
func (tx TxEditCandidacy) Wrap() sdk.Tx { return sdk.Tx{tx} }
|
||||
|
||||
// ValidateBasic - Check for non-empty candidate,
|
||||
func (tx TxEditCandidacy) ValidateBasic() error {
|
||||
if tx.PubKey.Empty() {
|
||||
return errCandidateEmpty
|
||||
}
|
||||
|
||||
empty := Description{}
|
||||
if tx.Description == empty {
|
||||
return fmt.Errorf("Transaction must include some information to modify")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TxDelegate - struct for bonding transactions
|
||||
type TxDelegate struct{ BondUpdate }
|
||||
|
||||
// NewTxDelegate - new TxDelegate
|
||||
func NewTxDelegate(bond sdk.Coin, pubKey crypto.PubKey) sdk.Tx {
|
||||
return TxDelegate{BondUpdate{
|
||||
PubKey: pubKey,
|
||||
Bond: bond,
|
||||
}}.Wrap()
|
||||
}
|
||||
|
||||
// Wrap - Wrap a Tx as a Basecoin Tx
|
||||
func (tx TxDelegate) Wrap() sdk.Tx { return sdk.Tx{tx} }
|
||||
|
||||
// TxUnbond - struct for unbonding transactions
|
||||
type TxUnbond struct {
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
Shares string `json:"amount"`
|
||||
}
|
||||
|
||||
// NewTxUnbond - new TxUnbond
|
||||
func NewTxUnbond(shares string, pubKey crypto.PubKey) sdk.Tx {
|
||||
return TxUnbond{
|
||||
PubKey: pubKey,
|
||||
Shares: shares,
|
||||
}.Wrap()
|
||||
}
|
||||
|
||||
// Wrap - Wrap a Tx as a Basecoin Tx
|
||||
func (tx TxUnbond) Wrap() sdk.Tx { return sdk.Tx{tx} }
|
||||
|
||||
// ValidateBasic - Check for non-empty candidate, positive shares
|
||||
func (tx TxUnbond) ValidateBasic() error {
|
||||
if tx.PubKey.Empty() {
|
||||
return errCandidateEmpty
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -24,29 +24,40 @@ var (
|
|||
coinNegNotAtoms = sdk.Coin{"foo", -10000}
|
||||
)
|
||||
|
||||
func TestBondUpdateValidateBasic(t *testing.T) {
|
||||
func TestMsgAddrValidateBasic(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
PubKey crypto.PubKey
|
||||
Bond sdk.Coin
|
||||
address sdk.Address
|
||||
wantErr bool
|
||||
}{
|
||||
{"basic good", pks[0], coinPos, false},
|
||||
{"empty delegator", crypto.PubKey{}, coinPos, true},
|
||||
{"zero coin", pks[0], coinZero, true},
|
||||
{"neg coin", pks[0], coinNeg, true},
|
||||
{"basic good", pks[0], false},
|
||||
{"empty delegator", crypto.PubKey{}, true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
tx := TxDelegate{BondUpdate{
|
||||
PubKey: tc.PubKey,
|
||||
Bond: tc.Bond,
|
||||
}}
|
||||
tx := NewMsgAddr(tc.address)
|
||||
assert.Equal(t, tc.wantErr, tx.ValidateBasic() != nil,
|
||||
"test: %v, tx.ValidateBasic: %v", tc.name, tx.ValidateBasic())
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateCoin(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
coin sdk.Coin
|
||||
wantErr bool
|
||||
}{
|
||||
{"basic good", coinPos, false},
|
||||
{"zero coin", coinZero, true},
|
||||
{"neg coin", coinNeg, true},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
assert.Equal(t, tc.wantErr, tx.validateCoin(tc.coin) != nil,
|
||||
"test: %v, tx.ValidateBasic: %v", tc.name, tx.ValidateBasic())
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllAreTx(t *testing.T) {
|
||||
|
||||
// make sure all types construct properly
|
||||
|
@ -54,23 +65,20 @@ func TestAllAreTx(t *testing.T) {
|
|||
bondAmt := 1234321
|
||||
bond := sdk.Coin{Denom: "ATOM", Amount: int64(bondAmt)}
|
||||
|
||||
// Note that Wrap is only defined on BondUpdate, so when you call it,
|
||||
// you lose all info on the embedding type. Please add Wrap()
|
||||
// method to all the parents
|
||||
txDelegate := NewTxDelegate(bond, pubKey)
|
||||
_, ok := txDelegate.Unwrap().(TxDelegate)
|
||||
txDelegate := NewMsgDelegate(bond, pubKey)
|
||||
_, ok := txDelegate.(MsgDelegate)
|
||||
assert.True(t, ok, "%#v", txDelegate)
|
||||
|
||||
txUnbond := NewTxUnbond(strconv.Itoa(bondAmt), pubKey)
|
||||
_, ok = txUnbond.Unwrap().(TxUnbond)
|
||||
txUnbond := NewMsgUnbond(strconv.Itoa(bondAmt), pubKey)
|
||||
_, ok = txUnbond.(MsgUnbond)
|
||||
assert.True(t, ok, "%#v", txUnbond)
|
||||
|
||||
txDecl := NewTxDeclareCandidacy(bond, pubKey, Description{})
|
||||
_, ok = txDecl.Unwrap().(TxDeclareCandidacy)
|
||||
txDecl := NewMsgDeclareCandidacy(bond, pubKey, Description{})
|
||||
_, ok = txDecl.(MsgDeclareCandidacy)
|
||||
assert.True(t, ok, "%#v", txDecl)
|
||||
|
||||
txEditCan := NewTxEditCandidacy(pubKey, Description{})
|
||||
_, ok = txEditCan.Unwrap().(TxEditCandidacy)
|
||||
txEditCan := NewMsgEditCandidacy(pubKey, Description{})
|
||||
_, ok = txEditCan.(MsgEditCandidacy)
|
||||
assert.True(t, ok, "%#v", txEditCan)
|
||||
}
|
||||
|
||||
|
@ -84,9 +92,9 @@ func TestSerializeTx(t *testing.T) {
|
|||
tests := []struct {
|
||||
tx sdk.Tx
|
||||
}{
|
||||
{NewTxUnbond(strconv.Itoa(bondAmt), pubKey)},
|
||||
{NewTxDeclareCandidacy(bond, pubKey, Description{})},
|
||||
{NewTxDeclareCandidacy(bond, pubKey, Description{})},
|
||||
{NewMsgUnbond(strconv.Itoa(bondAmt), pubKey)},
|
||||
{NewMsgDeclareCandidacy(bond, pubKey, Description{})},
|
||||
{NewMsgDeclareCandidacy(bond, pubKey, Description{})},
|
||||
// {NewTxRevokeCandidacy(pubKey)},
|
||||
}
|
||||
|
||||
|
|
|
@ -13,8 +13,8 @@ type Params struct {
|
|||
InflationMin sdk.Rational `json:"inflation_min"` // minimum inflation rate
|
||||
GoalBonded sdk.Rational `json:"goal_bonded"` // Goal of percent bonded atoms
|
||||
|
||||
MaxVals uint16 `json:"max_vals"` // maximum number of validators
|
||||
AllowedBondDenom string `json:"allowed_bond_denom"` // bondable coin denomination
|
||||
MaxVals uint16 `json:"max_vals"` // maximum number of validators
|
||||
BondDenom string `json:"bond_denom"` // bondable coin denomination
|
||||
|
||||
// gas costs for txs
|
||||
GasDeclareCandidacy int64 `json:"gas_declare_candidacy"`
|
||||
|
@ -30,7 +30,7 @@ func defaultParams() Params {
|
|||
InflationMin: sdk.NewRat(7, 100),
|
||||
GoalBonded: sdk.NewRat(67, 100),
|
||||
MaxVals: 100,
|
||||
AllowedBondDenom: "fermion",
|
||||
BondDenom: "fermion",
|
||||
GasDeclareCandidacy: 20,
|
||||
GasEditCandidacy: 20,
|
||||
GasDelegate: 20,
|
||||
|
@ -92,6 +92,7 @@ func (gs *GlobalState) unbondedShareExRate() sdk.Rational {
|
|||
// XXX XXX XXX
|
||||
// expand to include the function of actually transfering the tokens
|
||||
|
||||
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
|
||||
func (gs *GlobalState) addTokensBonded(amount int64) (issuedShares sdk.Rational) {
|
||||
issuedShares = gs.bondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens
|
||||
gs.BondedPool += amount
|
||||
|
@ -99,6 +100,7 @@ func (gs *GlobalState) addTokensBonded(amount int64) (issuedShares sdk.Rational)
|
|||
return
|
||||
}
|
||||
|
||||
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
|
||||
func (gs *GlobalState) removeSharesBonded(shares sdk.Rational) (removedTokens int64) {
|
||||
removedTokens = gs.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares
|
||||
gs.BondedShares = gs.BondedShares.Sub(shares)
|
||||
|
@ -106,6 +108,7 @@ func (gs *GlobalState) removeSharesBonded(shares sdk.Rational) (removedTokens in
|
|||
return
|
||||
}
|
||||
|
||||
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
|
||||
func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rational) {
|
||||
issuedShares = gs.unbondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens
|
||||
gs.UnbondedShares = gs.UnbondedShares.Add(issuedShares)
|
||||
|
@ -113,6 +116,7 @@ func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rationa
|
|||
return
|
||||
}
|
||||
|
||||
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
|
||||
func (gs *GlobalState) removeSharesUnbonded(shares sdk.Rational) (removedTokens int64) {
|
||||
removedTokens = gs.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares
|
||||
gs.UnbondedShares = gs.UnbondedShares.Sub(shares)
|
||||
|
@ -144,7 +148,7 @@ const (
|
|||
type Candidate struct {
|
||||
Status CandidateStatus `json:"status"` // Bonded status
|
||||
PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate
|
||||
Owner crypto.Address `json:"owner"` // Sender of BondTx - UnbondTx returns here
|
||||
Address sdk.Address `json:"owner"` // Sender of BondTx - UnbondTx returns here
|
||||
Assets sdk.Rational `json:"assets"` // total shares of a global hold pools TODO custom type PoolShares
|
||||
Liabilities sdk.Rational `json:"liabilities"` // total shares issued to a candidate's delegators TODO custom type DelegatorShares
|
||||
VotingPower sdk.Rational `json:"voting_power"` // Voting power if considered a validator
|
||||
|
@ -160,11 +164,11 @@ type Description struct {
|
|||
}
|
||||
|
||||
// NewCandidate - initialize a new candidate
|
||||
func NewCandidate(pubKey crypto.PubKey, owner crypto.Address, description Description) *Candidate {
|
||||
func NewCandidate(pubKey crypto.PubKey, address sdk.Address, description Description) *Candidate {
|
||||
return &Candidate{
|
||||
Status: Unbonded,
|
||||
PubKey: pubKey,
|
||||
Owner: owner,
|
||||
PubKey: pubKet,
|
||||
Address: address,
|
||||
Assets: sdk.ZeroRat,
|
||||
Liabilities: sdk.ZeroRat,
|
||||
VotingPower: sdk.ZeroRat,
|
||||
|
@ -172,8 +176,6 @@ func NewCandidate(pubKey crypto.PubKey, owner crypto.Address, description Descri
|
|||
}
|
||||
}
|
||||
|
||||
// XXX define candidate interface?
|
||||
|
||||
// get the exchange rate of global pool shares over delegator shares
|
||||
func (c *Candidate) delegatorShareExRate() sdk.Rational {
|
||||
if c.Liabilities.IsZero() {
|
||||
|
@ -254,6 +256,37 @@ type Candidates []*Candidate
|
|||
// owned by one delegator, and is associated with the voting power of one
|
||||
// pubKey.
|
||||
type DelegatorBond struct {
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
Shares sdk.Rational `json:"shares"`
|
||||
Address sdk.Address `json:"pub_key"`
|
||||
Shares sdk.Rational `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, d.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 ErrInsufficientFunds()
|
||||
}
|
||||
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, d.Address, returnCoins)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue