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.

775 lines
26 KiB

max-bytes PR follow-up (#2318) * ReapMaxTxs: return all txs if max is negative this mirrors ReapMaxBytes behavior See https://github.com/tendermint/tendermint/pull/2184#discussion_r214439950 * increase MaxAminoOverheadForBlock tested with: ``` func TestMaxAminoOverheadForBlock(t *testing.T) { maxChainID := "" for i := 0; i < MaxChainIDLen; i++ { maxChainID += "𠜎" } h := Header{ ChainID: maxChainID, Height: 10, Time: time.Now().UTC(), NumTxs: 100, TotalTxs: 200, LastBlockID: makeBlockID(make([]byte, 20), 300, make([]byte, 20)), LastCommitHash: tmhash.Sum([]byte("last_commit_hash")), DataHash: tmhash.Sum([]byte("data_hash")), ValidatorsHash: tmhash.Sum([]byte("validators_hash")), NextValidatorsHash: tmhash.Sum([]byte("next_validators_hash")), ConsensusHash: tmhash.Sum([]byte("consensus_hash")), AppHash: tmhash.Sum([]byte("app_hash")), LastResultsHash: tmhash.Sum([]byte("last_results_hash")), EvidenceHash: tmhash.Sum([]byte("evidence_hash")), ProposerAddress: tmhash.Sum([]byte("proposer_address")), } b := Block{ Header: h, Data: Data{Txs: makeTxs(10000, 100)}, Evidence: EvidenceData{}, LastCommit: &Commit{}, } bz, err := cdc.MarshalBinary(b) require.NoError(t, err) assert.Equal(t, MaxHeaderBytes+MaxAminoOverheadForBlock-2, len(bz)-1000000-20000-1) } ``` * fix MaxYYY constants calculation by using math.MaxInt64 See https://github.com/tendermint/tendermint/pull/2184#discussion_r214444244 * pass mempool filter as an option See https://github.com/tendermint/tendermint/pull/2184#discussion_r214445869 * fixes after Dev's comments
6 years ago
  1. package types
  2. import (
  3. "math"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. "github.com/tendermint/tendermint/crypto"
  9. "github.com/tendermint/tendermint/crypto/ed25519"
  10. "github.com/tendermint/tendermint/crypto/tmhash"
  11. tmrand "github.com/tendermint/tendermint/libs/rand"
  12. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  13. )
  14. type voteData struct {
  15. vote1 *Vote
  16. vote2 *Vote
  17. valid bool
  18. }
  19. var defaultVoteTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  20. func TestEvidence(t *testing.T) {
  21. val := NewMockPV()
  22. val2 := NewMockPV()
  23. blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  24. blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
  25. blockID3 := makeBlockID([]byte("blockhash"), 10000, []byte("partshash"))
  26. blockID4 := makeBlockID([]byte("blockhash"), 10000, []byte("partshash2"))
  27. const chainID = "mychain"
  28. vote1 := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime)
  29. v1 := vote1.ToProto()
  30. err := val.SignVote(chainID, v1)
  31. require.NoError(t, err)
  32. badVote := makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime)
  33. bv := badVote.ToProto()
  34. err = val2.SignVote(chainID, bv)
  35. require.NoError(t, err)
  36. vote1.Signature = v1.Signature
  37. badVote.Signature = bv.Signature
  38. cases := []voteData{
  39. {vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime), true}, // different block ids
  40. {vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID3, defaultVoteTime), true},
  41. {vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID4, defaultVoteTime), true},
  42. {vote1, makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime), false}, // wrong block id
  43. {vote1, makeVote(t, val, "mychain2", 0, 10, 2, 1, blockID2, defaultVoteTime), false}, // wrong chain id
  44. {vote1, makeVote(t, val, chainID, 1, 10, 2, 1, blockID2, defaultVoteTime), false}, // wrong val index
  45. {vote1, makeVote(t, val, chainID, 0, 11, 2, 1, blockID2, defaultVoteTime), false}, // wrong height
  46. {vote1, makeVote(t, val, chainID, 0, 10, 3, 1, blockID2, defaultVoteTime), false}, // wrong round
  47. {vote1, makeVote(t, val, chainID, 0, 10, 2, 2, blockID2, defaultVoteTime), false}, // wrong step
  48. {vote1, makeVote(t, val2, chainID, 0, 10, 2, 1, blockID, defaultVoteTime), false}, // wrong validator
  49. {vote1, makeVote(t, val2, chainID, 0, 10, 2, 1, blockID, time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)), false},
  50. {vote1, badVote, false}, // signed by wrong key
  51. }
  52. pubKey, err := val.GetPubKey()
  53. require.NoError(t, err)
  54. for _, c := range cases {
  55. ev := &DuplicateVoteEvidence{
  56. VoteA: c.vote1,
  57. VoteB: c.vote2,
  58. }
  59. if c.valid {
  60. assert.Nil(t, ev.Verify(chainID, pubKey), "evidence should be valid")
  61. } else {
  62. assert.NotNil(t, ev.Verify(chainID, pubKey), "evidence should be invalid")
  63. }
  64. }
  65. }
  66. func TestDuplicatedVoteEvidence(t *testing.T) {
  67. ev := randomDuplicatedVoteEvidence(t)
  68. assert.True(t, ev.Equal(ev))
  69. assert.False(t, ev.Equal(&DuplicateVoteEvidence{}))
  70. maxTime := ev.VoteB.Timestamp
  71. if ev.VoteA.Timestamp.After(ev.VoteB.Timestamp) {
  72. maxTime = ev.VoteA.Timestamp
  73. }
  74. assert.Equal(t, maxTime, ev.Time(), "expected time of the latest vote")
  75. }
  76. func TestEvidenceList(t *testing.T) {
  77. ev := randomDuplicatedVoteEvidence(t)
  78. evl := EvidenceList([]Evidence{ev})
  79. assert.NotNil(t, evl.Hash())
  80. assert.True(t, evl.Has(ev))
  81. assert.False(t, evl.Has(&DuplicateVoteEvidence{}))
  82. }
  83. func TestMaxEvidenceBytes(t *testing.T) {
  84. val := NewMockPV()
  85. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  86. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  87. maxTime := time.Date(9999, 0, 0, 0, 0, 0, 0, time.UTC)
  88. const chainID = "mychain"
  89. ev := &DuplicateVoteEvidence{
  90. VoteA: makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, math.MaxInt64, blockID, maxTime),
  91. VoteB: makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, math.MaxInt64, blockID2, maxTime),
  92. }
  93. //TODO: Add other types of evidence to test and set MaxEvidenceBytes accordingly
  94. // evl := &LunaticValidatorEvidence{
  95. // Header: makeHeaderRandom(),
  96. // Vote: makeVote(t, val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, math.MaxInt64, blockID2),
  97. // InvalidHeaderField: "",
  98. // }
  99. // signedHeader := SignedHeader{Header: makeHeaderRandom(), Commit: randCommit(time.Now())}
  100. // evc := &ConflictingHeadersEvidence{
  101. // H1: &signedHeader,
  102. // H2: &signedHeader,
  103. // }
  104. testCases := []struct {
  105. testName string
  106. evidence Evidence
  107. }{
  108. {"DuplicateVote", ev},
  109. // {"LunaticValidatorEvidence", evl},
  110. // {"ConflictingHeadersEvidence", evc},
  111. }
  112. for _, tt := range testCases {
  113. pb, err := EvidenceToProto(tt.evidence)
  114. require.NoError(t, err, tt.testName)
  115. bz, err := pb.Marshal()
  116. require.NoError(t, err, tt.testName)
  117. assert.LessOrEqual(t, int64(len(bz)), MaxEvidenceBytes, tt.testName)
  118. }
  119. }
  120. func randomDuplicatedVoteEvidence(t *testing.T) *DuplicateVoteEvidence {
  121. val := NewMockPV()
  122. blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  123. blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
  124. const chainID = "mychain"
  125. return &DuplicateVoteEvidence{
  126. VoteA: makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime),
  127. VoteB: makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime.Add(1*time.Minute)),
  128. }
  129. }
  130. func TestDuplicateVoteEvidenceValidation(t *testing.T) {
  131. val := NewMockPV()
  132. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  133. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  134. const chainID = "mychain"
  135. testCases := []struct {
  136. testName string
  137. malleateEvidence func(*DuplicateVoteEvidence)
  138. expectErr bool
  139. }{
  140. {"Good DuplicateVoteEvidence", func(ev *DuplicateVoteEvidence) {}, false},
  141. {"Nil vote A", func(ev *DuplicateVoteEvidence) { ev.VoteA = nil }, true},
  142. {"Nil vote B", func(ev *DuplicateVoteEvidence) { ev.VoteB = nil }, true},
  143. {"Nil votes", func(ev *DuplicateVoteEvidence) {
  144. ev.VoteA = nil
  145. ev.VoteB = nil
  146. }, true},
  147. {"Invalid vote type", func(ev *DuplicateVoteEvidence) {
  148. ev.VoteA = makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0, blockID2, defaultVoteTime)
  149. }, true},
  150. {"Invalid vote order", func(ev *DuplicateVoteEvidence) {
  151. swap := ev.VoteA.Copy()
  152. ev.VoteA = ev.VoteB.Copy()
  153. ev.VoteB = swap
  154. }, true},
  155. }
  156. for _, tc := range testCases {
  157. tc := tc
  158. t.Run(tc.testName, func(t *testing.T) {
  159. vote1 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
  160. vote2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
  161. ev := NewDuplicateVoteEvidence(vote1, vote2)
  162. tc.malleateEvidence(ev)
  163. assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  164. })
  165. }
  166. }
  167. func TestMockEvidenceValidateBasic(t *testing.T) {
  168. goodEvidence := NewMockDuplicateVoteEvidence(int64(1), time.Now(), "mock-chain-id")
  169. assert.Nil(t, goodEvidence.ValidateBasic())
  170. }
  171. func TestLunaticValidatorEvidence(t *testing.T) {
  172. var (
  173. invalidBlockID = makeBlockIDRandom()
  174. header = makeHeaderRandom()
  175. altHeader = makeHeaderRandom()
  176. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  177. val = NewMockPV()
  178. )
  179. header.Time = bTime
  180. blockID := BlockID{
  181. Hash: header.Hash(),
  182. PartSetHeader: PartSetHeader{
  183. Total: 100,
  184. Hash: crypto.CRandBytes(tmhash.Size),
  185. },
  186. }
  187. vote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
  188. ev := NewLunaticValidatorEvidence(header, vote, "AppHash")
  189. //happy path
  190. assert.Equal(t, header.Height, ev.Height())
  191. assert.Equal(t, defaultVoteTime, ev.Time())
  192. assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
  193. assert.NotEmpty(t, ev.Hash())
  194. assert.NotEmpty(t, ev.Bytes())
  195. assert.True(t, ev.Equal(ev))
  196. pubKey, err := val.GetPubKey()
  197. require.NoError(t, err)
  198. assert.NoError(t, ev.Verify(header.ChainID, pubKey))
  199. assert.NoError(t, ev.ValidateBasic())
  200. assert.NotEmpty(t, ev.String())
  201. assert.NoError(t, ev.VerifyHeader(altHeader))
  202. // invalid evidence
  203. assert.Error(t, ev.Verify("other", pubKey))
  204. privKey2 := ed25519.GenPrivKey()
  205. pubKey2 := privKey2.PubKey()
  206. assert.Error(t, ev.Verify(header.ChainID, pubKey2))
  207. assert.Error(t, ev.VerifyHeader(header))
  208. invalidVote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, invalidBlockID, defaultVoteTime)
  209. invalidHeightVote := makeVote(t, val, header.ChainID, 0, header.Height+1, 0, 2, blockID, defaultVoteTime)
  210. emptyBlockVote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, BlockID{}, defaultVoteTime)
  211. invalidLunaticEvidence := []*LunaticValidatorEvidence{
  212. NewLunaticValidatorEvidence(header, invalidVote, "AppHash"),
  213. NewLunaticValidatorEvidence(header, invalidHeightVote, "AppHash"),
  214. NewLunaticValidatorEvidence(nil, vote, "AppHash"),
  215. NewLunaticValidatorEvidence(header, nil, "AppHash"),
  216. NewLunaticValidatorEvidence(header, vote, "other"),
  217. NewLunaticValidatorEvidence(header, emptyBlockVote, "AppHash"),
  218. }
  219. for idx, ev := range invalidLunaticEvidence {
  220. assert.Error(t, ev.ValidateBasic(), "#%d", idx)
  221. }
  222. }
  223. func TestConflictingHeadersEvidence(t *testing.T) {
  224. const (
  225. chainID = "TestConflictingHeadersEvidence"
  226. height int64 = 37
  227. )
  228. var (
  229. blockID = makeBlockIDRandom()
  230. header1 = makeHeaderRandom()
  231. header2 = makeHeaderRandom()
  232. )
  233. header1.Height = height
  234. header1.LastBlockID = blockID
  235. header1.ChainID = chainID
  236. header2.Height = height
  237. header2.LastBlockID = blockID
  238. header2.ChainID = chainID
  239. voteSet1, valSet, vals := randVoteSet(height, 1, tmproto.PrecommitType, 10, 1)
  240. voteSet2 := NewVoteSet(chainID, height, 1, tmproto.PrecommitType, valSet)
  241. commit1, err := MakeCommit(BlockID{
  242. Hash: header1.Hash(),
  243. PartSetHeader: PartSetHeader{
  244. Total: 100,
  245. Hash: crypto.CRandBytes(tmhash.Size),
  246. },
  247. }, height, 1, voteSet1, vals, time.Now())
  248. require.NoError(t, err)
  249. commit2, err := MakeCommit(BlockID{
  250. Hash: header2.Hash(),
  251. PartSetHeader: PartSetHeader{
  252. Total: 100,
  253. Hash: crypto.CRandBytes(tmhash.Size),
  254. },
  255. }, height, 1, voteSet2, vals, time.Now())
  256. require.NoError(t, err)
  257. h1 := &SignedHeader{
  258. Header: header1,
  259. Commit: commit1,
  260. }
  261. h2 := &SignedHeader{
  262. Header: header2,
  263. Commit: commit2,
  264. }
  265. ev := NewConflictingHeadersEvidence(h1, h2)
  266. assert.Panics(t, func() {
  267. ev.Address()
  268. })
  269. assert.Panics(t, func() {
  270. pubKey, _ := vals[0].GetPubKey()
  271. ev.Verify(chainID, pubKey)
  272. })
  273. assert.Equal(t, height, ev.Height())
  274. assert.Equal(t, ev.H2.Time, ev.Time())
  275. assert.NotEmpty(t, ev.Hash())
  276. assert.NotEmpty(t, ev.Bytes())
  277. assert.NoError(t, ev.VerifyComposite(header1, valSet))
  278. assert.True(t, ev.Equal(ev))
  279. assert.NoError(t, ev.ValidateBasic())
  280. assert.NotEmpty(t, ev.String())
  281. }
  282. func TestPotentialAmnesiaEvidence(t *testing.T) {
  283. const (
  284. chainID = "TestPotentialAmnesiaEvidence"
  285. height int64 = 37
  286. )
  287. var (
  288. val = NewMockPV()
  289. val2 = NewMockPV()
  290. blockID = makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  291. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  292. vote1 = makeVote(t, val, chainID, 0, height, 0, 2, blockID, defaultVoteTime)
  293. vote2 = makeVote(t, val, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Second))
  294. vote3 = makeVote(t, val, chainID, 0, height, 2, 2, blockID, defaultVoteTime)
  295. )
  296. ev := NewPotentialAmnesiaEvidence(vote1, vote2)
  297. assert.Equal(t, height, ev.Height())
  298. assert.Equal(t, vote2.Timestamp, ev.Time())
  299. assert.EqualValues(t, vote1.ValidatorAddress, ev.Address())
  300. assert.NotEmpty(t, ev.Hash())
  301. assert.NotEmpty(t, ev.Bytes())
  302. pubKey, err := val.GetPubKey()
  303. require.NoError(t, err)
  304. assert.NoError(t, ev.Verify(chainID, pubKey))
  305. assert.Error(t, ev.Verify("other", pubKey))
  306. privKey2 := ed25519.GenPrivKey()
  307. pubKey2 := privKey2.PubKey()
  308. assert.Error(t, ev.Verify("other", pubKey2))
  309. assert.True(t, ev.Equal(ev))
  310. assert.NoError(t, ev.ValidateBasic())
  311. assert.NotEmpty(t, ev.String())
  312. ev2 := &PotentialAmnesiaEvidence{
  313. VoteA: vote1,
  314. VoteB: vote2,
  315. HeightStamp: 5,
  316. }
  317. assert.True(t, ev.Equal(ev2))
  318. assert.Equal(t, ev.Hash(), ev2.Hash())
  319. ev3 := NewPotentialAmnesiaEvidence(vote2, vote1)
  320. assert.True(t, ev3.Equal(ev))
  321. ev4 := &PotentialAmnesiaEvidence{
  322. VoteA: vote3,
  323. VoteB: vote2,
  324. }
  325. assert.NoError(t, ev4.ValidateBasic())
  326. assert.NotEqual(t, ev.Hash(), ev4.Hash())
  327. assert.False(t, ev.Equal(ev4))
  328. // bad evidence
  329. badEv := []*PotentialAmnesiaEvidence{
  330. // first vote is for a later time than the second vote
  331. {
  332. VoteA: vote2,
  333. VoteB: vote1,
  334. },
  335. // votes are for the same round
  336. {
  337. VoteA: vote1,
  338. VoteB: makeVote(t, val, chainID, 0, height, 0, 2, blockID2, defaultVoteTime.Add(1*time.Second)),
  339. },
  340. // first vote was for a nil block - not locked
  341. {
  342. VoteA: makeVote(t, val, chainID, 0, height, 0, 2, BlockID{}, defaultVoteTime.Add(1*time.Second)),
  343. VoteB: vote2,
  344. },
  345. // second vote is from a different validator
  346. {
  347. VoteA: vote1,
  348. VoteB: makeVote(t, val2, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Second)),
  349. },
  350. }
  351. for _, ev := range badEv {
  352. assert.Error(t, ev.ValidateBasic())
  353. }
  354. }
  355. func TestProofOfLockChange(t *testing.T) {
  356. const (
  357. chainID = "test_chain_id"
  358. height int64 = 37
  359. )
  360. // 1: valid POLC - nothing should fail
  361. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  362. pubKey, err := privValidators[7].GetPubKey()
  363. require.NoError(t, err)
  364. polc, err := NewPOLCFromVoteSet(voteSet, pubKey, blockID)
  365. assert.NoError(t, err)
  366. assert.Equal(t, height, polc.Height())
  367. assert.NoError(t, polc.ValidateBasic())
  368. assert.NoError(t, polc.ValidateVotes(valSet, chainID))
  369. assert.NotEmpty(t, polc.String())
  370. // tamper with one of the votes
  371. polc.Votes[0].Timestamp = time.Now().Add(1 * time.Second)
  372. err = polc.ValidateVotes(valSet, chainID)
  373. t.Log(err)
  374. assert.Error(t, err)
  375. // remove a vote such that majority wasn't reached
  376. polc.Votes = polc.Votes[1:]
  377. err = polc.ValidateVotes(valSet, chainID)
  378. t.Log(err)
  379. assert.Error(t, err)
  380. // test validate basic on a set of bad cases
  381. var badPOLCs []*ProofOfLockChange
  382. // 2: node has already voted in next round
  383. pubKey, err = privValidators[0].GetPubKey()
  384. require.NoError(t, err)
  385. polc2 := newPOLCFromVoteSet(voteSet, pubKey, blockID)
  386. badPOLCs = append(badPOLCs, polc2)
  387. // 3: one vote was from a different round
  388. voteSet, _, privValidators, blockID = buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  389. pubKey, err = privValidators[7].GetPubKey()
  390. require.NoError(t, err)
  391. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  392. badVote := makeVote(t, privValidators[8], chainID, 8, height, 2, 2, blockID, defaultVoteTime)
  393. polc.Votes = append(polc.Votes, badVote)
  394. badPOLCs = append(badPOLCs, polc)
  395. // 4: one vote was from a different height
  396. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  397. badVote = makeVote(t, privValidators[8], chainID, 8, height+1, 1, 2, blockID, defaultVoteTime)
  398. polc.Votes = append(polc.Votes, badVote)
  399. badPOLCs = append(badPOLCs, polc)
  400. // 5: one vote was from a different vote type
  401. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  402. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 1, blockID, defaultVoteTime)
  403. polc.Votes = append(polc.Votes, badVote)
  404. badPOLCs = append(badPOLCs, polc)
  405. // 5: one of the votes was for a nil block
  406. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  407. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 2, BlockID{}, defaultVoteTime)
  408. polc.Votes = append(polc.Votes, badVote)
  409. badPOLCs = append(badPOLCs, polc)
  410. for idx, polc := range badPOLCs {
  411. err := polc.ValidateBasic()
  412. t.Logf("case: %d: %v", idx+2, err)
  413. assert.Error(t, err)
  414. if err == nil {
  415. t.Errorf("test no. %d failed", idx+2)
  416. }
  417. }
  418. }
  419. func TestAmnesiaEvidence(t *testing.T) {
  420. const (
  421. chainID = "test_chain_id"
  422. height int64 = 37
  423. )
  424. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  425. var (
  426. val = privValidators[7]
  427. pubKey, _ = val.GetPubKey()
  428. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  429. vote1 = makeVote(t, val, chainID, 7, height, 0, 2, blockID2, time.Now())
  430. vote2 = makeVote(t, val, chainID, 7, height, 1, 2, blockID,
  431. time.Now().Add(time.Second))
  432. vote3 = makeVote(t, val, chainID, 7, height, 2, 2, blockID2, time.Now())
  433. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  434. )
  435. require.False(t, polc.IsAbsent())
  436. pe := &PotentialAmnesiaEvidence{
  437. VoteA: vote1,
  438. VoteB: vote2,
  439. }
  440. emptyAmnesiaEvidence := NewAmnesiaEvidence(pe, NewEmptyPOLC())
  441. assert.NoError(t, emptyAmnesiaEvidence.ValidateBasic())
  442. violated, reason := emptyAmnesiaEvidence.ViolatedConsensus()
  443. if assert.True(t, violated) {
  444. assert.Equal(t, reason, "no proof of lock was provided")
  445. }
  446. assert.NoError(t, emptyAmnesiaEvidence.Verify(chainID, pubKey))
  447. completeAmnesiaEvidence := NewAmnesiaEvidence(pe, polc)
  448. assert.NoError(t, completeAmnesiaEvidence.ValidateBasic())
  449. violated, reason = completeAmnesiaEvidence.ViolatedConsensus()
  450. if !assert.False(t, violated) {
  451. t.Log(reason)
  452. }
  453. assert.NoError(t, completeAmnesiaEvidence.Verify(chainID, pubKey))
  454. assert.NoError(t, completeAmnesiaEvidence.Polc.ValidateVotes(valSet, chainID))
  455. assert.True(t, completeAmnesiaEvidence.Equal(emptyAmnesiaEvidence))
  456. assert.Equal(t, completeAmnesiaEvidence.Hash(), emptyAmnesiaEvidence.Hash())
  457. assert.NotEmpty(t, completeAmnesiaEvidence.Hash())
  458. assert.NotEmpty(t, completeAmnesiaEvidence.Bytes())
  459. pe2 := &PotentialAmnesiaEvidence{
  460. VoteA: vote3,
  461. VoteB: vote2,
  462. }
  463. // validator has incorrectly voted for a previous round after voting for a later round
  464. ae := NewAmnesiaEvidence(pe2, NewEmptyPOLC())
  465. assert.NoError(t, ae.ValidateBasic())
  466. violated, reason = ae.ViolatedConsensus()
  467. if assert.True(t, violated) {
  468. assert.Equal(t, reason, "validator went back and voted on a previous round")
  469. }
  470. var badAE []*AmnesiaEvidence
  471. // 1) Polc is at an incorrect height
  472. voteSet, _, _ = buildVoteSetForBlock(height+1, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  473. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  474. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  475. // 2) Polc is of a later round
  476. voteSet, _, _ = buildVoteSetForBlock(height, 2, 2, 7, 0, tmproto.PrecommitType, blockID)
  477. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  478. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  479. // 3) Polc has a different public key
  480. voteSet, _, privValidators = buildVoteSetForBlock(height, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  481. pubKey2, _ := privValidators[7].GetPubKey()
  482. polc = newPOLCFromVoteSet(voteSet, pubKey2, blockID)
  483. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  484. // 4) Polc has a different block ID
  485. voteSet, _, _, blockID = buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  486. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  487. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  488. for idx, ae := range badAE {
  489. t.Log(ae.ValidateBasic())
  490. if !assert.Error(t, ae.ValidateBasic()) {
  491. t.Errorf("test no. %d failed", idx+1)
  492. }
  493. }
  494. }
  495. func makeVote(
  496. t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID,
  497. time time.Time) *Vote {
  498. pubKey, err := val.GetPubKey()
  499. require.NoError(t, err)
  500. v := &Vote{
  501. ValidatorAddress: pubKey.Address(),
  502. ValidatorIndex: valIndex,
  503. Height: height,
  504. Round: round,
  505. Type: tmproto.SignedMsgType(step),
  506. BlockID: blockID,
  507. Timestamp: time,
  508. }
  509. vpb := v.ToProto()
  510. err = val.SignVote(chainID, vpb)
  511. if err != nil {
  512. panic(err)
  513. }
  514. v.Signature = vpb.Signature
  515. return v
  516. }
  517. func makeHeaderRandom() *Header {
  518. return &Header{
  519. ChainID: tmrand.Str(12),
  520. Height: int64(tmrand.Uint16()) + 1,
  521. Time: time.Now(),
  522. LastBlockID: makeBlockIDRandom(),
  523. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  524. DataHash: crypto.CRandBytes(tmhash.Size),
  525. ValidatorsHash: crypto.CRandBytes(tmhash.Size),
  526. NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
  527. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  528. AppHash: crypto.CRandBytes(tmhash.Size),
  529. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  530. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  531. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  532. }
  533. }
  534. func TestEvidenceProto(t *testing.T) {
  535. // -------- Votes --------
  536. val := NewMockPV()
  537. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  538. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  539. const chainID = "mychain"
  540. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  541. v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  542. // -------- SignedHeaders --------
  543. const height int64 = 37
  544. var (
  545. header1 = makeHeaderRandom()
  546. header2 = makeHeaderRandom()
  547. )
  548. header1.Height = height
  549. header1.LastBlockID = blockID
  550. header1.ChainID = chainID
  551. header2.Height = height
  552. header2.LastBlockID = blockID
  553. header2.ChainID = chainID
  554. voteSet1, valSet, vals := randVoteSet(height, 1, tmproto.PrecommitType, 10, 1)
  555. voteSet2 := NewVoteSet(chainID, height, 1, tmproto.PrecommitType, valSet)
  556. commit1, err := MakeCommit(BlockID{
  557. Hash: header1.Hash(),
  558. PartSetHeader: PartSetHeader{
  559. Total: 100,
  560. Hash: crypto.CRandBytes(tmhash.Size),
  561. },
  562. }, height, 1, voteSet1, vals, time.Now())
  563. require.NoError(t, err)
  564. commit2, err := MakeCommit(BlockID{
  565. Hash: header2.Hash(),
  566. PartSetHeader: PartSetHeader{
  567. Total: 100,
  568. Hash: crypto.CRandBytes(tmhash.Size),
  569. },
  570. }, height, 1, voteSet2, vals, time.Now())
  571. require.NoError(t, err)
  572. h1 := &SignedHeader{
  573. Header: header1,
  574. Commit: commit1,
  575. }
  576. h2 := &SignedHeader{
  577. Header: header2,
  578. Commit: commit2,
  579. }
  580. tests := []struct {
  581. testName string
  582. evidence Evidence
  583. toProtoErr bool
  584. fromProtoErr bool
  585. }{
  586. {"nil fail", nil, true, true},
  587. {"DuplicateVoteEvidence empty fail", &DuplicateVoteEvidence{}, false, true},
  588. {"DuplicateVoteEvidence nil voteB", &DuplicateVoteEvidence{VoteA: v, VoteB: nil}, false, true},
  589. {"DuplicateVoteEvidence nil voteA", &DuplicateVoteEvidence{VoteA: nil, VoteB: v}, false, true},
  590. {"DuplicateVoteEvidence success", &DuplicateVoteEvidence{VoteA: v2, VoteB: v}, false, false},
  591. {"ConflictingHeadersEvidence empty fail", &ConflictingHeadersEvidence{}, false, true},
  592. {"ConflictingHeadersEvidence nil H2", &ConflictingHeadersEvidence{H1: h1, H2: nil}, false, true},
  593. {"ConflictingHeadersEvidence nil H1", &ConflictingHeadersEvidence{H1: nil, H2: h2}, false, true},
  594. {"ConflictingHeadersEvidence success", &ConflictingHeadersEvidence{H1: h1, H2: h2}, false, false},
  595. {"LunaticValidatorEvidence success", &LunaticValidatorEvidence{Header: header1,
  596. Vote: v, InvalidHeaderField: "ValidatorsHash"}, false, true},
  597. {"&LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  598. {"LunaticValidatorEvidence only header fail", &LunaticValidatorEvidence{Header: header1}, false, true},
  599. {"LunaticValidatorEvidence only vote fail", &LunaticValidatorEvidence{Vote: v}, false, true},
  600. {"LunaticValidatorEvidence header & vote fail", &LunaticValidatorEvidence{Header: header1, Vote: v}, false, true},
  601. {"LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  602. {"PotentialAmnesiaEvidence empty fail", &PotentialAmnesiaEvidence{}, false, true},
  603. {"PotentialAmnesiaEvidence nil VoteB", &PotentialAmnesiaEvidence{VoteA: v, VoteB: nil}, false, true},
  604. {"PotentialAmnesiaEvidence nil VoteA", &PotentialAmnesiaEvidence{VoteA: nil, VoteB: v2}, false, true},
  605. {"PotentialAmnesiaEvidence success", &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v}, false, false},
  606. {"AmnesiaEvidence nil ProofOfLockChange", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{},
  607. Polc: NewEmptyPOLC()}, false, true},
  608. {"AmnesiaEvidence nil Polc",
  609. &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  610. Polc: &ProofOfLockChange{}}, false, false},
  611. {"AmnesiaEvidence success", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  612. Polc: NewEmptyPOLC()}, false, false},
  613. }
  614. for _, tt := range tests {
  615. tt := tt
  616. t.Run(tt.testName, func(t *testing.T) {
  617. pb, err := EvidenceToProto(tt.evidence)
  618. if tt.toProtoErr {
  619. assert.Error(t, err, tt.testName)
  620. return
  621. }
  622. assert.NoError(t, err, tt.testName)
  623. evi, err := EvidenceFromProto(pb)
  624. if tt.fromProtoErr {
  625. assert.Error(t, err, tt.testName)
  626. return
  627. }
  628. require.Equal(t, tt.evidence, evi, tt.testName)
  629. })
  630. }
  631. }
  632. func TestProofOfLockChangeProtoBuf(t *testing.T) {
  633. // -------- Votes --------
  634. val := NewMockPV()
  635. val2 := NewMockPV()
  636. val3 := NewMockPV()
  637. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  638. const chainID = "mychain"
  639. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  640. v2 := makeVote(t, val2, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  641. testCases := []struct {
  642. msg string
  643. polc *ProofOfLockChange
  644. toProtoErr bool
  645. fromProtoErr bool
  646. }{
  647. {"failure, empty key", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: nil}, true, false},
  648. {"failure, empty votes", &ProofOfLockChange{PubKey: val3.PrivKey.PubKey()}, true, false},
  649. {"success empty ProofOfLockChange", NewEmptyPOLC(), false, false},
  650. {"success", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: val3.PrivKey.PubKey()}, false, false},
  651. }
  652. for _, tc := range testCases {
  653. tc := tc
  654. pbpolc, err := tc.polc.ToProto()
  655. if tc.toProtoErr {
  656. assert.Error(t, err, tc.msg)
  657. } else {
  658. assert.NoError(t, err, tc.msg)
  659. }
  660. c, err := ProofOfLockChangeFromProto(pbpolc)
  661. if !tc.fromProtoErr {
  662. assert.NoError(t, err, tc.msg)
  663. if !tc.toProtoErr {
  664. assert.Equal(t, tc.polc, c, tc.msg)
  665. }
  666. } else {
  667. assert.Error(t, err, tc.msg)
  668. }
  669. }
  670. }