You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

604 lines
23 KiB

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