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  }