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.

565 lines
18 KiB

7 years ago
  1. package evidence
  2. import (
  3. "os"
  4. "testing"
  5. "time"
  6. "github.com/gogo/protobuf/proto"
  7. "github.com/stretchr/testify/assert"
  8. "github.com/stretchr/testify/require"
  9. dbm "github.com/tendermint/tm-db"
  10. "github.com/tendermint/tendermint/crypto/tmhash"
  11. "github.com/tendermint/tendermint/libs/bytes"
  12. "github.com/tendermint/tendermint/libs/log"
  13. tmrand "github.com/tendermint/tendermint/libs/rand"
  14. tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
  15. sm "github.com/tendermint/tendermint/state"
  16. "github.com/tendermint/tendermint/store"
  17. "github.com/tendermint/tendermint/types"
  18. tmtime "github.com/tendermint/tendermint/types/time"
  19. )
  20. func TestMain(m *testing.M) {
  21. code := m.Run()
  22. os.Exit(code)
  23. }
  24. const evidenceChainID = "test_chain"
  25. func TestEvidencePool(t *testing.T) {
  26. var (
  27. val = types.NewMockPV()
  28. valAddr = val.PrivKey.PubKey().Address()
  29. height = int64(52)
  30. stateDB = initializeValidatorState(val, height)
  31. evidenceDB = dbm.NewMemDB()
  32. blockStoreDB = dbm.NewMemDB()
  33. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
  34. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  35. goodEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(height, evidenceTime, val, evidenceChainID)
  36. badEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(1, evidenceTime, val, evidenceChainID)
  37. )
  38. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  39. require.NoError(t, err)
  40. // bad evidence
  41. err = pool.AddEvidence(badEvidence)
  42. if assert.Error(t, err) {
  43. assert.Contains(t, err.Error(), "is too old; min height is 32 and evidence can not be older than")
  44. }
  45. assert.False(t, pool.IsPending(badEvidence))
  46. assert.True(t, pool.IsEvidenceExpired(badEvidence))
  47. // good evidence
  48. evAdded := make(chan struct{})
  49. go func() {
  50. <-pool.EvidenceWaitChan()
  51. close(evAdded)
  52. }()
  53. err = pool.AddEvidence(goodEvidence)
  54. require.NoError(t, err)
  55. select {
  56. case <-evAdded:
  57. case <-time.After(5 * time.Second):
  58. t.Fatal("evidence was not added to list after 5s")
  59. }
  60. assert.Equal(t, 1, pool.evidenceList.Len())
  61. // if we send it again, it shouldnt add and return an error
  62. err = pool.AddEvidence(goodEvidence)
  63. assert.NoError(t, err)
  64. assert.Equal(t, 1, pool.evidenceList.Len())
  65. }
  66. func TestProposingAndCommittingEvidence(t *testing.T) {
  67. var (
  68. val = types.NewMockPV()
  69. height = int64(1)
  70. stateDB = initializeValidatorState(val, height)
  71. evidenceDB = dbm.NewMemDB()
  72. blockStoreDB = dbm.NewMemDB()
  73. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), val.PrivKey.PubKey().Address())
  74. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  75. )
  76. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  77. require.NoError(t, err)
  78. // evidence not seen yet:
  79. evidence := types.NewMockDuplicateVoteEvidenceWithValidator(height, evidenceTime, val, evidenceChainID)
  80. assert.False(t, pool.IsCommitted(evidence))
  81. // evidence seen but not yet committed:
  82. assert.NoError(t, pool.AddEvidence(evidence))
  83. assert.False(t, pool.IsCommitted(evidence))
  84. // test evidence is proposed
  85. proposedEvidence := pool.AllPendingEvidence()
  86. assert.Equal(t, proposedEvidence[0], evidence)
  87. // evidence seen and committed:
  88. pool.MarkEvidenceAsCommitted(height, proposedEvidence)
  89. assert.True(t, pool.IsCommitted(evidence))
  90. assert.False(t, pool.IsPending(evidence))
  91. assert.Equal(t, 0, pool.evidenceList.Len())
  92. // evidence should
  93. }
  94. func TestAddEvidence(t *testing.T) {
  95. var (
  96. val = types.NewMockPV()
  97. valAddr = val.PrivKey.PubKey().Address()
  98. height = int64(30)
  99. stateDB = initializeValidatorState(val, height)
  100. evidenceDB = dbm.NewMemDB()
  101. blockStoreDB = dbm.NewMemDB()
  102. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
  103. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  104. )
  105. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  106. require.NoError(t, err)
  107. testCases := []struct {
  108. evHeight int64
  109. evTime time.Time
  110. expErr bool
  111. evDescription string
  112. }{
  113. {height, time.Now(), false, "valid evidence"},
  114. {height, evidenceTime, false, "valid evidence (despite old time)"},
  115. {int64(1), time.Now(), false, "valid evidence (despite old height)"},
  116. {int64(1), evidenceTime, true,
  117. "evidence from height 1 (created at: 2019-01-01 00:00:00 +0000 UTC) is too old"},
  118. }
  119. for _, tc := range testCases {
  120. tc := tc
  121. t.Run(tc.evDescription, func(t *testing.T) {
  122. ev := types.NewMockDuplicateVoteEvidence(tc.evHeight, tc.evTime, evidenceChainID)
  123. err := pool.AddEvidence(ev)
  124. if tc.expErr {
  125. assert.Error(t, err)
  126. t.Log(err)
  127. }
  128. })
  129. }
  130. }
  131. func TestEvidencePoolUpdate(t *testing.T) {
  132. var (
  133. val = types.NewMockPV()
  134. valAddr = val.PrivKey.PubKey().Address()
  135. height = int64(21)
  136. stateDB = initializeValidatorState(val, height)
  137. evidenceDB = dbm.NewMemDB()
  138. blockStoreDB = dbm.NewMemDB()
  139. state = sm.LoadState(stateDB)
  140. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  141. )
  142. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  143. require.NoError(t, err)
  144. // create new block (no need to save it to blockStore)
  145. evidence := types.NewMockDuplicateVoteEvidence(height, time.Now(), evidenceChainID)
  146. lastCommit := makeCommit(height, valAddr)
  147. block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{evidence})
  148. // update state (partially)
  149. state.LastBlockHeight = height + 1
  150. pool.Update(block, state)
  151. // a) Update marks evidence as committed
  152. assert.True(t, pool.IsCommitted(evidence))
  153. }
  154. func TestAddingAndPruningPOLC(t *testing.T) {
  155. var (
  156. val = types.NewMockPV()
  157. valAddr = val.PrivKey.PubKey().Address()
  158. stateDB = initializeValidatorState(val, 1)
  159. evidenceDB = dbm.NewMemDB()
  160. blockStoreDB = dbm.NewMemDB()
  161. state = sm.LoadState(stateDB)
  162. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  163. height = state.ConsensusParams.Evidence.MaxAgeNumBlocks * 2
  164. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  165. firstBlockID = types.BlockID{
  166. Hash: tmrand.Bytes(tmhash.Size),
  167. PartSetHeader: types.PartSetHeader{
  168. Total: 1,
  169. Hash: tmrand.Bytes(tmhash.Size),
  170. },
  171. }
  172. )
  173. voteA := makeVote(1, 1, 0, val.PrivKey.PubKey().Address(), firstBlockID, evidenceTime)
  174. vA := voteA.ToProto()
  175. err := val.SignVote(evidenceChainID, vA)
  176. require.NoError(t, err)
  177. voteA.Signature = vA.Signature
  178. pubKey, _ := types.NewMockPV().GetPubKey()
  179. polc := &types.ProofOfLockChange{
  180. Votes: []*types.Vote{voteA},
  181. PubKey: pubKey,
  182. }
  183. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  184. require.NoError(t, err)
  185. err = pool.AddPOLC(polc)
  186. assert.NoError(t, err)
  187. // should be able to retrieve polc
  188. newPolc, err := pool.RetrievePOLC(1, 1)
  189. assert.NoError(t, err)
  190. assert.True(t, polc.Equal(newPolc))
  191. // should not be able to retrieve because it doesn't exist
  192. emptyPolc, err := pool.RetrievePOLC(2, 1)
  193. assert.NoError(t, err)
  194. assert.Nil(t, emptyPolc)
  195. lastCommit := makeCommit(height-1, valAddr)
  196. block := types.MakeBlock(height, []types.Tx{}, lastCommit, []types.Evidence{})
  197. // update state (partially)
  198. state.LastBlockHeight = height
  199. pool.state.LastBlockHeight = height
  200. // update should prune the polc
  201. pool.Update(block, state)
  202. emptyPolc, err = pool.RetrievePOLC(1, 1)
  203. assert.NoError(t, err)
  204. assert.Nil(t, emptyPolc)
  205. }
  206. func TestRecoverPendingEvidence(t *testing.T) {
  207. var (
  208. val = types.NewMockPV()
  209. valAddr = val.PrivKey.PubKey().Address()
  210. height = int64(30)
  211. stateDB = initializeValidatorState(val, height)
  212. evidenceDB = dbm.NewMemDB()
  213. blockStoreDB = dbm.NewMemDB()
  214. state = sm.LoadState(stateDB)
  215. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  216. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  217. goodEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(height, time.Now(), val, evidenceChainID)
  218. expiredEvidence = types.NewMockDuplicateVoteEvidenceWithValidator(int64(1), evidenceTime, val, evidenceChainID)
  219. )
  220. // load good evidence
  221. goodKey := keyPending(goodEvidence)
  222. evi, err := types.EvidenceToProto(goodEvidence)
  223. require.NoError(t, err)
  224. goodEvidenceBytes, err := proto.Marshal(evi)
  225. require.NoError(t, err)
  226. _ = evidenceDB.Set(goodKey, goodEvidenceBytes)
  227. // load expired evidence
  228. expiredKey := keyPending(expiredEvidence)
  229. eevi, err := types.EvidenceToProto(expiredEvidence)
  230. require.NoError(t, err)
  231. expiredEvidenceBytes, err := proto.Marshal(eevi)
  232. require.NoError(t, err)
  233. _ = evidenceDB.Set(expiredKey, expiredEvidenceBytes)
  234. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  235. require.NoError(t, err)
  236. assert.Equal(t, 1, pool.evidenceList.Len())
  237. assert.True(t, pool.IsPending(goodEvidence))
  238. }
  239. // Comprehensive set of test cases relating to the adding, upgrading and overall
  240. // processing of PotentialAmnesiaEvidence and AmnesiaEvidence
  241. func TestAddingPotentialAmnesiaEvidence(t *testing.T) {
  242. var (
  243. val = types.NewMockPV()
  244. val2 = types.NewMockPV()
  245. pubKey = val.PrivKey.PubKey()
  246. pubKey2 = val2.PrivKey.PubKey()
  247. valSet = &types.ValidatorSet{
  248. Validators: []*types.Validator{
  249. val.ExtractIntoValidator(1),
  250. val2.ExtractIntoValidator(3),
  251. },
  252. Proposer: val.ExtractIntoValidator(1),
  253. }
  254. height = int64(30)
  255. stateDB = initializeStateFromValidatorSet(valSet, height)
  256. evidenceDB = dbm.NewMemDB()
  257. blockStoreDB = dbm.NewMemDB()
  258. state = sm.LoadState(stateDB)
  259. blockStore = initializeBlockStore(blockStoreDB, state, pubKey.Address())
  260. //evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  261. firstBlockID = types.BlockID{
  262. Hash: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
  263. PartSetHeader: types.PartSetHeader{
  264. Total: 1,
  265. Hash: []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
  266. },
  267. }
  268. secondBlockID = types.BlockID{
  269. Hash: []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
  270. PartSetHeader: types.PartSetHeader{
  271. Total: 1,
  272. Hash: []byte("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
  273. },
  274. }
  275. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  276. )
  277. // TEST SETUP
  278. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  279. require.NoError(t, err)
  280. pool.SetLogger(log.TestingLogger())
  281. voteA := makeVote(height, 0, 0, pubKey.Address(), firstBlockID, evidenceTime)
  282. vA := voteA.ToProto()
  283. err = val.SignVote(evidenceChainID, vA)
  284. voteA.Signature = vA.Signature
  285. require.NoError(t, err)
  286. voteB := makeVote(height, 1, 0, pubKey.Address(), secondBlockID, evidenceTime.Add(3*time.Second))
  287. vB := voteB.ToProto()
  288. err = val.SignVote(evidenceChainID, vB)
  289. voteB.Signature = vB.Signature
  290. require.NoError(t, err)
  291. voteC := makeVote(height, 2, 0, pubKey.Address(), firstBlockID, evidenceTime.Add(2*time.Second))
  292. vC := voteC.ToProto()
  293. err = val.SignVote(evidenceChainID, vC)
  294. voteC.Signature = vC.Signature
  295. require.NoError(t, err)
  296. ev := &types.PotentialAmnesiaEvidence{
  297. VoteA: voteA,
  298. VoteB: voteB,
  299. }
  300. polc := &types.ProofOfLockChange{
  301. Votes: []*types.Vote{voteB},
  302. PubKey: pubKey2,
  303. }
  304. err = pool.AddPOLC(polc)
  305. require.NoError(t, err)
  306. polc, err = pool.RetrievePOLC(height, 1)
  307. require.NoError(t, err)
  308. require.NotEmpty(t, polc)
  309. secondValVote := makeVote(height, 1, 0, pubKey2.Address(), secondBlockID, evidenceTime.Add(1*time.Second))
  310. vv2 := secondValVote.ToProto()
  311. err = val2.SignVote(evidenceChainID, vv2)
  312. require.NoError(t, err)
  313. secondValVote.Signature = vv2.Signature
  314. validPolc := &types.ProofOfLockChange{
  315. Votes: []*types.Vote{secondValVote},
  316. PubKey: pubKey,
  317. }
  318. // CASE A
  319. pool.logger.Info("CASE A")
  320. // we expect the evidence pool to find the polc but log an error as the polc is not valid -> vote was
  321. // not from a validator in this set. However, an error isn't thrown because the evidence pool
  322. // should still be able to save the regular potential amnesia evidence.
  323. err = pool.AddEvidence(ev)
  324. assert.NoError(t, err)
  325. // evidence requires trial period until it is available -> we expect no evidence to be returned
  326. assert.Equal(t, 0, len(pool.PendingEvidence(1)))
  327. assert.True(t, pool.IsOnTrial(ev))
  328. nextHeight := pool.nextEvidenceTrialEndedHeight
  329. assert.Greater(t, nextHeight, int64(0))
  330. // CASE B
  331. pool.logger.Info("CASE B")
  332. // evidence is not ready to be upgraded so we return the height we expect the evidence to be.
  333. nextHeight = pool.upgradePotentialAmnesiaEvidence()
  334. assert.Equal(t, height+pool.state.ConsensusParams.Evidence.ProofTrialPeriod, nextHeight)
  335. // CASE C
  336. pool.logger.Info("CASE C")
  337. // now evidence is ready to be upgraded to amnesia evidence -> we expect -1 to be the next height as their is
  338. // no more pending potential amnesia evidence left
  339. lastCommit := makeCommit(height+1, pubKey.Address())
  340. block := types.MakeBlock(height+2, []types.Tx{}, lastCommit, []types.Evidence{})
  341. state.LastBlockHeight = height + 2
  342. pool.Update(block, state)
  343. assert.Equal(t, int64(-1), pool.nextEvidenceTrialEndedHeight)
  344. assert.Equal(t, 1, len(pool.PendingEvidence(1)))
  345. // CASE D
  346. pool.logger.Info("CASE D")
  347. // evidence of voting back in the past which is instantly punishable -> amnesia evidence is made directly
  348. ev2 := &types.PotentialAmnesiaEvidence{
  349. VoteA: voteC,
  350. VoteB: voteB,
  351. }
  352. err = pool.AddEvidence(ev2)
  353. assert.NoError(t, err)
  354. expectedAe := &types.AmnesiaEvidence{
  355. PotentialAmnesiaEvidence: ev2,
  356. Polc: types.NewEmptyPOLC(),
  357. }
  358. assert.True(t, pool.IsPending(expectedAe))
  359. assert.Equal(t, 2, len(pool.AllPendingEvidence()))
  360. // CASE E
  361. pool.logger.Info("CASE E")
  362. // test for receiving amnesia evidence
  363. ae := types.NewAmnesiaEvidence(ev, types.NewEmptyPOLC())
  364. // we need to run the trial period ourselves so amnesia evidence should not be added, instead
  365. // we should extract out the potential amnesia evidence and trying to add that before realising
  366. // that we already have it -> no error
  367. err = pool.AddEvidence(ae)
  368. assert.NoError(t, err)
  369. assert.Equal(t, 2, len(pool.AllPendingEvidence()))
  370. voteD := makeVote(height, 2, 0, pubKey.Address(), firstBlockID, evidenceTime.Add(4*time.Second))
  371. vD := voteD.ToProto()
  372. err = val.SignVote(evidenceChainID, vD)
  373. require.NoError(t, err)
  374. voteD.Signature = vD.Signature
  375. // CASE F
  376. pool.logger.Info("CASE F")
  377. // a new amnesia evidence is seen. It has an empty polc so we should extract the potential amnesia evidence
  378. // and start our own trial
  379. newPe := &types.PotentialAmnesiaEvidence{
  380. VoteA: voteB,
  381. VoteB: voteD,
  382. }
  383. newAe := &types.AmnesiaEvidence{
  384. PotentialAmnesiaEvidence: newPe,
  385. Polc: types.NewEmptyPOLC(),
  386. }
  387. err = pool.AddEvidence(newAe)
  388. assert.NoError(t, err)
  389. assert.Equal(t, 2, len(pool.AllPendingEvidence()))
  390. assert.True(t, pool.IsOnTrial(newPe))
  391. // CASE G
  392. pool.logger.Info("CASE G")
  393. // Finally, we receive an amnesia evidence containing a valid polc for an earlier potential amnesia evidence
  394. // that we have already upgraded to. We should ad this new amnesia evidence in replace of the prior
  395. // amnesia evidence with an empty polc that we have
  396. aeWithPolc := &types.AmnesiaEvidence{
  397. PotentialAmnesiaEvidence: ev,
  398. Polc: validPolc,
  399. }
  400. err = pool.AddEvidence(aeWithPolc)
  401. assert.NoError(t, err)
  402. assert.True(t, pool.IsPending(aeWithPolc))
  403. assert.Equal(t, 2, len(pool.AllPendingEvidence()))
  404. t.Log(pool.AllPendingEvidence())
  405. }
  406. func initializeStateFromValidatorSet(valSet *types.ValidatorSet, height int64) dbm.DB {
  407. stateDB := dbm.NewMemDB()
  408. state := sm.State{
  409. ChainID: evidenceChainID,
  410. LastBlockHeight: height,
  411. LastBlockTime: tmtime.Now(),
  412. Validators: valSet,
  413. NextValidators: valSet.CopyIncrementProposerPriority(1),
  414. LastValidators: valSet,
  415. LastHeightValidatorsChanged: 1,
  416. ConsensusParams: tmproto.ConsensusParams{
  417. Block: tmproto.BlockParams{
  418. MaxBytes: 22020096,
  419. MaxGas: -1,
  420. },
  421. Evidence: tmproto.EvidenceParams{
  422. MaxAgeNumBlocks: 20,
  423. MaxAgeDuration: 48 * time.Hour,
  424. MaxNum: 50,
  425. ProofTrialPeriod: 1,
  426. },
  427. },
  428. }
  429. // save all states up to height
  430. for i := int64(0); i <= height; i++ {
  431. state.LastBlockHeight = i
  432. sm.SaveState(stateDB, state)
  433. }
  434. return stateDB
  435. }
  436. func initializeValidatorState(privVal types.PrivValidator, height int64) dbm.DB {
  437. pubKey, _ := privVal.GetPubKey()
  438. validator := &types.Validator{Address: pubKey.Address(), VotingPower: 0, PubKey: pubKey}
  439. // create validator set and state
  440. valSet := &types.ValidatorSet{
  441. Validators: []*types.Validator{validator},
  442. Proposer: validator,
  443. }
  444. return initializeStateFromValidatorSet(valSet, height)
  445. }
  446. // initializeBlockStore creates a block storage and populates it w/ a dummy
  447. // block at +height+.
  448. func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore {
  449. blockStore := store.NewBlockStore(db)
  450. for i := int64(1); i <= state.LastBlockHeight; i++ {
  451. lastCommit := makeCommit(i-1, valAddr)
  452. block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil,
  453. state.Validators.GetProposer().Address)
  454. const parts = 1
  455. partSet := block.MakePartSet(parts)
  456. seenCommit := makeCommit(i, valAddr)
  457. blockStore.SaveBlock(block, partSet, seenCommit)
  458. }
  459. return blockStore
  460. }
  461. func makeCommit(height int64, valAddr []byte) *types.Commit {
  462. commitSigs := []types.CommitSig{{
  463. BlockIDFlag: types.BlockIDFlagCommit,
  464. ValidatorAddress: valAddr,
  465. Timestamp: time.Now(),
  466. Signature: []byte("Signature"),
  467. }}
  468. return types.NewCommit(height, 0, types.BlockID{}, commitSigs)
  469. }
  470. func makeVote(height int64, round, index int32, addr bytes.HexBytes,
  471. blockID types.BlockID, time time.Time) *types.Vote {
  472. return &types.Vote{
  473. Type: tmproto.SignedMsgType(2),
  474. Height: height,
  475. Round: round,
  476. BlockID: blockID,
  477. Timestamp: time,
  478. ValidatorAddress: addr,
  479. ValidatorIndex: index,
  480. }
  481. }