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.

193 lines
4.6 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. // String returns a string representation of String.
  75. //
  76. // 1. address
  77. // 2. public key
  78. // 3. voting power
  79. // 4. proposer priority
  80. func (v *Validator) String() string {
  81. if v == nil {
  82. return "nil-Validator"
  83. }
  84. return fmt.Sprintf("Validator{%v %v VP:%v A:%v}",
  85. v.Address,
  86. v.PubKey,
  87. v.VotingPower,
  88. v.ProposerPriority)
  89. }
  90. // ValidatorListString returns a prettified validator list for logging purposes.
  91. func ValidatorListString(vals []*Validator) string {
  92. chunks := make([]string, len(vals))
  93. for i, val := range vals {
  94. chunks[i] = fmt.Sprintf("%s:%d", val.Address, val.VotingPower)
  95. }
  96. return strings.Join(chunks, ",")
  97. }
  98. // Bytes computes the unique encoding of a validator with a given voting power.
  99. // These are the bytes that gets hashed in consensus. It excludes address
  100. // as its redundant with the pubkey. This also excludes ProposerPriority
  101. // which changes every round.
  102. func (v *Validator) Bytes() []byte {
  103. pk, err := ce.PubKeyToProto(v.PubKey)
  104. if err != nil {
  105. panic(err)
  106. }
  107. pbv := tmproto.SimpleValidator{
  108. PubKey: &pk,
  109. VotingPower: v.VotingPower,
  110. }
  111. bz, err := pbv.Marshal()
  112. if err != nil {
  113. panic(err)
  114. }
  115. return bz
  116. }
  117. // ToProto converts Valiator to protobuf
  118. func (v *Validator) ToProto() (*tmproto.Validator, error) {
  119. if v == nil {
  120. return nil, errors.New("nil validator")
  121. }
  122. pk, err := ce.PubKeyToProto(v.PubKey)
  123. if err != nil {
  124. return nil, err
  125. }
  126. vp := tmproto.Validator{
  127. Address: v.Address,
  128. PubKey: pk,
  129. VotingPower: v.VotingPower,
  130. ProposerPriority: v.ProposerPriority,
  131. }
  132. return &vp, nil
  133. }
  134. // FromProto sets a protobuf Validator to the given pointer.
  135. // It returns an error if the public key is invalid.
  136. func ValidatorFromProto(vp *tmproto.Validator) (*Validator, error) {
  137. if vp == nil {
  138. return nil, errors.New("nil validator")
  139. }
  140. pk, err := ce.PubKeyFromProto(vp.PubKey)
  141. if err != nil {
  142. return nil, err
  143. }
  144. v := new(Validator)
  145. v.Address = vp.GetAddress()
  146. v.PubKey = pk
  147. v.VotingPower = vp.GetVotingPower()
  148. v.ProposerPriority = vp.GetProposerPriority()
  149. return v, nil
  150. }
  151. //----------------------------------------
  152. // RandValidator
  153. // RandValidator returns a randomized validator, useful for testing.
  154. // UNSTABLE
  155. func RandValidator(randPower bool, minPower int64) (*Validator, PrivValidator) {
  156. privVal := NewMockPV()
  157. votePower := minPower
  158. if randPower {
  159. votePower += int64(tmrand.Uint32())
  160. }
  161. pubKey, err := privVal.GetPubKey()
  162. if err != nil {
  163. panic(fmt.Errorf("could not retrieve pubkey %w", err))
  164. }
  165. val := NewValidator(pubKey, votePower)
  166. return val, privVal
  167. }