refactoring staking...

This commit is contained in:
rigelrozanski 2018-03-16 20:47:17 +01:00
parent dc8636390c
commit 8e3f8319af
6 changed files with 133 additions and 143 deletions

View File

@ -2,6 +2,8 @@
package stake
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
@ -43,6 +45,9 @@ func codeToDefaultMsg(code CodeType) string {
//----------------------------------------
// Error constructors
func ErrNotEnoughBondShares(shares string) sdk.Error {
return newError(CodeInvalidBond, fmt.Sprintf("not enough shares only have %v", shares))
}
func ErrCandidateEmpty() sdk.Error {
return newError(CodeInvalidValidator, "Cannot bond to an empty candidate")
}

View File

@ -1,10 +1,10 @@
package stake
import (
"bytes"
"fmt"
"strconv"
"github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
@ -214,7 +214,7 @@ func (tr transact) editCandidacy(tx MsgEditCandidacy) sdk.Error {
func (tr transact) delegate(tx MsgDelegate) sdk.Error {
if tr.mapper.loadCandidate(tx.Address) == nil { // does PubKey exist
if tr.mapper.loadCandidate(tx.Address) == nil {
return ErrBadCandidateAddr()
}
err := checkDenom(tr.mapper, tx.Bond)
@ -239,24 +239,17 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s
return ErrBondNotNominated()
}
var poolAccount crypto.Address
if candidate.Status == Bonded {
poolAccount = tr.params.HoldBonded
} else {
poolAccount = tr.params.HoldUnbonded
}
// Get or create the delegator bond
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
if bond == nil {
bond = &DelegatorBond{
PubKey: tx.Address,
Shares: sdk.ZeroRat,
Address: tx.Address,
Shares: sdk.ZeroRat,
}
}
// Account new shares, save
err := bond.BondTokens(candidate, tx.Bond, tr)
err := bond.BondCoins(candidate, tx.Bond, tr)
if err != nil {
return err
}
@ -269,38 +262,34 @@ func (tr transact) delegateWithCandidate(tx MsgDelegate, candidate *Candidate) s
func (tr transact) unbond(tx MsgUnbond) sdk.Error {
// check if bond has any shares in it unbond
existingBond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
sharesStr := viper.GetString(tx.Shares)
if existingBond.Shares.LT(sdk.ZeroRat) { // bond shares < tx shares
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
if bond == nil {
return ErrNoDelegatorForAddress()
}
if !bond.Shares.GT(sdk.ZeroRat) { // bond shares < tx shares
return ErrInsufficientFunds()
}
// if shares set to special case Max then we're good
if sharesStr != "MAX" {
if tx.Shares != "MAX" {
// test getting rational number from decimal provided
shares, err := sdk.NewRatFromDecimal(sharesStr)
shares, err := sdk.NewRatFromDecimal(tx.Shares)
if err != nil {
return err
}
// test that there are enough shares to unbond
if bond.Shares.LT(shares) {
return fmt.Errorf("not enough bond shares to unbond, have %v, trying to unbond %v",
bond.Shares, tx.Shares)
if !bond.Shares.GT(shares) {
return ErrNotEnoughBondShares(tx.Shares)
}
}
if tr.ctx.IsCheckTx() {
return nil
}
// get delegator bond
bond := tr.mapper.loadDelegatorBond(tr.sender, tx.Address)
if bond == nil {
return ErrNoDelegatorForAddress()
}
// retrieve the amount of bonds to remove (TODO remove redundancy already serialized)
var shares sdk.Rat
var err sdk.Error
if tx.Shares == "MAX" {
shares = bond.Shares
} else {
@ -327,7 +316,7 @@ func (tr transact) unbond(tx MsgUnbond) sdk.Error {
// if the bond is the owner of the candidate then
// trigger a revoke candidacy
if tr.sender.Equals(candidate.Owner) &&
if bytes.Equal(tr.sender, candidate.Address) &&
candidate.Status != Revoked {
revokeCandidacy = true
}
@ -338,20 +327,10 @@ func (tr transact) unbond(tx MsgUnbond) sdk.Error {
tr.mapper.saveDelegatorBond(tr.sender, bond)
}
// transfer coins back to account
var poolAccount crypto.Address
if candidate.Status == Bonded {
poolAccount = tr.params.HoldBonded
} else {
poolAccount = tr.params.HoldUnbonded
}
returnCoins := candidate.removeShares(shares, tr.gs)
err := tr.transfer(poolAccount, tr.sender,
sdk.Coins{{tr.params.BondDenom, returnCoins}})
if err != nil {
return err
}
// Add the coins
returnAmount := candidate.removeShares(shares, tr.gs)
returnCoins := sdk.Coins{{tr.params.BondDenom, returnAmount}}
tr.coinKeeper.AddCoins(tr.ctx, tr.sender, returnCoins)
// lastly if an revoke candidate if necessary
if revokeCandidacy {

View File

@ -1,6 +1,8 @@
package stake
import (
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
@ -26,7 +28,7 @@ func GetCandidateKey(address sdk.Address) []byte {
}
// GetValidatorKey - get the key for the validator used in the power-store
func GetValidatorKey(address sdk.Address, power sdk.Rational) []byte {
func GetValidatorKey(address sdk.Address, power sdk.Rational, cdc *wire.Codec) []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
}
@ -37,12 +39,12 @@ func GetValidatorUpdatesKey(address sdk.Address) []byte {
}
// GetDelegatorBondKey - get the key for delegator bond with candidate
func GetDelegatorBondKey(delegator, candidate sdk.Address) []byte {
return append(GetDelegatorBondKeyPrefix(delegator), candidate.Bytes()...)
func GetDelegatorBondKey(delegator, candidate sdk.Address, cdc *wire.Codec) []byte {
return append(GetDelegatorBondKeyPrefix(delegator, cdc), candidate.Bytes()...)
}
// GetDelegatorBondKeyPrefix - get the prefix for a delegator for all candidates
func GetDelegatorBondKeyPrefix(delegator sdk.Address) []byte {
func GetDelegatorBondKeyPrefix(delegator sdk.Address, cdc *wire.Codec) []byte {
res, err := cdc.MarshalJSON(&delegator)
if err != nil {
panic(err)
@ -51,7 +53,7 @@ func GetDelegatorBondKeyPrefix(delegator sdk.Address) []byte {
}
// GetDelegatorBondsKey - get the key for list of all the delegator's bonds
func GetDelegatorBondsKey(delegator sdk.Address) []byte {
func GetDelegatorBondsKey(delegator sdk.Address, cdc *wire.Codec) []byte {
res, err := cdc.MarshalJSON(&delegator)
if err != nil {
panic(err)
@ -68,8 +70,8 @@ type Mapper struct {
}
func NewMapper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey) Mapper {
return StakeMapper{
store: ctx.KVStore(m.key),
return Mapper{
store: ctx.KVStore(key),
cdc: cdc,
}
}
@ -80,7 +82,7 @@ func (m Mapper) loadCandidate(address sdk.Address) *Candidate {
return nil
}
candidate := new(Candidate)
err := cdc.UnmarshalJSON(b, candidate)
err := m.cdc.UnmarshalJSON(b, candidate)
if err != nil {
panic(err) // This error should never occur big problem if does
}
@ -90,11 +92,11 @@ func (m Mapper) loadCandidate(address sdk.Address) *Candidate {
func (m Mapper) saveCandidate(candidate *Candidate) {
// XXX should only remove validator if we know candidate is a validator
removeValidator(m.store, candidate.Address)
m.removeValidator(candidate.Address)
validator := &Validator{candidate.Address, candidate.VotingPower}
updateValidator(m.store, validator)
m.updateValidator(validator)
b, err := cdc.MarshalJSON(*candidate)
b, err := m.cdc.MarshalJSON(*candidate)
if err != nil {
panic(err)
}
@ -104,7 +106,7 @@ func (m Mapper) saveCandidate(candidate *Candidate) {
func (m Mapper) removeCandidate(address sdk.Address) {
// XXX should only remove validator if we know candidate is a validator
removeValidator(m.store, address)
m.removeValidator(address)
m.store.Delete(GetCandidateKey(address))
}
@ -127,7 +129,7 @@ func (m Mapper) removeCandidate(address sdk.Address) {
// in the changed validator substore
func (m Mapper) updateValidator(validator *Validator) {
b, err := cdc.MarshalJSON(*validator)
b, err := m.cdc.MarshalJSON(*validator)
if err != nil {
panic(err)
}
@ -136,41 +138,41 @@ func (m Mapper) updateValidator(validator *Validator) {
m.store.Set(GetValidatorUpdatesKey(validator.Address), b)
// update the list ordered by voting power
m.store.Set(GetValidatorKey(validator.Address, validator.VotingPower), b)
m.store.Set(GetValidatorKey(validator.Address, validator.VotingPower, m.cdc), b)
}
func (m Mapper) removeValidator(address sdk.Address) {
//add validator with zero power to the validator updates
b, err := cdc.MarshalJSON(Validator{address, sdk.ZeroRat})
b, err := m.cdc.MarshalJSON(Validator{address, sdk.ZeroRat})
if err != nil {
panic(err)
}
m.store.Set(GetValidatorUpdatesKey(address), b)
// now actually delete from the validator set
candidate := loadCandidate(m.store, address)
candidate := m.loadCandidate(address)
if candidate != nil {
m.store.Delete(GetValidatorKey(address, candidate.VotingPower))
m.store.Delete(GetValidatorKey(address, candidate.VotingPower, m.cdc))
}
}
// get the most recent updated validator set from the Candidates. These bonds
// are already sorted by VotingPower from the UpdateVotingPower function which
// is the only function which is to modify the VotingPower
func (m Mapper) getValidators(maxVal int) (validators []Validator) {
func (m Mapper) getValidators(maxVal uint16) (validators []Validator) {
iterator := m.store.Iterator(subspace(ValidatorKeyPrefix)) //smallest to largest
validators = make([]Validator, maxVal)
for i := 0; ; i++ {
if !iterator.Valid() || i > maxVal {
if !iterator.Valid() || i > int(maxVal) {
iterator.Close()
break
}
valBytes := iterator.Value()
var val Validator
err := cdc.UnmarshalJSON(valBytes, &val)
err := m.cdc.UnmarshalJSON(valBytes, &val)
if err != nil {
panic(err)
}
@ -191,7 +193,7 @@ func (m Mapper) getValidatorUpdates() (updates []Validator) {
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val Validator
err := cdc.UnmarshalJSON(valBytes, &val)
err := m.cdc.UnmarshalJSON(valBytes, &val)
if err != nil {
panic(err)
}
@ -223,7 +225,7 @@ func (m Mapper) loadCandidates() (candidates Candidates) {
for ; iterator.Valid(); iterator.Next() {
candidateBytes := iterator.Value()
var candidate Candidate
err := cdc.UnmarshalJSON(candidateBytes, &candidate)
err := m.cdc.UnmarshalJSON(candidateBytes, &candidate)
if err != nil {
panic(err)
}
@ -238,12 +240,12 @@ func (m Mapper) loadCandidates() (candidates Candidates) {
// load the pubkeys of all candidates a delegator is delegated too
func (m Mapper) loadDelegatorCandidates(delegator sdk.Address) (candidateAddrs []sdk.Address) {
candidateBytes := m.store.Get(GetDelegatorBondsKey(delegator))
candidateBytes := m.store.Get(GetDelegatorBondsKey(delegator, m.cdc))
if candidateBytes == nil {
return nil
}
err := cdc.UnmarshalJSON(candidateBytes, &candidateAddrs)
err := m.cdc.UnmarshalJSON(candidateBytes, &candidateAddrs)
if err != nil {
panic(err)
}
@ -254,13 +256,13 @@ func (m Mapper) loadDelegatorCandidates(delegator sdk.Address) (candidateAddrs [
func (m Mapper) loadDelegatorBond(delegator, candidate sdk.Address) *DelegatorBond {
delegatorBytes := m.store.Get(GetDelegatorBondKey(delegator, candidate))
delegatorBytes := m.store.Get(GetDelegatorBondKey(delegator, candidate, m.cdc))
if delegatorBytes == nil {
return nil
}
bond := new(DelegatorBond)
err := cdc.UnmarshalJSON(delegatorBytes, bond)
err := m.cdc.UnmarshalJSON(delegatorBytes, bond)
if err != nil {
panic(err)
}
@ -271,43 +273,43 @@ 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.Address) == nil {
pks := loadDelegatorCandidates(m.store, delegator)
if m.loadDelegatorBond(delegator, bond.Address) == nil {
pks := m.loadDelegatorCandidates(delegator)
pks = append(pks, (*bond).Address)
b, err := cdc.MarshalJSON(pks)
b, err := m.cdc.MarshalJSON(pks)
if err != nil {
panic(err)
}
m.store.Set(GetDelegatorBondsKey(delegator), b)
m.store.Set(GetDelegatorBondsKey(delegator, m.cdc), b)
}
// now actually save the bond
b, err := cdc.MarshalJSON(*bond)
b, err := m.cdc.MarshalJSON(*bond)
if err != nil {
panic(err)
}
m.store.Set(GetDelegatorBondKey(delegator, bond.Address), b)
//updateDelegatorBonds(store, delegator)
m.store.Set(GetDelegatorBondKey(delegator, bond.Address, m.cdc), b)
//updateDelegatorBonds(store, delegator) //XXX remove?
}
func (m Mapper) removeDelegatorBond(delegator sdk.Address, candidate sdk.Address) {
func (m Mapper) removeDelegatorBond(delegator sdk.Address, candidateAddr sdk.Address) {
// TODO use list queries on multistore to remove iterations here!
// first remove from the list of bonds
pks := loadDelegatorCandidates(m.store, delegator)
for i, pk := range pks {
if candidate.Equals(pk) {
pks = append(pks[:i], pks[i+1:]...)
addrs := m.loadDelegatorCandidates(delegator)
for i, addr := range addrs {
if bytes.Equal(candidateAddr, addr) {
addrs = append(addrs[:i], addrs[i+1:]...)
}
}
b, err := cdc.MarshalJSON(pks)
b, err := m.cdc.MarshalJSON(pks)
if err != nil {
panic(err)
}
m.store.Set(GetDelegatorBondsKey(delegator), b)
m.store.Set(GetDelegatorBondsKey(delegator, m.cdc), b)
// now remove the actual bond
m.store.Delete(GetDelegatorBondKey(delegator, candidate))
//updateDelegatorBonds(store, delegator)
m.store.Delete(GetDelegatorBondKey(delegator, candidateAddr, m.cdc))
//updateDelegatorBonds(store, delegator) //XXX remove?
}
//_______________________________________________________________________
@ -319,14 +321,14 @@ func (m Mapper) loadParams() (params Params) {
return defaultParams()
}
err := cdc.UnmarshalJSON(b, &params)
err := m.cdc.UnmarshalJSON(b, &params)
if err != nil {
panic(err) // This error should never occur big problem if does
}
return
}
func (m Mapper) saveParams(params Params) {
b, err := cdc.MarshalJSON(params)
b, err := m.cdc.MarshalJSON(params)
if err != nil {
panic(err)
}
@ -342,7 +344,7 @@ func (m Mapper) loadGlobalState() (gs *GlobalState) {
return initialGlobalState()
}
gs = new(GlobalState)
err := cdc.UnmarshalJSON(b, gs)
err := m.cdc.UnmarshalJSON(b, gs)
if err != nil {
panic(err) // This error should never occur big problem if does
}
@ -350,7 +352,7 @@ func (m Mapper) loadGlobalState() (gs *GlobalState) {
}
func (m Mapper) saveGlobalState(gs *GlobalState) {
b, err := cdc.MarshalJSON(*gs)
b, err := m.cdc.MarshalJSON(*gs)
if err != nil {
panic(err)
}

View File

@ -6,27 +6,29 @@ import (
)
// Tick - called at the end of every block
func Tick(ctx sdk.Context, store sdk.KVStore) (change []*abci.Validator, err error) {
func Tick(ctx sdk.Context, m Mapper) (change []*abci.Validator, err error) {
// retrieve params
params := loadParams(store)
gs := loadGlobalState(store)
params := m.loadParams()
gs := m.loadGlobalState()
height := ctx.BlockHeight()
// Process Validator Provisions
// XXX right now just process every 5 blocks, in new SDK make hourly
if gs.InflationLastTime+5 <= height {
gs.InflationLastTime = height
processProvisions(store, gs, params)
processProvisions(m, gs, params)
}
return UpdateValidatorSet(store, gs, params)
newVals := m.getValidators(params.MaxVals)
// XXX determine change from old validators, set to change
return change, nil
}
var hrsPerYr = sdk.NewRat(8766) // as defined by a julian year of 365.25 days
// process provisions for an hour period
func processProvisions(store sdk.KVStore, gs *GlobalState, params Params) {
func processProvisions(m Mapper, gs *GlobalState, params Params) {
gs.Inflation = nextInflation(gs, params).Round(1000000000)
@ -34,7 +36,7 @@ func processProvisions(store sdk.KVStore, gs *GlobalState, params Params) {
// more bonded tokens are added proportionally to all validators the only term
// which needs to be updated is the `BondedPool`. So for each previsions cycle:
provisions := gs.Inflation.Mul(sdk.New(gs.TotalSupply)).Quo(hrsPerYr).Evaluate()
provisions := gs.Inflation.Mul(sdk.NewRat(gs.TotalSupply)).Quo(hrsPerYr).Evaluate()
gs.BondedPool += provisions
gs.TotalSupply += provisions
@ -43,7 +45,7 @@ func processProvisions(store sdk.KVStore, gs *GlobalState, params Params) {
// XXX XXX XXX XXX XXX XXX XXX XXX XXX
// save the params
saveGlobalState(store, gs)
m.saveGlobalState(gs)
}
// get the next inflation rate for the hour
@ -56,7 +58,7 @@ func nextInflation(gs *GlobalState, params Params) (inflation sdk.Rat) {
// 7% and 20%.
// (1 - bondedRatio/GoalBonded) * InflationRateChange
inflationRateChangePerYear := sdk.One.Sub(gs.bondedRatio().Quo(params.GoalBonded)).Mul(params.InflationRateChange)
inflationRateChangePerYear := sdk.OneRat.Sub(gs.bondedRatio().Quo(params.GoalBonded)).Mul(params.InflationRateChange)
inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYr)
// increase the new annual inflation for this next cycle

View File

@ -34,9 +34,10 @@ func (msg MsgAddr) String() string {
// ValidateBasic - Check for non-empty candidate, and valid coins
func (msg MsgAddr) ValidateBasic() sdk.Error {
if msg.Address.Empty() {
return errCandidateEmpty
if msg.Address == nil {
return ErrCandidateEmpty()
}
return nil
}
//______________________________________________________________________
@ -54,7 +55,7 @@ func NewMsgDeclareCandidacy(bond sdk.Coin, address sdk.Address, pubkey crypto.Pu
MsgAddr: NewMsgAddr(address),
Description: description,
Bond: bond,
PubKey: PubKey,
PubKey: pubkey,
}
}
@ -69,17 +70,17 @@ func (msg MsgDeclareCandidacy) GetSignBytes() []byte {
// quick validity check
func (msg MsgDeclareCandidacy) ValidateBasic() sdk.Error {
err := MsgAddr.ValidateBasic()
err := msg.MsgAddr.ValidateBasic()
if err != nil {
return err
}
err := validateCoin(msg.Bond)
err = validateCoin(msg.Bond)
if err != nil {
return err
}
empty := Description{}
if msg.Description == empty {
return fmt.Errorf("description must be included")
return newError(CodeInvalidInput, "description must be included")
}
return nil
}
@ -110,13 +111,13 @@ func (msg MsgEditCandidacy) GetSignBytes() []byte {
// quick validity check
func (msg MsgEditCandidacy) ValidateBasic() sdk.Error {
err := MsgAddr.ValidateBasic()
err := msg.MsgAddr.ValidateBasic()
if err != nil {
return err
}
empty := Description{}
if msg.Description == empty {
return fmt.Errorf("Transaction must include some information to modify")
return newError(CodeInvalidInput, "Transaction must include some information to modify")
}
return nil
}
@ -147,11 +148,11 @@ func (msg MsgDelegate) GetSignBytes() []byte {
// quick validity check
func (msg MsgDelegate) ValidateBasic() sdk.Error {
err := MsgAddr.ValidateBasic()
err := msg.MsgAddr.ValidateBasic()
if err != nil {
return err
}
err := validateCoin(msg.Bond)
err = validateCoin(msg.Bond)
if err != nil {
return err
}
@ -167,7 +168,7 @@ type MsgUnbond struct {
}
func NewMsgUnbond(shares string, address sdk.Address) MsgDelegate {
return MsgUnbond{
return MsgDelegate{
MsgAddr: NewMsgAddr(address),
Shares: shares,
}
@ -184,11 +185,12 @@ func (msg MsgUnbond) GetSignBytes() []byte {
// quick validity check
func (msg MsgUnbond) ValidateBasic() sdk.Error {
err := MsgAddr.ValidateBasic()
err := msg.MsgAddr.ValidateBasic()
if err != nil {
return err
}
if msg.Shares {
if msg.Shares == "MAX" {
return ErrCandidateEmpty()
}
return nil
@ -197,9 +199,9 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error {
//______________________________________________________________________
// helper
func validateCoin(coin coin.Coin) sdk.Error {
coins := sdk.Coins{bond}
if !sdk.IsValid() {
func validateCoin(coin sdk.Coin) sdk.Error {
coins := sdk.Coins{coin}
if !coins.IsValid() {
return sdk.ErrInvalidCoins()
}
if !coins.IsPositive() {

View File

@ -8,10 +8,10 @@ import (
// Params defines the high level settings for staking
type Params struct {
InflationRateChange sdk.Rational `json:"inflation_rate_change"` // maximum annual change in inflation rate
InflationMax sdk.Rational `json:"inflation_max"` // maximum inflation rate
InflationMin sdk.Rational `json:"inflation_min"` // minimum inflation rate
GoalBonded sdk.Rational `json:"goal_bonded"` // Goal of percent bonded atoms
InflationRateChange sdk.Rat `json:"inflation_rate_change"` // maximum annual change in inflation rate
InflationMax sdk.Rat `json:"inflation_max"` // maximum inflation rate
InflationMin sdk.Rat `json:"inflation_min"` // minimum inflation rate
GoalBonded sdk.Rat `json:"goal_bonded"` // Goal of percent bonded atoms
MaxVals uint16 `json:"max_vals"` // maximum number of validators
BondDenom string `json:"bond_denom"` // bondable coin denomination
@ -42,13 +42,13 @@ func defaultParams() Params {
// GlobalState - dynamic parameters of the current state
type GlobalState struct {
TotalSupply int64 `json:"total_supply"` // total supply of all tokens
BondedShares sdk.Rational `json:"bonded_shares"` // sum of all shares distributed for the Bonded Pool
UnbondedShares sdk.Rational `json:"unbonded_shares"` // sum of all shares distributed for the Unbonded Pool
BondedPool int64 `json:"bonded_pool"` // reserve of bonded tokens
UnbondedPool int64 `json:"unbonded_pool"` // reserve of unbonded tokens held with candidates
InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time
Inflation sdk.Rational `json:"inflation"` // current annual inflation rate
TotalSupply int64 `json:"total_supply"` // total supply of all tokens
BondedShares sdk.Rat `json:"bonded_shares"` // sum of all shares distributed for the Bonded Pool
UnbondedShares sdk.Rat `json:"unbonded_shares"` // sum of all shares distributed for the Unbonded Pool
BondedPool int64 `json:"bonded_pool"` // reserve of bonded tokens
UnbondedPool int64 `json:"unbonded_pool"` // reserve of unbonded tokens held with candidates
InflationLastTime int64 `json:"inflation_last_time"` // block which the last inflation was processed // TODO make time
Inflation sdk.Rat `json:"inflation"` // current annual inflation rate
}
// XXX define globalstate interface?
@ -66,7 +66,7 @@ func initialGlobalState() *GlobalState {
}
// get the bond ratio of the global state
func (gs *GlobalState) bondedRatio() sdk.Rational {
func (gs *GlobalState) bondedRatio() sdk.Rat {
if gs.TotalSupply > 0 {
return sdk.NewRat(gs.BondedPool, gs.TotalSupply)
}
@ -74,7 +74,7 @@ func (gs *GlobalState) bondedRatio() sdk.Rational {
}
// get the exchange rate of bonded token per issued share
func (gs *GlobalState) bondedShareExRate() sdk.Rational {
func (gs *GlobalState) bondedShareExRate() sdk.Rat {
if gs.BondedShares.IsZero() {
return sdk.OneRat
}
@ -82,7 +82,7 @@ func (gs *GlobalState) bondedShareExRate() sdk.Rational {
}
// get the exchange rate of unbonded tokens held in candidates per issued share
func (gs *GlobalState) unbondedShareExRate() sdk.Rational {
func (gs *GlobalState) unbondedShareExRate() sdk.Rat {
if gs.UnbondedShares.IsZero() {
return sdk.OneRat
}
@ -93,7 +93,7 @@ func (gs *GlobalState) unbondedShareExRate() sdk.Rational {
// 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) {
func (gs *GlobalState) addTokensBonded(amount int64) (issuedShares sdk.Rat) {
issuedShares = gs.bondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens
gs.BondedPool += amount
gs.BondedShares = gs.BondedShares.Add(issuedShares)
@ -101,7 +101,7 @@ func (gs *GlobalState) addTokensBonded(amount int64) (issuedShares sdk.Rational)
}
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
func (gs *GlobalState) removeSharesBonded(shares sdk.Rational) (removedTokens int64) {
func (gs *GlobalState) removeSharesBonded(shares sdk.Rat) (removedTokens int64) {
removedTokens = gs.bondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares
gs.BondedShares = gs.BondedShares.Sub(shares)
gs.BondedPool -= removedTokens
@ -109,7 +109,7 @@ func (gs *GlobalState) removeSharesBonded(shares sdk.Rational) (removedTokens in
}
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rational) {
func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rat) {
issuedShares = gs.unbondedShareExRate().Inv().Mul(sdk.NewRat(amount)) // (tokens/shares)^-1 * tokens
gs.UnbondedShares = gs.UnbondedShares.Add(issuedShares)
gs.UnbondedPool += amount
@ -117,7 +117,7 @@ func (gs *GlobalState) addTokensUnbonded(amount int64) (issuedShares sdk.Rationa
}
//XXX CONFIRM that use of the exRate is correct with Zarko Spec!
func (gs *GlobalState) removeSharesUnbonded(shares sdk.Rational) (removedTokens int64) {
func (gs *GlobalState) removeSharesUnbonded(shares sdk.Rat) (removedTokens int64) {
removedTokens = gs.unbondedShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares
gs.UnbondedShares = gs.UnbondedShares.Sub(shares)
gs.UnbondedPool -= removedTokens
@ -149,9 +149,9 @@ type Candidate struct {
Status CandidateStatus `json:"status"` // Bonded status
PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate
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
Assets sdk.Rat `json:"assets"` // total shares of a global hold pools TODO custom type PoolShares
Liabilities sdk.Rat `json:"liabilities"` // total shares issued to a candidate's delegators TODO custom type DelegatorShares
VotingPower sdk.Rat `json:"voting_power"` // Voting power if considered a validator
Description Description `json:"description"` // Description terms for the candidate
}
@ -177,7 +177,7 @@ func NewCandidate(pubKey crypto.PubKey, address sdk.Address, description Descrip
}
// get the exchange rate of global pool shares over delegator shares
func (c *Candidate) delegatorShareExRate() sdk.Rational {
func (c *Candidate) delegatorShareExRate() sdk.Rat {
if c.Liabilities.IsZero() {
return sdk.OneRat
}
@ -185,11 +185,11 @@ func (c *Candidate) delegatorShareExRate() sdk.Rational {
}
// add tokens to a candidate
func (c *Candidate) addTokens(amount int64, gs *GlobalState) (issuedDelegatorShares sdk.Rational) {
func (c *Candidate) addTokens(amount int64, gs *GlobalState) (issuedDelegatorShares sdk.Rat) {
exRate := c.delegatorShareExRate()
var receivedGlobalShares sdk.Rational
var receivedGlobalShares sdk.Rat
if c.Status == Bonded {
receivedGlobalShares = gs.addTokensBonded(amount)
} else {
@ -203,14 +203,14 @@ func (c *Candidate) addTokens(amount int64, gs *GlobalState) (issuedDelegatorSha
}
// remove shares from a candidate
func (c *Candidate) removeShares(shares sdk.Rational, gs *GlobalState) (removedTokens int64) {
func (c *Candidate) removeShares(shares sdk.Rat, gs *GlobalState) (createdCoins int64) {
globalPoolSharesToRemove := c.delegatorShareExRate().Mul(shares)
if c.Status == Bonded {
removedTokens = gs.removeSharesBonded(globalPoolSharesToRemove)
createdCoins = gs.removeSharesBonded(globalPoolSharesToRemove)
} else {
removedTokens = gs.removeSharesUnbonded(globalPoolSharesToRemove)
createdCoins = gs.removeSharesUnbonded(globalPoolSharesToRemove)
}
c.Assets = c.Assets.Sub(globalPoolSharesToRemove)
@ -229,8 +229,8 @@ func (c *Candidate) validator() Validator {
// Validator is one of the top Candidates
type Validator struct {
PubKey crypto.PubKey `json:"pub_key"` // Pubkey of candidate
VotingPower sdk.Rational `json:"voting_power"` // Voting power if considered a validator
Address sdk.Address `json:"address"` // Address of validator
VotingPower sdk.Rat `json:"voting_power"` // Voting power if considered a validator
}
// ABCIValidator - Get the validator from a bond value
@ -256,8 +256,8 @@ type Candidates []*Candidate
// owned by one delegator, and is associated with the voting power of one
// pubKey.
type DelegatorBond struct {
Address sdk.Address `json:"pub_key"`
Shares sdk.Rational `json:"shares"`
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