introduce UpdateSharesLocation to deal with different share types
This commit is contained in:
parent
9bb01c9504
commit
eb87a5dbbf
@ -6,23 +6,23 @@ import (
|
||||
)
|
||||
|
||||
// status of a validator
|
||||
type ValidatorStatus byte
|
||||
type BondStatus byte
|
||||
|
||||
// nolint
|
||||
const (
|
||||
Bonded ValidatorStatus = 0x00
|
||||
Unbonding ValidatorStatus = 0x01
|
||||
Unbonded ValidatorStatus = 0x02
|
||||
Revoked ValidatorStatus = 0x03
|
||||
Bonded BondStatus = 0x00
|
||||
Unbonding BondStatus = 0x01
|
||||
Unbonded BondStatus = 0x02
|
||||
Revoked BondStatus = 0x03
|
||||
)
|
||||
|
||||
// validator for a delegated proof of stake system
|
||||
type Validator interface {
|
||||
GetStatus() ValidatorStatus // status of the validator
|
||||
GetAddress() Address // owner address to receive/return validators coins
|
||||
GetPubKey() crypto.PubKey // validation pubkey
|
||||
GetPower() Rat // validation power
|
||||
GetBondHeight() int64 // height in which the validator became active
|
||||
GetStatus() BondStatus // status of the validator
|
||||
GetAddress() Address // owner address to receive/return validators coins
|
||||
GetPubKey() crypto.PubKey // validation pubkey
|
||||
GetPower() Rat // validation power
|
||||
GetBondHeight() int64 // height in which the validator became active
|
||||
}
|
||||
|
||||
// validator which fulfills abci validator interface for use in Tendermint
|
||||
|
||||
@ -287,7 +287,8 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result {
|
||||
|
||||
// change the share types to unbonded if they were not already
|
||||
if validator.Status == sdk.Bonded {
|
||||
p, validator = p.bondedToUnbondedPool(validator)
|
||||
validator.Status = sdk.Unbonded
|
||||
p, validator = p.UpdateSharesLocation(validator)
|
||||
}
|
||||
|
||||
// lastly update the status
|
||||
|
||||
@ -69,19 +69,23 @@ func (k Keeper) GetValidators(ctx sdk.Context, maxRetrieve int16) (validators Va
|
||||
|
||||
func (k Keeper) setValidator(ctx sdk.Context, validator Validator) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
pool := k.getPool(store)
|
||||
address := validator.Address
|
||||
|
||||
// update the main list ordered by address before exiting
|
||||
defer func() {
|
||||
bz := k.cdc.MustMarshalBinary(validator)
|
||||
store.Set(GetValidatorKey(address), bz)
|
||||
}()
|
||||
|
||||
// retreive the old validator record
|
||||
oldValidator, oldFound := k.GetValidator(ctx, address)
|
||||
|
||||
// marshal the validator record and add to the state
|
||||
bz := k.cdc.MustMarshalBinary(validator)
|
||||
store.Set(GetValidatorKey(address), bz)
|
||||
|
||||
powerIncreasing := false
|
||||
if oldFound {
|
||||
// if the voting power is the same no need to update any of the other indexes
|
||||
if oldValidator.BondedShares.Equal(validator.BondedShares) {
|
||||
if oldValidator.Status == sdk.Bonded &&
|
||||
oldValidator.BondedShares.Equal(validator.BondedShares) {
|
||||
return
|
||||
} else if oldValidator.BondedShares.LT(validator.BondedShares) {
|
||||
powerIncreasing = true
|
||||
@ -116,7 +120,14 @@ func (k Keeper) setValidator(ctx sdk.Context, validator Validator) {
|
||||
}
|
||||
|
||||
// update the validator set for this validator
|
||||
k.updateValidators(ctx, store, validator.Address)
|
||||
valIsNowBonded := k.updateValidators(ctx, store, validator.Address)
|
||||
|
||||
if oldValidator.Status != sdk.Bonded && valIsNowBonded {
|
||||
validator.Status = sdk.Bonded
|
||||
pool, validator = pool.UpdateSharesLocation(validator)
|
||||
k.setPool(ctx, pool)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -187,6 +198,8 @@ func (k Keeper) GetValidatorsBondedByPower(ctx sdk.Context) []Validator {
|
||||
return validators
|
||||
}
|
||||
|
||||
// XXX TODO build in consideration for revoked
|
||||
//
|
||||
// Update the validator group and kick out any old validators. In addition this
|
||||
// function adds (or doesn't add) a validator which has updated its bonded
|
||||
// tokens to the validator group. -> this validator is specified through the
|
||||
@ -198,7 +211,8 @@ func (k Keeper) GetValidatorsBondedByPower(ctx sdk.Context) []Validator {
|
||||
// ValidatorsBondedKey. This store is used to determine if a validator is a
|
||||
// validator without needing to iterate over the subspace as we do in
|
||||
// GetValidators.
|
||||
func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedValidatorAddr sdk.Address) {
|
||||
func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedValidatorAddr sdk.Address) (updatedIsBonded bool) {
|
||||
updatedIsBonded = false
|
||||
|
||||
// clear the current validators store, add to the ToKickOut temp store
|
||||
toKickOut := make(map[string][]byte) // map[key]value
|
||||
@ -240,6 +254,7 @@ func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedVali
|
||||
if bytes.Equal(updatedValidatorAddr, validator.Address) {
|
||||
bz = k.cdc.MustMarshalBinary(validator.abciValidator(k.cdc))
|
||||
store.Set(GetTendermintUpdatesKey(updatedValidatorAddr), bz)
|
||||
updatedIsBonded = true // the updatedValidatorAddr is for a bonded validator
|
||||
}
|
||||
|
||||
iterator.Next()
|
||||
@ -257,6 +272,7 @@ func (k Keeper) updateValidators(ctx sdk.Context, store sdk.KVStore, updatedVali
|
||||
bz := k.cdc.MustMarshalBinary(validator.abciValidatorZero(k.cdc))
|
||||
store.Set(GetTendermintUpdatesKey(addr), bz)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
//_________________________________________________________________________
|
||||
@ -392,11 +408,14 @@ func (k Keeper) setParams(ctx sdk.Context, params Params) {
|
||||
|
||||
// load/save the pool
|
||||
func (k Keeper) GetPool(ctx sdk.Context) (pool Pool) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
return k.getPool(store)
|
||||
}
|
||||
func (k Keeper) getPool(store sdk.KVStore) (pool Pool) {
|
||||
// check if cached before anything
|
||||
if !k.pool.equal(Pool{}) {
|
||||
return k.pool
|
||||
}
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
b := store.Get(PoolKey)
|
||||
if b == nil {
|
||||
panic("Stored pool should not have been nil")
|
||||
|
||||
@ -20,6 +20,14 @@ func (p Pool) bondedShareExRate() sdk.Rat {
|
||||
return sdk.NewRat(p.BondedPool).Quo(p.BondedShares)
|
||||
}
|
||||
|
||||
// get the exchange rate of unbonding tokens held in validators per issued share
|
||||
func (p Pool) unbondingShareExRate() sdk.Rat {
|
||||
if p.UnbondingShares.IsZero() {
|
||||
return sdk.OneRat()
|
||||
}
|
||||
return sdk.NewRat(p.UnbondingPool).Quo(p.UnbondingShares)
|
||||
}
|
||||
|
||||
// get the exchange rate of unbonded tokens held in validators per issued share
|
||||
func (p Pool) unbondedShareExRate() sdk.Rat {
|
||||
if p.UnbondedShares.IsZero() {
|
||||
@ -28,23 +36,38 @@ func (p Pool) unbondedShareExRate() sdk.Rat {
|
||||
return sdk.NewRat(p.UnbondedPool).Quo(p.UnbondedShares)
|
||||
}
|
||||
|
||||
// move a validators asset pool from bonded to unbonded pool
|
||||
func (p Pool) bondedToUnbondedPool(validator Validator) (Pool, Validator) {
|
||||
// XXX write test
|
||||
// update the location of the shares within a validator if its bond status has changed
|
||||
func (p Pool) UpdateSharesLocation(validator Validator) (Pool, Validator) {
|
||||
var tokens int64
|
||||
|
||||
// replace bonded shares with unbonded shares
|
||||
p, tokens := p.removeSharesBonded(validator.BondedShares)
|
||||
p, validator.BondedShares = p.addTokensUnbonded(tokens)
|
||||
validator.Status = sdk.Unbonded
|
||||
return p, validator
|
||||
}
|
||||
switch {
|
||||
case !validator.BondedShares.IsZero():
|
||||
if validator.Status == sdk.Bonded { // return if nothing needs switching
|
||||
return p, validator
|
||||
}
|
||||
p, tokens = p.removeSharesBonded(validator.BondedShares)
|
||||
case !validator.UnbondingShares.IsZero():
|
||||
if validator.Status == sdk.Unbonding {
|
||||
return p, validator
|
||||
}
|
||||
p, tokens = p.removeSharesUnbonding(validator.BondedShares)
|
||||
case !validator.UnbondedShares.IsZero():
|
||||
if validator.Status == sdk.Unbonding {
|
||||
return p, validator
|
||||
}
|
||||
p, tokens = p.removeSharesUnbonded(validator.BondedShares)
|
||||
}
|
||||
|
||||
// move a validators asset pool from unbonded to bonded pool
|
||||
func (p Pool) unbondedToBondedPool(validator Validator) (Pool, Validator) {
|
||||
switch validator.Status {
|
||||
case sdk.Bonded:
|
||||
p, validator.BondedShares = p.addTokensBonded(tokens)
|
||||
case sdk.Unbonding:
|
||||
p, validator.UnbondingShares = p.addTokensUnbonding(tokens)
|
||||
case sdk.Unbonded, sdk.Revoked:
|
||||
p, validator.UnbondedShares = p.addTokensUnbonded(tokens)
|
||||
}
|
||||
|
||||
// replace unbonded shares with bonded shares
|
||||
p, tokens := p.removeSharesUnbonded(validator.BondedShares)
|
||||
p, validator.BondedShares = p.addTokensBonded(tokens)
|
||||
validator.Status = sdk.Bonded
|
||||
return p, validator
|
||||
}
|
||||
|
||||
@ -64,6 +87,20 @@ func (p Pool) removeSharesBonded(shares sdk.Rat) (p2 Pool, removedTokens int64)
|
||||
return p, removedTokens
|
||||
}
|
||||
|
||||
func (p Pool) addTokensUnbonding(amount int64) (p2 Pool, issuedShares sdk.Rat) {
|
||||
issuedShares = sdk.NewRat(amount).Quo(p.unbondingShareExRate()) // tokens * (shares/tokens)
|
||||
p.UnbondingShares = p.UnbondingShares.Add(issuedShares)
|
||||
p.UnbondingPool += amount
|
||||
return p, issuedShares
|
||||
}
|
||||
|
||||
func (p Pool) removeSharesUnbonding(shares sdk.Rat) (p2 Pool, removedTokens int64) {
|
||||
removedTokens = p.unbondingShareExRate().Mul(shares).Evaluate() // (tokens/shares) * shares
|
||||
p.UnbondingShares = p.UnbondingShares.Sub(shares)
|
||||
p.UnbondingPool -= removedTokens
|
||||
return p, removedTokens
|
||||
}
|
||||
|
||||
func (p Pool) addTokensUnbonded(amount int64) (p2 Pool, issuedShares sdk.Rat) {
|
||||
issuedShares = sdk.NewRat(amount).Quo(p.unbondedShareExRate()) // tokens * (shares/tokens)
|
||||
p.UnbondedShares = p.UnbondedShares.Add(issuedShares)
|
||||
|
||||
@ -258,7 +258,7 @@ func TestValidatorRemoveShares(t *testing.T) {
|
||||
|
||||
// generate a random validator
|
||||
func randomValidator(r *rand.Rand) Validator {
|
||||
var status sdk.ValidatorStatus
|
||||
var status sdk.BondStatus
|
||||
if r.Float64() < float64(0.5) {
|
||||
status = sdk.Bonded
|
||||
} else {
|
||||
|
||||
@ -126,17 +126,21 @@ func initialPool() Pool {
|
||||
// exchange rate. Voting power can be calculated as total bonds multiplied by
|
||||
// exchange rate.
|
||||
type Validator struct {
|
||||
Status sdk.ValidatorStatus `json:"status"` // Bonded status
|
||||
Address sdk.Address `json:"address"` // Sender of BondTx - UnbondTx returns here
|
||||
PubKey crypto.PubKey `json:"pub_key"` // Pubkey of validator
|
||||
BondedShares sdk.Rat `json:"bonded_shares"` // total shares of bonded global hold pool
|
||||
UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of unbonding global hold pool
|
||||
UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of unbonded global hold pool
|
||||
DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a validator's delegators
|
||||
Status sdk.BondStatus `json:"status"` // bonded status
|
||||
Address sdk.Address `json:"address"` // sender of BondTx - UnbondTx returns here
|
||||
PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator
|
||||
|
||||
Description Description `json:"description"` // Description terms for the validator
|
||||
BondHeight int64 `json:"validator_bond_height"` // Earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 `json:"validator_bond_counter"` // Block-local tx index of validator change
|
||||
// note: There should only be one of the following 3 shares ever active in a delegator
|
||||
// multiple terms are only added here for clarity.
|
||||
BondedShares sdk.Rat `json:"bonded_shares"` // total shares of bonded global hold pool
|
||||
UnbondingShares sdk.Rat `json:"unbonding_shares"` // total shares of unbonding global hold pool
|
||||
UnbondedShares sdk.Rat `json:"unbonded_shares"` // total shares of unbonded global hold pool
|
||||
|
||||
DelegatorShares sdk.Rat `json:"liabilities"` // total shares issued to a validator's delegators
|
||||
|
||||
Description Description `json:"description"` // description terms for the validator
|
||||
BondHeight int64 `json:"validator_bond_height"` // earliest height as a bonded validator
|
||||
BondIntraTxCounter int16 `json:"validator_bond_counter"` // block-local tx index of validator change
|
||||
ProposerRewardPool sdk.Coins `json:"proposer_reward_pool"` // XXX reward pool collected from being the proposer
|
||||
|
||||
Commission sdk.Rat `json:"commission"` // XXX the commission rate of fees charged to any delegators
|
||||
@ -246,7 +250,7 @@ func (v Validator) abciValidatorZero(cdc *wire.Codec) abci.Validator {
|
||||
var _ sdk.Validator = Validator{}
|
||||
|
||||
// nolint - for sdk.Validator
|
||||
func (v Validator) GetStatus() sdk.ValidatorStatus { return v.Status }
|
||||
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
|
||||
func (v Validator) GetAddress() sdk.Address { return v.Address }
|
||||
func (v Validator) GetPubKey() crypto.PubKey { return v.PubKey }
|
||||
func (v Validator) GetPower() sdk.Rat { return v.BondedShares }
|
||||
|
||||
Loading…
Reference in New Issue
Block a user