github.com/okex/exchain@v1.8.0/libs/tendermint/types/vote.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"time"
     8  
     9  	"github.com/tendermint/go-amino"
    10  
    11  	"github.com/okex/exchain/libs/tendermint/crypto"
    12  	tmbytes "github.com/okex/exchain/libs/tendermint/libs/bytes"
    13  	tmproto "github.com/okex/exchain/libs/tendermint/proto/types"
    14  )
    15  
    16  const (
    17  	// MaxVoteBytes is a maximum vote size (including amino overhead).
    18  	MaxVoteBytes int64  = 223
    19  	nilVoteStr   string = "nil-Vote"
    20  )
    21  
    22  var (
    23  	ErrVoteUnexpectedStep            = errors.New("unexpected step")
    24  	ErrVoteInvalidValidatorIndex     = errors.New("invalid validator index")
    25  	ErrVoteInvalidValidatorAddress   = errors.New("invalid validator address")
    26  	ErrVoteInvalidSignature          = errors.New("invalid signature")
    27  	ErrVoteInvalidBlockHash          = errors.New("invalid block hash")
    28  	ErrVoteNonDeterministicSignature = errors.New("non-deterministic signature")
    29  	ErrVoteNil                       = errors.New("nil vote")
    30  )
    31  
    32  type ErrVoteConflictingVotes struct {
    33  	*DuplicateVoteEvidence
    34  }
    35  
    36  func (err *ErrVoteConflictingVotes) Error() string {
    37  	return fmt.Sprintf("Conflicting votes from validator %v", err.PubKey.Address())
    38  }
    39  
    40  func NewConflictingVoteError(val *Validator, vote1, vote2 *Vote) *ErrVoteConflictingVotes {
    41  	return &ErrVoteConflictingVotes{
    42  		NewDuplicateVoteEvidence(val.PubKey, vote1, vote2),
    43  	}
    44  }
    45  
    46  // Address is hex bytes.
    47  type Address = crypto.Address
    48  
    49  // Vote represents a prevote, precommit, or commit vote from validators for
    50  // consensus.
    51  type Vote struct {
    52  	Type             SignedMsgType `json:"type"`
    53  	Height           int64         `json:"height"`
    54  	Round            int           `json:"round"`
    55  	BlockID          BlockID       `json:"block_id"` // zero if vote is nil.
    56  	Timestamp        time.Time     `json:"timestamp"`
    57  	ValidatorAddress Address       `json:"validator_address"`
    58  	ValidatorIndex   int           `json:"validator_index"`
    59  	Signature        []byte        `json:"signature"`
    60  	HasVC            bool          `json:"has_vc"` // enterNewRoundAVC at this Height
    61  }
    62  
    63  func (vote Vote) AminoSize(cdc *amino.Codec) int {
    64  	var size = 0
    65  
    66  	if vote.Type != 0 {
    67  		size += 1 + amino.UvarintSize(uint64(vote.Type))
    68  	}
    69  
    70  	if vote.Height != 0 {
    71  		size += 1 + amino.UvarintSize(uint64(vote.Height))
    72  	}
    73  
    74  	if vote.Round != 0 {
    75  		size += 1 + amino.UvarintSize(uint64(vote.Round))
    76  	}
    77  
    78  	blockIDSize := vote.BlockID.AminoSize(cdc)
    79  	if blockIDSize != 0 {
    80  		size += 1 + amino.UvarintSize(uint64(blockIDSize)) + blockIDSize
    81  	}
    82  
    83  	timestampSize := amino.TimeSize(vote.Timestamp)
    84  	if timestampSize != 0 {
    85  		size += 1 + amino.UvarintSize(uint64(timestampSize)) + timestampSize
    86  	}
    87  
    88  	if len(vote.ValidatorAddress) != 0 {
    89  		size += 1 + amino.ByteSliceSize(vote.ValidatorAddress)
    90  	}
    91  
    92  	if vote.ValidatorIndex != 0 {
    93  		size += 1 + amino.UvarintSize(uint64(vote.ValidatorIndex))
    94  	}
    95  
    96  	if len(vote.Signature) != 0 {
    97  		size += 1 + amino.ByteSliceSize(vote.Signature)
    98  	}
    99  	if vote.HasVC {
   100  		size += 1 + 1
   101  	}
   102  
   103  	return size
   104  }
   105  
   106  func (vote *Vote) UnmarshalFromAmino(cdc *amino.Codec, data []byte) error {
   107  	var dataLen uint64 = 0
   108  	var subData []byte
   109  	var timestampUpdated bool
   110  
   111  	for {
   112  		data = data[dataLen:]
   113  		if len(data) == 0 {
   114  			break
   115  		}
   116  
   117  		pos, pbType, err := amino.ParseProtoPosAndTypeMustOneByte(data[0])
   118  		if err != nil {
   119  			return err
   120  		}
   121  		data = data[1:]
   122  
   123  		if pbType == amino.Typ3_ByteLength {
   124  			var n int
   125  			dataLen, n, err = amino.DecodeUvarint(data)
   126  			if err != nil {
   127  				return err
   128  			}
   129  			data = data[n:]
   130  			if len(data) < int(dataLen) {
   131  				return fmt.Errorf("invalid data len")
   132  			}
   133  			subData = data[:dataLen]
   134  		}
   135  
   136  		switch pos {
   137  		case 1:
   138  			u64, n, err := amino.DecodeUvarint(data)
   139  			if err != nil {
   140  				return err
   141  			}
   142  			vote.Type = SignedMsgType(u64)
   143  			dataLen = uint64(n)
   144  		case 2:
   145  			u64, n, err := amino.DecodeUvarint(data)
   146  			if err != nil {
   147  				return err
   148  			}
   149  			vote.Height = int64(u64)
   150  			dataLen = uint64(n)
   151  		case 3:
   152  			u64, n, err := amino.DecodeUvarint(data)
   153  			if err != nil {
   154  				return err
   155  			}
   156  			vote.Round = int(u64)
   157  			dataLen = uint64(n)
   158  		case 4:
   159  			err = vote.BlockID.UnmarshalFromAmino(cdc, subData)
   160  			if err != nil {
   161  				return err
   162  			}
   163  		case 5:
   164  			vote.Timestamp, _, err = amino.DecodeTime(subData)
   165  			if err != nil {
   166  				return err
   167  			}
   168  			timestampUpdated = true
   169  		case 6:
   170  			vote.ValidatorAddress = make([]byte, len(subData))
   171  			copy(vote.ValidatorAddress, subData)
   172  		case 7:
   173  			u64, n, err := amino.DecodeUvarint(data)
   174  			if err != nil {
   175  				return err
   176  			}
   177  			vote.ValidatorIndex = int(u64)
   178  			dataLen = uint64(n)
   179  		case 8:
   180  			vote.Signature = make([]byte, len(subData))
   181  			copy(vote.Signature, subData)
   182  		case 9:
   183  			var n int
   184  			vote.HasVC, n, err = amino.DecodeBool(data)
   185  			if err != nil {
   186  				return err
   187  			}
   188  			dataLen = uint64(n)
   189  		default:
   190  			return fmt.Errorf("unexpect feild num %d", pos)
   191  		}
   192  	}
   193  	if !timestampUpdated {
   194  		vote.Timestamp = amino.ZeroTime
   195  	}
   196  	return nil
   197  }
   198  
   199  // CommitSig converts the Vote to a CommitSig.
   200  func (vote *Vote) CommitSig() CommitSig {
   201  	if vote == nil {
   202  		return NewCommitSigAbsent()
   203  	}
   204  
   205  	var blockIDFlag BlockIDFlag
   206  	switch {
   207  	case vote.BlockID.IsComplete():
   208  		blockIDFlag = BlockIDFlagCommit
   209  	case vote.BlockID.IsZero():
   210  		blockIDFlag = BlockIDFlagNil
   211  	default:
   212  		panic(fmt.Sprintf("Invalid vote %v - expected BlockID to be either empty or complete", vote))
   213  	}
   214  
   215  	return CommitSig{
   216  		BlockIDFlag:      blockIDFlag,
   217  		ValidatorAddress: vote.ValidatorAddress,
   218  		Timestamp:        vote.Timestamp,
   219  		Signature:        vote.Signature,
   220  	}
   221  }
   222  
   223  func (vote *Vote) SignBytes(chainID string) []byte {
   224  	if HigherThanVenus1(vote.Height) {
   225  		return vote.ibcSignBytes(chainID)
   226  	}
   227  	return vote.originSignBytes(chainID)
   228  }
   229  
   230  func (vote *Vote) ibcSignBytes(chainID string) []byte {
   231  	return VoteSignBytes(chainID, vote)
   232  }
   233  func (vote *Vote) originSignBytes(chainId string) []byte {
   234  	bz, err := cdc.MarshalBinaryLengthPrefixed(CanonicalizeVote(chainId, vote))
   235  	if err != nil {
   236  		panic(err)
   237  	}
   238  	return bz
   239  }
   240  
   241  func (vote *Vote) Copy() *Vote {
   242  	voteCopy := *vote
   243  	return &voteCopy
   244  }
   245  
   246  func (vote *Vote) String() string {
   247  	if vote == nil {
   248  		return nilVoteStr
   249  	}
   250  
   251  	var typeString string
   252  	switch vote.Type {
   253  	case PrevoteType:
   254  		typeString = "Prevote"
   255  	case PrecommitType:
   256  		typeString = "Precommit"
   257  	default:
   258  		panic("Unknown vote type")
   259  	}
   260  
   261  	return fmt.Sprintf("Vote{%v:%X %v/%02d/%v(%v) %X %X @ %s}",
   262  		vote.ValidatorIndex,
   263  		tmbytes.Fingerprint(vote.ValidatorAddress),
   264  		vote.Height,
   265  		vote.Round,
   266  		vote.Type,
   267  		typeString,
   268  		tmbytes.Fingerprint(vote.BlockID.Hash),
   269  		tmbytes.Fingerprint(vote.Signature),
   270  		CanonicalTime(vote.Timestamp),
   271  	)
   272  }
   273  
   274  func (vote *Vote) Verify(chainID string, pubKey crypto.PubKey) error {
   275  	if !bytes.Equal(pubKey.Address(), vote.ValidatorAddress) {
   276  		return ErrVoteInvalidValidatorAddress
   277  	}
   278  
   279  	if !pubKey.VerifyBytes(vote.SignBytes(chainID), vote.Signature) {
   280  		return ErrVoteInvalidSignature
   281  	}
   282  	return nil
   283  }
   284  
   285  // ValidateBasic performs basic validation.
   286  func (vote *Vote) ValidateBasic() error {
   287  	if !IsVoteTypeValid(vote.Type) {
   288  		return errors.New("invalid Type")
   289  	}
   290  	if vote.Height < 0 {
   291  		return errors.New("negative Height")
   292  	}
   293  	if vote.Round < 0 {
   294  		return errors.New("negative Round")
   295  	}
   296  
   297  	// NOTE: Timestamp validation is subtle and handled elsewhere.
   298  
   299  	if err := vote.BlockID.ValidateBasic(); err != nil {
   300  		return fmt.Errorf("wrong BlockID: %v", err)
   301  	}
   302  	// BlockID.ValidateBasic would not err if we for instance have an empty hash but a
   303  	// non-empty PartsSetHeader:
   304  	if !vote.BlockID.IsZero() && !vote.BlockID.IsComplete() {
   305  		return fmt.Errorf("blockID must be either empty or complete, got: %v", vote.BlockID)
   306  	}
   307  	if len(vote.ValidatorAddress) != crypto.AddressSize {
   308  		return fmt.Errorf("expected ValidatorAddress size to be %d bytes, got %d bytes",
   309  			crypto.AddressSize,
   310  			len(vote.ValidatorAddress),
   311  		)
   312  	}
   313  	if vote.ValidatorIndex < 0 {
   314  		return errors.New("negative ValidatorIndex")
   315  	}
   316  	if len(vote.Signature) == 0 {
   317  		return errors.New("signature is missing")
   318  	}
   319  	if len(vote.Signature) > MaxSignatureSize {
   320  		return fmt.Errorf("signature is too big (max: %d)", MaxSignatureSize)
   321  	}
   322  	return nil
   323  }
   324  
   325  // ToProto converts the handwritten type to proto generated type
   326  // return type, nil if everything converts safely, otherwise nil, error
   327  func (vote *Vote) ToProto() *tmproto.Vote {
   328  	if vote == nil {
   329  		return nil
   330  	}
   331  
   332  	return &tmproto.Vote{
   333  		Type:             tmproto.SignedMsgType(vote.Type),
   334  		Height:           vote.Height,
   335  		Round:            int64(vote.Round),
   336  		BlockID:          vote.BlockID.ToProto(),
   337  		Timestamp:        vote.Timestamp,
   338  		ValidatorAddress: vote.ValidatorAddress,
   339  		ValidatorIndex:   int64(vote.ValidatorIndex),
   340  		Signature:        vote.Signature,
   341  	}
   342  }
   343  
   344  // FromProto converts a proto generetad type to a handwritten type
   345  // return type, nil if everything converts safely, otherwise nil, error
   346  func VoteFromProto(pv *tmproto.Vote) (*Vote, error) {
   347  	if pv == nil {
   348  		return nil, errors.New("nil vote")
   349  	}
   350  
   351  	blockID, err := BlockIDFromProto(&pv.BlockID)
   352  	if err != nil {
   353  		return nil, err
   354  	}
   355  
   356  	vote := new(Vote)
   357  	vote.Type = SignedMsgType(pv.Type)
   358  	vote.Height = pv.Height
   359  	vote.Round = int(pv.Round)
   360  	vote.BlockID = *blockID
   361  	vote.Timestamp = pv.Timestamp
   362  	vote.ValidatorAddress = pv.ValidatorAddress
   363  	vote.ValidatorIndex = int(pv.ValidatorIndex)
   364  	vote.Signature = pv.Signature
   365  
   366  	return vote, vote.ValidateBasic()
   367  }