func VerifyDuplicateVote(e *types.DuplicateVoteEvidence, chainID string, valSet *types.ValidatorSet) error {
	_, val := valSet.GetByAddress(e.VoteA.ValidatorAddress)
	if val == nil {
		return fmt.Errorf("address %X was not a validator at height %d", e.VoteA.ValidatorAddress, e.Height())
	}
	pubKey := val.PubKey
	if e.VoteA.Height != e.VoteB.Height ||
		e.VoteA.Round != e.VoteB.Round ||
		e.VoteA.Type != e.VoteB.Type {
		return fmt.Errorf("h/r/s does not match: %d/%d/%v vs %d/%d/%v",
			e.VoteA.Height, e.VoteA.Round, e.VoteA.Type,
			e.VoteB.Height, e.VoteB.Round, e.VoteB.Type)
	}
	if !bytes.Equal(e.VoteA.ValidatorAddress, e.VoteB.ValidatorAddress) {
		return fmt.Errorf("validator addresses do not match: %X vs %X",
			e.VoteA.ValidatorAddress,
			e.VoteB.ValidatorAddress,
		)
	}
	if e.VoteA.BlockID.Equals(e.VoteB.BlockID) {
		return fmt.Errorf(
			"block IDs are the same (%v) - not a real duplicate vote",
			e.VoteA.BlockID,
		)
	}
	addr := e.VoteA.ValidatorAddress
	if !bytes.Equal(pubKey.Address(), addr) {
		return fmt.Errorf("address (%X) doesn't match pubkey (%v - %X)",
			addr, pubKey, pubKey.Address())
	}
	va := e.VoteA.ToProto()
	vb := e.VoteB.ToProto()
	if !pubKey.VerifySignature(types.VoteSignBytes(chainID, va), e.VoteA.Signature) {
		return fmt.Errorf("verifying VoteA: %w", types.ErrVoteInvalidSignature)
	}
	if !pubKey.VerifySignature(types.VoteSignBytes(chainID, vb), e.VoteB.Signature) {
		return fmt.Errorf("verifying VoteB: %w", types.ErrVoteInvalidSignature)
	}
	return nil
}
VerifyDuplicateVote verifies DuplicateVoteEvidence against the state of full node. This involves the
following checks:
- the validator is in the validator set at the height of the evidence
- the height, round, type and validator address of the votes must be the same
- the block ID's must be different
- The signatures must both be valid
package evidence
import (
	"bytes"
	"errors"
	"fmt"
	"time"
	"github.com/tendermint/tendermint/light"
	"github.com/tendermint/tendermint/types"
)
func (evpool *Pool) verify(evidence types.Evidence) error {
	var (
		state          = evpool.State()
		height         = state.LastBlockHeight
		evidenceParams = state.ConsensusParams.Evidence
		ageNumBlocks   = height - evidence.Height()
	)
	blockMeta := evpool.blockStore.LoadBlockMeta(evidence.Height())
	if blockMeta == nil {
		return fmt.Errorf("failed to verify evidence; missing block for height %d", evidence.Height())
	}
	evTime := blockMeta.Header.Time
	ageDuration := state.LastBlockTime.Sub(evTime)
	if ageDuration > evidenceParams.MaxAgeDuration && ageNumBlocks > evidenceParams.MaxAgeNumBlocks {
		return types.NewErrInvalidEvidence(
			evidence,
			fmt.Errorf(
				"evidence from height %d (created at: %v) is too old; min height is %d and evidence can not be older than %v",
				evidence.Height(),
				evTime,
				height-evidenceParams.MaxAgeNumBlocks,
				state.LastBlockTime.Add(evidenceParams.MaxAgeDuration),
			),
		)
	}
	switch ev := evidence.(type) {
	case *types.DuplicateVoteEvidence:
		valSet, err := evpool.stateDB.LoadValidators(evidence.Height())
		if err != nil {
			return err
		}
		if err := VerifyDuplicateVote(ev, state.ChainID, valSet); err != nil {
			return types.NewErrInvalidEvidence(evidence, err)
		}
		_, val := valSet.GetByAddress(ev.VoteA.ValidatorAddress)
		if err := ev.ValidateABCI(val, valSet, evTime); err != nil {
			ev.GenerateABCI(val, valSet, evTime)
			if addErr := evpool.addPendingEvidence(ev); addErr != nil {
				evpool.logger.Error("adding pending duplicate vote evidence failed", "err", addErr)
			}
			return err
		}
		return nil
	case *types.LightClientAttackEvidence:
		commonHeader, err := getSignedHeader(evpool.blockStore, evidence.Height())
		if err != nil {
			return err
		}
		commonVals, err := evpool.stateDB.LoadValidators(evidence.Height())
		if err != nil {
			return err
		}
		trustedHeader := commonHeader
		if evidence.Height() != ev.ConflictingBlock.Height {
			trustedHeader, err = getSignedHeader(evpool.blockStore, ev.ConflictingBlock.Height)
			if err != nil {
				latestHeight := evpool.blockStore.Height()
				trustedHeader, err = getSignedHeader(evpool.blockStore, latestHeight)
				if err != nil {
					return err
				}
				if trustedHeader.Time.Before(ev.ConflictingBlock.Time) {
					return fmt.Errorf("latest block time (%v) is before conflicting block time (%v)",
						trustedHeader.Time, ev.ConflictingBlock.Time,
					)
				}
			}
		}
		err = VerifyLightClientAttack(
			ev,
			commonHeader,
			trustedHeader,
			commonVals,
			state.LastBlockTime,
			state.ConsensusParams.Evidence.MaxAgeDuration,
		)
		if err != nil {
			return types.NewErrInvalidEvidence(evidence, err)
		}
		if err := ev.ValidateABCI(commonVals, trustedHeader, evTime); err != nil {
			ev.GenerateABCI(commonVals, trustedHeader, evTime)
			if addErr := evpool.addPendingEvidence(ev); addErr != nil {
				evpool.logger.Error("adding pending light client attack evidence failed", "err", addErr)
			}
			return err
		}
		return nil
	default:
		return types.NewErrInvalidEvidence(evidence, fmt.Errorf("unrecognized evidence type: %T", evidence))
	}
}
func VerifyLightClientAttack(e *types.LightClientAttackEvidence, commonHeader, trustedHeader *types.SignedHeader,
	commonVals *types.ValidatorSet, now time.Time, trustPeriod time.Duration) error {
	if commonHeader.Height != e.ConflictingBlock.Height {
		err := commonVals.VerifyCommitLightTrusting(trustedHeader.ChainID, e.ConflictingBlock.Commit, light.DefaultTrustLevel)
		if err != nil {
			return fmt.Errorf("skipping verification of conflicting block failed: %w", err)
		}
	} else if e.ConflictingHeaderIsInvalid(trustedHeader.Header) {
		return errors.New("common height is the same as conflicting block height so expected the conflicting" +
			" block to be correctly derived yet it wasn't")
	}
	if err := e.ConflictingBlock.ValidatorSet.VerifyCommitLight(trustedHeader.ChainID, e.ConflictingBlock.Commit.BlockID,
		e.ConflictingBlock.Height, e.ConflictingBlock.Commit); err != nil {
		return fmt.Errorf("invalid commit from conflicting block: %w", err)
	}
	if e.ConflictingBlock.Height > trustedHeader.Height && e.ConflictingBlock.Time.After(trustedHeader.Time) {
		return fmt.Errorf("conflicting block doesn't violate monotonically increasing time (%v is after %v)",
			e.ConflictingBlock.Time, trustedHeader.Time,
		)
	} else if bytes.Equal(trustedHeader.Hash(), e.ConflictingBlock.Hash()) {
		return fmt.Errorf("trusted header hash matches the evidence's conflicting header hash: %X",
			trustedHeader.Hash())
	}
	return nil
}