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.

789 lines
27 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. // evp := &PhantomValidatorEvidence{
  100. // Header: makeHeaderRandom(),
  101. // Vote: makeVote(t, val, chainID, math.MaxInt64, math.MaxInt64, math.MaxInt64, math.MaxInt64, blockID2),
  102. // LastHeightValidatorWasInSet: math.MaxInt64,
  103. // }
  104. // signedHeader := SignedHeader{Header: makeHeaderRandom(), Commit: randCommit(time.Now())}
  105. // evc := &ConflictingHeadersEvidence{
  106. // H1: &signedHeader,
  107. // H2: &signedHeader,
  108. // }
  109. testCases := []struct {
  110. testName string
  111. evidence Evidence
  112. }{
  113. {"DuplicateVote", ev},
  114. // {"LunaticValidatorEvidence", evl},
  115. // {"PhantomValidatorEvidence", evp},
  116. // {"ConflictingHeadersEvidence", evc},
  117. }
  118. for _, tt := range testCases {
  119. pb, err := EvidenceToProto(tt.evidence)
  120. require.NoError(t, err, tt.testName)
  121. bz, err := pb.Marshal()
  122. require.NoError(t, err, tt.testName)
  123. assert.LessOrEqual(t, int64(len(bz)), MaxEvidenceBytes, tt.testName)
  124. }
  125. }
  126. func randomDuplicatedVoteEvidence(t *testing.T) *DuplicateVoteEvidence {
  127. val := NewMockPV()
  128. blockID := makeBlockID([]byte("blockhash"), 1000, []byte("partshash"))
  129. blockID2 := makeBlockID([]byte("blockhash2"), 1000, []byte("partshash"))
  130. const chainID = "mychain"
  131. return &DuplicateVoteEvidence{
  132. VoteA: makeVote(t, val, chainID, 0, 10, 2, 1, blockID, defaultVoteTime),
  133. VoteB: makeVote(t, val, chainID, 0, 10, 2, 1, blockID2, defaultVoteTime.Add(1*time.Minute)),
  134. }
  135. }
  136. func TestDuplicateVoteEvidenceValidation(t *testing.T) {
  137. val := NewMockPV()
  138. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  139. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  140. const chainID = "mychain"
  141. testCases := []struct {
  142. testName string
  143. malleateEvidence func(*DuplicateVoteEvidence)
  144. expectErr bool
  145. }{
  146. {"Good DuplicateVoteEvidence", func(ev *DuplicateVoteEvidence) {}, false},
  147. {"Nil vote A", func(ev *DuplicateVoteEvidence) { ev.VoteA = nil }, true},
  148. {"Nil vote B", func(ev *DuplicateVoteEvidence) { ev.VoteB = nil }, true},
  149. {"Nil votes", func(ev *DuplicateVoteEvidence) {
  150. ev.VoteA = nil
  151. ev.VoteB = nil
  152. }, true},
  153. {"Invalid vote type", func(ev *DuplicateVoteEvidence) {
  154. ev.VoteA = makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0, blockID2, defaultVoteTime)
  155. }, true},
  156. {"Invalid vote order", func(ev *DuplicateVoteEvidence) {
  157. swap := ev.VoteA.Copy()
  158. ev.VoteA = ev.VoteB.Copy()
  159. ev.VoteB = swap
  160. }, true},
  161. }
  162. for _, tc := range testCases {
  163. tc := tc
  164. t.Run(tc.testName, func(t *testing.T) {
  165. vote1 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID, defaultVoteTime)
  166. vote2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, math.MaxInt32, 0x02, blockID2, defaultVoteTime)
  167. ev := NewDuplicateVoteEvidence(vote1, vote2)
  168. tc.malleateEvidence(ev)
  169. assert.Equal(t, tc.expectErr, ev.ValidateBasic() != nil, "Validate Basic had an unexpected result")
  170. })
  171. }
  172. }
  173. func TestMockEvidenceValidateBasic(t *testing.T) {
  174. goodEvidence := NewMockDuplicateVoteEvidence(int64(1), time.Now(), "mock-chain-id")
  175. assert.Nil(t, goodEvidence.ValidateBasic())
  176. }
  177. func TestLunaticValidatorEvidence(t *testing.T) {
  178. var (
  179. invalidBlockID = makeBlockIDRandom()
  180. header = makeHeaderRandom()
  181. altHeader = makeHeaderRandom()
  182. bTime, _ = time.Parse(time.RFC3339, "2006-01-02T15:04:05Z")
  183. val = NewMockPV()
  184. )
  185. header.Time = bTime
  186. blockID := BlockID{
  187. Hash: header.Hash(),
  188. PartSetHeader: PartSetHeader{
  189. Total: 100,
  190. Hash: crypto.CRandBytes(tmhash.Size),
  191. },
  192. }
  193. vote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
  194. ev := NewLunaticValidatorEvidence(header, vote, "AppHash")
  195. //happy path
  196. assert.Equal(t, header.Height, ev.Height())
  197. assert.Equal(t, defaultVoteTime, ev.Time())
  198. assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
  199. assert.NotEmpty(t, ev.Hash())
  200. assert.NotEmpty(t, ev.Bytes())
  201. assert.True(t, ev.Equal(ev))
  202. pubKey, err := val.GetPubKey()
  203. require.NoError(t, err)
  204. assert.NoError(t, ev.Verify(header.ChainID, pubKey))
  205. assert.NoError(t, ev.ValidateBasic())
  206. assert.NotEmpty(t, ev.String())
  207. assert.NoError(t, ev.VerifyHeader(altHeader))
  208. // invalid evidence
  209. assert.Error(t, ev.Verify("other", pubKey))
  210. privKey2 := ed25519.GenPrivKey()
  211. pubKey2 := privKey2.PubKey()
  212. assert.Error(t, ev.Verify(header.ChainID, pubKey2))
  213. assert.Error(t, ev.VerifyHeader(header))
  214. invalidVote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, invalidBlockID, defaultVoteTime)
  215. invalidHeightVote := makeVote(t, val, header.ChainID, 0, header.Height+1, 0, 2, blockID, defaultVoteTime)
  216. emptyBlockVote := makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, BlockID{}, defaultVoteTime)
  217. invalidLunaticEvidence := []*LunaticValidatorEvidence{
  218. NewLunaticValidatorEvidence(header, invalidVote, "AppHash"),
  219. NewLunaticValidatorEvidence(header, invalidHeightVote, "AppHash"),
  220. NewLunaticValidatorEvidence(nil, vote, "AppHash"),
  221. NewLunaticValidatorEvidence(header, nil, "AppHash"),
  222. NewLunaticValidatorEvidence(header, vote, "other"),
  223. NewLunaticValidatorEvidence(header, emptyBlockVote, "AppHash"),
  224. }
  225. for idx, ev := range invalidLunaticEvidence {
  226. assert.Error(t, ev.ValidateBasic(), "#%d", idx)
  227. }
  228. }
  229. func TestPhantomValidatorEvidence(t *testing.T) {
  230. var (
  231. blockID = makeBlockIDRandom()
  232. header = makeHeaderRandom()
  233. val = NewMockPV()
  234. vote = makeVote(t, val, header.ChainID, 0, header.Height, 0, 2, blockID, defaultVoteTime)
  235. )
  236. ev := NewPhantomValidatorEvidence(vote, header.Height-1)
  237. assert.Equal(t, header.Height, ev.Height())
  238. assert.Equal(t, defaultVoteTime, ev.Time())
  239. assert.EqualValues(t, vote.ValidatorAddress, ev.Address())
  240. assert.NotEmpty(t, ev.Hash())
  241. assert.NotEmpty(t, ev.Bytes())
  242. pubKey, err := val.GetPubKey()
  243. require.NoError(t, err)
  244. assert.NoError(t, ev.Verify(header.ChainID, pubKey))
  245. assert.Error(t, ev.Verify("other", pubKey))
  246. privKey2 := ed25519.GenPrivKey()
  247. pubKey2 := privKey2.PubKey()
  248. assert.Error(t, ev.Verify("other", pubKey2))
  249. assert.True(t, ev.Equal(ev))
  250. assert.NoError(t, ev.ValidateBasic())
  251. assert.NotEmpty(t, ev.String())
  252. }
  253. func TestConflictingHeadersEvidence(t *testing.T) {
  254. const (
  255. chainID = "TestConflictingHeadersEvidence"
  256. height int64 = 37
  257. )
  258. var (
  259. blockID = makeBlockIDRandom()
  260. header1 = makeHeaderRandom()
  261. header2 = makeHeaderRandom()
  262. )
  263. header1.Height = height
  264. header1.LastBlockID = blockID
  265. header1.ChainID = chainID
  266. header2.Height = height
  267. header2.LastBlockID = blockID
  268. header2.ChainID = chainID
  269. voteSet1, valSet, vals := randVoteSet(height, 1, tmproto.PrecommitType, 10, 1)
  270. voteSet2 := NewVoteSet(chainID, height, 1, tmproto.PrecommitType, valSet)
  271. commit1, err := MakeCommit(BlockID{
  272. Hash: header1.Hash(),
  273. PartSetHeader: PartSetHeader{
  274. Total: 100,
  275. Hash: crypto.CRandBytes(tmhash.Size),
  276. },
  277. }, height, 1, voteSet1, vals, time.Now())
  278. require.NoError(t, err)
  279. commit2, err := MakeCommit(BlockID{
  280. Hash: header2.Hash(),
  281. PartSetHeader: PartSetHeader{
  282. Total: 100,
  283. Hash: crypto.CRandBytes(tmhash.Size),
  284. },
  285. }, height, 1, voteSet2, vals, time.Now())
  286. require.NoError(t, err)
  287. h1 := &SignedHeader{
  288. Header: header1,
  289. Commit: commit1,
  290. }
  291. h2 := &SignedHeader{
  292. Header: header2,
  293. Commit: commit2,
  294. }
  295. ev := NewConflictingHeadersEvidence(h1, h2)
  296. assert.Panics(t, func() {
  297. ev.Address()
  298. })
  299. assert.Panics(t, func() {
  300. pubKey, _ := vals[0].GetPubKey()
  301. ev.Verify(chainID, pubKey)
  302. })
  303. assert.Equal(t, height, ev.Height())
  304. assert.Equal(t, ev.H2.Time, ev.Time())
  305. assert.NotEmpty(t, ev.Hash())
  306. assert.NotEmpty(t, ev.Bytes())
  307. assert.NoError(t, ev.VerifyComposite(header1, valSet))
  308. assert.True(t, ev.Equal(ev))
  309. assert.NoError(t, ev.ValidateBasic())
  310. assert.NotEmpty(t, ev.String())
  311. }
  312. func TestPotentialAmnesiaEvidence(t *testing.T) {
  313. const (
  314. chainID = "TestPotentialAmnesiaEvidence"
  315. height int64 = 37
  316. )
  317. var (
  318. val = NewMockPV()
  319. blockID = makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  320. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  321. vote1 = makeVote(t, val, chainID, 0, height, 0, 2, blockID, defaultVoteTime)
  322. vote2 = makeVote(t, val, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Second))
  323. vote3 = makeVote(t, val, chainID, 0, height, 2, 2, blockID, defaultVoteTime)
  324. )
  325. ev := NewPotentialAmnesiaEvidence(vote1, vote2)
  326. assert.Equal(t, height, ev.Height())
  327. assert.Equal(t, vote2.Timestamp, ev.Time())
  328. assert.EqualValues(t, vote1.ValidatorAddress, ev.Address())
  329. assert.NotEmpty(t, ev.Hash())
  330. assert.NotEmpty(t, ev.Bytes())
  331. pubKey, err := val.GetPubKey()
  332. require.NoError(t, err)
  333. assert.NoError(t, ev.Verify(chainID, pubKey))
  334. assert.Error(t, ev.Verify("other", pubKey))
  335. privKey2 := ed25519.GenPrivKey()
  336. pubKey2 := privKey2.PubKey()
  337. assert.Error(t, ev.Verify("other", pubKey2))
  338. assert.True(t, ev.Equal(ev))
  339. assert.NoError(t, ev.ValidateBasic())
  340. assert.NotEmpty(t, ev.String())
  341. ev2 := &PotentialAmnesiaEvidence{
  342. VoteA: vote1,
  343. VoteB: vote2,
  344. HeightStamp: 5,
  345. }
  346. assert.True(t, ev.Equal(ev2))
  347. assert.Equal(t, ev.Hash(), ev2.Hash())
  348. ev3 := &PotentialAmnesiaEvidence{
  349. VoteA: vote2,
  350. VoteB: vote1,
  351. }
  352. assert.Error(t, ev3.ValidateBasic())
  353. ev3 = NewPotentialAmnesiaEvidence(vote2, vote1)
  354. assert.True(t, ev3.Equal(ev))
  355. ev4 := &PotentialAmnesiaEvidence{
  356. VoteA: vote3,
  357. VoteB: vote2,
  358. }
  359. assert.NoError(t, ev4.ValidateBasic())
  360. assert.NotEqual(t, ev.Hash(), ev4.Hash())
  361. assert.False(t, ev.Equal(ev4))
  362. }
  363. func TestProofOfLockChange(t *testing.T) {
  364. const (
  365. chainID = "test_chain_id"
  366. height int64 = 37
  367. )
  368. // 1: valid POLC - nothing should fail
  369. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  370. pubKey, err := privValidators[7].GetPubKey()
  371. require.NoError(t, err)
  372. polc, err := NewPOLCFromVoteSet(voteSet, pubKey, blockID)
  373. assert.NoError(t, err)
  374. assert.Equal(t, height, polc.Height())
  375. assert.NoError(t, polc.ValidateBasic())
  376. assert.NoError(t, polc.ValidateVotes(valSet, chainID))
  377. assert.NotEmpty(t, polc.String())
  378. // tamper with one of the votes
  379. polc.Votes[0].Timestamp = time.Now().Add(1 * time.Second)
  380. err = polc.ValidateVotes(valSet, chainID)
  381. t.Log(err)
  382. assert.Error(t, err)
  383. // remove a vote such that majority wasn't reached
  384. polc.Votes = polc.Votes[1:]
  385. err = polc.ValidateVotes(valSet, chainID)
  386. t.Log(err)
  387. assert.Error(t, err)
  388. // test validate basic on a set of bad cases
  389. var badPOLCs []*ProofOfLockChange
  390. // 2: node has already voted in next round
  391. pubKey, err = privValidators[0].GetPubKey()
  392. require.NoError(t, err)
  393. polc2 := newPOLCFromVoteSet(voteSet, pubKey, blockID)
  394. badPOLCs = append(badPOLCs, polc2)
  395. // 3: one vote was from a different round
  396. voteSet, _, privValidators, blockID = buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  397. pubKey, err = privValidators[7].GetPubKey()
  398. require.NoError(t, err)
  399. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  400. badVote := makeVote(t, privValidators[8], chainID, 8, height, 2, 2, blockID, defaultVoteTime)
  401. polc.Votes = append(polc.Votes, badVote)
  402. badPOLCs = append(badPOLCs, polc)
  403. // 4: one vote was from a different height
  404. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  405. badVote = makeVote(t, privValidators[8], chainID, 8, height+1, 1, 2, blockID, defaultVoteTime)
  406. polc.Votes = append(polc.Votes, badVote)
  407. badPOLCs = append(badPOLCs, polc)
  408. // 5: one vote was from a different vote type
  409. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  410. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 1, blockID, defaultVoteTime)
  411. polc.Votes = append(polc.Votes, badVote)
  412. badPOLCs = append(badPOLCs, polc)
  413. // 5: one of the votes was for a nil block
  414. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  415. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 2, BlockID{}, defaultVoteTime)
  416. polc.Votes = append(polc.Votes, badVote)
  417. badPOLCs = append(badPOLCs, polc)
  418. for idx, polc := range badPOLCs {
  419. err := polc.ValidateBasic()
  420. t.Logf("case: %d: %v", idx+2, err)
  421. assert.Error(t, err)
  422. if err == nil {
  423. t.Errorf("test no. %d failed", idx+2)
  424. }
  425. }
  426. }
  427. func TestAmnesiaEvidence(t *testing.T) {
  428. const (
  429. chainID = "test_chain_id"
  430. height int64 = 37
  431. )
  432. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  433. var (
  434. val = privValidators[7]
  435. pubKey, _ = val.GetPubKey()
  436. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  437. vote1 = makeVote(t, val, chainID, 7, height, 0, 2, blockID2, time.Now())
  438. vote2 = makeVote(t, val, chainID, 7, height, 1, 2, blockID,
  439. time.Now().Add(time.Second))
  440. vote3 = makeVote(t, val, chainID, 7, height, 2, 2, blockID2, time.Now())
  441. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  442. )
  443. require.False(t, polc.IsAbsent())
  444. pe := &PotentialAmnesiaEvidence{
  445. VoteA: vote1,
  446. VoteB: vote2,
  447. }
  448. emptyAmnesiaEvidence := NewAmnesiaEvidence(pe, NewEmptyPOLC())
  449. assert.NoError(t, emptyAmnesiaEvidence.ValidateBasic())
  450. violated, reason := emptyAmnesiaEvidence.ViolatedConsensus()
  451. if assert.True(t, violated) {
  452. assert.Equal(t, reason, "no proof of lock was provided")
  453. }
  454. assert.NoError(t, emptyAmnesiaEvidence.Verify(chainID, pubKey))
  455. completeAmnesiaEvidence := NewAmnesiaEvidence(pe, polc)
  456. assert.NoError(t, completeAmnesiaEvidence.ValidateBasic())
  457. violated, reason = completeAmnesiaEvidence.ViolatedConsensus()
  458. if !assert.False(t, violated) {
  459. t.Log(reason)
  460. }
  461. assert.NoError(t, completeAmnesiaEvidence.Verify(chainID, pubKey))
  462. assert.NoError(t, completeAmnesiaEvidence.Polc.ValidateVotes(valSet, chainID))
  463. assert.True(t, completeAmnesiaEvidence.Equal(emptyAmnesiaEvidence))
  464. assert.Equal(t, completeAmnesiaEvidence.Hash(), emptyAmnesiaEvidence.Hash())
  465. assert.NotEmpty(t, completeAmnesiaEvidence.Hash())
  466. assert.NotEmpty(t, completeAmnesiaEvidence.Bytes())
  467. pe2 := &PotentialAmnesiaEvidence{
  468. VoteA: vote3,
  469. VoteB: vote2,
  470. }
  471. // validator has incorrectly voted for a previous round after voting for a later round
  472. ae := NewAmnesiaEvidence(pe2, NewEmptyPOLC())
  473. assert.NoError(t, ae.ValidateBasic())
  474. violated, reason = ae.ViolatedConsensus()
  475. if assert.True(t, violated) {
  476. assert.Equal(t, reason, "validator went back and voted on a previous round")
  477. }
  478. var badAE []*AmnesiaEvidence
  479. // 1) Polc is at an incorrect height
  480. voteSet, _, _ = buildVoteSetForBlock(height+1, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  481. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  482. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  483. // 2) Polc is of a later round
  484. voteSet, _, _ = buildVoteSetForBlock(height, 2, 2, 7, 0, tmproto.PrecommitType, blockID)
  485. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  486. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  487. // 3) Polc has a different public key
  488. voteSet, _, privValidators = buildVoteSetForBlock(height, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  489. pubKey2, _ := privValidators[7].GetPubKey()
  490. polc = newPOLCFromVoteSet(voteSet, pubKey2, blockID)
  491. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  492. // 4) Polc has a different block ID
  493. voteSet, _, _, blockID = buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  494. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  495. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  496. for idx, ae := range badAE {
  497. t.Log(ae.ValidateBasic())
  498. if !assert.Error(t, ae.ValidateBasic()) {
  499. t.Errorf("test no. %d failed", idx+1)
  500. }
  501. }
  502. }
  503. func makeVote(
  504. t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID,
  505. time time.Time) *Vote {
  506. pubKey, err := val.GetPubKey()
  507. require.NoError(t, err)
  508. v := &Vote{
  509. ValidatorAddress: pubKey.Address(),
  510. ValidatorIndex: valIndex,
  511. Height: height,
  512. Round: round,
  513. Type: tmproto.SignedMsgType(step),
  514. BlockID: blockID,
  515. Timestamp: time,
  516. }
  517. vpb := v.ToProto()
  518. err = val.SignVote(chainID, vpb)
  519. if err != nil {
  520. panic(err)
  521. }
  522. v.Signature = vpb.Signature
  523. return v
  524. }
  525. func makeHeaderRandom() *Header {
  526. return &Header{
  527. ChainID: tmrand.Str(12),
  528. Height: int64(tmrand.Uint16()) + 1,
  529. Time: time.Now(),
  530. LastBlockID: makeBlockIDRandom(),
  531. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  532. DataHash: crypto.CRandBytes(tmhash.Size),
  533. ValidatorsHash: crypto.CRandBytes(tmhash.Size),
  534. NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
  535. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  536. AppHash: crypto.CRandBytes(tmhash.Size),
  537. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  538. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  539. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  540. }
  541. }
  542. func TestEvidenceProto(t *testing.T) {
  543. // -------- Votes --------
  544. val := NewMockPV()
  545. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  546. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  547. const chainID = "mychain"
  548. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  549. v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  550. // -------- SignedHeaders --------
  551. const height int64 = 37
  552. var (
  553. header1 = makeHeaderRandom()
  554. header2 = makeHeaderRandom()
  555. )
  556. header1.Height = height
  557. header1.LastBlockID = blockID
  558. header1.ChainID = chainID
  559. header2.Height = height
  560. header2.LastBlockID = blockID
  561. header2.ChainID = chainID
  562. voteSet1, valSet, vals := randVoteSet(height, 1, tmproto.PrecommitType, 10, 1)
  563. voteSet2 := NewVoteSet(chainID, height, 1, tmproto.PrecommitType, valSet)
  564. commit1, err := MakeCommit(BlockID{
  565. Hash: header1.Hash(),
  566. PartSetHeader: PartSetHeader{
  567. Total: 100,
  568. Hash: crypto.CRandBytes(tmhash.Size),
  569. },
  570. }, height, 1, voteSet1, vals, time.Now())
  571. require.NoError(t, err)
  572. commit2, err := MakeCommit(BlockID{
  573. Hash: header2.Hash(),
  574. PartSetHeader: PartSetHeader{
  575. Total: 100,
  576. Hash: crypto.CRandBytes(tmhash.Size),
  577. },
  578. }, height, 1, voteSet2, vals, time.Now())
  579. require.NoError(t, err)
  580. h1 := &SignedHeader{
  581. Header: header1,
  582. Commit: commit1,
  583. }
  584. h2 := &SignedHeader{
  585. Header: header2,
  586. Commit: commit2,
  587. }
  588. tests := []struct {
  589. testName string
  590. evidence Evidence
  591. toProtoErr bool
  592. fromProtoErr bool
  593. }{
  594. {"nil fail", nil, true, true},
  595. {"DuplicateVoteEvidence empty fail", &DuplicateVoteEvidence{}, false, true},
  596. {"DuplicateVoteEvidence nil voteB", &DuplicateVoteEvidence{VoteA: v, VoteB: nil}, false, true},
  597. {"DuplicateVoteEvidence nil voteA", &DuplicateVoteEvidence{VoteA: nil, VoteB: v}, false, true},
  598. {"DuplicateVoteEvidence success", &DuplicateVoteEvidence{VoteA: v2, VoteB: v}, false, false},
  599. {"ConflictingHeadersEvidence empty fail", &ConflictingHeadersEvidence{}, false, true},
  600. {"ConflictingHeadersEvidence nil H2", &ConflictingHeadersEvidence{H1: h1, H2: nil}, false, true},
  601. {"ConflictingHeadersEvidence nil H1", &ConflictingHeadersEvidence{H1: nil, H2: h2}, false, true},
  602. {"ConflictingHeadersEvidence success", &ConflictingHeadersEvidence{H1: h1, H2: h2}, false, false},
  603. {"LunaticValidatorEvidence success", &LunaticValidatorEvidence{Header: header1,
  604. Vote: v, InvalidHeaderField: "ValidatorsHash"}, false, true},
  605. {"&LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  606. {"LunaticValidatorEvidence only header fail", &LunaticValidatorEvidence{Header: header1}, false, true},
  607. {"LunaticValidatorEvidence only vote fail", &LunaticValidatorEvidence{Vote: v}, false, true},
  608. {"LunaticValidatorEvidence header & vote fail", &LunaticValidatorEvidence{Header: header1, Vote: v}, false, true},
  609. {"LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  610. {"PotentialAmnesiaEvidence empty fail", &PotentialAmnesiaEvidence{}, false, true},
  611. {"PotentialAmnesiaEvidence nil VoteB", &PotentialAmnesiaEvidence{VoteA: v, VoteB: nil}, false, true},
  612. {"PotentialAmnesiaEvidence nil VoteA", &PotentialAmnesiaEvidence{VoteA: nil, VoteB: v2}, false, true},
  613. {"PotentialAmnesiaEvidence success", &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v}, false, false},
  614. {"PhantomValidatorEvidence empty fail", &PhantomValidatorEvidence{}, false, true},
  615. {"PhantomValidatorEvidence nil LastHeightValidatorWasInSet", &PhantomValidatorEvidence{Vote: v}, false, true},
  616. {"PhantomValidatorEvidence nil Vote", &PhantomValidatorEvidence{LastHeightValidatorWasInSet: 2}, false, true},
  617. {"PhantomValidatorEvidence success", &PhantomValidatorEvidence{Vote: v2, LastHeightValidatorWasInSet: 2},
  618. false, false},
  619. {"AmnesiaEvidence nil ProofOfLockChange", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{},
  620. Polc: NewEmptyPOLC()}, false, true},
  621. {"AmnesiaEvidence nil Polc",
  622. &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  623. Polc: &ProofOfLockChange{}}, false, false},
  624. {"AmnesiaEvidence success", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  625. Polc: NewEmptyPOLC()}, false, false},
  626. }
  627. for _, tt := range tests {
  628. tt := tt
  629. t.Run(tt.testName, func(t *testing.T) {
  630. pb, err := EvidenceToProto(tt.evidence)
  631. if tt.toProtoErr {
  632. assert.Error(t, err, tt.testName)
  633. return
  634. }
  635. assert.NoError(t, err, tt.testName)
  636. evi, err := EvidenceFromProto(pb)
  637. if tt.fromProtoErr {
  638. assert.Error(t, err, tt.testName)
  639. return
  640. }
  641. require.Equal(t, tt.evidence, evi, tt.testName)
  642. })
  643. }
  644. }
  645. func TestProofOfLockChangeProtoBuf(t *testing.T) {
  646. // -------- Votes --------
  647. val := NewMockPV()
  648. val2 := NewMockPV()
  649. val3 := NewMockPV()
  650. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  651. const chainID = "mychain"
  652. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  653. v2 := makeVote(t, val2, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  654. testCases := []struct {
  655. msg string
  656. polc *ProofOfLockChange
  657. toProtoErr bool
  658. fromProtoErr bool
  659. }{
  660. {"failure, empty key", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: nil}, true, false},
  661. {"failure, empty votes", &ProofOfLockChange{PubKey: val3.PrivKey.PubKey()}, true, false},
  662. {"success empty ProofOfLockChange", NewEmptyPOLC(), false, false},
  663. {"success", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: val3.PrivKey.PubKey()}, false, false},
  664. }
  665. for _, tc := range testCases {
  666. tc := tc
  667. pbpolc, err := tc.polc.ToProto()
  668. if tc.toProtoErr {
  669. assert.Error(t, err, tc.msg)
  670. } else {
  671. assert.NoError(t, err, tc.msg)
  672. }
  673. c, err := ProofOfLockChangeFromProto(pbpolc)
  674. if !tc.fromProtoErr {
  675. assert.NoError(t, err, tc.msg)
  676. if !tc.toProtoErr {
  677. assert.Equal(t, tc.polc, c, tc.msg)
  678. }
  679. } else {
  680. assert.Error(t, err, tc.msg)
  681. }
  682. }
  683. }