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.

173 lines
4.4 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. package consensus
  2. import (
  3. "encoding/binary"
  4. "testing"
  5. "time"
  6. abci "github.com/tendermint/abci/types"
  7. "github.com/tendermint/tendermint/types"
  8. . "github.com/tendermint/tmlibs/common"
  9. )
  10. func init() {
  11. config = ResetConfig("consensus_mempool_test")
  12. }
  13. func TestNoProgressUntilTxsAvailable(t *testing.T) {
  14. config := ResetConfig("consensus_mempool_txs_available_test")
  15. config.Consensus.NoEmptyBlocks = true
  16. state, privVals := randGenesisState(1, false, 10)
  17. cs := newConsensusStateWithConfig(config, state, privVals[0], NewCounterApplication())
  18. cs.mempool.EnableTxsAvailable()
  19. height, round := cs.Height, cs.Round
  20. newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
  21. startTestRound(cs, height, round)
  22. ensureNewStep(newBlockCh) // first block gets committed
  23. ensureNoNewStep(newBlockCh)
  24. deliverTxsRange(cs, 0, 2)
  25. ensureNewStep(newBlockCh) // commit txs
  26. ensureNewStep(newBlockCh) // commit updated app hash
  27. ensureNoNewStep(newBlockCh)
  28. }
  29. func deliverTxsRange(cs *ConsensusState, start, end int) {
  30. // Deliver some txs.
  31. for i := start; i < end; i++ {
  32. txBytes := make([]byte, 8)
  33. binary.BigEndian.PutUint64(txBytes, uint64(i))
  34. err := cs.mempool.CheckTx(txBytes, nil)
  35. if err != nil {
  36. panic(Fmt("Error after CheckTx: %v", err))
  37. }
  38. }
  39. }
  40. func TestTxConcurrentWithCommit(t *testing.T) {
  41. state, privVals := randGenesisState(1, false, 10)
  42. cs := newConsensusState(state, privVals[0], NewCounterApplication())
  43. height, round := cs.Height, cs.Round
  44. newBlockCh := subscribeToEvent(cs.evsw, "tester", types.EventStringNewBlock(), 1)
  45. NTxs := 10000
  46. go deliverTxsRange(cs, 0, NTxs)
  47. startTestRound(cs, height, round)
  48. ticker := time.NewTicker(time.Second * 20)
  49. for nTxs := 0; nTxs < NTxs; {
  50. select {
  51. case b := <-newBlockCh:
  52. nTxs += b.(types.TMEventData).Unwrap().(types.EventDataNewBlock).Block.Header.NumTxs
  53. case <-ticker.C:
  54. panic("Timed out waiting to commit blocks with transactions")
  55. }
  56. }
  57. }
  58. func TestRmBadTx(t *testing.T) {
  59. state, privVals := randGenesisState(1, false, 10)
  60. app := NewCounterApplication()
  61. cs := newConsensusState(state, privVals[0], app)
  62. // increment the counter by 1
  63. txBytes := make([]byte, 8)
  64. binary.BigEndian.PutUint64(txBytes, uint64(0))
  65. app.DeliverTx(txBytes)
  66. app.Commit()
  67. ch := make(chan struct{})
  68. cbCh := make(chan struct{})
  69. go func() {
  70. // Try to send the tx through the mempool.
  71. // CheckTx should not err, but the app should return a bad abci code
  72. // and the tx should get removed from the pool
  73. err := cs.mempool.CheckTx(txBytes, func(r *abci.Response) {
  74. if r.GetCheckTx().Code != abci.CodeType_BadNonce {
  75. t.Fatalf("expected checktx to return bad nonce, got %v", r)
  76. }
  77. cbCh <- struct{}{}
  78. })
  79. if err != nil {
  80. t.Fatal("Error after CheckTx: %v", err)
  81. }
  82. // check for the tx
  83. for {
  84. time.Sleep(time.Second)
  85. txs := cs.mempool.Reap(1)
  86. if len(txs) == 0 {
  87. ch <- struct{}{}
  88. return
  89. }
  90. }
  91. }()
  92. // Wait until the tx returns
  93. ticker := time.After(time.Second * 5)
  94. select {
  95. case <-cbCh:
  96. // success
  97. case <-ticker:
  98. t.Fatalf("Timed out waiting for tx to return")
  99. }
  100. // Wait until the tx is removed
  101. ticker = time.After(time.Second * 5)
  102. select {
  103. case <-ch:
  104. // success
  105. case <-ticker:
  106. t.Fatalf("Timed out waiting for tx to be removed")
  107. }
  108. }
  109. // CounterApplication that maintains a mempool state and resets it upon commit
  110. type CounterApplication struct {
  111. abci.BaseApplication
  112. txCount int
  113. mempoolTxCount int
  114. }
  115. func NewCounterApplication() *CounterApplication {
  116. return &CounterApplication{}
  117. }
  118. func (app *CounterApplication) Info() abci.ResponseInfo {
  119. return abci.ResponseInfo{Data: Fmt("txs:%v", app.txCount)}
  120. }
  121. func (app *CounterApplication) DeliverTx(tx []byte) abci.Result {
  122. return runTx(tx, &app.txCount)
  123. }
  124. func (app *CounterApplication) CheckTx(tx []byte) abci.Result {
  125. return runTx(tx, &app.mempoolTxCount)
  126. }
  127. func runTx(tx []byte, countPtr *int) abci.Result {
  128. count := *countPtr
  129. tx8 := make([]byte, 8)
  130. copy(tx8[len(tx8)-len(tx):], tx)
  131. txValue := binary.BigEndian.Uint64(tx8)
  132. if txValue != uint64(count) {
  133. return abci.ErrBadNonce.AppendLog(Fmt("Invalid nonce. Expected %v, got %v", count, txValue))
  134. }
  135. *countPtr += 1
  136. return abci.OK
  137. }
  138. func (app *CounterApplication) Commit() abci.Result {
  139. app.mempoolTxCount = app.txCount
  140. if app.txCount == 0 {
  141. return abci.OK
  142. } else {
  143. hash := make([]byte, 8)
  144. binary.BigEndian.PutUint64(hash, uint64(app.txCount))
  145. return abci.NewResultOK(hash, "")
  146. }
  147. }