Skip to content

Commit

Permalink
Merge pull request #745 from cosmos/joon/732-stake-keeper
Browse files Browse the repository at this point in the history
Joon/732 stake keeper
  • Loading branch information
rigelrozanski authored Apr 2, 2018
2 parents 7d67d00 + 47aaae8 commit d880262
Show file tree
Hide file tree
Showing 3 changed files with 425 additions and 96 deletions.
82 changes: 73 additions & 9 deletions x/stake/keeper.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package stake

import (
"bytes"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank"
Expand Down Expand Up @@ -87,18 +89,31 @@ func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) {
panic(err)
}

// if the voting power is the same no need to update any of the other indexes
if oldFound && oldCandidate.Assets.Equal(candidate.Assets) {
return
}

// update the list ordered by voting power
if oldFound {
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
}
store.Set(GetValidatorKey(address, validator.VotingPower, k.cdc), bz)

// add to the validators to update list if is already a validator
if store.Get(GetRecentValidatorKey(address)) == nil {
return
// or is a new validator
setAcc := false
if store.Get(GetRecentValidatorKey(address)) != nil {
setAcc = true

// want to check in the else statement because inefficient
} else if k.isNewValidator(ctx, store, address) {
setAcc = true
}
store.Set(GetAccUpdateValidatorKey(validator.Address), bz)

if setAcc {
store.Set(GetAccUpdateValidatorKey(validator.Address), bz)
}
return
}

func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
Expand All @@ -112,6 +127,7 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
// delete the old candidate record
store := ctx.KVStore(k.storeKey)
store.Delete(GetCandidateKey(address))
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))

// delete from recent and power weighted validator groups if the validator
// exists and add validator with zero power to the validator updates
Expand All @@ -124,7 +140,6 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
}
store.Set(GetAccUpdateValidatorKey(address), bz)
store.Delete(GetRecentValidatorKey(address))
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
}

//___________________________________________________________________________
Expand All @@ -136,12 +151,18 @@ func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
store := ctx.KVStore(k.storeKey)

// clear the recent validators store
k.deleteSubSpace(store, RecentValidatorsKey)
// clear the recent validators store, add to the ToKickOut Temp store
iterator := store.Iterator(subspace(RecentValidatorsKey))
for ; iterator.Valid(); iterator.Next() {
addr := AddrFromKey(iterator.Key())
store.Set(GetToKickOutValidatorKey(addr), []byte{})
store.Delete(iterator.Key())
}
iterator.Close()

// add the actual validator power sorted store
maxVal := k.GetParams(ctx).MaxValidators
iterator := store.ReverseIterator(subspace(ValidatorsKey)) //smallest to largest
iterator = store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
validators = make([]Validator, maxVal)
i := 0
for ; ; i++ {
Expand All @@ -157,15 +178,58 @@ func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
}
validators[i] = val

// remove from ToKickOut group
store.Delete(GetToKickOutValidatorKey(val.Address))

// also add to the recent validators group
store.Set(GetRecentValidatorKey(val.Address), bz)
store.Set(GetRecentValidatorKey(val.Address), bz) // XXX should store nothing

iterator.Next()
}

// add any kicked out validators to the acc change
iterator = store.Iterator(subspace(ToKickOutValidatorsKey))
for ; iterator.Valid(); iterator.Next() {
addr := AddrFromKey(iterator.Key())
bz, err := k.cdc.MarshalBinary(Validator{addr, sdk.ZeroRat})
if err != nil {
panic(err)
}
store.Set(GetAccUpdateValidatorKey(addr), bz)
store.Delete(iterator.Key())
}
iterator.Close()

return validators[:i] // trim
}

// TODO this is madly inefficient because need to call every time we set a candidate
// Should use something better than an iterator maybe?
// Used to determine if something has just been added to the actual validator set
func (k Keeper) isNewValidator(ctx sdk.Context, store sdk.KVStore, address sdk.Address) bool {
// add the actual validator power sorted store
maxVal := k.GetParams(ctx).MaxValidators
iterator := store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
for i := 0; ; i++ {
if !iterator.Valid() || i > int(maxVal-1) {
iterator.Close()
break
}
bz := iterator.Value()
var val Validator
err := k.cdc.UnmarshalBinary(bz, &val)
if err != nil {
panic(err)
}
if bytes.Equal(val.Address, address) {
return true
}
iterator.Next()
}

return false
}

// Is the address provided a part of the most recently saved validator group?
func (k Keeper) IsRecentValidator(ctx sdk.Context, address sdk.Address) bool {
store := ctx.KVStore(k.storeKey)
Expand Down
14 changes: 13 additions & 1 deletion x/stake/keeper_keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ var (
AccUpdateValidatorsKey = []byte{0x04} // prefix for each key to a validator which is being updated
RecentValidatorsKey = []byte{0x05} // prefix for each key to the last updated validator group

DelegatorBondKeyPrefix = []byte{0x06} // prefix for each key to a delegator's bond
ToKickOutValidatorsKey = []byte{0x06} // prefix for each key to the last updated validator group

DelegatorBondKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond
)

const maxDigitsForAccount = 12 // ~220,000,000 atoms created at launch
Expand All @@ -43,6 +45,16 @@ func GetRecentValidatorKey(addr sdk.Address) []byte {
return append(RecentValidatorsKey, addr.Bytes()...)
}

// reverse operation of GetRecentValidatorKey
func AddrFromKey(key []byte) sdk.Address {
return key[1:]
}

// get the key for the accumulated update validators
func GetToKickOutValidatorKey(addr sdk.Address) []byte {
return append(ToKickOutValidatorsKey, addr.Bytes()...)
}

// get the key for delegator bond with candidate
func GetDelegatorBondKey(delegatorAddr, candidateAddr sdk.Address, cdc *wire.Codec) []byte {
return append(GetDelegatorBondsKey(delegatorAddr, cdc), candidateAddr.Bytes()...)
Expand Down
Loading

0 comments on commit d880262

Please sign in to comment.