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