cosmos-sdk/x/stake/mapper.go

361 lines
10 KiB
Go
Raw Normal View History

2018-01-11 21:30:39 -08:00
package stake
import (
2018-03-16 12:47:17 -07:00
"bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
2018-01-11 21:30:39 -08:00
)
//nolint
2018-01-11 21:30:39 -08:00
var (
// Keys for store prefixes
CandidatesAddrKey = []byte{0x01} // key for all candidates' addresses
ParamKey = []byte{0x02} // key for global parameters relating to staking
GlobalStateKey = []byte{0x03} // key for global parameters relating to staking
2018-01-11 21:30:39 -08:00
// Key prefixes
CandidateKeyPrefix = []byte{0x04} // prefix for each key to a candidate
ValidatorKeyPrefix = []byte{0x05} // prefix for each key to a candidate
ValidatorUpdatesKeyPrefix = []byte{0x06} // prefix for each key to a candidate
DelegatorBondKeyPrefix = []byte{0x07} // prefix for each key to a delegator's bond
DelegatorBondsKeyPrefix = []byte{0x08} // prefix for each key to a delegator's bond
2018-01-11 21:30:39 -08:00
)
// GetCandidateKey - get the key for the candidate with address
func GetCandidateKey(address sdk.Address) []byte {
return append(CandidateKeyPrefix, address.Bytes()...)
2018-01-11 21:30:39 -08:00
}
2018-01-25 01:06:25 -08:00
// GetValidatorKey - get the key for the validator used in the power-store
2018-03-16 12:47:17 -07:00
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
2018-01-25 01:06:25 -08:00
}
// GetValidatorUpdatesKey - get the key for the validator used in the power-store
func GetValidatorUpdatesKey(address sdk.Address) []byte {
return append(ValidatorUpdatesKeyPrefix, address.Bytes()...) // TODO does this need prefix if its in its own store
}
2018-01-11 21:30:39 -08:00
// GetDelegatorBondKey - get the key for delegator bond with candidate
2018-03-16 12:47:17 -07:00
func GetDelegatorBondKey(delegator, candidate sdk.Address, cdc *wire.Codec) []byte {
return append(GetDelegatorBondKeyPrefix(delegator, cdc), candidate.Bytes()...)
2018-01-11 21:30:39 -08:00
}
// GetDelegatorBondKeyPrefix - get the prefix for a delegator for all candidates
2018-03-16 12:47:17 -07:00
func GetDelegatorBondKeyPrefix(delegator sdk.Address, cdc *wire.Codec) []byte {
res, err := cdc.MarshalJSON(&delegator)
2018-01-18 00:39:16 -08:00
if err != nil {
panic(err)
}
return append(DelegatorBondKeyPrefix, res...)
2018-01-11 21:30:39 -08:00
}
// GetDelegatorBondsKey - get the key for list of all the delegator's bonds
2018-03-16 12:47:17 -07:00
func GetDelegatorBondsKey(delegator sdk.Address, cdc *wire.Codec) []byte {
res, err := cdc.MarshalJSON(&delegator)
2018-01-18 00:39:16 -08:00
if err != nil {
panic(err)
}
return append(DelegatorBondsKeyPrefix, res...)
2018-01-11 21:30:39 -08:00
}
//___________________________________________________________________________
// mapper of the staking store
type Mapper struct {
store sdk.KVStore
cdc *wire.Codec
}
2018-01-11 21:30:39 -08:00
func NewMapper(ctx sdk.Context, cdc *wire.Codec, key sdk.StoreKey) Mapper {
2018-03-16 12:47:17 -07:00
return Mapper{
store: ctx.KVStore(key),
cdc: cdc,
}
}
func (m Mapper) loadCandidate(address sdk.Address) *Candidate {
b := m.store.Get(GetCandidateKey(address))
2018-01-11 21:30:39 -08:00
if b == nil {
return nil
}
candidate := new(Candidate)
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(b, candidate)
2018-01-11 21:30:39 -08:00
if err != nil {
2018-01-25 01:06:25 -08:00
panic(err) // This error should never occur big problem if does
2018-01-11 21:30:39 -08:00
}
return candidate
}
func (m Mapper) saveCandidate(candidate *Candidate) {
2018-01-11 21:30:39 -08:00
// XXX should only remove validator if we know candidate is a validator
2018-03-16 12:47:17 -07:00
m.removeValidator(candidate.Address)
validator := &Validator{candidate.Address, candidate.VotingPower}
2018-03-16 12:47:17 -07:00
m.updateValidator(validator)
2018-01-11 21:30:39 -08:00
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(*candidate)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
m.store.Set(GetCandidateKey(candidate.Address), b)
2018-01-11 21:30:39 -08:00
}
func (m Mapper) removeCandidate(address sdk.Address) {
// XXX should only remove validator if we know candidate is a validator
2018-03-16 12:47:17 -07:00
m.removeValidator(address)
m.store.Delete(GetCandidateKey(address))
2018-01-11 21:30:39 -08:00
}
//___________________________________________________________________________
2018-01-11 21:30:39 -08:00
//func loadValidator(m.store sdk.KVStore, address sdk.Address, votingPower sdk.Rational) *Validator {
//b := m.store.Get(GetValidatorKey(address, votingPower))
//if b == nil {
//return nil
//}
//validator := new(Validator)
//err := cdc.UnmarshalJSON(b, validator)
//if err != nil {
//panic(err) // This error should never occur big problem if does
//}
//return validator
//}
// updateValidator - update a validator and create accumulate any changes
// in the changed validator substore
func (m Mapper) updateValidator(validator *Validator) {
2018-01-25 01:06:25 -08:00
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(*validator)
2018-01-23 01:04:36 -08:00
if err != nil {
panic(err)
}
// add to the validators to update list if necessary
m.store.Set(GetValidatorUpdatesKey(validator.Address), b)
// update the list ordered by voting power
2018-03-16 12:47:17 -07:00
m.store.Set(GetValidatorKey(validator.Address, validator.VotingPower, m.cdc), b)
2018-01-23 01:04:36 -08:00
}
func (m Mapper) removeValidator(address sdk.Address) {
//add validator with zero power to the validator updates
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(Validator{address, sdk.ZeroRat})
if err != nil {
panic(err)
}
m.store.Set(GetValidatorUpdatesKey(address), b)
2018-01-25 01:06:25 -08:00
// now actually delete from the validator set
2018-03-16 12:47:17 -07:00
candidate := m.loadCandidate(address)
2018-01-25 01:06:25 -08:00
if candidate != nil {
2018-03-16 12:47:17 -07:00
m.store.Delete(GetValidatorKey(address, candidate.VotingPower, m.cdc))
2018-01-23 01:04:36 -08:00
}
}
// 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
2018-03-16 12:47:17 -07:00
func (m Mapper) getValidators(maxVal uint16) (validators []Validator) {
2018-01-23 01:04:36 -08:00
iterator := m.store.Iterator(subspace(ValidatorKeyPrefix)) //smallest to largest
2018-01-23 01:04:36 -08:00
validators = make([]Validator, maxVal)
2018-01-23 01:04:36 -08:00
for i := 0; ; i++ {
2018-03-16 12:47:17 -07:00
if !iterator.Valid() || i > int(maxVal) {
2018-01-23 01:04:36 -08:00
iterator.Close()
break
}
2018-01-25 01:06:25 -08:00
valBytes := iterator.Value()
var val Validator
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(valBytes, &val)
2018-01-23 01:04:36 -08:00
if err != nil {
panic(err)
}
2018-01-25 01:06:25 -08:00
validators[i] = val
2018-01-23 01:04:36 -08:00
iterator.Next()
}
return
}
//_________________________________________________________________________
// get the most updated validators
func (m Mapper) getValidatorUpdates() (updates []Validator) {
iterator := m.store.Iterator(subspace(ValidatorUpdatesKeyPrefix)) //smallest to largest
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val Validator
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(valBytes, &val)
if err != nil {
panic(err)
}
updates = append(updates, val)
}
iterator.Close()
return
}
// remove all validator update entries
func (m Mapper) clearValidatorUpdates(maxVal int) {
iterator := m.store.Iterator(subspace(ValidatorUpdatesKeyPrefix))
for ; iterator.Valid(); iterator.Next() {
m.store.Delete(iterator.Key()) // XXX write test for this, may need to be in a second loop
}
iterator.Close()
2018-01-23 01:04:36 -08:00
}
//---------------------------------------------------------------------
2018-01-25 01:06:25 -08:00
// loadCandidates - get the active list of all candidates TODO replace with multistore
func (m Mapper) loadCandidates() (candidates Candidates) {
2018-01-25 01:06:25 -08:00
iterator := m.store.Iterator(subspace(CandidateKeyPrefix))
//iterator := m.store.Iterator(CandidateKeyPrefix, []byte(nil))
//iterator := m.store.Iterator([]byte{}, []byte(nil))
2018-01-25 01:06:25 -08:00
for ; iterator.Valid(); iterator.Next() {
2018-01-25 01:06:25 -08:00
candidateBytes := iterator.Value()
var candidate Candidate
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(candidateBytes, &candidate)
2018-01-25 01:06:25 -08:00
if err != nil {
panic(err)
}
candidates = append(candidates, &candidate)
2018-01-25 01:06:25 -08:00
}
iterator.Close()
2018-01-25 01:06:25 -08:00
return candidates
}
//_____________________________________________________________________
2018-01-25 01:06:25 -08:00
2018-01-11 21:30:39 -08:00
// load the pubkeys of all candidates a delegator is delegated too
func (m Mapper) loadDelegatorCandidates(delegator sdk.Address) (candidateAddrs []sdk.Address) {
2018-01-11 21:30:39 -08:00
2018-03-16 12:47:17 -07:00
candidateBytes := m.store.Get(GetDelegatorBondsKey(delegator, m.cdc))
2018-01-11 21:30:39 -08:00
if candidateBytes == nil {
return nil
}
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(candidateBytes, &candidateAddrs)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
return
}
//_____________________________________________________________________
2018-01-11 21:30:39 -08:00
func (m Mapper) loadDelegatorBond(delegator, candidate sdk.Address) *DelegatorBond {
2018-01-11 21:30:39 -08:00
2018-03-16 12:47:17 -07:00
delegatorBytes := m.store.Get(GetDelegatorBondKey(delegator, candidate, m.cdc))
2018-01-11 21:30:39 -08:00
if delegatorBytes == nil {
return nil
}
bond := new(DelegatorBond)
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(delegatorBytes, bond)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
return bond
}
func (m Mapper) saveDelegatorBond(delegator sdk.Address,
bond *DelegatorBond) {
2018-01-11 21:30:39 -08:00
// if a new bond add to the list of bonds
2018-03-16 12:47:17 -07:00
if m.loadDelegatorBond(delegator, bond.Address) == nil {
pks := m.loadDelegatorCandidates(delegator)
pks = append(pks, (*bond).Address)
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(pks)
2018-01-18 00:39:16 -08:00
if err != nil {
panic(err)
}
2018-03-16 12:47:17 -07:00
m.store.Set(GetDelegatorBondsKey(delegator, m.cdc), b)
2018-01-11 21:30:39 -08:00
}
// now actually save the bond
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(*bond)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
2018-03-16 12:47:17 -07:00
m.store.Set(GetDelegatorBondKey(delegator, bond.Address, m.cdc), b)
//updateDelegatorBonds(store, delegator) //XXX remove?
2018-01-11 21:30:39 -08:00
}
2018-03-16 12:47:17 -07:00
func (m Mapper) removeDelegatorBond(delegator sdk.Address, candidateAddr sdk.Address) {
2018-01-11 21:30:39 -08:00
// TODO use list queries on multistore to remove iterations here!
// first remove from the list of bonds
2018-03-16 12:47:17 -07:00
addrs := m.loadDelegatorCandidates(delegator)
for i, addr := range addrs {
if bytes.Equal(candidateAddr, addr) {
addrs = append(addrs[:i], addrs[i+1:]...)
2018-01-11 21:30:39 -08:00
}
}
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(pks)
2018-01-18 00:39:16 -08:00
if err != nil {
panic(err)
}
2018-03-16 12:47:17 -07:00
m.store.Set(GetDelegatorBondsKey(delegator, m.cdc), b)
2018-01-11 21:30:39 -08:00
// now remove the actual bond
2018-03-16 12:47:17 -07:00
m.store.Delete(GetDelegatorBondKey(delegator, candidateAddr, m.cdc))
//updateDelegatorBonds(store, delegator) //XXX remove?
2018-01-11 21:30:39 -08:00
}
//_______________________________________________________________________
// load/save the global staking params
func (m Mapper) loadParams() (params Params) {
b := m.store.Get(ParamKey)
2018-01-11 21:30:39 -08:00
if b == nil {
return defaultParams()
}
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(b, &params)
2018-01-11 21:30:39 -08:00
if err != nil {
2018-01-25 01:06:25 -08:00
panic(err) // This error should never occur big problem if does
2018-01-11 21:30:39 -08:00
}
return
}
func (m Mapper) saveParams(params Params) {
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(params)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
m.store.Set(ParamKey, b)
2018-01-11 21:30:39 -08:00
}
//_______________________________________________________________________
// load/save the global staking state
func (m Mapper) loadGlobalState() (gs *GlobalState) {
b := m.store.Get(GlobalStateKey)
2018-01-11 21:30:39 -08:00
if b == nil {
return initialGlobalState()
}
gs = new(GlobalState)
2018-03-16 12:47:17 -07:00
err := m.cdc.UnmarshalJSON(b, gs)
2018-01-11 21:30:39 -08:00
if err != nil {
2018-01-25 01:06:25 -08:00
panic(err) // This error should never occur big problem if does
2018-01-11 21:30:39 -08:00
}
return
}
func (m Mapper) saveGlobalState(gs *GlobalState) {
2018-03-16 12:47:17 -07:00
b, err := m.cdc.MarshalJSON(*gs)
2018-01-11 21:30:39 -08:00
if err != nil {
panic(err)
}
m.store.Set(GlobalStateKey, b)
2018-01-11 21:30:39 -08:00
}