github.com/Finschia/finschia-sdk@v0.48.1/x/staking/types/validator.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"strings"
     8  	"time"
     9  
    10  	abci "github.com/tendermint/tendermint/abci/types"
    11  	tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto"
    12  
    13  	"gopkg.in/yaml.v2"
    14  
    15  	"github.com/Finschia/finschia-sdk/codec"
    16  	codectypes "github.com/Finschia/finschia-sdk/codec/types"
    17  	cryptocodec "github.com/Finschia/finschia-sdk/crypto/codec"
    18  	cryptotypes "github.com/Finschia/finschia-sdk/crypto/types"
    19  	sdk "github.com/Finschia/finschia-sdk/types"
    20  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    21  )
    22  
    23  const (
    24  	// TODO: Why can't we just have one string description which can be JSON by convention
    25  	MaxMonikerLength         = 70
    26  	MaxIdentityLength        = 3000
    27  	MaxWebsiteLength         = 140
    28  	MaxSecurityContactLength = 140
    29  	MaxDetailsLength         = 280
    30  )
    31  
    32  var (
    33  	BondStatusUnspecified = BondStatus_name[int32(Unspecified)]
    34  	BondStatusUnbonded    = BondStatus_name[int32(Unbonded)]
    35  	BondStatusUnbonding   = BondStatus_name[int32(Unbonding)]
    36  	BondStatusBonded      = BondStatus_name[int32(Bonded)]
    37  )
    38  
    39  var _ ValidatorI = Validator{}
    40  
    41  // NewValidator constructs a new Validator
    42  //
    43  //nolint:interfacer
    44  func NewValidator(operator sdk.ValAddress, pubKey cryptotypes.PubKey, description Description) (Validator, error) {
    45  	pkAny, err := codectypes.NewAnyWithValue(pubKey)
    46  	if err != nil {
    47  		return Validator{}, err
    48  	}
    49  
    50  	return Validator{
    51  		OperatorAddress:   operator.String(),
    52  		ConsensusPubkey:   pkAny,
    53  		Jailed:            false,
    54  		Status:            Unbonded,
    55  		Tokens:            sdk.ZeroInt(),
    56  		DelegatorShares:   sdk.ZeroDec(),
    57  		Description:       description,
    58  		UnbondingHeight:   int64(0),
    59  		UnbondingTime:     time.Unix(0, 0).UTC(),
    60  		Commission:        NewCommission(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
    61  		MinSelfDelegation: sdk.OneInt(),
    62  	}, nil
    63  }
    64  
    65  // String implements the Stringer interface for a Validator object.
    66  func (v Validator) String() string {
    67  	out, _ := yaml.Marshal(v)
    68  	return string(out)
    69  }
    70  
    71  // Validators is a collection of Validator
    72  type Validators []Validator
    73  
    74  func (v Validators) String() (out string) {
    75  	for _, val := range v {
    76  		out += val.String() + "\n"
    77  	}
    78  
    79  	return strings.TrimSpace(out)
    80  }
    81  
    82  // ToSDKValidators -  convenience function convert []Validator to []sdk.ValidatorI
    83  func (v Validators) ToSDKValidators() (validators []ValidatorI) {
    84  	for _, val := range v {
    85  		validators = append(validators, val)
    86  	}
    87  
    88  	return validators
    89  }
    90  
    91  // Sort Validators sorts validator array in ascending operator address order
    92  func (v Validators) Sort() {
    93  	sort.Sort(v)
    94  }
    95  
    96  // Implements sort interface
    97  func (v Validators) Len() int {
    98  	return len(v)
    99  }
   100  
   101  // Implements sort interface
   102  func (v Validators) Less(i, j int) bool {
   103  	return bytes.Compare(v[i].GetOperator().Bytes(), v[j].GetOperator().Bytes()) == -1
   104  }
   105  
   106  // Implements sort interface
   107  func (v Validators) Swap(i, j int) {
   108  	v[i], v[j] = v[j], v[i]
   109  }
   110  
   111  // ValidatorsByVotingPower implements sort.Interface for []Validator based on
   112  // the VotingPower and Address fields.
   113  // The validators are sorted first by their voting power (descending). Secondary index - Address (ascending).
   114  // Copied from ostracon/types/validator_set.go
   115  type ValidatorsByVotingPower []Validator
   116  
   117  func (valz ValidatorsByVotingPower) Len() int { return len(valz) }
   118  
   119  func (valz ValidatorsByVotingPower) Less(i, j int, r sdk.Int) bool {
   120  	if valz[i].ConsensusPower(r) == valz[j].ConsensusPower(r) {
   121  		addrI, errI := valz[i].GetConsAddr()
   122  		addrJ, errJ := valz[j].GetConsAddr()
   123  		// If either returns error, then return false
   124  		if errI != nil || errJ != nil {
   125  			return false
   126  		}
   127  		return bytes.Compare(addrI, addrJ) == -1
   128  	}
   129  	return valz[i].ConsensusPower(r) > valz[j].ConsensusPower(r)
   130  }
   131  
   132  func (valz ValidatorsByVotingPower) Swap(i, j int) {
   133  	valz[i], valz[j] = valz[j], valz[i]
   134  }
   135  
   136  // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
   137  func (v Validators) UnpackInterfaces(c codectypes.AnyUnpacker) error {
   138  	for i := range v {
   139  		if err := v[i].UnpackInterfaces(c); err != nil {
   140  			return err
   141  		}
   142  	}
   143  	return nil
   144  }
   145  
   146  // return the redelegation
   147  func MustMarshalValidator(cdc codec.BinaryCodec, validator *Validator) []byte {
   148  	return cdc.MustMarshal(validator)
   149  }
   150  
   151  // unmarshal a redelegation from a store value
   152  func MustUnmarshalValidator(cdc codec.BinaryCodec, value []byte) Validator {
   153  	validator, err := UnmarshalValidator(cdc, value)
   154  	if err != nil {
   155  		panic(err)
   156  	}
   157  
   158  	return validator
   159  }
   160  
   161  // unmarshal a redelegation from a store value
   162  func UnmarshalValidator(cdc codec.BinaryCodec, value []byte) (v Validator, err error) {
   163  	err = cdc.Unmarshal(value, &v)
   164  	return v, err
   165  }
   166  
   167  // IsBonded checks if the validator status equals Bonded
   168  func (v Validator) IsBonded() bool {
   169  	return v.GetStatus() == Bonded
   170  }
   171  
   172  // IsUnbonded checks if the validator status equals Unbonded
   173  func (v Validator) IsUnbonded() bool {
   174  	return v.GetStatus() == Unbonded
   175  }
   176  
   177  // IsUnbonding checks if the validator status equals Unbonding
   178  func (v Validator) IsUnbonding() bool {
   179  	return v.GetStatus() == Unbonding
   180  }
   181  
   182  // constant used in flags to indicate that description field should not be updated
   183  const DoNotModifyDesc = "[do-not-modify]"
   184  
   185  func NewDescription(moniker, identity, website, securityContact, details string) Description {
   186  	return Description{
   187  		Moniker:         moniker,
   188  		Identity:        identity,
   189  		Website:         website,
   190  		SecurityContact: securityContact,
   191  		Details:         details,
   192  	}
   193  }
   194  
   195  // String implements the Stringer interface for a Description object.
   196  func (d Description) String() string {
   197  	out, _ := yaml.Marshal(d)
   198  	return string(out)
   199  }
   200  
   201  // UpdateDescription updates the fields of a given description. An error is
   202  // returned if the resulting description contains an invalid length.
   203  func (d Description) UpdateDescription(d2 Description) (Description, error) {
   204  	if d2.Moniker == DoNotModifyDesc {
   205  		d2.Moniker = d.Moniker
   206  	}
   207  
   208  	if d2.Identity == DoNotModifyDesc {
   209  		d2.Identity = d.Identity
   210  	}
   211  
   212  	if d2.Website == DoNotModifyDesc {
   213  		d2.Website = d.Website
   214  	}
   215  
   216  	if d2.SecurityContact == DoNotModifyDesc {
   217  		d2.SecurityContact = d.SecurityContact
   218  	}
   219  
   220  	if d2.Details == DoNotModifyDesc {
   221  		d2.Details = d.Details
   222  	}
   223  
   224  	return NewDescription(
   225  		d2.Moniker,
   226  		d2.Identity,
   227  		d2.Website,
   228  		d2.SecurityContact,
   229  		d2.Details,
   230  	).EnsureLength()
   231  }
   232  
   233  // EnsureLength ensures the length of a validator's description.
   234  func (d Description) EnsureLength() (Description, error) {
   235  	if len(d.Moniker) > MaxMonikerLength {
   236  		return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid moniker length; got: %d, max: %d", len(d.Moniker), MaxMonikerLength)
   237  	}
   238  
   239  	if len(d.Identity) > MaxIdentityLength {
   240  		return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid identity length; got: %d, max: %d", len(d.Identity), MaxIdentityLength)
   241  	}
   242  
   243  	if len(d.Website) > MaxWebsiteLength {
   244  		return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid website length; got: %d, max: %d", len(d.Website), MaxWebsiteLength)
   245  	}
   246  
   247  	if len(d.SecurityContact) > MaxSecurityContactLength {
   248  		return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid security contact length; got: %d, max: %d", len(d.SecurityContact), MaxSecurityContactLength)
   249  	}
   250  
   251  	if len(d.Details) > MaxDetailsLength {
   252  		return d, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid details length; got: %d, max: %d", len(d.Details), MaxDetailsLength)
   253  	}
   254  
   255  	return d, nil
   256  }
   257  
   258  // ABCIValidatorUpdate returns an abci.ValidatorUpdate from a staking validator type
   259  // with the full validator power
   260  func (v Validator) ABCIValidatorUpdate(r sdk.Int) abci.ValidatorUpdate {
   261  	ocProtoPk, err := v.OcConsPublicKey()
   262  	if err != nil {
   263  		panic(err)
   264  	}
   265  
   266  	return abci.ValidatorUpdate{
   267  		PubKey: ocProtoPk,
   268  		Power:  v.ConsensusPower(r),
   269  	}
   270  }
   271  
   272  // ABCIValidatorUpdateZero returns an abci.ValidatorUpdate from a staking validator type
   273  // with zero power used for validator updates.
   274  func (v Validator) ABCIValidatorUpdateZero() abci.ValidatorUpdate {
   275  	ocprotoPk, err := v.OcConsPublicKey()
   276  	if err != nil {
   277  		panic(err)
   278  	}
   279  
   280  	return abci.ValidatorUpdate{
   281  		PubKey: ocprotoPk,
   282  		Power:  0,
   283  	}
   284  }
   285  
   286  // SetInitialCommission attempts to set a validator's initial commission. An
   287  // error is returned if the commission is invalid.
   288  func (v Validator) SetInitialCommission(commission Commission) (Validator, error) {
   289  	if err := commission.Validate(); err != nil {
   290  		return v, err
   291  	}
   292  
   293  	v.Commission = commission
   294  
   295  	return v, nil
   296  }
   297  
   298  // In some situations, the exchange rate becomes invalid, e.g. if
   299  // Validator loses all tokens due to slashing. In this case,
   300  // make all future delegations invalid.
   301  func (v Validator) InvalidExRate() bool {
   302  	return v.Tokens.IsZero() && v.DelegatorShares.IsPositive()
   303  }
   304  
   305  // calculate the token worth of provided shares
   306  func (v Validator) TokensFromShares(shares sdk.Dec) sdk.Dec {
   307  	return (shares.MulInt(v.Tokens)).Quo(v.DelegatorShares)
   308  }
   309  
   310  // calculate the token worth of provided shares, truncated
   311  func (v Validator) TokensFromSharesTruncated(shares sdk.Dec) sdk.Dec {
   312  	return (shares.MulInt(v.Tokens)).QuoTruncate(v.DelegatorShares)
   313  }
   314  
   315  // TokensFromSharesRoundUp returns the token worth of provided shares, rounded
   316  // up.
   317  func (v Validator) TokensFromSharesRoundUp(shares sdk.Dec) sdk.Dec {
   318  	return (shares.MulInt(v.Tokens)).QuoRoundUp(v.DelegatorShares)
   319  }
   320  
   321  // SharesFromTokens returns the shares of a delegation given a bond amount. It
   322  // returns an error if the validator has no tokens.
   323  func (v Validator) SharesFromTokens(amt sdk.Int) (sdk.Dec, error) {
   324  	if v.Tokens.IsZero() {
   325  		return sdk.ZeroDec(), ErrInsufficientShares
   326  	}
   327  
   328  	return v.GetDelegatorShares().MulInt(amt).QuoInt(v.GetTokens()), nil
   329  }
   330  
   331  // SharesFromTokensTruncated returns the truncated shares of a delegation given
   332  // a bond amount. It returns an error if the validator has no tokens.
   333  func (v Validator) SharesFromTokensTruncated(amt sdk.Int) (sdk.Dec, error) {
   334  	if v.Tokens.IsZero() {
   335  		return sdk.ZeroDec(), ErrInsufficientShares
   336  	}
   337  
   338  	return v.GetDelegatorShares().MulInt(amt).QuoTruncate(v.GetTokens().ToDec()), nil
   339  }
   340  
   341  // get the bonded tokens which the validator holds
   342  func (v Validator) BondedTokens() sdk.Int {
   343  	if v.IsBonded() {
   344  		return v.Tokens
   345  	}
   346  
   347  	return sdk.ZeroInt()
   348  }
   349  
   350  // ConsensusPower gets the consensus-engine power. Aa reduction of 10^6 from
   351  // validator tokens is applied
   352  func (v Validator) ConsensusPower(r sdk.Int) int64 {
   353  	if v.IsBonded() {
   354  		return v.PotentialConsensusPower(r)
   355  	}
   356  
   357  	return 0
   358  }
   359  
   360  // PotentialConsensusPower returns the potential consensus-engine power.
   361  func (v Validator) PotentialConsensusPower(r sdk.Int) int64 {
   362  	return sdk.TokensToConsensusPower(v.Tokens, r)
   363  }
   364  
   365  // UpdateStatus updates the location of the shares within a validator
   366  // to reflect the new status
   367  func (v Validator) UpdateStatus(newStatus BondStatus) Validator {
   368  	v.Status = newStatus
   369  	return v
   370  }
   371  
   372  // AddTokensFromDel adds tokens to a validator
   373  func (v Validator) AddTokensFromDel(amount sdk.Int) (Validator, sdk.Dec) {
   374  	// calculate the shares to issue
   375  	var issuedShares sdk.Dec
   376  	if v.DelegatorShares.IsZero() {
   377  		// the first delegation to a validator sets the exchange rate to one
   378  		issuedShares = amount.ToDec()
   379  	} else {
   380  		shares, err := v.SharesFromTokens(amount)
   381  		if err != nil {
   382  			panic(err)
   383  		}
   384  
   385  		issuedShares = shares
   386  	}
   387  
   388  	v.Tokens = v.Tokens.Add(amount)
   389  	v.DelegatorShares = v.DelegatorShares.Add(issuedShares)
   390  
   391  	return v, issuedShares
   392  }
   393  
   394  // RemoveTokens removes tokens from a validator
   395  func (v Validator) RemoveTokens(tokens sdk.Int) Validator {
   396  	if tokens.IsNegative() {
   397  		panic(fmt.Sprintf("should not happen: trying to remove negative tokens %v", tokens))
   398  	}
   399  
   400  	if v.Tokens.LT(tokens) {
   401  		panic(fmt.Sprintf("should not happen: only have %v tokens, trying to remove %v", v.Tokens, tokens))
   402  	}
   403  
   404  	v.Tokens = v.Tokens.Sub(tokens)
   405  
   406  	return v
   407  }
   408  
   409  // RemoveDelShares removes delegator shares from a validator.
   410  // NOTE: because token fractions are left in the valiadator,
   411  //
   412  //	the exchange rate of future shares of this validator can increase.
   413  func (v Validator) RemoveDelShares(delShares sdk.Dec) (Validator, sdk.Int) {
   414  	remainingShares := v.DelegatorShares.Sub(delShares)
   415  
   416  	var issuedTokens sdk.Int
   417  	if remainingShares.IsZero() {
   418  		// last delegation share gets any trimmings
   419  		issuedTokens = v.Tokens
   420  		v.Tokens = sdk.ZeroInt()
   421  	} else {
   422  		// leave excess tokens in the validator
   423  		// however fully use all the delegator shares
   424  		issuedTokens = v.TokensFromShares(delShares).TruncateInt()
   425  		v.Tokens = v.Tokens.Sub(issuedTokens)
   426  
   427  		if v.Tokens.IsNegative() {
   428  			panic("attempting to remove more tokens than available in validator")
   429  		}
   430  	}
   431  
   432  	v.DelegatorShares = remainingShares
   433  
   434  	return v, issuedTokens
   435  }
   436  
   437  // MinEqual defines a more minimum set of equality conditions when comparing two
   438  // validators.
   439  func (v *Validator) MinEqual(other *Validator) bool {
   440  	return v.OperatorAddress == other.OperatorAddress &&
   441  		v.Status == other.Status &&
   442  		v.Tokens.Equal(other.Tokens) &&
   443  		v.DelegatorShares.Equal(other.DelegatorShares) &&
   444  		v.Description.Equal(other.Description) &&
   445  		v.Commission.Equal(other.Commission) &&
   446  		v.Jailed == other.Jailed &&
   447  		v.MinSelfDelegation.Equal(other.MinSelfDelegation) &&
   448  		v.ConsensusPubkey.Equal(other.ConsensusPubkey)
   449  }
   450  
   451  // Equal checks if the receiver equals the parameter
   452  func (v *Validator) Equal(v2 *Validator) bool {
   453  	return v.MinEqual(v2) &&
   454  		v.UnbondingHeight == v2.UnbondingHeight &&
   455  		v.UnbondingTime.Equal(v2.UnbondingTime)
   456  }
   457  
   458  func (v Validator) IsJailed() bool        { return v.Jailed }
   459  func (v Validator) GetMoniker() string    { return v.Description.Moniker }
   460  func (v Validator) GetStatus() BondStatus { return v.Status }
   461  func (v Validator) GetOperator() sdk.ValAddress {
   462  	if v.OperatorAddress == "" {
   463  		return nil
   464  	}
   465  	addr, err := sdk.ValAddressFromBech32(v.OperatorAddress)
   466  	if err != nil {
   467  		panic(err)
   468  	}
   469  	return addr
   470  }
   471  
   472  // ConsPubKey returns the validator PubKey as a cryptotypes.PubKey.
   473  func (v Validator) ConsPubKey() (cryptotypes.PubKey, error) {
   474  	pk, ok := v.ConsensusPubkey.GetCachedValue().(cryptotypes.PubKey)
   475  	if !ok {
   476  		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expecting cryptotypes.PubKey, got %T", pk)
   477  	}
   478  
   479  	return pk, nil
   480  }
   481  
   482  // OcConsPublicKey casts Validator.ConsensusPubkey to tmprotocrypto.PubKey.
   483  func (v Validator) OcConsPublicKey() (tmprotocrypto.PublicKey, error) {
   484  	pk, err := v.ConsPubKey()
   485  	if err != nil {
   486  		return tmprotocrypto.PublicKey{}, err
   487  	}
   488  
   489  	tmPk, err := cryptocodec.ToOcProtoPublicKey(pk)
   490  	if err != nil {
   491  		return tmprotocrypto.PublicKey{}, err
   492  	}
   493  
   494  	return tmPk, nil
   495  }
   496  
   497  // GetConsAddr extracts Consensus key address
   498  func (v Validator) GetConsAddr() (sdk.ConsAddress, error) {
   499  	pk, ok := v.ConsensusPubkey.GetCachedValue().(cryptotypes.PubKey)
   500  	if !ok {
   501  		return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "expecting cryptotypes.PubKey, got %T", pk)
   502  	}
   503  
   504  	return sdk.ConsAddress(pk.Address()), nil
   505  }
   506  
   507  func (v Validator) GetTokens() sdk.Int       { return v.Tokens }
   508  func (v Validator) GetBondedTokens() sdk.Int { return v.BondedTokens() }
   509  func (v Validator) GetConsensusPower(r sdk.Int) int64 {
   510  	return v.ConsensusPower(r)
   511  }
   512  func (v Validator) GetCommission() sdk.Dec        { return v.Commission.Rate }
   513  func (v Validator) GetMinSelfDelegation() sdk.Int { return v.MinSelfDelegation }
   514  func (v Validator) GetDelegatorShares() sdk.Dec   { return v.DelegatorShares }
   515  
   516  // UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
   517  func (v Validator) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
   518  	var pk cryptotypes.PubKey
   519  	return unpacker.UnpackAny(v.ConsensusPubkey, &pk)
   520  }