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.

815 lines
28 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. val2 = NewMockPV()
  320. blockID = makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  321. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  322. vote1 = makeVote(t, val, chainID, 0, height, 0, 2, blockID, defaultVoteTime)
  323. vote2 = makeVote(t, val, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Second))
  324. vote3 = makeVote(t, val, chainID, 0, height, 2, 2, blockID, defaultVoteTime)
  325. )
  326. ev := NewPotentialAmnesiaEvidence(vote1, vote2)
  327. assert.Equal(t, height, ev.Height())
  328. assert.Equal(t, vote2.Timestamp, ev.Time())
  329. assert.EqualValues(t, vote1.ValidatorAddress, ev.Address())
  330. assert.NotEmpty(t, ev.Hash())
  331. assert.NotEmpty(t, ev.Bytes())
  332. pubKey, err := val.GetPubKey()
  333. require.NoError(t, err)
  334. assert.NoError(t, ev.Verify(chainID, pubKey))
  335. assert.Error(t, ev.Verify("other", pubKey))
  336. privKey2 := ed25519.GenPrivKey()
  337. pubKey2 := privKey2.PubKey()
  338. assert.Error(t, ev.Verify("other", pubKey2))
  339. assert.True(t, ev.Equal(ev))
  340. assert.NoError(t, ev.ValidateBasic())
  341. assert.NotEmpty(t, ev.String())
  342. ev2 := &PotentialAmnesiaEvidence{
  343. VoteA: vote1,
  344. VoteB: vote2,
  345. HeightStamp: 5,
  346. }
  347. assert.True(t, ev.Equal(ev2))
  348. assert.Equal(t, ev.Hash(), ev2.Hash())
  349. ev3 := NewPotentialAmnesiaEvidence(vote2, vote1)
  350. assert.True(t, ev3.Equal(ev))
  351. ev4 := &PotentialAmnesiaEvidence{
  352. VoteA: vote3,
  353. VoteB: vote2,
  354. }
  355. assert.NoError(t, ev4.ValidateBasic())
  356. assert.NotEqual(t, ev.Hash(), ev4.Hash())
  357. assert.False(t, ev.Equal(ev4))
  358. // bad evidence
  359. badEv := []*PotentialAmnesiaEvidence{
  360. // first vote is for a later time than the second vote
  361. {
  362. VoteA: vote2,
  363. VoteB: vote1,
  364. },
  365. // votes are for the same round
  366. {
  367. VoteA: vote1,
  368. VoteB: makeVote(t, val, chainID, 0, height, 0, 2, blockID2, defaultVoteTime.Add(1*time.Second)),
  369. },
  370. // first vote was for a nil block - not locked
  371. {
  372. VoteA: makeVote(t, val, chainID, 0, height, 0, 2, BlockID{}, defaultVoteTime.Add(1*time.Second)),
  373. VoteB: vote2,
  374. },
  375. // second vote is from a different validator
  376. {
  377. VoteA: vote1,
  378. VoteB: makeVote(t, val2, chainID, 0, height, 1, 2, blockID2, defaultVoteTime.Add(1*time.Second)),
  379. },
  380. }
  381. for _, ev := range badEv {
  382. assert.Error(t, ev.ValidateBasic())
  383. }
  384. }
  385. func TestProofOfLockChange(t *testing.T) {
  386. const (
  387. chainID = "test_chain_id"
  388. height int64 = 37
  389. )
  390. // 1: valid POLC - nothing should fail
  391. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  392. pubKey, err := privValidators[7].GetPubKey()
  393. require.NoError(t, err)
  394. polc, err := NewPOLCFromVoteSet(voteSet, pubKey, blockID)
  395. assert.NoError(t, err)
  396. assert.Equal(t, height, polc.Height())
  397. assert.NoError(t, polc.ValidateBasic())
  398. assert.NoError(t, polc.ValidateVotes(valSet, chainID))
  399. assert.NotEmpty(t, polc.String())
  400. // tamper with one of the votes
  401. polc.Votes[0].Timestamp = time.Now().Add(1 * time.Second)
  402. err = polc.ValidateVotes(valSet, chainID)
  403. t.Log(err)
  404. assert.Error(t, err)
  405. // remove a vote such that majority wasn't reached
  406. polc.Votes = polc.Votes[1:]
  407. err = polc.ValidateVotes(valSet, chainID)
  408. t.Log(err)
  409. assert.Error(t, err)
  410. // test validate basic on a set of bad cases
  411. var badPOLCs []*ProofOfLockChange
  412. // 2: node has already voted in next round
  413. pubKey, err = privValidators[0].GetPubKey()
  414. require.NoError(t, err)
  415. polc2 := newPOLCFromVoteSet(voteSet, pubKey, blockID)
  416. badPOLCs = append(badPOLCs, polc2)
  417. // 3: one vote was from a different round
  418. voteSet, _, privValidators, blockID = buildVoteSet(height, 1, 3, 7, 0, tmproto.PrecommitType)
  419. pubKey, err = privValidators[7].GetPubKey()
  420. require.NoError(t, err)
  421. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  422. badVote := makeVote(t, privValidators[8], chainID, 8, height, 2, 2, blockID, defaultVoteTime)
  423. polc.Votes = append(polc.Votes, badVote)
  424. badPOLCs = append(badPOLCs, polc)
  425. // 4: one vote was from a different height
  426. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  427. badVote = makeVote(t, privValidators[8], chainID, 8, height+1, 1, 2, blockID, defaultVoteTime)
  428. polc.Votes = append(polc.Votes, badVote)
  429. badPOLCs = append(badPOLCs, polc)
  430. // 5: one vote was from a different vote type
  431. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  432. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 1, blockID, defaultVoteTime)
  433. polc.Votes = append(polc.Votes, badVote)
  434. badPOLCs = append(badPOLCs, polc)
  435. // 5: one of the votes was for a nil block
  436. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  437. badVote = makeVote(t, privValidators[8], chainID, 8, height, 1, 2, BlockID{}, defaultVoteTime)
  438. polc.Votes = append(polc.Votes, badVote)
  439. badPOLCs = append(badPOLCs, polc)
  440. for idx, polc := range badPOLCs {
  441. err := polc.ValidateBasic()
  442. t.Logf("case: %d: %v", idx+2, err)
  443. assert.Error(t, err)
  444. if err == nil {
  445. t.Errorf("test no. %d failed", idx+2)
  446. }
  447. }
  448. }
  449. func TestAmnesiaEvidence(t *testing.T) {
  450. const (
  451. chainID = "test_chain_id"
  452. height int64 = 37
  453. )
  454. voteSet, valSet, privValidators, blockID := buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  455. var (
  456. val = privValidators[7]
  457. pubKey, _ = val.GetPubKey()
  458. blockID2 = makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  459. vote1 = makeVote(t, val, chainID, 7, height, 0, 2, blockID2, time.Now())
  460. vote2 = makeVote(t, val, chainID, 7, height, 1, 2, blockID,
  461. time.Now().Add(time.Second))
  462. vote3 = makeVote(t, val, chainID, 7, height, 2, 2, blockID2, time.Now())
  463. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  464. )
  465. require.False(t, polc.IsAbsent())
  466. pe := &PotentialAmnesiaEvidence{
  467. VoteA: vote1,
  468. VoteB: vote2,
  469. }
  470. emptyAmnesiaEvidence := NewAmnesiaEvidence(pe, NewEmptyPOLC())
  471. assert.NoError(t, emptyAmnesiaEvidence.ValidateBasic())
  472. violated, reason := emptyAmnesiaEvidence.ViolatedConsensus()
  473. if assert.True(t, violated) {
  474. assert.Equal(t, reason, "no proof of lock was provided")
  475. }
  476. assert.NoError(t, emptyAmnesiaEvidence.Verify(chainID, pubKey))
  477. completeAmnesiaEvidence := NewAmnesiaEvidence(pe, polc)
  478. assert.NoError(t, completeAmnesiaEvidence.ValidateBasic())
  479. violated, reason = completeAmnesiaEvidence.ViolatedConsensus()
  480. if !assert.False(t, violated) {
  481. t.Log(reason)
  482. }
  483. assert.NoError(t, completeAmnesiaEvidence.Verify(chainID, pubKey))
  484. assert.NoError(t, completeAmnesiaEvidence.Polc.ValidateVotes(valSet, chainID))
  485. assert.True(t, completeAmnesiaEvidence.Equal(emptyAmnesiaEvidence))
  486. assert.Equal(t, completeAmnesiaEvidence.Hash(), emptyAmnesiaEvidence.Hash())
  487. assert.NotEmpty(t, completeAmnesiaEvidence.Hash())
  488. assert.NotEmpty(t, completeAmnesiaEvidence.Bytes())
  489. pe2 := &PotentialAmnesiaEvidence{
  490. VoteA: vote3,
  491. VoteB: vote2,
  492. }
  493. // validator has incorrectly voted for a previous round after voting for a later round
  494. ae := NewAmnesiaEvidence(pe2, NewEmptyPOLC())
  495. assert.NoError(t, ae.ValidateBasic())
  496. violated, reason = ae.ViolatedConsensus()
  497. if assert.True(t, violated) {
  498. assert.Equal(t, reason, "validator went back and voted on a previous round")
  499. }
  500. var badAE []*AmnesiaEvidence
  501. // 1) Polc is at an incorrect height
  502. voteSet, _, _ = buildVoteSetForBlock(height+1, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  503. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  504. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  505. // 2) Polc is of a later round
  506. voteSet, _, _ = buildVoteSetForBlock(height, 2, 2, 7, 0, tmproto.PrecommitType, blockID)
  507. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  508. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  509. // 3) Polc has a different public key
  510. voteSet, _, privValidators = buildVoteSetForBlock(height, 1, 2, 7, 0, tmproto.PrecommitType, blockID)
  511. pubKey2, _ := privValidators[7].GetPubKey()
  512. polc = newPOLCFromVoteSet(voteSet, pubKey2, blockID)
  513. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  514. // 4) Polc has a different block ID
  515. voteSet, _, _, blockID = buildVoteSet(height, 1, 2, 7, 0, tmproto.PrecommitType)
  516. polc = newPOLCFromVoteSet(voteSet, pubKey, blockID)
  517. badAE = append(badAE, NewAmnesiaEvidence(pe, polc))
  518. for idx, ae := range badAE {
  519. t.Log(ae.ValidateBasic())
  520. if !assert.Error(t, ae.ValidateBasic()) {
  521. t.Errorf("test no. %d failed", idx+1)
  522. }
  523. }
  524. }
  525. func makeVote(
  526. t *testing.T, val PrivValidator, chainID string, valIndex int32, height int64, round int32, step int, blockID BlockID,
  527. time time.Time) *Vote {
  528. pubKey, err := val.GetPubKey()
  529. require.NoError(t, err)
  530. v := &Vote{
  531. ValidatorAddress: pubKey.Address(),
  532. ValidatorIndex: valIndex,
  533. Height: height,
  534. Round: round,
  535. Type: tmproto.SignedMsgType(step),
  536. BlockID: blockID,
  537. Timestamp: time,
  538. }
  539. vpb := v.ToProto()
  540. err = val.SignVote(chainID, vpb)
  541. if err != nil {
  542. panic(err)
  543. }
  544. v.Signature = vpb.Signature
  545. return v
  546. }
  547. func makeHeaderRandom() *Header {
  548. return &Header{
  549. ChainID: tmrand.Str(12),
  550. Height: int64(tmrand.Uint16()) + 1,
  551. Time: time.Now(),
  552. LastBlockID: makeBlockIDRandom(),
  553. LastCommitHash: crypto.CRandBytes(tmhash.Size),
  554. DataHash: crypto.CRandBytes(tmhash.Size),
  555. ValidatorsHash: crypto.CRandBytes(tmhash.Size),
  556. NextValidatorsHash: crypto.CRandBytes(tmhash.Size),
  557. ConsensusHash: crypto.CRandBytes(tmhash.Size),
  558. AppHash: crypto.CRandBytes(tmhash.Size),
  559. LastResultsHash: crypto.CRandBytes(tmhash.Size),
  560. EvidenceHash: crypto.CRandBytes(tmhash.Size),
  561. ProposerAddress: crypto.CRandBytes(crypto.AddressSize),
  562. }
  563. }
  564. func TestEvidenceProto(t *testing.T) {
  565. // -------- Votes --------
  566. val := NewMockPV()
  567. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  568. blockID2 := makeBlockID(tmhash.Sum([]byte("blockhash2")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  569. const chainID = "mychain"
  570. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  571. v2 := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 2, 0x01, blockID2, defaultVoteTime)
  572. // -------- SignedHeaders --------
  573. const height int64 = 37
  574. var (
  575. header1 = makeHeaderRandom()
  576. header2 = makeHeaderRandom()
  577. )
  578. header1.Height = height
  579. header1.LastBlockID = blockID
  580. header1.ChainID = chainID
  581. header2.Height = height
  582. header2.LastBlockID = blockID
  583. header2.ChainID = chainID
  584. voteSet1, valSet, vals := randVoteSet(height, 1, tmproto.PrecommitType, 10, 1)
  585. voteSet2 := NewVoteSet(chainID, height, 1, tmproto.PrecommitType, valSet)
  586. commit1, err := MakeCommit(BlockID{
  587. Hash: header1.Hash(),
  588. PartSetHeader: PartSetHeader{
  589. Total: 100,
  590. Hash: crypto.CRandBytes(tmhash.Size),
  591. },
  592. }, height, 1, voteSet1, vals, time.Now())
  593. require.NoError(t, err)
  594. commit2, err := MakeCommit(BlockID{
  595. Hash: header2.Hash(),
  596. PartSetHeader: PartSetHeader{
  597. Total: 100,
  598. Hash: crypto.CRandBytes(tmhash.Size),
  599. },
  600. }, height, 1, voteSet2, vals, time.Now())
  601. require.NoError(t, err)
  602. h1 := &SignedHeader{
  603. Header: header1,
  604. Commit: commit1,
  605. }
  606. h2 := &SignedHeader{
  607. Header: header2,
  608. Commit: commit2,
  609. }
  610. tests := []struct {
  611. testName string
  612. evidence Evidence
  613. toProtoErr bool
  614. fromProtoErr bool
  615. }{
  616. {"nil fail", nil, true, true},
  617. {"DuplicateVoteEvidence empty fail", &DuplicateVoteEvidence{}, false, true},
  618. {"DuplicateVoteEvidence nil voteB", &DuplicateVoteEvidence{VoteA: v, VoteB: nil}, false, true},
  619. {"DuplicateVoteEvidence nil voteA", &DuplicateVoteEvidence{VoteA: nil, VoteB: v}, false, true},
  620. {"DuplicateVoteEvidence success", &DuplicateVoteEvidence{VoteA: v2, VoteB: v}, false, false},
  621. {"ConflictingHeadersEvidence empty fail", &ConflictingHeadersEvidence{}, false, true},
  622. {"ConflictingHeadersEvidence nil H2", &ConflictingHeadersEvidence{H1: h1, H2: nil}, false, true},
  623. {"ConflictingHeadersEvidence nil H1", &ConflictingHeadersEvidence{H1: nil, H2: h2}, false, true},
  624. {"ConflictingHeadersEvidence success", &ConflictingHeadersEvidence{H1: h1, H2: h2}, false, false},
  625. {"LunaticValidatorEvidence success", &LunaticValidatorEvidence{Header: header1,
  626. Vote: v, InvalidHeaderField: "ValidatorsHash"}, false, true},
  627. {"&LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  628. {"LunaticValidatorEvidence only header fail", &LunaticValidatorEvidence{Header: header1}, false, true},
  629. {"LunaticValidatorEvidence only vote fail", &LunaticValidatorEvidence{Vote: v}, false, true},
  630. {"LunaticValidatorEvidence header & vote fail", &LunaticValidatorEvidence{Header: header1, Vote: v}, false, true},
  631. {"LunaticValidatorEvidence empty fail", &LunaticValidatorEvidence{}, false, true},
  632. {"PotentialAmnesiaEvidence empty fail", &PotentialAmnesiaEvidence{}, false, true},
  633. {"PotentialAmnesiaEvidence nil VoteB", &PotentialAmnesiaEvidence{VoteA: v, VoteB: nil}, false, true},
  634. {"PotentialAmnesiaEvidence nil VoteA", &PotentialAmnesiaEvidence{VoteA: nil, VoteB: v2}, false, true},
  635. {"PotentialAmnesiaEvidence success", &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v}, false, false},
  636. {"PhantomValidatorEvidence empty fail", &PhantomValidatorEvidence{}, false, true},
  637. {"PhantomValidatorEvidence nil LastHeightValidatorWasInSet", &PhantomValidatorEvidence{Vote: v}, false, true},
  638. {"PhantomValidatorEvidence nil Vote", &PhantomValidatorEvidence{LastHeightValidatorWasInSet: 2}, false, true},
  639. {"PhantomValidatorEvidence success", &PhantomValidatorEvidence{Vote: v2, LastHeightValidatorWasInSet: 2},
  640. false, false},
  641. {"AmnesiaEvidence nil ProofOfLockChange", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{},
  642. Polc: NewEmptyPOLC()}, false, true},
  643. {"AmnesiaEvidence nil Polc",
  644. &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  645. Polc: &ProofOfLockChange{}}, false, false},
  646. {"AmnesiaEvidence success", &AmnesiaEvidence{PotentialAmnesiaEvidence: &PotentialAmnesiaEvidence{VoteA: v2, VoteB: v},
  647. Polc: NewEmptyPOLC()}, false, false},
  648. }
  649. for _, tt := range tests {
  650. tt := tt
  651. t.Run(tt.testName, func(t *testing.T) {
  652. pb, err := EvidenceToProto(tt.evidence)
  653. if tt.toProtoErr {
  654. assert.Error(t, err, tt.testName)
  655. return
  656. }
  657. assert.NoError(t, err, tt.testName)
  658. evi, err := EvidenceFromProto(pb)
  659. if tt.fromProtoErr {
  660. assert.Error(t, err, tt.testName)
  661. return
  662. }
  663. require.Equal(t, tt.evidence, evi, tt.testName)
  664. })
  665. }
  666. }
  667. func TestProofOfLockChangeProtoBuf(t *testing.T) {
  668. // -------- Votes --------
  669. val := NewMockPV()
  670. val2 := NewMockPV()
  671. val3 := NewMockPV()
  672. blockID := makeBlockID(tmhash.Sum([]byte("blockhash")), math.MaxInt32, tmhash.Sum([]byte("partshash")))
  673. const chainID = "mychain"
  674. v := makeVote(t, val, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  675. v2 := makeVote(t, val2, chainID, math.MaxInt32, math.MaxInt64, 1, 0x01, blockID, defaultVoteTime)
  676. testCases := []struct {
  677. msg string
  678. polc *ProofOfLockChange
  679. toProtoErr bool
  680. fromProtoErr bool
  681. }{
  682. {"failure, empty key", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: nil}, true, false},
  683. {"failure, empty votes", &ProofOfLockChange{PubKey: val3.PrivKey.PubKey()}, true, false},
  684. {"success empty ProofOfLockChange", NewEmptyPOLC(), false, false},
  685. {"success", &ProofOfLockChange{Votes: []*Vote{v, v2}, PubKey: val3.PrivKey.PubKey()}, false, false},
  686. }
  687. for _, tc := range testCases {
  688. tc := tc
  689. pbpolc, err := tc.polc.ToProto()
  690. if tc.toProtoErr {
  691. assert.Error(t, err, tc.msg)
  692. } else {
  693. assert.NoError(t, err, tc.msg)
  694. }
  695. c, err := ProofOfLockChangeFromProto(pbpolc)
  696. if !tc.fromProtoErr {
  697. assert.NoError(t, err, tc.msg)
  698. if !tc.toProtoErr {
  699. assert.Equal(t, tc.polc, c, tc.msg)
  700. }
  701. } else {
  702. assert.Error(t, err, tc.msg)
  703. }
  704. }
  705. }