From 8e3f8319af5d6cf5df28a395a5fd4ff158ae3ef8 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 16 Mar 2018 20:47:17 +0100 Subject: [PATCH] refactoring staking... --- x/stake/errors.go | 5 +++ x/stake/handler.go | 61 ++++++++++-------------------- x/stake/mapper.go | 94 +++++++++++++++++++++++----------------------- x/stake/tick.go | 20 +++++----- x/stake/tx.go | 34 +++++++++-------- x/stake/types.go | 62 +++++++++++++++--------------- 6 files changed, 133 insertions(+), 143 deletions(-) diff --git a/x/stake/errors.go b/x/stake/errors.go index fae872f1c..68b6bd9a6 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -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") } diff --git a/x/stake/handler.go b/x/stake/handler.go index ae5dc4283..d13881864 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -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 { diff --git a/x/stake/mapper.go b/x/stake/mapper.go index 22a9f96e5..b763a2682 100644 --- a/x/stake/mapper.go +++ b/x/stake/mapper.go @@ -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, ¶ms) + err := m.cdc.UnmarshalJSON(b, ¶ms) 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) } diff --git a/x/stake/tick.go b/x/stake/tick.go index 3da581ae3..3f0d38bcd 100644 --- a/x/stake/tick.go +++ b/x/stake/tick.go @@ -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 diff --git a/x/stake/tx.go b/x/stake/tx.go index 3bc58b0dd..6cae6746f 100644 --- a/x/stake/tx.go +++ b/x/stake/tx.go @@ -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() { diff --git a/x/stake/types.go b/x/stake/types.go index fe7a4ebf0..dd5272e0d 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -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