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.

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