github.com/adoriasoft/tendermint@v0.34.0-dev1.0.20200722151356-96d84601a75a/types/validator.go (about)

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