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