github.com/line/ostracon@v1.0.10-0.20230328032236-7f20145f065d/evidence/verify_test.go (about)

     1  package evidence_test
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  	"time"
     7  
     8  	"github.com/stretchr/testify/assert"
     9  	"github.com/stretchr/testify/require"
    10  
    11  	tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
    12  	tmversion "github.com/tendermint/tendermint/proto/tendermint/version"
    13  	dbm "github.com/tendermint/tm-db"
    14  
    15  	"github.com/line/ostracon/crypto"
    16  	"github.com/line/ostracon/crypto/tmhash"
    17  	"github.com/line/ostracon/evidence"
    18  	"github.com/line/ostracon/evidence/mocks"
    19  	"github.com/line/ostracon/libs/log"
    20  	"github.com/line/ostracon/light"
    21  	sm "github.com/line/ostracon/state"
    22  	smmocks "github.com/line/ostracon/state/mocks"
    23  	"github.com/line/ostracon/types"
    24  	"github.com/line/ostracon/version"
    25  )
    26  
    27  const (
    28  	defaultVotingPower = 10
    29  )
    30  
    31  func TestVerifyLightClientAttack_Lunatic(t *testing.T) {
    32  	const (
    33  		height       int64 = 10
    34  		commonHeight int64 = 4
    35  		totalVals          = 10
    36  		byzVals            = 4
    37  	)
    38  	attackTime := defaultEvidenceTime.Add(1 * time.Hour)
    39  	// create valid lunatic evidence
    40  	ev, trusted, common := makeLunaticEvidence(
    41  		t, height, commonHeight, totalVals, byzVals, totalVals-byzVals, defaultEvidenceTime, attackTime)
    42  	require.NoError(t, ev.ValidateBasic())
    43  
    44  	// good pass -> no error
    45  	err := evidence.VerifyLightClientAttack(ev, common.SignedHeader, trusted.SignedHeader, common.ValidatorSet,
    46  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    47  	assert.NoError(t, err)
    48  
    49  	// trusted and conflicting hashes are the same -> an error should be returned
    50  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, ev.ConflictingBlock.SignedHeader, common.ValidatorSet,
    51  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    52  	assert.Error(t, err)
    53  
    54  	// evidence with different total validator power should fail
    55  	ev.TotalVotingPower = 1 * defaultVotingPower
    56  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, trusted.SignedHeader, common.ValidatorSet,
    57  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    58  	assert.Error(t, err)
    59  
    60  	// evidence without enough malicious votes should fail
    61  	ev, trusted, common = makeLunaticEvidence(
    62  		t, height, commonHeight, totalVals, byzVals-1, totalVals-byzVals, defaultEvidenceTime, attackTime)
    63  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, trusted.SignedHeader, common.ValidatorSet,
    64  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    65  	assert.Error(t, err)
    66  }
    67  
    68  func TestVerifyLightClientAttack_validateABCIEvidence(t *testing.T) {
    69  	const (
    70  		height             = int64(10)
    71  		commonHeight int64 = 4
    72  		totalVals          = 10
    73  		byzVals            = 4
    74  		votingPower        = defaultVotingPower
    75  	)
    76  	attackTime := defaultEvidenceTime.Add(1 * time.Hour)
    77  	// create valid lunatic evidence
    78  	ev, trusted, common := makeLunaticEvidence(
    79  		t, height, commonHeight, totalVals, byzVals, totalVals-byzVals, defaultEvidenceTime, attackTime)
    80  	require.NoError(t, ev.ValidateBasic())
    81  
    82  	// good pass -> no error
    83  	err := evidence.VerifyLightClientAttack(ev, common.SignedHeader, trusted.SignedHeader, common.ValidatorSet,
    84  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    85  	assert.NoError(t, err)
    86  
    87  	// illegal nil validators
    88  	validator, _ := types.RandValidator(false, votingPower)
    89  	ev.ByzantineValidators = []*types.Validator{validator}
    90  	amnesiaHeader, err := types.SignedHeaderFromProto(ev.ConflictingBlock.SignedHeader.ToProto())
    91  	require.NoError(t, err)
    92  	amnesiaHeader.ProposerAddress = nil
    93  	amnesiaHeader.Commit.Round = 2
    94  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, amnesiaHeader, common.ValidatorSet, // illegal header
    95  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
    96  	require.Error(t, err)
    97  	require.Equal(t, "expected nil validators from an amnesia light client attack but got 1", err.Error())
    98  
    99  	// illegal byzantine validators
   100  	equivocationHeader, err := types.SignedHeaderFromProto(ev.ConflictingBlock.SignedHeader.ToProto())
   101  	require.NoError(t, err)
   102  	equivocationHeader.ProposerAddress = nil
   103  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, equivocationHeader, common.ValidatorSet, // illegal header
   104  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
   105  	require.Error(t, err)
   106  	require.Equal(t, "expected 10 byzantine validators from evidence but got 1", err.Error())
   107  
   108  	// illegal byzantine validator address
   109  	phantomValidatorSet, _ := types.RandValidatorSet(totalVals, defaultVotingPower)
   110  	ev.ByzantineValidators = phantomValidatorSet.Validators
   111  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, equivocationHeader, common.ValidatorSet,
   112  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
   113  	require.Error(t, err)
   114  	require.Contains(t, err.Error(), "evidence contained an unexpected byzantine validator address;")
   115  
   116  	// illegal byzantine validator voting power
   117  	phantomValidatorSet = ev.ConflictingBlock.ValidatorSet.Copy()
   118  	phantomValidatorSet.Validators[0].VotingPower = votingPower + 1
   119  	ev.ByzantineValidators = phantomValidatorSet.Validators
   120  	err = evidence.VerifyLightClientAttack(ev, common.SignedHeader, equivocationHeader, common.ValidatorSet,
   121  		defaultEvidenceTime.Add(2*time.Hour), 3*time.Hour)
   122  	require.Error(t, err)
   123  	require.Contains(t, err.Error(), "evidence contained unexpected byzantine validator voting power;")
   124  }
   125  
   126  func TestVerify_LunaticAttackAgainstState(t *testing.T) {
   127  	const (
   128  		height       int64 = 10
   129  		commonHeight int64 = 4
   130  		totalVals          = 10
   131  		byzVals            = 4
   132  	)
   133  	attackTime := defaultEvidenceTime.Add(1 * time.Hour)
   134  	// create valid lunatic evidence
   135  	ev, trusted, common := makeLunaticEvidence(
   136  		t, height, commonHeight, totalVals, byzVals, totalVals-byzVals, defaultEvidenceTime, attackTime)
   137  
   138  	// now we try to test verification against state
   139  	state := sm.State{
   140  		LastBlockTime:   defaultEvidenceTime.Add(2 * time.Hour),
   141  		LastBlockHeight: height + 1,
   142  		ConsensusParams: *types.DefaultConsensusParams(),
   143  	}
   144  	stateStore := &smmocks.Store{}
   145  	stateStore.On("LoadValidators", commonHeight).Return(common.ValidatorSet, nil)
   146  	stateStore.On("Load").Return(state, nil)
   147  	blockStore := &mocks.BlockStore{}
   148  	blockStore.On("LoadBlockMeta", commonHeight).Return(&types.BlockMeta{Header: *common.Header})
   149  	blockStore.On("LoadBlockMeta", height).Return(&types.BlockMeta{Header: *trusted.Header})
   150  	blockStore.On("LoadBlockCommit", commonHeight).Return(common.Commit)
   151  	blockStore.On("LoadBlockCommit", height).Return(trusted.Commit)
   152  	pool, err := evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   153  	require.NoError(t, err)
   154  	pool.SetLogger(log.TestingLogger())
   155  
   156  	evList := types.EvidenceList{ev}
   157  	// check that the evidence pool correctly verifies the evidence
   158  	assert.NoError(t, pool.CheckEvidence(evList))
   159  
   160  	// as it was not originally in the pending bucket, it should now have been added
   161  	pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   162  	assert.Equal(t, 1, len(pendingEvs))
   163  	assert.Equal(t, ev, pendingEvs[0])
   164  
   165  	// if we submit evidence only against a single byzantine validator when we see there are more validators then this
   166  	// should return an error
   167  	ev.ByzantineValidators = ev.ByzantineValidators[:1]
   168  	t.Log(evList)
   169  	assert.Error(t, pool.CheckEvidence(evList))
   170  	// restore original byz vals
   171  	ev.ByzantineValidators = ev.GetByzantineValidators(common.ValidatorSet, trusted.SignedHeader)
   172  
   173  	// duplicate evidence should be rejected
   174  	evList = types.EvidenceList{ev, ev}
   175  	pool, err = evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   176  	require.NoError(t, err)
   177  	assert.Error(t, pool.CheckEvidence(evList))
   178  
   179  	// If evidence is submitted with an altered timestamp it should return an error
   180  	ev.Timestamp = defaultEvidenceTime.Add(1 * time.Minute)
   181  	pool, err = evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   182  	require.NoError(t, err)
   183  	assert.Error(t, pool.AddEvidence(ev))
   184  	ev.Timestamp = defaultEvidenceTime
   185  
   186  	// Evidence submitted with a different validator power should fail
   187  	ev.TotalVotingPower = 1
   188  	pool, err = evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   189  	require.NoError(t, err)
   190  	assert.Error(t, pool.AddEvidence(ev))
   191  	ev.TotalVotingPower = common.ValidatorSet.TotalVotingPower()
   192  }
   193  
   194  func TestVerify_ForwardLunaticAttack(t *testing.T) {
   195  	const (
   196  		nodeHeight   int64 = 8
   197  		attackHeight int64 = 10
   198  		commonHeight int64 = 4
   199  		totalVals          = 10
   200  		byzVals            = 5
   201  	)
   202  	attackTime := defaultEvidenceTime.Add(1 * time.Hour)
   203  
   204  	// create a forward lunatic attack
   205  	ev, trusted, common := makeLunaticEvidence(
   206  		t, attackHeight, commonHeight, totalVals, byzVals, totalVals-byzVals, defaultEvidenceTime, attackTime)
   207  
   208  	// now we try to test verification against state
   209  	state := sm.State{
   210  		LastBlockTime:   defaultEvidenceTime.Add(2 * time.Hour),
   211  		LastBlockHeight: nodeHeight,
   212  		ConsensusParams: *types.DefaultConsensusParams(),
   213  	}
   214  
   215  	// modify trusted light block so that it is of a height less than the conflicting one
   216  	trusted.Header.Height = state.LastBlockHeight
   217  	trusted.Header.Time = state.LastBlockTime
   218  
   219  	stateStore := &smmocks.Store{}
   220  	stateStore.On("LoadValidators", commonHeight).Return(common.ValidatorSet, nil)
   221  	stateStore.On("Load").Return(state, nil)
   222  	blockStore := &mocks.BlockStore{}
   223  	blockStore.On("LoadBlockMeta", commonHeight).Return(&types.BlockMeta{Header: *common.Header})
   224  	blockStore.On("LoadBlockMeta", nodeHeight).Return(&types.BlockMeta{Header: *trusted.Header})
   225  	blockStore.On("LoadBlockMeta", attackHeight).Return(nil)
   226  	blockStore.On("LoadBlockCommit", commonHeight).Return(common.Commit)
   227  	blockStore.On("LoadBlockCommit", nodeHeight).Return(trusted.Commit)
   228  	blockStore.On("Height").Return(nodeHeight)
   229  	pool, err := evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   230  	require.NoError(t, err)
   231  
   232  	// check that the evidence pool correctly verifies the evidence
   233  	assert.NoError(t, pool.CheckEvidence(types.EvidenceList{ev}))
   234  
   235  	// now we use a time which isn't able to contradict the FLA - thus we can't verify the evidence
   236  	oldBlockStore := &mocks.BlockStore{}
   237  	oldHeader := trusted.Header
   238  	oldHeader.Time = defaultEvidenceTime
   239  	oldBlockStore.On("LoadBlockMeta", commonHeight).Return(&types.BlockMeta{Header: *common.Header})
   240  	oldBlockStore.On("LoadBlockMeta", nodeHeight).Return(&types.BlockMeta{Header: *oldHeader})
   241  	oldBlockStore.On("LoadBlockMeta", attackHeight).Return(nil)
   242  	oldBlockStore.On("LoadBlockCommit", commonHeight).Return(common.Commit)
   243  	oldBlockStore.On("LoadBlockCommit", nodeHeight).Return(trusted.Commit)
   244  	oldBlockStore.On("Height").Return(nodeHeight)
   245  	require.Equal(t, defaultEvidenceTime, oldBlockStore.LoadBlockMeta(nodeHeight).Header.Time)
   246  
   247  	pool, err = evidence.NewPool(dbm.NewMemDB(), stateStore, oldBlockStore)
   248  	require.NoError(t, err)
   249  	assert.Error(t, pool.CheckEvidence(types.EvidenceList{ev}))
   250  }
   251  
   252  func TestVerifyLightClientAttack_Equivocation(t *testing.T) {
   253  	conflictingVals, conflictingPrivVals := types.RandValidatorSet(5, 10)
   254  	trustedHeader := makeHeaderRandom(10)
   255  
   256  	conflictingHeader := makeHeaderRandom(10)
   257  	conflictingHeader.ValidatorsHash = conflictingVals.Hash()
   258  
   259  	trustedHeader.ValidatorsHash = conflictingHeader.ValidatorsHash
   260  	trustedHeader.NextValidatorsHash = conflictingHeader.NextValidatorsHash
   261  	trustedHeader.ConsensusHash = conflictingHeader.ConsensusHash
   262  	trustedHeader.AppHash = conflictingHeader.AppHash
   263  	trustedHeader.LastResultsHash = conflictingHeader.LastResultsHash
   264  
   265  	// we are simulating a duplicate vote attack where all the validators in the conflictingVals set
   266  	// except the last validator vote twice
   267  	blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
   268  	voteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
   269  	commit, err := types.MakeCommit(blockID, 10, 1, voteSet, conflictingPrivVals[:4], defaultEvidenceTime)
   270  	require.NoError(t, err)
   271  	ev := &types.LightClientAttackEvidence{
   272  		ConflictingBlock: &types.LightBlock{
   273  			SignedHeader: &types.SignedHeader{
   274  				Header: conflictingHeader,
   275  				Commit: commit,
   276  			},
   277  			ValidatorSet: conflictingVals,
   278  		},
   279  		CommonHeight:        10,
   280  		ByzantineValidators: conflictingVals.Validators[:4],
   281  		TotalVotingPower:    50,
   282  		Timestamp:           defaultEvidenceTime,
   283  	}
   284  
   285  	trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
   286  	trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
   287  	trustedCommit, err := types.MakeCommit(trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
   288  	require.NoError(t, err)
   289  	trustedSignedHeader := &types.SignedHeader{
   290  		Header: trustedHeader,
   291  		Commit: trustedCommit,
   292  	}
   293  
   294  	// good pass -> no error
   295  	err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals,
   296  		defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)
   297  	assert.NoError(t, err)
   298  
   299  	// trusted and conflicting hashes are the same -> an error should be returned
   300  	err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals,
   301  		defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)
   302  	assert.Error(t, err)
   303  
   304  	// conflicting header has different next validators hash which should have been correctly derived from
   305  	// the previous round
   306  	ev.ConflictingBlock.Header.NextValidatorsHash = crypto.CRandBytes(tmhash.Size)
   307  	err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, nil,
   308  		defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)
   309  	assert.Error(t, err)
   310  	// revert next validators hash
   311  	ev.ConflictingBlock.Header.NextValidatorsHash = trustedHeader.NextValidatorsHash
   312  
   313  	state := sm.State{
   314  		LastBlockTime:   defaultEvidenceTime.Add(1 * time.Minute),
   315  		LastBlockHeight: 11,
   316  		ConsensusParams: *types.DefaultConsensusParams(),
   317  	}
   318  	stateStore := &smmocks.Store{}
   319  	stateStore.On("LoadValidators", int64(10)).Return(conflictingVals, nil)
   320  	stateStore.On("Load").Return(state, nil)
   321  	blockStore := &mocks.BlockStore{}
   322  	blockStore.On("LoadBlockMeta", int64(10)).Return(&types.BlockMeta{Header: *trustedHeader})
   323  	blockStore.On("LoadBlockCommit", int64(10)).Return(trustedCommit)
   324  
   325  	pool, err := evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   326  	require.NoError(t, err)
   327  	pool.SetLogger(log.TestingLogger())
   328  
   329  	evList := types.EvidenceList{ev}
   330  	err = pool.CheckEvidence(evList)
   331  	assert.NoError(t, err)
   332  
   333  	pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   334  	assert.Equal(t, 1, len(pendingEvs))
   335  }
   336  
   337  func TestVerifyLightClientAttack_Amnesia(t *testing.T) {
   338  	conflictingVals, conflictingPrivVals := types.RandValidatorSet(5, 10)
   339  
   340  	conflictingHeader := makeHeaderRandom(10)
   341  	conflictingHeader.ValidatorsHash = conflictingVals.Hash()
   342  	trustedHeader := makeHeaderRandom(10)
   343  	trustedHeader.ValidatorsHash = conflictingHeader.ValidatorsHash
   344  	trustedHeader.NextValidatorsHash = conflictingHeader.NextValidatorsHash
   345  	trustedHeader.AppHash = conflictingHeader.AppHash
   346  	trustedHeader.ConsensusHash = conflictingHeader.ConsensusHash
   347  	trustedHeader.LastResultsHash = conflictingHeader.LastResultsHash
   348  
   349  	// we are simulating an amnesia attack where all the validators in the conflictingVals set
   350  	// except the last validator vote twice. However this time the commits are of different rounds.
   351  	blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
   352  	voteSet := types.NewVoteSet(evidenceChainID, 10, 0, tmproto.SignedMsgType(2), conflictingVals)
   353  	commit, err := types.MakeCommit(blockID, 10, 0, voteSet, conflictingPrivVals, defaultEvidenceTime)
   354  	require.NoError(t, err)
   355  	ev := &types.LightClientAttackEvidence{
   356  		ConflictingBlock: &types.LightBlock{
   357  			SignedHeader: &types.SignedHeader{
   358  				Header: conflictingHeader,
   359  				Commit: commit,
   360  			},
   361  			ValidatorSet: conflictingVals,
   362  		},
   363  		CommonHeight:        10,
   364  		ByzantineValidators: nil, // with amnesia evidence no validators are submitted as abci evidence
   365  		TotalVotingPower:    50,
   366  		Timestamp:           defaultEvidenceTime,
   367  	}
   368  
   369  	trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
   370  	trustedVoteSet := types.NewVoteSet(evidenceChainID, 10, 1, tmproto.SignedMsgType(2), conflictingVals)
   371  	trustedCommit, err := types.MakeCommit(trustedBlockID, 10, 1, trustedVoteSet, conflictingPrivVals, defaultEvidenceTime)
   372  	require.NoError(t, err)
   373  	trustedSignedHeader := &types.SignedHeader{
   374  		Header: trustedHeader,
   375  		Commit: trustedCommit,
   376  	}
   377  
   378  	// good pass -> no error
   379  	err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, trustedSignedHeader, conflictingVals,
   380  		defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)
   381  	assert.NoError(t, err)
   382  
   383  	// trusted and conflicting hashes are the same -> an error should be returned
   384  	err = evidence.VerifyLightClientAttack(ev, trustedSignedHeader, ev.ConflictingBlock.SignedHeader, conflictingVals,
   385  		defaultEvidenceTime.Add(1*time.Minute), 2*time.Hour)
   386  	assert.Error(t, err)
   387  
   388  	state := sm.State{
   389  		LastBlockTime:   defaultEvidenceTime.Add(1 * time.Minute),
   390  		LastBlockHeight: 11,
   391  		ConsensusParams: *types.DefaultConsensusParams(),
   392  	}
   393  	stateStore := &smmocks.Store{}
   394  	stateStore.On("LoadValidators", int64(10)).Return(conflictingVals, nil)
   395  	stateStore.On("Load").Return(state, nil)
   396  	blockStore := &mocks.BlockStore{}
   397  	blockStore.On("LoadBlockMeta", int64(10)).Return(&types.BlockMeta{Header: *trustedHeader})
   398  	blockStore.On("LoadBlockCommit", int64(10)).Return(trustedCommit)
   399  
   400  	pool, err := evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   401  	require.NoError(t, err)
   402  	pool.SetLogger(log.TestingLogger())
   403  
   404  	evList := types.EvidenceList{ev}
   405  	err = pool.CheckEvidence(evList)
   406  	assert.NoError(t, err)
   407  
   408  	pendingEvs, _ := pool.PendingEvidence(state.ConsensusParams.Evidence.MaxBytes)
   409  	assert.Equal(t, 1, len(pendingEvs))
   410  }
   411  
   412  type voteData struct {
   413  	vote1 *types.Vote
   414  	vote2 *types.Vote
   415  	valid bool
   416  }
   417  
   418  func TestVerifyDuplicateVoteEvidence(t *testing.T) {
   419  	val := types.NewMockPV()
   420  	val2 := types.NewMockPV()
   421  	valSet := types.NewValidatorSet([]*types.Validator{val.ExtractIntoValidator(1)})
   422  
   423  	blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
   424  	blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
   425  	blockID3 := makeBlockID([]byte("blockhash"), 10000, []byte("partshash"))
   426  	blockID4 := makeBlockID([]byte("blockhash"), 10000, []byte("partshash2"))
   427  
   428  	const chainID = "mychain"
   429  
   430  	vote1 := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultEvidenceTime)
   431  	v1 := vote1.ToProto()
   432  	err := val.SignVote(chainID, v1)
   433  	require.NoError(t, err)
   434  	badVote := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultEvidenceTime)
   435  	bv := badVote.ToProto()
   436  	err = val2.SignVote(chainID, bv)
   437  	require.NoError(t, err)
   438  
   439  	vote1.Signature = v1.Signature
   440  	badVote.Signature = bv.Signature
   441  
   442  	cases := []voteData{
   443  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultEvidenceTime), true}, // different block ids
   444  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID3, defaultEvidenceTime), true},
   445  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID4, defaultEvidenceTime), true},
   446  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultEvidenceTime), false},     // wrong block id
   447  		{vote1, makeVote(t, val, "mychain2", 0, 10, 2, 1, blockID2, defaultEvidenceTime), false}, // wrong chain id
   448  		{vote1, makeVote(t, val, chainID, 0, 11, 2, 1, blockID2, defaultEvidenceTime), false},    // wrong height
   449  		{vote1, makeVote(t, val, chainID, 0, 10, 3, 1, blockID2, defaultEvidenceTime), false},    // wrong round
   450  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 2, blockID2, defaultEvidenceTime), false},    // wrong step
   451  		{vote1, makeVote(t, val2, chainID, 0, 10, 2, 1, blockID2, defaultEvidenceTime), false},   // wrong validator
   452  		// a different vote time doesn't matter
   453  		{vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)), true},
   454  		{vote1, badVote, false}, // signed by wrong key
   455  	}
   456  
   457  	require.NoError(t, err)
   458  	for _, c := range cases {
   459  		ev := &types.DuplicateVoteEvidence{
   460  			VoteA:            c.vote1,
   461  			VoteB:            c.vote2,
   462  			ValidatorPower:   1,
   463  			TotalVotingPower: 1,
   464  			Timestamp:        defaultEvidenceTime,
   465  		}
   466  		if c.valid {
   467  			assert.Nil(t, evidence.VerifyDuplicateVote(ev, chainID, valSet), "evidence should be valid")
   468  		} else {
   469  			assert.NotNil(t, evidence.VerifyDuplicateVote(ev, chainID, valSet), "evidence should be invalid")
   470  		}
   471  	}
   472  
   473  	// create good evidence and correct validator power
   474  	goodEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
   475  	goodEv.ValidatorPower = 1
   476  	goodEv.TotalVotingPower = 1
   477  	badEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime, val, chainID)
   478  	badTimeEv := types.NewMockDuplicateVoteEvidenceWithValidator(10, defaultEvidenceTime.Add(1*time.Minute), val, chainID)
   479  	badTimeEv.ValidatorPower = 1
   480  	badTimeEv.TotalVotingPower = 1
   481  	state := sm.State{
   482  		ChainID:         chainID,
   483  		LastBlockTime:   defaultEvidenceTime.Add(1 * time.Minute),
   484  		LastBlockHeight: 11,
   485  		ConsensusParams: *types.DefaultConsensusParams(),
   486  	}
   487  	stateStore := &smmocks.Store{}
   488  	stateStore.On("LoadValidators", int64(10)).Return(valSet, nil)
   489  	stateStore.On("Load").Return(state, nil)
   490  	blockStore := &mocks.BlockStore{}
   491  	blockStore.On("LoadBlockMeta", int64(10)).Return(&types.BlockMeta{Header: types.Header{Time: defaultEvidenceTime}})
   492  
   493  	pool, err := evidence.NewPool(dbm.NewMemDB(), stateStore, blockStore)
   494  	require.NoError(t, err)
   495  
   496  	evList := types.EvidenceList{goodEv}
   497  	err = pool.CheckEvidence(evList)
   498  	assert.NoError(t, err)
   499  
   500  	// evidence with a different validator power should fail
   501  	evList = types.EvidenceList{badEv}
   502  	err = pool.CheckEvidence(evList)
   503  	assert.Error(t, err)
   504  
   505  	// evidence with a different timestamp should fail
   506  	evList = types.EvidenceList{badTimeEv}
   507  	err = pool.CheckEvidence(evList)
   508  	assert.Error(t, err)
   509  }
   510  
   511  func makeLunaticEvidence(
   512  	t *testing.T,
   513  	height, commonHeight int64,
   514  	totalVals, byzVals, phantomVals int,
   515  	commonTime, attackTime time.Time,
   516  ) (ev *types.LightClientAttackEvidence, trusted *types.LightBlock, common *types.LightBlock) {
   517  	commonValSet, commonPrivVals := types.RandValidatorSet(totalVals, defaultVotingPower)
   518  
   519  	require.Greater(t, totalVals, byzVals)
   520  
   521  	// extract out the subset of byzantine validators in the common validator set
   522  	byzValSet, byzPrivVals := commonValSet.Validators[:byzVals], commonPrivVals[:byzVals]
   523  
   524  	phantomValSet, phantomPrivVals := types.RandValidatorSet(phantomVals, defaultVotingPower)
   525  
   526  	conflictingVals := phantomValSet.Copy()
   527  	require.NoError(t, conflictingVals.UpdateWithChangeSet(byzValSet))
   528  	conflictingPrivVals := append(phantomPrivVals, byzPrivVals...)
   529  
   530  	conflictingPrivVals = orderPrivValsByValSet(t, conflictingVals, conflictingPrivVals)
   531  
   532  	commonHeader := makeHeaderRandom(commonHeight)
   533  	commonHeader.Time = commonTime
   534  	trustedHeader := makeHeaderRandom(height)
   535  
   536  	conflictingHeader := makeHeaderRandom(height)
   537  	conflictingHeader.Time = attackTime
   538  	conflictingHeader.ValidatorsHash = conflictingVals.Hash()
   539  
   540  	blockID := makeBlockID(conflictingHeader.Hash(), 1000, []byte("partshash"))
   541  	voteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), conflictingVals)
   542  	commit, err := types.MakeCommit(blockID, height, 1, voteSet, conflictingPrivVals, defaultEvidenceTime)
   543  	require.NoError(t, err)
   544  	err = conflictingVals.VerifyCommitLightTrusting(evidenceChainID, commit, light.DefaultTrustLevel)
   545  	require.NoError(t, err)
   546  	ev = &types.LightClientAttackEvidence{
   547  		ConflictingBlock: &types.LightBlock{
   548  			SignedHeader: &types.SignedHeader{
   549  				Header: conflictingHeader,
   550  				Commit: commit,
   551  			},
   552  			ValidatorSet: conflictingVals,
   553  		},
   554  		CommonHeight:        commonHeight,
   555  		TotalVotingPower:    commonValSet.TotalVotingPower(),
   556  		ByzantineValidators: byzValSet,
   557  		Timestamp:           commonTime,
   558  	}
   559  
   560  	common = &types.LightBlock{
   561  		SignedHeader: &types.SignedHeader{
   562  			Header: commonHeader,
   563  			// we can leave this empty because we shouldn't be checking this
   564  			Commit: &types.Commit{},
   565  		},
   566  		ValidatorSet: commonValSet,
   567  	}
   568  	trustedBlockID := makeBlockID(trustedHeader.Hash(), 1000, []byte("partshash"))
   569  	trustedVals, privVals := types.RandValidatorSet(totalVals, defaultVotingPower)
   570  	privVals = orderPrivValsByValSet(t, trustedVals, privVals)
   571  	trustedVoteSet := types.NewVoteSet(evidenceChainID, height, 1, tmproto.SignedMsgType(2), trustedVals)
   572  	trustedCommit, err := types.MakeCommit(trustedBlockID, height, 1, trustedVoteSet, privVals, defaultEvidenceTime)
   573  	require.NoError(t, err)
   574  	err = trustedVals.VerifyCommitLightTrusting(evidenceChainID, trustedCommit, light.DefaultTrustLevel)
   575  	require.NoError(t, err)
   576  	trusted = &types.LightBlock{
   577  		SignedHeader: &types.SignedHeader{
   578  			Header: trustedHeader,
   579  			Commit: trustedCommit,
   580  		},
   581  		ValidatorSet: trustedVals,
   582  	}
   583  	return ev, trusted, common
   584  }
   585  
   586  // func makeEquivocationEvidence() *types.LightClientAttackEvidence {
   587  
   588  // }
   589  
   590  // func makeAmnesiaEvidence() *types.LightClientAttackEvidence {
   591  
   592  // }
   593  
   594  func makeVote(
   595  	t *testing.T, val types.PrivValidator, chainID string, valIndex int32, height int64,
   596  	round int32, step int, blockID types.BlockID, time time.Time) *types.Vote {
   597  	pubKey, err := val.GetPubKey()
   598  	require.NoError(t, err)
   599  	v := &types.Vote{
   600  		ValidatorAddress: pubKey.Address(),
   601  		ValidatorIndex:   valIndex,
   602  		Height:           height,
   603  		Round:            round,
   604  		Type:             tmproto.SignedMsgType(step),
   605  		BlockID:          blockID,
   606  		Timestamp:        time,
   607  		Signature:        []byte{},
   608  	}
   609  
   610  	vpb := v.ToProto()
   611  	err = val.SignVote(chainID, vpb)
   612  	if err != nil {
   613  		panic(err)
   614  	}
   615  	v.Signature = vpb.Signature
   616  	return v
   617  }
   618  
   619  func makeHeaderRandom(height int64) *types.Header {
   620  	return &types.Header{
   621  		Version:            tmversion.Consensus{Block: version.BlockProtocol, App: version.AppProtocol},
   622  		ChainID:            evidenceChainID,
   623  		Height:             height,
   624  		Time:               defaultEvidenceTime,
   625  		LastBlockID:        makeBlockID([]byte("headerhash"), 1000, []byte("partshash")),
   626  		LastCommitHash:     crypto.CRandBytes(tmhash.Size),
   627  		DataHash:           crypto.CRandBytes(tmhash.Size),
   628  		ValidatorsHash:     crypto.CRandBytes(tmhash.Size),
   629  		NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
   630  		ConsensusHash:      crypto.CRandBytes(tmhash.Size),
   631  		AppHash:            crypto.CRandBytes(tmhash.Size),
   632  		LastResultsHash:    crypto.CRandBytes(tmhash.Size),
   633  		EvidenceHash:       crypto.CRandBytes(tmhash.Size),
   634  		ProposerAddress:    crypto.CRandBytes(crypto.AddressSize),
   635  	}
   636  }
   637  
   638  func makeBlockID(hash []byte, partSetSize uint32, partSetHash []byte) types.BlockID {
   639  	var (
   640  		h   = make([]byte, tmhash.Size)
   641  		psH = make([]byte, tmhash.Size)
   642  	)
   643  	copy(h, hash)
   644  	copy(psH, partSetHash)
   645  	return types.BlockID{
   646  		Hash: h,
   647  		PartSetHeader: types.PartSetHeader{
   648  			Total: partSetSize,
   649  			Hash:  psH,
   650  		},
   651  	}
   652  }
   653  
   654  func orderPrivValsByValSet(
   655  	t *testing.T, vals *types.ValidatorSet, privVals []types.PrivValidator) []types.PrivValidator {
   656  	output := make([]types.PrivValidator, len(privVals))
   657  	for idx, v := range vals.Validators {
   658  		for _, p := range privVals {
   659  			pubKey, err := p.GetPubKey()
   660  			require.NoError(t, err)
   661  			if bytes.Equal(v.Address, pubKey.Address()) {
   662  				output[idx] = p
   663  				break
   664  			}
   665  		}
   666  		require.NotEmpty(t, output[idx])
   667  	}
   668  	return output
   669  }