2018-06-26 19:00:12 -07:00
|
|
|
package types
|
2018-01-25 19:31:07 -08:00
|
|
|
|
|
|
|
import (
|
2018-04-30 23:07:06 -07:00
|
|
|
"bytes"
|
2018-05-26 14:21:29 -07:00
|
|
|
"fmt"
|
2019-01-22 09:28:39 -08:00
|
|
|
"strings"
|
2018-08-24 18:47:31 -07:00
|
|
|
"time"
|
2018-04-30 23:07:06 -07:00
|
|
|
|
2018-06-28 17:54:47 -07:00
|
|
|
abci "github.com/tendermint/tendermint/abci/types"
|
|
|
|
"github.com/tendermint/tendermint/crypto"
|
2018-06-04 16:42:01 -07:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
2018-06-26 19:00:12 -07:00
|
|
|
|
2018-09-13 11:17:32 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2018-06-26 19:00:12 -07:00
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2018-01-25 19:31:07 -08:00
|
|
|
)
|
|
|
|
|
2019-02-07 17:41:23 -08:00
|
|
|
// nolint
|
|
|
|
const (
|
|
|
|
// TODO: Why can't we just have one string description which can be JSON by convention
|
|
|
|
MaxMonikerLength = 70
|
|
|
|
MaxIdentityLength = 3000
|
|
|
|
MaxWebsiteLength = 140
|
|
|
|
MaxDetailsLength = 280
|
|
|
|
)
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// Validator defines the total amount of bond shares and their exchange rate to
|
2019-02-07 17:41:23 -08:00
|
|
|
// coins. Slashing results in a decrease in the exchange rate, allowing correct
|
|
|
|
// calculation of future undelegations without iterating over delegators.
|
|
|
|
// When coins are delegated to this validator, the validator is credited with a
|
|
|
|
// delegation whose number of bond shares is based on the amount of coins delegated
|
|
|
|
// divided by the current exchange rate. Voting power can be calculated as total
|
|
|
|
// bonded shares multiplied by exchange rate.
|
2018-05-09 21:01:58 -07:00
|
|
|
type Validator struct {
|
2019-02-25 07:16:52 -08:00
|
|
|
OperatorAddress sdk.ValAddress `json:"operator_address"` // address of the validator's operator; bech encoded in JSON
|
2019-02-08 12:44:19 -08:00
|
|
|
ConsPubKey crypto.PubKey `json:"consensus_pubkey"` // the consensus public key of the validator; bech encoded in JSON
|
|
|
|
Jailed bool `json:"jailed"` // has the validator been jailed from bonded status?
|
|
|
|
Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded)
|
|
|
|
Tokens sdk.Int `json:"tokens"` // delegated tokens (incl. self-delegation)
|
|
|
|
DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators
|
|
|
|
Description Description `json:"description"` // description terms for the validator
|
|
|
|
UnbondingHeight int64 `json:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
|
|
|
|
UnbondingCompletionTime time.Time `json:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding
|
|
|
|
Commission Commission `json:"commission"` // commission parameters
|
|
|
|
MinSelfDelegation sdk.Int `json:"min_self_delegation"` // validator's self declared minimum self delegation
|
2018-01-25 19:31:07 -08:00
|
|
|
}
|
|
|
|
|
2019-01-22 09:28:39 -08:00
|
|
|
// Validators is a collection of Validator
|
|
|
|
type Validators []Validator
|
|
|
|
|
|
|
|
func (v Validators) String() (out string) {
|
|
|
|
for _, val := range v {
|
|
|
|
out += val.String() + "\n"
|
|
|
|
}
|
|
|
|
return strings.TrimSpace(out)
|
|
|
|
}
|
|
|
|
|
2019-02-13 15:01:50 -08:00
|
|
|
// ToSDKValidators - convenience function convert []Validators to []sdk.Validators
|
|
|
|
func (v Validators) ToSDKValidators() (validators []sdk.Validator) {
|
|
|
|
for _, val := range v {
|
|
|
|
validators = append(validators, val)
|
|
|
|
}
|
|
|
|
return validators
|
|
|
|
}
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// NewValidator - initialize a new validator
|
2018-08-30 21:06:44 -07:00
|
|
|
func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator {
|
2018-05-09 21:01:58 -07:00
|
|
|
return Validator{
|
2019-02-25 07:16:52 -08:00
|
|
|
OperatorAddress: operator,
|
2019-01-17 09:53:22 -08:00
|
|
|
ConsPubKey: pubKey,
|
|
|
|
Jailed: false,
|
|
|
|
Status: sdk.Unbonded,
|
|
|
|
Tokens: sdk.ZeroInt(),
|
|
|
|
DelegatorShares: sdk.ZeroDec(),
|
|
|
|
Description: description,
|
|
|
|
UnbondingHeight: int64(0),
|
|
|
|
UnbondingCompletionTime: time.Unix(0, 0).UTC(),
|
|
|
|
Commission: NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
2019-02-08 12:44:19 -08:00
|
|
|
MinSelfDelegation: sdk.OneInt(),
|
2018-01-25 19:31:07 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-07 12:42:52 -08:00
|
|
|
// return the redelegation
|
2018-09-13 11:17:32 -07:00
|
|
|
func MustMarshalValidator(cdc *codec.Codec, validator Validator) []byte {
|
2019-01-07 12:42:52 -08:00
|
|
|
return cdc.MustMarshalBinaryLengthPrefixed(validator)
|
2018-07-03 22:32:49 -07:00
|
|
|
}
|
|
|
|
|
2019-01-07 12:42:52 -08:00
|
|
|
// unmarshal a redelegation from a store value
|
|
|
|
func MustUnmarshalValidator(cdc *codec.Codec, value []byte) Validator {
|
|
|
|
validator, err := UnmarshalValidator(cdc, value)
|
2018-07-04 14:07:06 -07:00
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
return validator
|
|
|
|
}
|
|
|
|
|
2019-01-07 12:42:52 -08:00
|
|
|
// unmarshal a redelegation from a store value
|
|
|
|
func UnmarshalValidator(cdc *codec.Codec, value []byte) (validator Validator, err error) {
|
|
|
|
err = cdc.UnmarshalBinaryLengthPrefixed(value, &validator)
|
|
|
|
return validator, err
|
2018-07-03 22:32:49 -07:00
|
|
|
}
|
|
|
|
|
2019-01-22 09:28:39 -08:00
|
|
|
// String returns a human readable string representation of a validator.
|
|
|
|
func (v Validator) String() string {
|
2018-09-08 01:44:58 -07:00
|
|
|
bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey)
|
2018-07-18 13:09:40 -07:00
|
|
|
if err != nil {
|
2019-01-22 09:28:39 -08:00
|
|
|
panic(err)
|
2018-07-18 13:09:40 -07:00
|
|
|
}
|
2019-01-22 09:28:39 -08:00
|
|
|
return fmt.Sprintf(`Validator
|
|
|
|
Operator Address: %s
|
|
|
|
Validator Consensus Pubkey: %s
|
|
|
|
Jailed: %v
|
|
|
|
Status: %s
|
|
|
|
Tokens: %s
|
|
|
|
Delegator Shares: %s
|
|
|
|
Description: %s
|
|
|
|
Unbonding Height: %d
|
|
|
|
Unbonding Completion Time: %v
|
2019-02-08 12:44:19 -08:00
|
|
|
Minimum Self Delegation: %v
|
2019-02-25 07:16:52 -08:00
|
|
|
Commission: %s`, v.OperatorAddress, bechConsPubKey,
|
2019-01-22 09:28:39 -08:00
|
|
|
v.Jailed, sdk.BondStatusToString(v.Status), v.Tokens,
|
2019-02-07 17:41:23 -08:00
|
|
|
v.DelegatorShares, v.Description,
|
2019-02-08 12:44:19 -08:00
|
|
|
v.UnbondingHeight, v.UnbondingCompletionTime, v.MinSelfDelegation, v.Commission)
|
2018-07-18 13:09:40 -07:00
|
|
|
}
|
|
|
|
|
2018-09-10 15:37:03 -07:00
|
|
|
// this is a helper struct used for JSON de- and encoding only
|
|
|
|
type bechValidator struct {
|
2019-02-25 07:16:52 -08:00
|
|
|
OperatorAddress sdk.ValAddress `json:"operator_address"` // the bech32 address of the validator's operator
|
2019-02-08 12:44:19 -08:00
|
|
|
ConsPubKey string `json:"consensus_pubkey"` // the bech32 consensus public key of the validator
|
|
|
|
Jailed bool `json:"jailed"` // has the validator been jailed from bonded status?
|
|
|
|
Status sdk.BondStatus `json:"status"` // validator status (bonded/unbonding/unbonded)
|
|
|
|
Tokens sdk.Int `json:"tokens"` // delegated tokens (incl. self-delegation)
|
|
|
|
DelegatorShares sdk.Dec `json:"delegator_shares"` // total shares issued to a validator's delegators
|
|
|
|
Description Description `json:"description"` // description terms for the validator
|
|
|
|
UnbondingHeight int64 `json:"unbonding_height"` // if unbonding, height at which this validator has begun unbonding
|
|
|
|
UnbondingCompletionTime time.Time `json:"unbonding_time"` // if unbonding, min time for the validator to complete unbonding
|
|
|
|
Commission Commission `json:"commission"` // commission parameters
|
|
|
|
MinSelfDelegation sdk.Int `json:"min_self_delegation"` // minimum self delegation
|
2018-07-13 13:46:14 -07:00
|
|
|
}
|
|
|
|
|
2018-09-10 15:37:03 -07:00
|
|
|
// MarshalJSON marshals the validator to JSON using Bech32
|
|
|
|
func (v Validator) MarshalJSON() ([]byte, error) {
|
2018-09-08 01:44:58 -07:00
|
|
|
bechConsPubKey, err := sdk.Bech32ifyConsPub(v.ConsPubKey)
|
2018-07-13 13:46:14 -07:00
|
|
|
if err != nil {
|
2018-09-10 15:37:03 -07:00
|
|
|
return nil, err
|
2018-07-13 13:46:14 -07:00
|
|
|
}
|
|
|
|
|
2018-09-13 11:17:32 -07:00
|
|
|
return codec.Cdc.MarshalJSON(bechValidator{
|
2019-02-25 07:16:52 -08:00
|
|
|
OperatorAddress: v.OperatorAddress,
|
2019-01-17 09:53:22 -08:00
|
|
|
ConsPubKey: bechConsPubKey,
|
|
|
|
Jailed: v.Jailed,
|
|
|
|
Status: v.Status,
|
|
|
|
Tokens: v.Tokens,
|
|
|
|
DelegatorShares: v.DelegatorShares,
|
|
|
|
Description: v.Description,
|
|
|
|
UnbondingHeight: v.UnbondingHeight,
|
|
|
|
UnbondingCompletionTime: v.UnbondingCompletionTime,
|
2019-02-08 12:44:19 -08:00
|
|
|
MinSelfDelegation: v.MinSelfDelegation,
|
2019-01-17 09:53:22 -08:00
|
|
|
Commission: v.Commission,
|
2018-09-10 15:37:03 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnmarshalJSON unmarshals the validator from JSON using Bech32
|
|
|
|
func (v *Validator) UnmarshalJSON(data []byte) error {
|
|
|
|
bv := &bechValidator{}
|
2018-09-13 11:17:32 -07:00
|
|
|
if err := codec.Cdc.UnmarshalJSON(data, bv); err != nil {
|
2018-09-10 15:37:03 -07:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
consPubKey, err := sdk.GetConsPubKeyBech32(bv.ConsPubKey)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
*v = Validator{
|
2019-02-25 07:16:52 -08:00
|
|
|
OperatorAddress: bv.OperatorAddress,
|
2019-01-17 09:53:22 -08:00
|
|
|
ConsPubKey: consPubKey,
|
|
|
|
Jailed: bv.Jailed,
|
|
|
|
Tokens: bv.Tokens,
|
|
|
|
Status: bv.Status,
|
|
|
|
DelegatorShares: bv.DelegatorShares,
|
|
|
|
Description: bv.Description,
|
|
|
|
UnbondingHeight: bv.UnbondingHeight,
|
|
|
|
UnbondingCompletionTime: bv.UnbondingCompletionTime,
|
|
|
|
Commission: bv.Commission,
|
2019-02-08 12:44:19 -08:00
|
|
|
MinSelfDelegation: bv.MinSelfDelegation,
|
2018-09-10 15:37:03 -07:00
|
|
|
}
|
|
|
|
return nil
|
2018-07-13 13:46:14 -07:00
|
|
|
}
|
|
|
|
|
2018-12-10 02:49:37 -08:00
|
|
|
// only the vitals
|
2019-02-07 17:41:23 -08:00
|
|
|
func (v Validator) TestEquivalent(v2 Validator) bool {
|
2018-09-24 15:23:58 -07:00
|
|
|
return v.ConsPubKey.Equals(v2.ConsPubKey) &&
|
2019-02-25 07:16:52 -08:00
|
|
|
bytes.Equal(v.OperatorAddress, v2.OperatorAddress) &&
|
2018-09-24 15:23:58 -07:00
|
|
|
v.Status.Equal(v2.Status) &&
|
|
|
|
v.Tokens.Equal(v2.Tokens) &&
|
|
|
|
v.DelegatorShares.Equal(v2.DelegatorShares) &&
|
|
|
|
v.Description == v2.Description &&
|
|
|
|
v.Commission.Equal(v2.Commission)
|
2018-04-30 23:07:06 -07:00
|
|
|
}
|
|
|
|
|
2018-08-31 17:01:23 -07:00
|
|
|
// return the TM validator address
|
|
|
|
func (v Validator) ConsAddress() sdk.ConsAddress {
|
2018-09-08 01:44:58 -07:00
|
|
|
return sdk.ConsAddress(v.ConsPubKey.Address())
|
2018-08-31 17:01:23 -07:00
|
|
|
}
|
|
|
|
|
2018-07-26 10:41:34 -07:00
|
|
|
// constant used in flags to indicate that description field should not be updated
|
|
|
|
const DoNotModifyDesc = "[do-not-modify]"
|
|
|
|
|
2018-05-09 21:01:58 -07:00
|
|
|
// Description - description fields for a validator
|
2018-03-26 07:48:15 -07:00
|
|
|
type Description struct {
|
2018-05-23 12:42:37 -07:00
|
|
|
Moniker string `json:"moniker"` // name
|
|
|
|
Identity string `json:"identity"` // optional identity signature (ex. UPort or Keybase)
|
|
|
|
Website string `json:"website"` // optional website link
|
|
|
|
Details string `json:"details"` // optional details
|
2018-03-26 07:48:15 -07:00
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// NewDescription returns a new Description with the provided values.
|
2018-03-26 07:48:15 -07:00
|
|
|
func NewDescription(moniker, identity, website, details string) Description {
|
|
|
|
return Description{
|
|
|
|
Moniker: moniker,
|
|
|
|
Identity: identity,
|
|
|
|
Website: website,
|
|
|
|
Details: details,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// UpdateDescription updates the fields of a given description. An error is
|
|
|
|
// returned if the resulting description contains an invalid length.
|
2018-06-26 19:00:12 -07:00
|
|
|
func (d Description) UpdateDescription(d2 Description) (Description, sdk.Error) {
|
2018-07-26 10:41:34 -07:00
|
|
|
if d2.Moniker == DoNotModifyDesc {
|
2018-06-26 19:00:12 -07:00
|
|
|
d2.Moniker = d.Moniker
|
|
|
|
}
|
2018-07-26 10:41:34 -07:00
|
|
|
if d2.Identity == DoNotModifyDesc {
|
2018-06-26 19:00:12 -07:00
|
|
|
d2.Identity = d.Identity
|
|
|
|
}
|
2018-07-26 10:41:34 -07:00
|
|
|
if d2.Website == DoNotModifyDesc {
|
2018-06-26 19:00:12 -07:00
|
|
|
d2.Website = d.Website
|
|
|
|
}
|
2018-07-26 10:41:34 -07:00
|
|
|
if d2.Details == DoNotModifyDesc {
|
2018-06-26 19:00:12 -07:00
|
|
|
d2.Details = d.Details
|
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
return Description{
|
|
|
|
Moniker: d2.Moniker,
|
|
|
|
Identity: d2.Identity,
|
|
|
|
Website: d2.Website,
|
|
|
|
Details: d2.Details,
|
|
|
|
}.EnsureLength()
|
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// EnsureLength ensures the length of a validator's description.
|
2018-06-26 19:00:12 -07:00
|
|
|
func (d Description) EnsureLength() (Description, sdk.Error) {
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Moniker) > MaxMonikerLength {
|
|
|
|
return d, ErrDescriptionLength(DefaultCodespace, "moniker", len(d.Moniker), MaxMonikerLength)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Identity) > MaxIdentityLength {
|
|
|
|
return d, ErrDescriptionLength(DefaultCodespace, "identity", len(d.Identity), MaxIdentityLength)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Website) > MaxWebsiteLength {
|
|
|
|
return d, ErrDescriptionLength(DefaultCodespace, "website", len(d.Website), MaxWebsiteLength)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Details) > MaxDetailsLength {
|
|
|
|
return d, ErrDescriptionLength(DefaultCodespace, "details", len(d.Details), MaxDetailsLength)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-06-26 19:00:12 -07:00
|
|
|
return d, nil
|
|
|
|
}
|
2018-05-12 15:54:50 -07:00
|
|
|
|
2019-02-07 17:41:23 -08:00
|
|
|
// ABCIValidatorUpdate returns an abci.ValidatorUpdate from a staking validator type
|
2018-10-03 08:48:23 -07:00
|
|
|
// with the full validator power
|
|
|
|
func (v Validator) ABCIValidatorUpdate() abci.ValidatorUpdate {
|
|
|
|
return abci.ValidatorUpdate{
|
|
|
|
PubKey: tmtypes.TM2PB.PubKey(v.ConsPubKey),
|
2019-02-05 21:30:48 -08:00
|
|
|
Power: v.TendermintPower(),
|
2018-04-04 20:22:13 -07:00
|
|
|
}
|
2018-01-31 18:56:46 -08:00
|
|
|
}
|
|
|
|
|
2019-02-07 17:41:23 -08:00
|
|
|
// ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staking validator type
|
2018-10-03 08:48:23 -07:00
|
|
|
// with zero power used for validator updates.
|
|
|
|
func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {
|
|
|
|
return abci.ValidatorUpdate{
|
|
|
|
PubKey: tmtypes.TM2PB.PubKey(v.ConsPubKey),
|
|
|
|
Power: 0,
|
2018-04-05 09:31:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
// UpdateStatus updates the location of the shares within a validator
|
|
|
|
// to reflect the new status
|
2018-05-20 14:39:04 -07:00
|
|
|
func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator, Pool) {
|
2018-05-12 15:54:50 -07:00
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
switch v.Status {
|
2018-05-20 14:39:04 -07:00
|
|
|
case sdk.Unbonded:
|
2018-07-13 13:46:14 -07:00
|
|
|
|
|
|
|
switch NewStatus {
|
|
|
|
case sdk.Unbonded:
|
2018-05-20 14:39:04 -07:00
|
|
|
return v, pool
|
2018-07-13 13:46:14 -07:00
|
|
|
case sdk.Bonded:
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.notBondedTokensToBonded(v.Tokens)
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
2018-05-20 14:39:04 -07:00
|
|
|
case sdk.Unbonding:
|
2018-07-13 13:46:14 -07:00
|
|
|
|
|
|
|
switch NewStatus {
|
|
|
|
case sdk.Unbonding:
|
2018-05-20 14:39:04 -07:00
|
|
|
return v, pool
|
2018-07-13 13:46:14 -07:00
|
|
|
case sdk.Bonded:
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.notBondedTokensToBonded(v.Tokens)
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
2018-05-20 14:39:04 -07:00
|
|
|
case sdk.Bonded:
|
2018-07-13 13:46:14 -07:00
|
|
|
|
|
|
|
switch NewStatus {
|
|
|
|
case sdk.Bonded:
|
2018-05-20 14:39:04 -07:00
|
|
|
return v, pool
|
2018-07-13 13:46:14 -07:00
|
|
|
default:
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.bondedTokensToNotBonded(v.Tokens)
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
v.Status = NewStatus
|
2018-05-20 14:39:04 -07:00
|
|
|
return v, pool
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
// removes tokens from a validator
|
2019-01-02 12:29:47 -08:00
|
|
|
func (v Validator) RemoveTokens(pool Pool, tokens sdk.Int) (Validator, Pool) {
|
2018-12-07 16:04:52 -08:00
|
|
|
if tokens.IsNegative() {
|
|
|
|
panic(fmt.Sprintf("should not happen: trying to remove negative tokens %v", tokens))
|
|
|
|
}
|
|
|
|
if v.Tokens.LT(tokens) {
|
|
|
|
panic(fmt.Sprintf("should not happen: only have %v tokens, trying to remove %v", v.Tokens, tokens))
|
|
|
|
}
|
|
|
|
v.Tokens = v.Tokens.Sub(tokens)
|
2019-02-07 17:41:23 -08:00
|
|
|
// TODO: It is not obvious from the name of the function that this will happen. Either justify or move outside.
|
2018-07-13 13:46:14 -07:00
|
|
|
if v.Status == sdk.Bonded {
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.bondedTokensToNotBonded(tokens)
|
2018-05-24 16:03:26 -07:00
|
|
|
}
|
2018-07-13 13:46:14 -07:00
|
|
|
return v, pool
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
|
|
|
|
2018-09-24 15:23:58 -07:00
|
|
|
// SetInitialCommission attempts to set a validator's initial commission. An
|
|
|
|
// error is returned if the commission is invalid.
|
|
|
|
func (v Validator) SetInitialCommission(commission Commission) (Validator, sdk.Error) {
|
|
|
|
if err := commission.Validate(); err != nil {
|
|
|
|
return v, err
|
|
|
|
}
|
|
|
|
|
|
|
|
v.Commission = commission
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// AddTokensFromDel adds tokens to a validator
|
2019-02-07 17:41:23 -08:00
|
|
|
// CONTRACT: Tokens are assumed to have come from not-bonded pool.
|
2018-08-27 15:18:18 -07:00
|
|
|
func (v Validator) AddTokensFromDel(pool Pool, amount sdk.Int) (Validator, Pool, sdk.Dec) {
|
2018-05-12 15:54:50 -07:00
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// bondedShare/delegatedShare
|
2018-07-13 13:46:14 -07:00
|
|
|
exRate := v.DelegatorShareExRate()
|
2019-01-02 12:29:47 -08:00
|
|
|
if exRate.IsZero() {
|
|
|
|
panic("zero exRate should not happen")
|
|
|
|
}
|
2018-05-15 21:41:21 -07:00
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
if v.Status == sdk.Bonded {
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.notBondedTokensToBonded(amount)
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
|
|
|
|
2019-01-02 12:29:47 -08:00
|
|
|
v.Tokens = v.Tokens.Add(amount)
|
2019-02-21 00:05:31 -08:00
|
|
|
issuedShares := amount.ToDec().Quo(exRate)
|
2018-07-13 13:46:14 -07:00
|
|
|
v.DelegatorShares = v.DelegatorShares.Add(issuedShares)
|
2018-05-12 15:54:50 -07:00
|
|
|
|
2018-07-13 13:46:14 -07:00
|
|
|
return v, pool, issuedShares
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// RemoveDelShares removes delegator shares from a validator.
|
2019-01-02 12:29:47 -08:00
|
|
|
// NOTE: because token fractions are left in the valiadator,
|
|
|
|
// the exchange rate of future shares of this validator can increase.
|
2019-02-07 17:41:23 -08:00
|
|
|
// CONTRACT: Tokens are assumed to move to the not-bonded pool.
|
2019-01-02 12:29:47 -08:00
|
|
|
func (v Validator) RemoveDelShares(pool Pool, delShares sdk.Dec) (Validator, Pool, sdk.Int) {
|
|
|
|
|
|
|
|
remainingShares := v.DelegatorShares.Sub(delShares)
|
|
|
|
var issuedTokens sdk.Int
|
|
|
|
if remainingShares.IsZero() {
|
|
|
|
|
|
|
|
// last delegation share gets any trimmings
|
|
|
|
issuedTokens = v.Tokens
|
|
|
|
v.Tokens = sdk.ZeroInt()
|
|
|
|
} else {
|
|
|
|
|
|
|
|
// leave excess tokens in the validator
|
|
|
|
// however fully use all the delegator shares
|
|
|
|
issuedTokens = v.DelegatorShareExRate().Mul(delShares).TruncateInt()
|
|
|
|
v.Tokens = v.Tokens.Sub(issuedTokens)
|
|
|
|
if v.Tokens.IsNegative() {
|
|
|
|
panic("attempting to remove more tokens than available in validator")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v.DelegatorShares = remainingShares
|
|
|
|
if v.Status == sdk.Bonded {
|
2019-01-21 16:52:03 -08:00
|
|
|
pool = pool.bondedTokensToNotBonded(issuedTokens)
|
2019-01-02 12:29:47 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
return v, pool, issuedTokens
|
2018-05-12 15:54:50 -07:00
|
|
|
}
|
2018-05-06 07:18:45 -07:00
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// DelegatorShareExRate gets the exchange rate of tokens over delegator shares.
|
2018-07-13 13:46:14 -07:00
|
|
|
// UNITS: tokens/delegator-shares
|
2018-08-14 17:15:02 -07:00
|
|
|
func (v Validator) DelegatorShareExRate() sdk.Dec {
|
2018-05-15 21:41:21 -07:00
|
|
|
if v.DelegatorShares.IsZero() {
|
2019-02-07 17:41:23 -08:00
|
|
|
// the first delegation to a validator sets the exchange rate to one
|
2018-08-14 17:15:02 -07:00
|
|
|
return sdk.OneDec()
|
2018-05-15 21:41:21 -07:00
|
|
|
}
|
2019-02-21 00:05:31 -08:00
|
|
|
return v.Tokens.ToDec().Quo(v.DelegatorShares)
|
2018-07-13 13:46:14 -07:00
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2019-02-05 21:30:48 -08:00
|
|
|
// get the bonded tokens which the validator holds
|
2019-01-02 12:29:47 -08:00
|
|
|
func (v Validator) BondedTokens() sdk.Int {
|
2018-07-13 13:46:14 -07:00
|
|
|
if v.Status == sdk.Bonded {
|
|
|
|
return v.Tokens
|
|
|
|
}
|
2019-01-02 12:29:47 -08:00
|
|
|
return sdk.ZeroInt()
|
2018-05-15 21:41:21 -07:00
|
|
|
}
|
|
|
|
|
2019-02-05 21:30:48 -08:00
|
|
|
// get the Tendermint Power
|
2019-02-15 07:55:21 -08:00
|
|
|
// a reduction of 10^6 from validator tokens is applied
|
2019-02-05 21:30:48 -08:00
|
|
|
func (v Validator) TendermintPower() int64 {
|
|
|
|
if v.Status == sdk.Bonded {
|
|
|
|
return v.PotentialTendermintPower()
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// potential Tendermint power
|
|
|
|
func (v Validator) PotentialTendermintPower() int64 {
|
2019-02-13 15:01:50 -08:00
|
|
|
return sdk.TokensToTendermintPower(v.Tokens)
|
2019-02-05 21:30:48 -08:00
|
|
|
}
|
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// ensure fulfills the sdk validator types
|
|
|
|
var _ sdk.Validator = Validator{}
|
2018-05-06 07:18:45 -07:00
|
|
|
|
2018-05-09 18:39:14 -07:00
|
|
|
// nolint - for sdk.Validator
|
2019-01-16 13:38:05 -08:00
|
|
|
func (v Validator) GetJailed() bool { return v.Jailed }
|
|
|
|
func (v Validator) GetMoniker() string { return v.Description.Moniker }
|
|
|
|
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
|
2019-02-25 07:16:52 -08:00
|
|
|
func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddress }
|
2019-01-16 13:38:05 -08:00
|
|
|
func (v Validator) GetConsPubKey() crypto.PubKey { return v.ConsPubKey }
|
|
|
|
func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) }
|
|
|
|
func (v Validator) GetTokens() sdk.Int { return v.Tokens }
|
2019-02-05 21:30:48 -08:00
|
|
|
func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() }
|
|
|
|
func (v Validator) GetTendermintPower() int64 { return v.TendermintPower() }
|
2019-01-16 13:38:05 -08:00
|
|
|
func (v Validator) GetCommission() sdk.Dec { return v.Commission.Rate }
|
2019-02-08 12:44:19 -08:00
|
|
|
func (v Validator) GetMinSelfDelegation() sdk.Int { return v.MinSelfDelegation }
|
2019-01-16 13:38:05 -08:00
|
|
|
func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares }
|
|
|
|
func (v Validator) GetDelegatorShareExRate() sdk.Dec { return v.DelegatorShareExRate() }
|