You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
4.4 KiB

  1. package types
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "strings"
  7. "github.com/tendermint/tendermint/crypto"
  8. ce "github.com/tendermint/tendermint/crypto/encoding"
  9. tmrand "github.com/tendermint/tendermint/libs/rand"
  10. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  11. )
  12. // Volatile state for each Validator
  13. // NOTE: The ProposerPriority is not included in Validator.Hash();
  14. // make sure to update that method if changes are made here
  15. type Validator struct {
  16. Address Address `json:"address"`
  17. PubKey crypto.PubKey `json:"pub_key"`
  18. VotingPower int64 `json:"voting_power"`
  19. ProposerPriority int64 `json:"proposer_priority"`
  20. }
  21. // NewValidator returns a new validator with the given pubkey and voting power.
  22. func NewValidator(pubKey crypto.PubKey, votingPower int64) *Validator {
  23. return &Validator{
  24. Address: pubKey.Address(),
  25. PubKey: pubKey,
  26. VotingPower: votingPower,
  27. ProposerPriority: 0,
  28. }
  29. }
  30. // ValidateBasic performs basic validation.
  31. func (v *Validator) ValidateBasic() error {
  32. if v == nil {
  33. return errors.New("nil validator")
  34. }
  35. if v.PubKey == nil {
  36. return errors.New("validator does not have a public key")
  37. }
  38. if v.VotingPower < 0 {
  39. return errors.New("validator has negative voting power")
  40. }
  41. if len(v.Address) != crypto.AddressSize {
  42. return fmt.Errorf("validator address is the wrong size: %v", v.Address)
  43. }
  44. return nil
  45. }
  46. // Creates a new copy of the validator so we can mutate ProposerPriority.
  47. // Panics if the validator is nil.
  48. func (v *Validator) Copy() *Validator {
  49. vCopy := *v
  50. return &vCopy
  51. }
  52. // Returns the one with higher ProposerPriority.
  53. func (v *Validator) CompareProposerPriority(other *Validator) *Validator {
  54. if v == nil {
  55. return other
  56. }
  57. switch {
  58. case v.ProposerPriority > other.ProposerPriority:
  59. return v
  60. case v.ProposerPriority < other.ProposerPriority:
  61. return other
  62. default:
  63. result := bytes.Compare(v.Address, other.Address)
  64. switch {
  65. case result < 0:
  66. return v
  67. case result > 0:
  68. return other
  69. default:
  70. panic("Cannot compare identical validators")
  71. }
  72. }
  73. }
  74. func (v *Validator) String() string {
  75. if v == nil {
  76. return "nil-Validator"
  77. }
  78. return fmt.Sprintf("Validator{%v %v VP:%v A:%v}",
  79. v.Address,
  80. v.PubKey,
  81. v.VotingPower,
  82. v.ProposerPriority)
  83. }
  84. // ValidatorListString returns a prettified validator list for logging purposes.
  85. func ValidatorListString(vals []*Validator) string {
  86. chunks := make([]string, len(vals))
  87. for i, val := range vals {
  88. chunks[i] = fmt.Sprintf("%s:%d", val.Address, val.VotingPower)
  89. }
  90. return strings.Join(chunks, ",")
  91. }
  92. // Bytes computes the unique encoding of a validator with a given voting power.
  93. // These are the bytes that gets hashed in consensus. It excludes address
  94. // as its redundant with the pubkey. This also excludes ProposerPriority
  95. // which changes every round.
  96. func (v *Validator) Bytes() []byte {
  97. pk, err := ce.PubKeyToProto(v.PubKey)
  98. if err != nil {
  99. panic(err)
  100. }
  101. pbv := tmproto.SimpleValidator{
  102. PubKey: &pk,
  103. VotingPower: v.VotingPower,
  104. }
  105. bz, err := pbv.Marshal()
  106. if err != nil {
  107. panic(err)
  108. }
  109. return bz
  110. }
  111. // ToProto converts Valiator to protobuf
  112. func (v *Validator) ToProto() (*tmproto.Validator, error) {
  113. if v == nil {
  114. return nil, errors.New("nil validator")
  115. }
  116. pk, err := ce.PubKeyToProto(v.PubKey)
  117. if err != nil {
  118. return nil, err
  119. }
  120. vp := tmproto.Validator{
  121. Address: v.Address,
  122. PubKey: pk,
  123. VotingPower: v.VotingPower,
  124. ProposerPriority: v.ProposerPriority,
  125. }
  126. return &vp, nil
  127. }
  128. // FromProto sets a protobuf Validator to the given pointer.
  129. // It returns an error if the public key is invalid.
  130. func ValidatorFromProto(vp *tmproto.Validator) (*Validator, error) {
  131. if vp == nil {
  132. return nil, errors.New("nil validator")
  133. }
  134. pk, err := ce.PubKeyFromProto(vp.PubKey)
  135. if err != nil {
  136. return nil, err
  137. }
  138. v := new(Validator)
  139. v.Address = vp.GetAddress()
  140. v.PubKey = pk
  141. v.VotingPower = vp.GetVotingPower()
  142. v.ProposerPriority = vp.GetProposerPriority()
  143. return v, nil
  144. }
  145. //----------------------------------------
  146. // RandValidator
  147. // RandValidator returns a randomized validator, useful for testing.
  148. // UNSTABLE
  149. func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) {
  150. privVal := NewMockPV()
  151. votePower := minPower
  152. if randPower {
  153. votePower += int64(tmrand.Uint32())
  154. }
  155. pubKey, err := privVal.GetPubKey()
  156. if err != nil {
  157. panic(fmt.Errorf("could not retrieve pubkey %w", err))
  158. }
  159. val := NewValidator(pubKey, votePower)
  160. return val, privVal
  161. }