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-12-18 05:20:02 -08:00
|
|
|
"sort"
|
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"
|
2019-06-10 02:57:38 -07:00
|
|
|
yaml "gopkg.in/yaml.v2"
|
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"
|
2019-12-27 09:57:54 -08:00
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
2019-06-05 10:42:25 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/staking/exported"
|
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
|
2019-08-12 06:10:16 -07:00
|
|
|
MaxMonikerLength = 70
|
|
|
|
MaxIdentityLength = 3000
|
|
|
|
MaxWebsiteLength = 140
|
|
|
|
MaxSecurityContactLength = 140
|
|
|
|
MaxDetailsLength = 280
|
2019-02-07 17:41:23 -08:00
|
|
|
)
|
|
|
|
|
2019-06-05 10:42:25 -07:00
|
|
|
var _ exported.ValidatorI = Validator{}
|
2019-06-04 15:06:58 -07:00
|
|
|
|
2020-02-06 11:21:02 -08:00
|
|
|
func NewValidator(operator sdk.ValAddress, pubKey crypto.PubKey, description Description) Validator {
|
|
|
|
var pkStr string
|
|
|
|
if pubKey != nil {
|
|
|
|
pkStr = sdk.MustBech32ifyPubKey(sdk.Bech32PubKeyTypeConsPub, pubKey)
|
|
|
|
}
|
|
|
|
|
|
|
|
return Validator{
|
|
|
|
OperatorAddress: operator,
|
|
|
|
ConsensusPubkey: pkStr,
|
|
|
|
Jailed: false,
|
|
|
|
Status: sdk.Unbonded,
|
|
|
|
Tokens: sdk.ZeroInt(),
|
|
|
|
DelegatorShares: sdk.ZeroDec(),
|
|
|
|
Description: description,
|
|
|
|
UnbondingHeight: int64(0),
|
|
|
|
UnbondingTime: time.Unix(0, 0).UTC(),
|
|
|
|
Commission: NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
|
|
|
MinSelfDelegation: sdk.OneInt(),
|
2019-06-08 11:00:36 -07:00
|
|
|
}
|
2020-02-06 11:21:02 -08:00
|
|
|
}
|
2019-06-08 11:00:36 -07:00
|
|
|
|
2020-02-06 11:21:02 -08:00
|
|
|
// String implements the Stringer interface for a Validator object.
|
|
|
|
func (v Validator) String() string {
|
|
|
|
out, _ := yaml.Marshal(v)
|
|
|
|
return string(out)
|
2019-06-08 11:00:36 -07: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
|
2019-06-05 10:42:25 -07:00
|
|
|
func (v Validators) ToSDKValidators() (validators []exported.ValidatorI) {
|
2019-02-13 15:01:50 -08:00
|
|
|
for _, val := range v {
|
|
|
|
validators = append(validators, val)
|
|
|
|
}
|
|
|
|
return validators
|
|
|
|
}
|
|
|
|
|
2020-01-29 05:35:49 -08:00
|
|
|
// ToTmValidators casts all validators to the corresponding tendermint type.
|
|
|
|
func (v Validators) ToTmValidators() []*tmtypes.Validator {
|
|
|
|
validators := make([]*tmtypes.Validator, len(v))
|
|
|
|
for i, val := range v {
|
|
|
|
validators[i] = val.ToTmValidator()
|
|
|
|
}
|
|
|
|
return validators
|
|
|
|
}
|
|
|
|
|
2019-12-18 05:20:02 -08:00
|
|
|
// Sort Validators sorts validator array in ascending operator address order
|
|
|
|
func (v Validators) Sort() {
|
|
|
|
sort.Sort(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implements sort interface
|
|
|
|
func (v Validators) Len() int {
|
|
|
|
return len(v)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implements sort interface
|
|
|
|
func (v Validators) Less(i, j int) bool {
|
|
|
|
return bytes.Compare(v[i].OperatorAddress, v[j].OperatorAddress) == -1
|
|
|
|
}
|
|
|
|
|
|
|
|
// Implements sort interface
|
|
|
|
func (v Validators) Swap(i, j int) {
|
|
|
|
it := v[i]
|
|
|
|
v[i] = v[j]
|
|
|
|
v[j] = it
|
|
|
|
}
|
|
|
|
|
2019-01-07 12:42:52 -08:00
|
|
|
// return the redelegation
|
2020-02-06 11:21:02 -08:00
|
|
|
func MustMarshalValidator(cdc codec.Marshaler, validator Validator) []byte {
|
|
|
|
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
|
2020-02-06 11:21:02 -08:00
|
|
|
func MustUnmarshalValidator(cdc codec.Marshaler, value []byte) Validator {
|
2019-01-07 12:42:52 -08:00
|
|
|
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
|
2020-02-06 11:21:02 -08:00
|
|
|
func UnmarshalValidator(cdc codec.Marshaler, value []byte) (v Validator, err error) {
|
|
|
|
err = cdc.UnmarshalBinaryLengthPrefixed(value, &v)
|
|
|
|
return v, err
|
2018-08-31 17:01:23 -07:00
|
|
|
}
|
|
|
|
|
2019-06-04 15:06:58 -07:00
|
|
|
// IsBonded checks if the validator status equals Bonded
|
|
|
|
func (v Validator) IsBonded() bool {
|
|
|
|
return v.GetStatus().Equal(sdk.Bonded)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsUnbonded checks if the validator status equals Unbonded
|
|
|
|
func (v Validator) IsUnbonded() bool {
|
|
|
|
return v.GetStatus().Equal(sdk.Unbonded)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsUnbonding checks if the validator status equals Unbonding
|
|
|
|
func (v Validator) IsUnbonding() bool {
|
|
|
|
return v.GetStatus().Equal(sdk.Unbonding)
|
|
|
|
}
|
|
|
|
|
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]"
|
|
|
|
|
2019-08-12 06:10:16 -07:00
|
|
|
func NewDescription(moniker, identity, website, securityContact, details string) Description {
|
2018-03-26 07:48:15 -07:00
|
|
|
return Description{
|
2019-08-12 06:10:16 -07:00
|
|
|
Moniker: moniker,
|
|
|
|
Identity: identity,
|
|
|
|
Website: website,
|
|
|
|
SecurityContact: securityContact,
|
|
|
|
Details: details,
|
2018-03-26 07:48:15 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-06 11:21:02 -08:00
|
|
|
// String implements the Stringer interface for a Description object.
|
|
|
|
func (d Description) String() string {
|
|
|
|
out, _ := yaml.Marshal(d)
|
|
|
|
return string(out)
|
|
|
|
}
|
|
|
|
|
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.
|
2019-12-27 09:57:54 -08:00
|
|
|
func (d Description) UpdateDescription(d2 Description) (Description, 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
|
|
|
|
}
|
2019-08-12 06:10:16 -07:00
|
|
|
if d2.SecurityContact == DoNotModifyDesc {
|
|
|
|
d2.SecurityContact = d.SecurityContact
|
|
|
|
}
|
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
|
|
|
|
2019-08-12 06:10:16 -07:00
|
|
|
return NewDescription(
|
|
|
|
d2.Moniker,
|
|
|
|
d2.Identity,
|
|
|
|
d2.Website,
|
|
|
|
d2.SecurityContact,
|
|
|
|
d2.Details,
|
|
|
|
).EnsureLength()
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
|
|
|
|
2018-07-03 21:21:36 -07:00
|
|
|
// EnsureLength ensures the length of a validator's description.
|
2019-12-27 09:57:54 -08:00
|
|
|
func (d Description) EnsureLength() (Description, error) {
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Moniker) > MaxMonikerLength {
|
2019-12-27 09:57:54 -08:00
|
|
|
return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid moniker length; got: %d, max: %d", 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 {
|
2019-12-27 09:57:54 -08:00
|
|
|
return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid identity length; got: %d, max: %d", 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 {
|
2019-12-27 09:57:54 -08:00
|
|
|
return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid website length; got: %d, max: %d", len(d.Website), MaxWebsiteLength)
|
2018-06-26 19:00:12 -07:00
|
|
|
}
|
2019-08-12 06:10:16 -07:00
|
|
|
if len(d.SecurityContact) > MaxSecurityContactLength {
|
2019-12-27 09:57:54 -08:00
|
|
|
return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid security contact length; got: %d, max: %d", len(d.SecurityContact), MaxSecurityContactLength)
|
2019-08-12 06:10:16 -07:00
|
|
|
}
|
2019-02-07 17:41:23 -08:00
|
|
|
if len(d.Details) > MaxDetailsLength {
|
2019-12-27 09:57:54 -08:00
|
|
|
return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid details length; got: %d, max: %d", 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{
|
2020-02-06 11:21:02 -08:00
|
|
|
PubKey: tmtypes.TM2PB.PubKey(v.GetConsPubKey()),
|
2019-06-12 08:57:47 -07:00
|
|
|
Power: v.ConsensusPower(),
|
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{
|
2020-02-06 11:21:02 -08:00
|
|
|
PubKey: tmtypes.TM2PB.PubKey(v.GetConsPubKey()),
|
2018-10-03 08:48:23 -07:00
|
|
|
Power: 0,
|
2018-04-05 09:31:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-29 05:35:49 -08:00
|
|
|
// ToTmValidator casts an SDK validator to a tendermint type Validator.
|
|
|
|
func (v Validator) ToTmValidator() *tmtypes.Validator {
|
2020-02-06 11:21:02 -08:00
|
|
|
return tmtypes.NewValidator(v.GetConsPubKey(), v.ConsensusPower())
|
2020-01-29 05:35:49 -08: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.
|
2019-12-27 09:57:54 -08:00
|
|
|
func (v Validator) SetInitialCommission(commission Commission) (Validator, error) {
|
2018-09-24 15:23:58 -07:00
|
|
|
if err := commission.Validate(); err != nil {
|
|
|
|
return v, err
|
|
|
|
}
|
|
|
|
|
|
|
|
v.Commission = commission
|
|
|
|
return v, nil
|
|
|
|
}
|
|
|
|
|
2019-03-06 10:54:12 -08:00
|
|
|
// In some situations, the exchange rate becomes invalid, e.g. if
|
|
|
|
// Validator loses all tokens due to slashing. In this case,
|
|
|
|
// make all future delegations invalid.
|
|
|
|
func (v Validator) InvalidExRate() bool {
|
|
|
|
return v.Tokens.IsZero() && v.DelegatorShares.IsPositive()
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the token worth of provided shares
|
2019-03-25 14:13:02 -07:00
|
|
|
func (v Validator) TokensFromShares(shares sdk.Dec) sdk.Dec {
|
2019-03-06 10:54:12 -08:00
|
|
|
return (shares.MulInt(v.Tokens)).Quo(v.DelegatorShares)
|
|
|
|
}
|
|
|
|
|
|
|
|
// calculate the token worth of provided shares, truncated
|
2019-03-25 14:13:02 -07:00
|
|
|
func (v Validator) TokensFromSharesTruncated(shares sdk.Dec) sdk.Dec {
|
2019-03-06 10:54:12 -08:00
|
|
|
return (shares.MulInt(v.Tokens)).QuoTruncate(v.DelegatorShares)
|
2018-07-13 13:46:14 -07:00
|
|
|
}
|
2018-07-03 21:21:36 -07:00
|
|
|
|
2019-04-10 15:53:42 -07:00
|
|
|
// TokensFromSharesRoundUp returns the token worth of provided shares, rounded
|
|
|
|
// up.
|
|
|
|
func (v Validator) TokensFromSharesRoundUp(shares sdk.Dec) sdk.Dec {
|
|
|
|
return (shares.MulInt(v.Tokens)).QuoRoundUp(v.DelegatorShares)
|
|
|
|
}
|
|
|
|
|
2019-03-25 14:13:02 -07:00
|
|
|
// SharesFromTokens returns the shares of a delegation given a bond amount. It
|
|
|
|
// returns an error if the validator has no tokens.
|
2019-12-27 09:57:54 -08:00
|
|
|
func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, error) {
|
2019-03-25 14:13:02 -07:00
|
|
|
if v.Tokens.IsZero() {
|
2019-12-27 09:57:54 -08:00
|
|
|
return sdk.ZeroDec(), ErrInsufficientShares
|
2019-03-25 14:13:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return v.GetDelegatorShares().MulInt(amt).QuoInt(v.GetTokens()), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SharesFromTokensTruncated returns the truncated shares of a delegation given
|
|
|
|
// a bond amount. It returns an error if the validator has no tokens.
|
2019-12-27 09:57:54 -08:00
|
|
|
func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) {
|
2019-03-25 14:13:02 -07:00
|
|
|
if v.Tokens.IsZero() {
|
2019-12-27 09:57:54 -08:00
|
|
|
return sdk.ZeroDec(), ErrInsufficientShares
|
2019-03-25 14:13:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return v.GetDelegatorShares().MulInt(amt).QuoTruncate(v.GetTokens().ToDec()), nil
|
|
|
|
}
|
|
|
|
|
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 {
|
2019-06-04 15:06:58 -07:00
|
|
|
if v.IsBonded() {
|
2018-07-13 13:46:14 -07:00
|
|
|
return v.Tokens
|
|
|
|
}
|
2019-01-02 12:29:47 -08:00
|
|
|
return sdk.ZeroInt()
|
2018-05-15 21:41:21 -07:00
|
|
|
}
|
|
|
|
|
2019-06-12 08:57:47 -07:00
|
|
|
// get the consensus-engine power
|
2019-02-15 07:55:21 -08:00
|
|
|
// a reduction of 10^6 from validator tokens is applied
|
2019-06-12 08:57:47 -07:00
|
|
|
func (v Validator) ConsensusPower() int64 {
|
2019-06-04 15:06:58 -07:00
|
|
|
if v.IsBonded() {
|
2019-06-12 08:57:47 -07:00
|
|
|
return v.PotentialConsensusPower()
|
2019-02-05 21:30:48 -08:00
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2019-06-12 08:57:47 -07:00
|
|
|
// potential consensus-engine power
|
|
|
|
func (v Validator) PotentialConsensusPower() int64 {
|
|
|
|
return sdk.TokensToConsensusPower(v.Tokens)
|
2019-02-05 21:30:48 -08:00
|
|
|
}
|
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
// UpdateStatus updates the location of the shares within a validator
|
|
|
|
// to reflect the new status
|
|
|
|
func (v Validator) UpdateStatus(newStatus sdk.BondStatus) Validator {
|
|
|
|
v.Status = newStatus
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddTokensFromDel adds tokens to a validator
|
|
|
|
func (v Validator) AddTokensFromDel(amount sdk.Int) (Validator, sdk.Dec) {
|
|
|
|
|
|
|
|
// calculate the shares to issue
|
|
|
|
var issuedShares sdk.Dec
|
|
|
|
if v.DelegatorShares.IsZero() {
|
|
|
|
// the first delegation to a validator sets the exchange rate to one
|
|
|
|
issuedShares = amount.ToDec()
|
|
|
|
} else {
|
|
|
|
shares, err := v.SharesFromTokens(amount)
|
|
|
|
if err != nil {
|
|
|
|
panic(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
issuedShares = shares
|
|
|
|
}
|
|
|
|
|
|
|
|
v.Tokens = v.Tokens.Add(amount)
|
|
|
|
v.DelegatorShares = v.DelegatorShares.Add(issuedShares)
|
|
|
|
|
|
|
|
return v, issuedShares
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveTokens removes tokens from a validator
|
|
|
|
func (v Validator) RemoveTokens(tokens sdk.Int) Validator {
|
|
|
|
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)
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveDelShares removes delegator shares from a validator.
|
|
|
|
// NOTE: because token fractions are left in the valiadator,
|
|
|
|
// the exchange rate of future shares of this validator can increase.
|
|
|
|
func (v Validator) RemoveDelShares(delShares sdk.Dec) (Validator, sdk.Int) {
|
|
|
|
remainingShares := v.DelegatorShares.Sub(delShares)
|
2020-02-06 11:21:02 -08:00
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
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.TokensFromShares(delShares).TruncateInt()
|
|
|
|
v.Tokens = v.Tokens.Sub(issuedTokens)
|
2020-02-06 11:21:02 -08:00
|
|
|
|
2019-06-28 13:11:27 -07:00
|
|
|
if v.Tokens.IsNegative() {
|
|
|
|
panic("attempting to remove more tokens than available in validator")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v.DelegatorShares = remainingShares
|
|
|
|
return v, issuedTokens
|
|
|
|
}
|
|
|
|
|
2020-02-06 11:21:02 -08:00
|
|
|
// MinEqual defines a more minimum set of equality conditions when comparing two
|
|
|
|
// validators.
|
|
|
|
func (v Validator) MinEqual(other Validator) bool {
|
|
|
|
return v.ConsensusPubkey == other.ConsensusPubkey &&
|
|
|
|
bytes.Equal(v.OperatorAddress, other.OperatorAddress) &&
|
|
|
|
v.Status.Equal(other.Status) &&
|
|
|
|
v.Tokens.Equal(other.Tokens) &&
|
|
|
|
v.DelegatorShares.Equal(other.DelegatorShares) &&
|
|
|
|
v.Description == other.Description &&
|
|
|
|
v.Commission.Equal(other.Commission)
|
|
|
|
}
|
|
|
|
|
2019-06-04 15:06:58 -07:00
|
|
|
// nolint - for ValidatorI
|
2020-02-06 11:21:02 -08:00
|
|
|
func (v Validator) IsJailed() bool { return v.Jailed }
|
|
|
|
func (v Validator) GetMoniker() string { return v.Description.Moniker }
|
|
|
|
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
|
|
|
|
func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddress }
|
|
|
|
func (v Validator) GetConsPubKey() crypto.PubKey {
|
|
|
|
return sdk.MustGetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, v.ConsensusPubkey)
|
|
|
|
}
|
|
|
|
func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.GetConsPubKey().Address()) }
|
2019-03-06 10:54:12 -08:00
|
|
|
func (v Validator) GetTokens() sdk.Int { return v.Tokens }
|
|
|
|
func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() }
|
2019-06-12 08:57:47 -07:00
|
|
|
func (v Validator) GetConsensusPower() int64 { return v.ConsensusPower() }
|
2019-03-06 10:54:12 -08:00
|
|
|
func (v Validator) GetCommission() sdk.Dec { return v.Commission.Rate }
|
|
|
|
func (v Validator) GetMinSelfDelegation() sdk.Int { return v.MinSelfDelegation }
|
|
|
|
func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares }
|