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 }