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.

292 lines
8.5 KiB

7 years ago
  1. package evidence
  2. import (
  3. "os"
  4. "testing"
  5. "time"
  6. "github.com/stretchr/testify/assert"
  7. "github.com/stretchr/testify/require"
  8. dbm "github.com/tendermint/tm-db"
  9. sm "github.com/tendermint/tendermint/state"
  10. "github.com/tendermint/tendermint/store"
  11. "github.com/tendermint/tendermint/types"
  12. tmtime "github.com/tendermint/tendermint/types/time"
  13. )
  14. func TestMain(m *testing.M) {
  15. RegisterMockEvidences()
  16. code := m.Run()
  17. os.Exit(code)
  18. }
  19. func TestEvidencePool(t *testing.T) {
  20. var (
  21. valAddr = []byte("val1")
  22. height = int64(52)
  23. stateDB = initializeValidatorState(valAddr, height)
  24. evidenceDB = dbm.NewMemDB()
  25. blockStoreDB = dbm.NewMemDB()
  26. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
  27. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  28. goodEvidence = types.NewMockEvidence(height, time.Now(), valAddr)
  29. badEvidence = types.NewMockEvidence(1, evidenceTime, valAddr)
  30. )
  31. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  32. require.NoError(t, err)
  33. // bad evidence
  34. err = pool.AddEvidence(badEvidence)
  35. if assert.Error(t, err) {
  36. assert.Contains(t, err.Error(), "is too old; min height is 32 and evidence can not be older than")
  37. }
  38. assert.False(t, pool.IsPending(badEvidence))
  39. assert.True(t, pool.IsExpired(badEvidence))
  40. // good evidence
  41. evAdded := make(chan struct{})
  42. go func() {
  43. <-pool.EvidenceWaitChan()
  44. close(evAdded)
  45. }()
  46. err = pool.AddEvidence(goodEvidence)
  47. require.NoError(t, err)
  48. select {
  49. case <-evAdded:
  50. case <-time.After(5 * time.Second):
  51. t.Fatal("evidence was not added to list after 5s")
  52. }
  53. assert.Equal(t, 1, pool.evidenceList.Len())
  54. // if we send it again, it shouldnt add and return an error
  55. err = pool.AddEvidence(goodEvidence)
  56. assert.NoError(t, err)
  57. assert.Equal(t, 1, pool.evidenceList.Len())
  58. }
  59. func TestProposingAndCommittingEvidence(t *testing.T) {
  60. var (
  61. valAddr = []byte("validator_address")
  62. height = int64(1)
  63. lastBlockTime = time.Now()
  64. stateDB = initializeValidatorState(valAddr, height)
  65. evidenceDB = dbm.NewMemDB()
  66. blockStoreDB = dbm.NewMemDB()
  67. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
  68. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  69. )
  70. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  71. require.NoError(t, err)
  72. // evidence not seen yet:
  73. evidence := types.NewMockEvidence(height, evidenceTime, valAddr)
  74. assert.False(t, pool.IsCommitted(evidence))
  75. // evidence seen but not yet committed:
  76. assert.NoError(t, pool.AddEvidence(evidence))
  77. assert.False(t, pool.IsCommitted(evidence))
  78. // test evidence is proposed
  79. proposedEvidence := pool.AllPendingEvidence()
  80. assert.Equal(t, proposedEvidence[0], evidence)
  81. // evidence seen and committed:
  82. pool.MarkEvidenceAsCommitted(height, lastBlockTime, proposedEvidence)
  83. assert.True(t, pool.IsCommitted(evidence))
  84. assert.False(t, pool.IsPending(evidence))
  85. assert.Equal(t, 0, pool.evidenceList.Len())
  86. // evidence should
  87. }
  88. func TestEvidencePoolAddEvidence(t *testing.T) {
  89. var (
  90. valAddr = []byte("val1")
  91. height = int64(30)
  92. stateDB = initializeValidatorState(valAddr, height)
  93. evidenceDB = dbm.NewMemDB()
  94. blockStoreDB = dbm.NewMemDB()
  95. blockStore = initializeBlockStore(blockStoreDB, sm.LoadState(stateDB), valAddr)
  96. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  97. )
  98. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  99. require.NoError(t, err)
  100. testCases := []struct {
  101. evHeight int64
  102. evTime time.Time
  103. expErr bool
  104. evDescription string
  105. }{
  106. {height, time.Now(), false, "valid evidence"},
  107. {height, evidenceTime, false, "valid evidence (despite old time)"},
  108. {int64(1), time.Now(), false, "valid evidence (despite old height)"},
  109. {int64(1), evidenceTime, true,
  110. "evidence from height 1 (created at: 2019-01-01 00:00:00 +0000 UTC) is too old"},
  111. }
  112. for _, tc := range testCases {
  113. tc := tc
  114. t.Run(tc.evDescription, func(t *testing.T) {
  115. ev := types.NewMockEvidence(tc.evHeight, tc.evTime, valAddr)
  116. err := pool.AddEvidence(ev)
  117. if tc.expErr {
  118. assert.Error(t, err)
  119. t.Log(err)
  120. }
  121. })
  122. }
  123. }
  124. func TestEvidencePoolUpdate(t *testing.T) {
  125. var (
  126. valAddr = []byte("validator_address")
  127. height = int64(1)
  128. stateDB = initializeValidatorState(valAddr, height)
  129. evidenceDB = dbm.NewMemDB()
  130. blockStoreDB = dbm.NewMemDB()
  131. state = sm.LoadState(stateDB)
  132. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  133. )
  134. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  135. require.NoError(t, err)
  136. // create new block (no need to save it to blockStore)
  137. evidence := types.NewMockEvidence(height, time.Now(), valAddr)
  138. lastCommit := makeCommit(height, valAddr)
  139. block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{evidence})
  140. // update state (partially)
  141. state.LastBlockHeight = height + 1
  142. pool.Update(block, state)
  143. // a) Update marks evidence as committed
  144. assert.True(t, pool.IsCommitted(evidence))
  145. // b) Update updates valToLastHeight map
  146. assert.Equal(t, height+1, pool.ValidatorLastHeight(valAddr))
  147. }
  148. func TestEvidencePoolNewPool(t *testing.T) {
  149. var (
  150. valAddr = []byte("validator_address")
  151. height = int64(1)
  152. stateDB = initializeValidatorState(valAddr, height)
  153. evidenceDB = dbm.NewMemDB()
  154. blockStoreDB = dbm.NewMemDB()
  155. state = sm.LoadState(stateDB)
  156. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  157. )
  158. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  159. require.NoError(t, err)
  160. assert.Equal(t, height, pool.ValidatorLastHeight(valAddr))
  161. assert.EqualValues(t, 0, pool.ValidatorLastHeight([]byte("non-existent-validator")))
  162. }
  163. func TestRecoverPendingEvidence(t *testing.T) {
  164. var (
  165. valAddr = []byte("val1")
  166. height = int64(30)
  167. stateDB = initializeValidatorState(valAddr, height)
  168. evidenceDB = dbm.NewMemDB()
  169. blockStoreDB = dbm.NewMemDB()
  170. state = sm.LoadState(stateDB)
  171. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  172. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  173. goodEvidence = types.NewMockEvidence(height, time.Now(), valAddr)
  174. expiredEvidence = types.NewMockEvidence(int64(1), evidenceTime, valAddr)
  175. )
  176. // load good evidence
  177. goodKey := keyPending(goodEvidence)
  178. goodEvidenceBytes := cdc.MustMarshalBinaryBare(goodEvidence)
  179. _ = evidenceDB.Set(goodKey, goodEvidenceBytes)
  180. // load expired evidence
  181. expiredKey := keyPending(expiredEvidence)
  182. expiredEvidenceBytes := cdc.MustMarshalBinaryBare(expiredEvidence)
  183. _ = evidenceDB.Set(expiredKey, expiredEvidenceBytes)
  184. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  185. require.NoError(t, err)
  186. assert.Equal(t, 1, pool.evidenceList.Len())
  187. assert.True(t, pool.IsPending(goodEvidence))
  188. }
  189. func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
  190. stateDB := dbm.NewMemDB()
  191. // create validator set and state
  192. valSet := &types.ValidatorSet{
  193. Validators: []*types.Validator{
  194. {Address: valAddr, VotingPower: 0},
  195. },
  196. }
  197. state := sm.State{
  198. LastBlockHeight: height,
  199. LastBlockTime: tmtime.Now(),
  200. LastValidators: valSet,
  201. Validators: valSet,
  202. NextValidators: valSet.CopyIncrementProposerPriority(1),
  203. LastHeightValidatorsChanged: 1,
  204. ConsensusParams: types.ConsensusParams{
  205. Block: types.BlockParams{
  206. MaxBytes: 22020096,
  207. MaxGas: -1,
  208. },
  209. Evidence: types.EvidenceParams{
  210. MaxAgeNumBlocks: 20,
  211. MaxAgeDuration: 48 * time.Hour,
  212. },
  213. },
  214. }
  215. // save all states up to height
  216. for i := int64(0); i <= height; i++ {
  217. state.LastBlockHeight = i
  218. sm.SaveState(stateDB, state)
  219. }
  220. return stateDB
  221. }
  222. // initializeBlockStore creates a block storage and populates it w/ a dummy
  223. // block at +height+.
  224. func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore {
  225. blockStore := store.NewBlockStore(db)
  226. for i := int64(1); i <= state.LastBlockHeight; i++ {
  227. lastCommit := makeCommit(i-1, valAddr)
  228. block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil,
  229. state.Validators.GetProposer().Address)
  230. const parts = 1
  231. partSet := block.MakePartSet(parts)
  232. seenCommit := makeCommit(i, valAddr)
  233. blockStore.SaveBlock(block, partSet, seenCommit)
  234. }
  235. return blockStore
  236. }
  237. func makeCommit(height int64, valAddr []byte) *types.Commit {
  238. commitSigs := []types.CommitSig{{
  239. BlockIDFlag: types.BlockIDFlagCommit,
  240. ValidatorAddress: valAddr,
  241. Timestamp: time.Now(),
  242. Signature: []byte("Signature"),
  243. }}
  244. return types.NewCommit(height, 0, types.BlockID{}, commitSigs)
  245. }