cosmos-sdk/x/stake/keeper.go

407 lines
11 KiB
Go
Raw Normal View History

2018-03-20 06:56:07 -07:00
package stake
import (
"bytes"
"encoding/json"
"errors"
2018-03-20 06:56:07 -07:00
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/bank"
)
// keeper of the staking store
type Keeper struct {
storeKey sdk.StoreKey
cdc *wire.Codec
coinKeeper bank.CoinKeeper
2018-03-22 14:47:57 -07:00
// caches
2018-03-22 09:00:45 -07:00
gs Pool
2018-03-20 06:56:07 -07:00
params Params
}
func NewKeeper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey, ck bank.CoinKeeper) Keeper {
keeper := Keeper{
storeKey: key,
cdc: cdc,
coinKeeper: ck,
}
return keeper
}
// InitGenesis - store genesis parameters
func (k Keeper) InitGenesis(ctx sdk.Context, data json.RawMessage) error {
var state GenesisState
if err := json.Unmarshal(data, &state); err != nil {
return err
}
k.setPool(ctx, state.Pool)
k.setParams(ctx, state.Params)
return nil
}
2018-03-22 09:00:45 -07:00
//_________________________________________________________________________
// get a single candidate
func (k Keeper) GetCandidate(ctx sdk.Context, addr sdk.Address) (candidate Candidate, found bool) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-20 06:56:07 -07:00
b := store.Get(GetCandidateKey(addr))
if b == nil {
2018-03-20 14:21:18 -07:00
return candidate, false
2018-03-20 06:56:07 -07:00
}
2018-03-22 06:39:31 -07:00
err := k.cdc.UnmarshalBinary(b, &candidate)
2018-03-20 06:56:07 -07:00
if err != nil {
2018-03-20 14:21:18 -07:00
panic(err)
2018-03-20 06:56:07 -07:00
}
2018-03-20 14:21:18 -07:00
return candidate, true
2018-03-20 06:56:07 -07:00
}
// Get the set of all candidates, retrieve a maxRetrieve number of records
func (k Keeper) GetCandidates(ctx sdk.Context, maxRetrieve int16) (candidates Candidates) {
2018-03-22 09:00:45 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-22 14:47:57 -07:00
iterator := store.Iterator(subspace(CandidatesKey))
2018-03-20 06:56:07 -07:00
2018-03-22 09:00:45 -07:00
candidates = make([]Candidate, maxRetrieve)
i := 0
for ; ; i++ {
if !iterator.Valid() || i > int(maxRetrieve-1) {
iterator.Close()
break
}
bz := iterator.Value()
var candidate Candidate
err := k.cdc.UnmarshalBinary(bz, &candidate)
if err != nil {
panic(err)
}
candidates[i] = candidate
iterator.Next()
}
return candidates[:i] // trim
}
2018-03-22 14:47:57 -07:00
func (k Keeper) setCandidate(ctx sdk.Context, candidate Candidate) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-22 14:47:57 -07:00
address := candidate.Address
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// retreive the old candidate record
oldCandidate, oldFound := k.GetCandidate(ctx, address)
// marshal the candidate record and add to the state
bz, err := k.cdc.MarshalBinary(candidate)
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
2018-03-22 14:47:57 -07:00
store.Set(GetCandidateKey(candidate.Address), bz)
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// mashal the new validator record
validator := Validator{address, candidate.Assets}
2018-03-22 14:47:57 -07:00
bz, err = k.cdc.MarshalBinary(validator)
if err != nil {
panic(err)
}
2018-03-20 06:56:07 -07:00
2018-04-02 11:37:35 -07:00
// if the voting power is the same no need to update any of the other indexes
if oldFound && oldCandidate.Assets.Equal(candidate.Assets) {
return
}
2018-03-20 06:56:07 -07:00
// update the list ordered by voting power
2018-03-22 14:47:57 -07:00
if oldFound {
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
2018-03-22 14:47:57 -07:00
}
store.Set(GetValidatorKey(address, validator.VotingPower, k.cdc), bz)
// add to the validators to update list if is already a validator
2018-04-02 11:37:35 -07:00
// 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
}
if setAcc {
store.Set(GetAccUpdateValidatorKey(validator.Address), bz)
}
return
2018-03-20 06:56:07 -07:00
}
2018-03-22 14:47:57 -07:00
func (k Keeper) removeCandidate(ctx sdk.Context, address sdk.Address) {
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// first retreive the old candidate record
oldCandidate, found := k.GetCandidate(ctx, address)
if !found {
return
}
// delete the old candidate record
store := ctx.KVStore(k.storeKey)
store.Delete(GetCandidateKey(address))
2018-04-02 13:18:54 -07:00
store.Delete(GetValidatorKey(address, oldCandidate.Assets, k.cdc))
2018-03-22 09:00:45 -07:00
2018-03-22 14:47:57 -07:00
// delete from recent and power weighted validator groups if the validator
// exists and add validator with zero power to the validator updates
2018-04-02 13:18:54 -07:00
if store.Get(GetRecentValidatorKey(address)) == nil {
2018-03-22 14:47:57 -07:00
return
}
bz, err := k.cdc.MarshalBinary(Validator{address, sdk.ZeroRat})
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
2018-03-22 14:47:57 -07:00
store.Set(GetAccUpdateValidatorKey(address), bz)
store.Delete(GetRecentValidatorKey(address))
2018-03-20 06:56:07 -07:00
}
2018-03-22 14:47:57 -07:00
//___________________________________________________________________________
2018-03-20 06:56:07 -07:00
// get the most recent updated validator set from the Candidates. These bonds
// are already sorted by Assets from the UpdateVotingPower function which
// is the only function which is to modify the Assets
2018-03-22 14:47:57 -07:00
// this function also updaates the most recent validators saved in store
func (k Keeper) GetValidators(ctx sdk.Context) (validators []Validator) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-20 06:56:07 -07:00
2018-04-02 11:37:35 -07:00
// 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()
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// add the actual validator power sorted store
maxVal := k.GetParams(ctx).MaxValidators
2018-04-02 11:37:35 -07:00
iterator = store.ReverseIterator(subspace(ValidatorsKey)) // largest to smallest
2018-03-20 06:56:07 -07:00
validators = make([]Validator, maxVal)
i := 0
for ; ; i++ {
2018-03-22 06:39:31 -07:00
if !iterator.Valid() || i > int(maxVal-1) {
2018-03-20 06:56:07 -07:00
iterator.Close()
break
}
2018-03-22 14:47:57 -07:00
bz := iterator.Value()
2018-03-20 06:56:07 -07:00
var val Validator
2018-03-22 14:47:57 -07:00
err := k.cdc.UnmarshalBinary(bz, &val)
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
validators[i] = val
2018-03-22 14:47:57 -07:00
2018-04-02 11:37:35 -07:00
// remove from ToKickOut group
store.Delete(GetToKickOutValidatorKey(val.Address))
2018-03-22 14:47:57 -07:00
// also add to the recent validators group
2018-04-02 11:37:35 -07:00
store.Set(GetRecentValidatorKey(val.Address), bz) // XXX should store nothing
2018-03-22 14:47:57 -07:00
2018-03-20 06:56:07 -07:00
iterator.Next()
}
2018-03-22 14:47:57 -07:00
2018-04-02 11:37:35 -07:00
// 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
2018-03-20 06:56:07 -07:00
}
// 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
}
2018-03-22 14:47:57 -07:00
// 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)
if store.Get(GetRecentValidatorKey(address)) == nil {
return false
}
return true
}
2018-03-20 06:56:07 -07:00
//_________________________________________________________________________
2018-03-22 14:47:57 -07:00
// Accumulated updates to the validator set
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// get the most recently updated validators
func (k Keeper) getAccUpdateValidators(ctx sdk.Context) (updates []Validator) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
iterator := store.Iterator(subspace(AccUpdateValidatorsKey)) //smallest to largest
2018-03-20 06:56:07 -07:00
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val Validator
2018-03-22 06:39:31 -07:00
err := k.cdc.UnmarshalBinary(valBytes, &val)
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
updates = append(updates, val)
}
iterator.Close()
return
}
// remove all validator update entries
2018-03-22 14:47:57 -07:00
func (k Keeper) clearAccUpdateValidators(ctx sdk.Context) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-22 14:47:57 -07:00
k.deleteSubSpace(store, AccUpdateValidatorsKey)
}
// TODO move to common functionality somewhere
func (k Keeper) deleteSubSpace(store sdk.KVStore, key []byte) {
iterator := store.Iterator(subspace(key))
2018-03-20 06:56:07 -07:00
for ; iterator.Valid(); iterator.Next() {
2018-03-22 14:47:57 -07:00
store.Delete(iterator.Key())
2018-03-20 06:56:07 -07:00
}
iterator.Close()
}
//_____________________________________________________________________
2018-03-20 14:21:18 -07:00
func (k Keeper) getDelegatorBond(ctx sdk.Context,
delegatorAddr, candidateAddr sdk.Address) (bond DelegatorBond, found bool) {
2018-03-20 06:56:07 -07:00
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
delegatorBytes := store.Get(GetDelegatorBondKey(delegatorAddr, candidateAddr, k.cdc))
2018-03-20 06:56:07 -07:00
if delegatorBytes == nil {
2018-03-20 14:21:18 -07:00
return bond, false
2018-03-20 06:56:07 -07:00
}
2018-03-22 06:39:31 -07:00
err := k.cdc.UnmarshalBinary(delegatorBytes, &bond)
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
2018-03-20 14:21:18 -07:00
return bond, true
2018-03-20 06:56:07 -07:00
}
2018-03-22 09:00:45 -07:00
// load all bonds of a delegator
func (k Keeper) getDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegatorBondsKey(delegator, k.cdc)
iterator := store.Iterator(subspace(delegatorPrefixKey)) //smallest to largest
bonds = make([]DelegatorBond, maxRetrieve)
i := 0
for ; ; i++ {
if !iterator.Valid() || i > int(maxRetrieve-1) {
iterator.Close()
break
}
bondBytes := iterator.Value()
var bond DelegatorBond
err := k.cdc.UnmarshalBinary(bondBytes, &bond)
if err != nil {
panic(err)
}
bonds[i] = bond
iterator.Next()
}
return bonds[:i] // trim
2018-03-20 06:56:07 -07:00
}
2018-03-22 14:47:57 -07:00
func (k Keeper) setDelegatorBond(ctx sdk.Context, bond DelegatorBond) {
store := ctx.KVStore(k.storeKey)
b, err := k.cdc.MarshalBinary(bond)
if err != nil {
panic(err)
}
store.Set(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc), b)
}
func (k Keeper) removeDelegatorBond(ctx sdk.Context, bond DelegatorBond) {
store := ctx.KVStore(k.storeKey)
store.Delete(GetDelegatorBondKey(bond.DelegatorAddr, bond.CandidateAddr, k.cdc))
}
2018-03-20 06:56:07 -07:00
//_______________________________________________________________________
// load/save the global staking params
func (k Keeper) GetParams(ctx sdk.Context) (params Params) {
2018-03-20 06:56:07 -07:00
// check if cached before anything
2018-03-20 14:21:18 -07:00
if k.params != (Params{}) {
return k.params
2018-03-20 06:56:07 -07:00
}
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-20 06:56:07 -07:00
b := store.Get(ParamKey)
if b == nil {
panic(errors.New("Stored params should not have been nil"))
2018-03-20 06:56:07 -07:00
}
2018-03-22 06:39:31 -07:00
err := k.cdc.UnmarshalBinary(b, &params)
2018-03-20 06:56:07 -07:00
if err != nil {
2018-03-22 09:00:45 -07:00
panic(err)
2018-03-20 06:56:07 -07:00
}
return
}
2018-03-20 14:21:18 -07:00
func (k Keeper) setParams(ctx sdk.Context, params Params) {
store := ctx.KVStore(k.storeKey)
2018-03-22 06:39:31 -07:00
b, err := k.cdc.MarshalBinary(params)
2018-03-20 06:56:07 -07:00
if err != nil {
panic(err)
}
store.Set(ParamKey, b)
2018-03-20 14:21:18 -07:00
k.params = Params{} // clear the cache
2018-03-20 06:56:07 -07:00
}
2018-03-28 13:37:42 -07:00
//_______________________________________________________________________
// load/save the pool
func (k Keeper) GetPool(ctx sdk.Context) (gs Pool) {
// check if cached before anything
if k.gs != (Pool{}) {
return k.gs
}
store := ctx.KVStore(k.storeKey)
b := store.Get(PoolKey)
if b == nil {
panic(errors.New("Stored pool should not have been nil"))
2018-03-28 13:37:42 -07:00
}
err := k.cdc.UnmarshalBinary(b, &gs)
if err != nil {
panic(err) // This error should never occur big problem if does
}
return
}
func (k Keeper) setPool(ctx sdk.Context, p Pool) {
store := ctx.KVStore(k.storeKey)
b, err := k.cdc.MarshalBinary(p)
if err != nil {
panic(err)
}
store.Set(PoolKey, b)
k.gs = Pool{} // clear the cache
}