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 }