cosmos-sdk/x/stake/keeper.go

541 lines
15 KiB
Go
Raw Normal View History

2018-03-20 06:56:07 -07:00
package stake
import (
"bytes"
2018-05-04 18:29:12 -07:00
"sort"
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"
abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
2018-03-20 06:56:07 -07:00
)
// keeper of the staking store
type Keeper struct {
storeKey sdk.StoreKey
cdc *wire.Codec
2018-04-18 21:49:24 -07:00
coinKeeper bank.Keeper
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
// caches
2018-04-30 14:21:14 -07:00
pool Pool
2018-03-20 06:56:07 -07:00
params Params
// codespace
codespace sdk.CodespaceType
2018-03-20 06:56:07 -07:00
}
2018-04-18 21:49:24 -07:00
func NewKeeper(cdc *wire.Codec, key sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
2018-03-20 06:56:07 -07:00
keeper := Keeper{
storeKey: key,
cdc: cdc,
coinKeeper: ck,
codespace: codespace,
2018-03-20 06:56:07 -07:00
}
return keeper
}
// get the current in-block validator operation counter
2018-05-03 23:00:30 -07:00
func (k Keeper) getIntraTxCounter(ctx sdk.Context) int16 {
store := ctx.KVStore(k.storeKey)
2018-05-03 23:00:30 -07:00
b := store.Get(IntraTxCounterKey)
if b == nil {
return 0
}
var counter int16
k.cdc.MustUnmarshalBinary(b, &counter)
return counter
}
// set the current in-block validator operation counter
2018-05-03 23:00:30 -07:00
func (k Keeper) setIntraTxCounter(ctx sdk.Context, counter int16) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinary(counter)
2018-05-03 23:00:30 -07:00
store.Set(IntraTxCounterKey, bz)
}
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
}
k.cdc.MustUnmarshalBinary(b, &candidate)
2018-03-20 14:21:18 -07:00
return candidate, true
2018-03-20 06:56:07 -07:00
}
2018-04-24 06:46:39 -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)
iterator := store.SubspaceIterator(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++ {
2018-04-24 06:46:39 -07:00
if !iterator.Valid() || i > int(maxRetrieve-1) {
2018-03-22 09:00:45 -07:00
iterator.Close()
break
}
bz := iterator.Value()
var candidate Candidate
k.cdc.MustUnmarshalBinary(bz, &candidate)
2018-03-22 09:00:45 -07:00
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)
// if found, copy the old block height and counter
if oldFound {
candidate.ValidatorBondHeight = oldCandidate.ValidatorBondHeight
candidate.ValidatorBondCounter = oldCandidate.ValidatorBondCounter
}
2018-03-22 14:47:57 -07:00
// marshal the candidate record and add to the state
bz := k.cdc.MustMarshalBinary(candidate)
store.Set(GetCandidateKey(address), bz)
2018-03-20 06:56:07 -07:00
2018-03-22 14:47:57 -07:00
if oldFound {
2018-05-04 18:29:12 -07:00
// if the voting power is the same no need to update any of the other indexes
if oldCandidate.BondedShares.Equal(candidate.BondedShares) {
return
}
2018-05-04 16:15:24 -07:00
// if this candidate wasn't just bonded then update the height and counter
2018-05-04 18:29:12 -07:00
if oldCandidate.Status != Bonded {
2018-05-04 16:15:24 -07:00
candidate.ValidatorBondHeight = ctx.BlockHeight()
counter := k.getIntraTxCounter(ctx)
candidate.ValidatorBondCounter = counter
k.setIntraTxCounter(ctx, counter+1)
2018-04-12 03:37:38 -07:00
}
2018-05-04 16:15:24 -07:00
// delete the old record in the power ordered list
store.Delete(GetValidatorKey(oldCandidate.validator()))
2018-03-22 14:47:57 -07:00
}
2018-04-09 04:12:08 -07:00
2018-05-04 16:15:24 -07:00
// set the new candidate record
bz = k.cdc.MustMarshalBinary(candidate)
store.Set(GetCandidateKey(address), bz)
2018-04-09 04:12:08 -07:00
2018-05-04 18:29:12 -07:00
// update the list ordered by voting power
2018-04-09 04:12:08 -07:00
validator := candidate.validator()
2018-05-04 18:29:12 -07:00
bzVal := k.cdc.MustMarshalBinary(validator)
store.Set(GetValidatorKey(validator), bzVal)
2018-03-22 14:47:57 -07:00
// add to the validators to update list if is already a validator
if store.Get(GetRecentValidatorKey(candidate.PubKey)) != nil {
2018-05-04 18:29:12 -07:00
bzAbci := k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc))
store.Set(GetAccUpdateValidatorKey(address), bzAbci)
2018-04-09 03:17:45 -07:00
2018-05-04 18:29:12 -07:00
// also update the recent validator store
store.Set(GetRecentValidatorKey(validator.PubKey), bzVal)
return
2018-05-04 16:15:24 -07:00
}
2018-05-03 23:00:30 -07:00
2018-05-04 18:29:12 -07:00
// maybe add to the validator list and kick somebody off
k.addNewValidatorOrNot(ctx, store, candidate.Address)
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
candidate, found := k.GetCandidate(ctx, address)
2018-03-22 14:47:57 -07:00
if !found {
return
}
// delete the old candidate record
store := ctx.KVStore(k.storeKey)
store.Delete(GetCandidateKey(address))
2018-05-04 16:15:24 -07:00
store.Delete(GetValidatorKey(candidate.validator()))
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
if store.Get(GetRecentValidatorKey(candidate.PubKey)) == nil {
2018-03-22 14:47:57 -07:00
return
}
bz := k.cdc.MustMarshalBinary(candidate.validator().abciValidatorZero(k.cdc))
2018-03-22 14:47:57 -07:00
store.Set(GetAccUpdateValidatorKey(address), bz)
store.Delete(GetRecentValidatorKey(candidate.PubKey))
2018-03-20 06:56:07 -07:00
}
2018-03-22 14:47:57 -07:00
//___________________________________________________________________________
2018-05-04 18:29:12 -07:00
// get the group of the most recent validators
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-05-04 18:29:12 -07:00
// add the actual validator power sorted store
maxValidators := k.GetParams(ctx).MaxValidators
validators = make([]Validator, maxValidators)
iterator := store.SubspaceIterator(RecentValidatorsKey)
i := 0
for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value()
var validator Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
validators[i] = validator
i++
}
iterator.Close()
return validators[:i] // trim
}
// Only used for testing
// get the group of the most recent validators
func (k Keeper) getValidatorsOrdered(ctx sdk.Context) []Validator {
vals := k.GetValidators(ctx)
sort.Sort(sort.Reverse(validators(vals)))
return vals
}
// Is the address provided a part of the most recently saved validator group?
func (k Keeper) IsValidator(ctx sdk.Context, pk crypto.PubKey) bool {
store := ctx.KVStore(k.storeKey)
if store.Get(GetRecentValidatorKey(pk)) == nil {
return false
}
return true
}
// This function add's (or doesn't add) a candidate record to the validator group
// simultaniously it kicks any old validators out
//
// The correct subset is retrieved by iterating through an index of the
// candidates sorted by power, stored using the ValidatorsKey. Simultaniously
// the most recent the validator records are updated in store with the
// RecentValidatorsKey. This store is used to determine if a candidate is a
// validator without needing to iterate over the subspace as we do in
// GetValidators
func (k Keeper) addNewValidatorOrNot(ctx sdk.Context, store sdk.KVStore, address sdk.Address) {
// clear the recent validators store, add to the ToKickOut temp store
iterator := store.SubspaceIterator(RecentValidatorsKey)
2018-04-02 11:37:35 -07:00
for ; iterator.Valid(); iterator.Next() {
bz := iterator.Value()
var validator Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
2018-05-04 18:29:12 -07:00
addr := validator.Address
// iterator.Value is the validator object
store.Set(GetToKickOutValidatorKey(addr), iterator.Value())
2018-04-02 11:37:35 -07:00
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
maxValidators := k.GetParams(ctx).MaxValidators
iterator = store.ReverseSubspaceIterator(ValidatorsKey) // largest to smallest
i := 0
for ; ; i++ {
if !iterator.Valid() || i > int(maxValidators-1) {
2018-03-20 06:56:07 -07:00
iterator.Close()
break
}
2018-03-22 14:47:57 -07:00
bz := iterator.Value()
var validator Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
2018-03-22 14:47:57 -07:00
2018-04-02 11:37:35 -07:00
// remove from ToKickOut group
store.Delete(GetToKickOutValidatorKey(validator.Address))
2018-04-02 11:37:35 -07:00
2018-03-22 14:47:57 -07:00
// also add to the recent validators group
store.Set(GetRecentValidatorKey(validator.PubKey), bz)
2018-03-22 14:47:57 -07:00
2018-05-04 18:29:12 -07:00
// MOST IMPORTANTLY, add to the accumulated changes if this is the modified candidate
if bytes.Equal(address, validator.Address) {
bz = k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc))
store.Set(GetAccUpdateValidatorKey(address), bz)
}
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.SubspaceIterator(ToKickOutValidatorsKey)
2018-04-02 11:37:35 -07:00
for ; iterator.Valid(); iterator.Next() {
key := iterator.Key()
addr := AddrFromKey(key)
// get the zero abci validator from the ToKickOut iterator value
bz := iterator.Value()
var validator Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
bz = k.cdc.MustMarshalBinary(validator.abciValidatorZero(k.cdc))
2018-04-02 11:37:35 -07:00
store.Set(GetAccUpdateValidatorKey(addr), bz)
store.Delete(key)
2018-04-02 11:37:35 -07:00
}
iterator.Close()
2018-03-22 14:47:57 -07:00
}
2018-05-03 21:02:45 -07:00
// cummulative power of the non-absent prevotes
func (k Keeper) GetTotalPrecommitVotingPower(ctx sdk.Context) sdk.Rat {
store := ctx.KVStore(k.storeKey)
// get absent prevote indexes
absents := ctx.AbsentValidators()
TotalPower := sdk.ZeroRat()
i := int32(0)
iterator := store.SubspaceIterator(RecentValidatorsKey)
for ; iterator.Valid(); iterator.Next() {
skip := false
for j, absentIndex := range absents {
if absentIndex > i {
break
}
// if non-voting validator found, skip adding its power
if absentIndex == i {
absents = append(absents[:j], absents[j+1:]...) // won't need again
skip = true
break
}
}
if skip {
2018-05-03 21:02:45 -07:00
continue
}
bz := iterator.Value()
var validator Validator
k.cdc.MustUnmarshalBinary(bz, &validator)
TotalPower = TotalPower.Add(validator.Power)
i++
}
iterator.Close()
return TotalPower
}
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 []abci.Validator) {
2018-03-20 14:21:18 -07:00
store := ctx.KVStore(k.storeKey)
2018-03-20 06:56:07 -07:00
iterator := store.SubspaceIterator(AccUpdateValidatorsKey) //smallest to largest
2018-03-20 06:56:07 -07:00
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val abci.Validator
k.cdc.MustUnmarshalBinary(valBytes, &val)
2018-03-20 06:56:07 -07:00
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
// delete subspace
iterator := store.SubspaceIterator(AccUpdateValidatorsKey)
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-04-23 09:17:21 -07:00
// load a delegator bond
2018-04-10 20:51:09 -07:00
func (k Keeper) GetDelegatorBond(ctx sdk.Context,
2018-03-20 14:21:18 -07:00
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
}
k.cdc.MustUnmarshalBinary(delegatorBytes, &bond)
2018-03-20 14:21:18 -07:00
return bond, true
2018-03-20 06:56:07 -07:00
}
2018-04-24 06:46:39 -07:00
// load all bonds
2018-04-26 11:13:16 -07:00
func (k Keeper) getBonds(ctx sdk.Context, maxRetrieve int16) (bonds []DelegatorBond) {
store := ctx.KVStore(k.storeKey)
iterator := store.SubspaceIterator(DelegatorBondKeyPrefix)
bonds = make([]DelegatorBond, maxRetrieve)
i := 0
for ; ; i++ {
2018-04-24 06:46:39 -07:00
if !iterator.Valid() || i > int(maxRetrieve-1) {
iterator.Close()
break
}
bondBytes := iterator.Value()
var bond DelegatorBond
k.cdc.MustUnmarshalBinary(bondBytes, &bond)
bonds[i] = bond
iterator.Next()
}
return bonds[:i] // trim
}
2018-03-22 09:00:45 -07:00
// load all bonds of a delegator
2018-04-10 20:51:09 -07:00
func (k Keeper) GetDelegatorBonds(ctx sdk.Context, delegator sdk.Address, maxRetrieve int16) (bonds []DelegatorBond) {
2018-03-22 09:00:45 -07:00
store := ctx.KVStore(k.storeKey)
delegatorPrefixKey := GetDelegatorBondsKey(delegator, k.cdc)
iterator := store.SubspaceIterator(delegatorPrefixKey) //smallest to largest
2018-03-22 09:00:45 -07:00
bonds = make([]DelegatorBond, maxRetrieve)
i := 0
for ; ; i++ {
if !iterator.Valid() || i > int(maxRetrieve-1) {
iterator.Close()
break
}
bondBytes := iterator.Value()
var bond DelegatorBond
k.cdc.MustUnmarshalBinary(bondBytes, &bond)
2018-03-22 09:00:45 -07:00
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 := k.cdc.MustMarshalBinary(bond)
2018-03-22 14:47:57 -07:00
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
//_______________________________________________________________________
2018-05-03 23:00:30 -07:00
// XXX TODO trim functionality
// retrieve all the power changes which occur after a height
func (k Keeper) GetPowerChangesAfterHeight(ctx sdk.Context, earliestHeight int64) (pcs []PowerChange) {
store := ctx.KVStore(k.storeKey)
iterator := store.SubspaceIterator(PowerChangeKey) //smallest to largest
for ; iterator.Valid(); iterator.Next() {
pcBytes := iterator.Value()
var pc PowerChange
k.cdc.MustUnmarshalBinary(pcBytes, &pc)
if pc.Height < earliestHeight {
break
}
pcs = append(pcs, pc)
}
iterator.Close()
return
}
// set a power change
func (k Keeper) setPowerChange(ctx sdk.Context, pc PowerChange) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinary(pc)
store.Set(GetPowerChangeKey(pc.Height), b)
}
//_______________________________________________________________________
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-04-30 14:21:14 -07:00
if !k.params.equal(Params{}) {
2018-03-20 14:21:18 -07:00
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 {
2018-04-03 11:50:31 -07:00
panic("Stored params should not have been nil")
2018-03-20 06:56:07 -07:00
}
k.cdc.MustUnmarshalBinary(b, &params)
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)
b := k.cdc.MustMarshalBinary(params)
2018-03-20 06:56:07 -07:00
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
2018-04-30 14:21:14 -07:00
func (k Keeper) GetPool(ctx sdk.Context) (pool Pool) {
2018-03-28 13:37:42 -07:00
// check if cached before anything
2018-04-30 14:21:14 -07:00
if !k.pool.equal(Pool{}) {
return k.pool
2018-03-28 13:37:42 -07:00
}
store := ctx.KVStore(k.storeKey)
b := store.Get(PoolKey)
if b == nil {
2018-04-03 11:50:31 -07:00
panic("Stored pool should not have been nil")
2018-03-28 13:37:42 -07:00
}
k.cdc.MustUnmarshalBinary(b, &pool)
2018-03-28 13:37:42 -07:00
return
}
func (k Keeper) setPool(ctx sdk.Context, p Pool) {
store := ctx.KVStore(k.storeKey)
b := k.cdc.MustMarshalBinary(p)
2018-03-28 13:37:42 -07:00
store.Set(PoolKey, b)
2018-04-30 14:21:14 -07:00
k.pool = Pool{} //clear the cache
2018-03-28 13:37:42 -07:00
}
2018-04-25 07:12:59 -07:00
//__________________________________________________________________________
// Implements ValidatorSetKeeper
var _ sdk.ValidatorSetKeeper = Keeper{}
2018-05-06 07:18:45 -07:00
func (k Keeper) ValidatorSet(ctx sdk.Context) sdk.ValidatorSet {
vals := k.GetValidators(ctx)
2018-05-06 07:18:45 -07:00
return ValidatorSet(vals)
2018-04-25 07:12:59 -07:00
}
2018-05-06 11:39:50 -07:00
func (k Keeper) Validator(ctx sdk.Context, addr sdk.Address) sdk.Validator {
2018-05-06 07:18:45 -07:00
can, ok := k.GetCandidate(ctx, addr)
if !ok {
return nil
2018-04-25 07:12:59 -07:00
}
2018-05-06 07:18:45 -07:00
if can.Status != Bonded {
2018-04-25 07:12:59 -07:00
return nil
}
2018-05-06 07:18:45 -07:00
return can.validator()
2018-04-25 07:12:59 -07:00
}
2018-04-17 14:38:12 -07:00
func (k Keeper) TotalPower(ctx sdk.Context) sdk.Rat {
2018-05-02 11:50:50 -07:00
pool := k.GetPool(ctx)
return pool.BondedShares
2018-04-25 07:12:59 -07:00
}
2018-05-06 11:39:50 -07:00
func (k Keeper) Delegation(ctx sdk.Context, del sdk.Address, val sdk.Address) sdk.Delegation {
bond, ok := k.GetDelegatorBond(ctx, del, val)
if !ok {
return nil
}
return bond
}
func (k Keeper) DelegationSet(ctx sdk.Context, del sdk.Address) sdk.DelegationSet {
bs := k.GetDelegatorBonds(ctx, del, 32767)
return DelegationSet(bs)
}