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.

346 lines
10 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.IsEvidenceExpired(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 TestAddEvidence(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(21)
  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. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  134. )
  135. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  136. require.NoError(t, err)
  137. expiredEvidence := types.NewMockEvidence(1, evidenceTime, valAddr)
  138. err = pool.AddEvidence(expiredEvidence)
  139. require.NoError(t, err)
  140. // create new block (no need to save it to blockStore)
  141. evidence := types.NewMockEvidence(height, time.Now(), valAddr)
  142. lastCommit := makeCommit(height, valAddr)
  143. block := types.MakeBlock(height+1, []types.Tx{}, lastCommit, []types.Evidence{evidence})
  144. // update state (partially)
  145. state.LastBlockHeight = height + 1
  146. pool.Update(block, state)
  147. // a) Update marks evidence as committed
  148. assert.True(t, pool.IsCommitted(evidence))
  149. // b) Update updates valToLastHeight map
  150. assert.Equal(t, height+1, pool.ValidatorLastHeight(valAddr))
  151. // c) Expired ecvidence should be removed
  152. assert.False(t, pool.IsPending(expiredEvidence))
  153. }
  154. func TestEvidencePoolNewPool(t *testing.T) {
  155. var (
  156. valAddr = []byte("validator_address")
  157. height = int64(1)
  158. stateDB = initializeValidatorState(valAddr, height)
  159. evidenceDB = dbm.NewMemDB()
  160. blockStoreDB = dbm.NewMemDB()
  161. state = sm.LoadState(stateDB)
  162. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  163. )
  164. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  165. require.NoError(t, err)
  166. assert.Equal(t, height, pool.ValidatorLastHeight(valAddr))
  167. assert.EqualValues(t, 0, pool.ValidatorLastHeight([]byte("non-existent-validator")))
  168. }
  169. func TestAddingAndPruningPOLC(t *testing.T) {
  170. var (
  171. valAddr = []byte("validator_address")
  172. stateDB = initializeValidatorState(valAddr, 1)
  173. evidenceDB = dbm.NewMemDB()
  174. blockStoreDB = dbm.NewMemDB()
  175. state = sm.LoadState(stateDB)
  176. blockStore = initializeBlockStore(blockStoreDB, state, valAddr)
  177. height = state.ConsensusParams.Evidence.MaxAgeNumBlocks * 2
  178. evidenceTime = time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC)
  179. )
  180. pubKey, _ := types.NewMockPV().GetPubKey()
  181. polc := types.NewMockPOLC(1, evidenceTime, pubKey)
  182. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  183. require.NoError(t, err)
  184. err = pool.AddPOLC(polc)
  185. assert.NoError(t, err)
  186. // should be able to retrieve polc
  187. newPolc, err := pool.RetrievePOLC(1, 1)
  188. assert.NoError(t, err)
  189. assert.True(t, polc.Equal(newPolc))
  190. // should not be able to retrieve
  191. emptyPolc, err := pool.RetrievePOLC(2, 1)
  192. assert.Error(t, err)
  193. assert.Equal(t, types.ProofOfLockChange{}, emptyPolc)
  194. lastCommit := makeCommit(height-1, valAddr)
  195. block := types.MakeBlock(height, []types.Tx{}, lastCommit, []types.Evidence{})
  196. // update state (partially)
  197. state.LastBlockHeight = height
  198. pool.state.LastBlockHeight = height
  199. // update should prune the polc
  200. pool.Update(block, state)
  201. emptyPolc, err = pool.RetrievePOLC(1, 1)
  202. if assert.Error(t, err) {
  203. assert.Equal(t, "unable to find polc at height 1 and round 1", err.Error())
  204. }
  205. assert.Equal(t, types.ProofOfLockChange{}, emptyPolc)
  206. }
  207. func TestRecoverPendingEvidence(t *testing.T) {
  208. var (
  209. valAddr = []byte("val1")
  210. height = int64(30)
  211. stateDB = initializeValidatorState(valAddr, 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.NewMockEvidence(height, time.Now(), valAddr)
  218. expiredEvidence = types.NewMockEvidence(int64(1), evidenceTime, valAddr)
  219. )
  220. // load good evidence
  221. goodKey := keyPending(goodEvidence)
  222. goodEvidenceBytes := cdc.MustMarshalBinaryBare(goodEvidence)
  223. _ = evidenceDB.Set(goodKey, goodEvidenceBytes)
  224. // load expired evidence
  225. expiredKey := keyPending(expiredEvidence)
  226. expiredEvidenceBytes := cdc.MustMarshalBinaryBare(expiredEvidence)
  227. _ = evidenceDB.Set(expiredKey, expiredEvidenceBytes)
  228. pool, err := NewPool(stateDB, evidenceDB, blockStore)
  229. require.NoError(t, err)
  230. assert.Equal(t, 1, pool.evidenceList.Len())
  231. assert.True(t, pool.IsPending(goodEvidence))
  232. }
  233. func initializeValidatorState(valAddr []byte, height int64) dbm.DB {
  234. stateDB := dbm.NewMemDB()
  235. // create validator set and state
  236. valSet := &types.ValidatorSet{
  237. Validators: []*types.Validator{
  238. {Address: valAddr, VotingPower: 0},
  239. },
  240. }
  241. state := sm.State{
  242. LastBlockHeight: height,
  243. LastBlockTime: tmtime.Now(),
  244. LastValidators: valSet,
  245. Validators: valSet,
  246. NextValidators: valSet.CopyIncrementProposerPriority(1),
  247. LastHeightValidatorsChanged: 1,
  248. ConsensusParams: types.ConsensusParams{
  249. Block: types.BlockParams{
  250. MaxBytes: 22020096,
  251. MaxGas: -1,
  252. },
  253. Evidence: types.EvidenceParams{
  254. MaxAgeNumBlocks: 20,
  255. MaxAgeDuration: 48 * time.Hour,
  256. },
  257. },
  258. }
  259. // save all states up to height
  260. for i := int64(0); i <= height; i++ {
  261. state.LastBlockHeight = i
  262. sm.SaveState(stateDB, state)
  263. }
  264. return stateDB
  265. }
  266. // initializeBlockStore creates a block storage and populates it w/ a dummy
  267. // block at +height+.
  268. func initializeBlockStore(db dbm.DB, state sm.State, valAddr []byte) *store.BlockStore {
  269. blockStore := store.NewBlockStore(db)
  270. for i := int64(1); i <= state.LastBlockHeight; i++ {
  271. lastCommit := makeCommit(i-1, valAddr)
  272. block, _ := state.MakeBlock(i, []types.Tx{}, lastCommit, nil,
  273. state.Validators.GetProposer().Address)
  274. const parts = 1
  275. partSet := block.MakePartSet(parts)
  276. seenCommit := makeCommit(i, valAddr)
  277. blockStore.SaveBlock(block, partSet, seenCommit)
  278. }
  279. return blockStore
  280. }
  281. func makeCommit(height int64, valAddr []byte) *types.Commit {
  282. commitSigs := []types.CommitSig{{
  283. BlockIDFlag: types.BlockIDFlagCommit,
  284. ValidatorAddress: valAddr,
  285. Timestamp: time.Now(),
  286. Signature: []byte("Signature"),
  287. }}
  288. return types.NewCommit(height, 0, types.BlockID{}, commitSigs)
  289. }