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.

194 lines
4.6 KiB

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