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.

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