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