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.

631 lines
17 KiB

abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
abci: Synchronize FinalizeBlock with the updated specification (#7983) This change set implements the most recent version of `FinalizeBlock`. # What does this change actually contain? * This change set is rather large but fear not! The majority of the files touched and changes are renaming `ResponseDeliverTx` to `ExecTxResult`. This should be a pretty inoffensive change since they're effectively the same type but with a different name. * The `execBlockOnProxyApp` was totally removed since it served as just a wrapper around the logic that is now mostly encapsulated within `FinalizeBlock` * The `updateState` helper function has been made a public method on `State`. It was being exposed as a shim through the testing infrastructure, so this seemed innocuous. * Tests already existed to ensure that the application received the `ByzantineValidators` and the `ValidatorUpdates`, but one was fixed up to ensure that `LastCommitInfo` was being sent across. * Tests were removed from the `psql` indexer that seemed to search for an event in the indexer that was not being created. # Questions for reviewers * We store this [ABCIResponses](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/proto/tendermint/state/types.pb.go#L37) type in the data base as the block results. This type has changed since v0.35 to contain the `FinalizeBlock` response. I'm wondering if we need to do any shimming to keep the old data retrieveable? * Similarly, this change is exposed via the RPC through [ResultBlockResults](https://github.com/tendermint/tendermint/blob/5721a13ab1f4479f9807f449f0bf5c536b9a05f2/rpc/coretypes/responses.go#L69) changing. Should we somehow shim or notify for this change? closes: #7658
3 years ago
  1. package mempool
  2. import (
  3. "bytes"
  4. "context"
  5. "errors"
  6. "fmt"
  7. "math/rand"
  8. "os"
  9. "sort"
  10. "strconv"
  11. "strings"
  12. "sync"
  13. "testing"
  14. "time"
  15. "github.com/stretchr/testify/require"
  16. abciclient "github.com/tendermint/tendermint/abci/client"
  17. "github.com/tendermint/tendermint/abci/example/code"
  18. "github.com/tendermint/tendermint/abci/example/kvstore"
  19. abci "github.com/tendermint/tendermint/abci/types"
  20. "github.com/tendermint/tendermint/config"
  21. "github.com/tendermint/tendermint/libs/log"
  22. "github.com/tendermint/tendermint/types"
  23. )
  24. // application extends the KV store application by overriding CheckTx to provide
  25. // transaction priority based on the value in the key/value pair.
  26. type application struct {
  27. *kvstore.Application
  28. }
  29. type testTx struct {
  30. tx types.Tx
  31. priority int64
  32. }
  33. func (app *application) CheckTx(req abci.RequestCheckTx) abci.ResponseCheckTx {
  34. var (
  35. priority int64
  36. sender string
  37. )
  38. // infer the priority from the raw transaction value (sender=key=value)
  39. parts := bytes.Split(req.Tx, []byte("="))
  40. if len(parts) == 3 {
  41. v, err := strconv.ParseInt(string(parts[2]), 10, 64)
  42. if err != nil {
  43. return abci.ResponseCheckTx{
  44. Priority: priority,
  45. Code: 100,
  46. GasWanted: 1,
  47. }
  48. }
  49. priority = v
  50. sender = string(parts[0])
  51. } else {
  52. return abci.ResponseCheckTx{
  53. Priority: priority,
  54. Code: 101,
  55. GasWanted: 1,
  56. }
  57. }
  58. return abci.ResponseCheckTx{
  59. Priority: priority,
  60. Sender: sender,
  61. Code: code.CodeTypeOK,
  62. GasWanted: 1,
  63. }
  64. }
  65. func setup(ctx context.Context, t testing.TB, app abciclient.Client, cacheSize int, options ...TxMempoolOption) *TxMempool {
  66. t.Helper()
  67. logger := log.TestingLogger()
  68. cfg, err := config.ResetTestRoot(t.TempDir(), strings.ReplaceAll(t.Name(), "/", "|"))
  69. require.NoError(t, err)
  70. cfg.Mempool.CacheSize = cacheSize
  71. t.Cleanup(func() { os.RemoveAll(cfg.RootDir) })
  72. return NewTxMempool(logger.With("test", t.Name()), cfg.Mempool, app, options...)
  73. }
  74. func checkTxs(ctx context.Context, t *testing.T, txmp *TxMempool, numTxs int, peerID uint16) []testTx {
  75. t.Helper()
  76. txs := make([]testTx, numTxs)
  77. txInfo := TxInfo{SenderID: peerID}
  78. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  79. for i := 0; i < numTxs; i++ {
  80. prefix := make([]byte, 20)
  81. _, err := rng.Read(prefix)
  82. require.NoError(t, err)
  83. priority := int64(rng.Intn(9999-1000) + 1000)
  84. txs[i] = testTx{
  85. tx: []byte(fmt.Sprintf("sender-%d-%d=%X=%d", i, peerID, prefix, priority)),
  86. priority: priority,
  87. }
  88. require.NoError(t, txmp.CheckTx(ctx, txs[i].tx, nil, txInfo))
  89. }
  90. return txs
  91. }
  92. func convertTex(in []testTx) types.Txs {
  93. out := make([]types.Tx, len(in))
  94. for idx := range in {
  95. out[idx] = in[idx].tx
  96. }
  97. return out
  98. }
  99. func TestTxMempool_TxsAvailable(t *testing.T) {
  100. ctx, cancel := context.WithCancel(context.Background())
  101. defer cancel()
  102. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  103. if err := client.Start(ctx); err != nil {
  104. t.Fatal(err)
  105. }
  106. t.Cleanup(client.Wait)
  107. txmp := setup(ctx, t, client, 0)
  108. txmp.EnableTxsAvailable()
  109. ensureNoTxFire := func() {
  110. timer := time.NewTimer(500 * time.Millisecond)
  111. select {
  112. case <-txmp.TxsAvailable():
  113. require.Fail(t, "unexpected transactions event")
  114. case <-timer.C:
  115. }
  116. }
  117. ensureTxFire := func() {
  118. timer := time.NewTimer(500 * time.Millisecond)
  119. select {
  120. case <-txmp.TxsAvailable():
  121. case <-timer.C:
  122. require.Fail(t, "expected transactions event")
  123. }
  124. }
  125. // ensure no event as we have not executed any transactions yet
  126. ensureNoTxFire()
  127. // Execute CheckTx for some transactions and ensure TxsAvailable only fires
  128. // once.
  129. txs := checkTxs(ctx, t, txmp, 100, 0)
  130. ensureTxFire()
  131. ensureNoTxFire()
  132. rawTxs := make([]types.Tx, len(txs))
  133. for i, tx := range txs {
  134. rawTxs[i] = tx.tx
  135. }
  136. responses := make([]*abci.ExecTxResult, len(rawTxs[:50]))
  137. for i := 0; i < len(responses); i++ {
  138. responses[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
  139. }
  140. // commit half the transactions and ensure we fire an event
  141. txmp.Lock()
  142. require.NoError(t, txmp.Update(ctx, 1, rawTxs[:50], responses, nil, nil))
  143. txmp.Unlock()
  144. ensureTxFire()
  145. ensureNoTxFire()
  146. // Execute CheckTx for more transactions and ensure we do not fire another
  147. // event as we're still on the same height (1).
  148. _ = checkTxs(ctx, t, txmp, 100, 0)
  149. ensureNoTxFire()
  150. }
  151. func TestTxMempool_Size(t *testing.T) {
  152. ctx, cancel := context.WithCancel(context.Background())
  153. defer cancel()
  154. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  155. if err := client.Start(ctx); err != nil {
  156. t.Fatal(err)
  157. }
  158. t.Cleanup(client.Wait)
  159. txmp := setup(ctx, t, client, 0)
  160. txs := checkTxs(ctx, t, txmp, 100, 0)
  161. require.Equal(t, len(txs), txmp.Size())
  162. require.Equal(t, int64(5690), txmp.SizeBytes())
  163. rawTxs := make([]types.Tx, len(txs))
  164. for i, tx := range txs {
  165. rawTxs[i] = tx.tx
  166. }
  167. responses := make([]*abci.ExecTxResult, len(rawTxs[:50]))
  168. for i := 0; i < len(responses); i++ {
  169. responses[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
  170. }
  171. txmp.Lock()
  172. require.NoError(t, txmp.Update(ctx, 1, rawTxs[:50], responses, nil, nil))
  173. txmp.Unlock()
  174. require.Equal(t, len(rawTxs)/2, txmp.Size())
  175. require.Equal(t, int64(2850), txmp.SizeBytes())
  176. }
  177. func TestTxMempool_Flush(t *testing.T) {
  178. ctx, cancel := context.WithCancel(context.Background())
  179. defer cancel()
  180. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  181. if err := client.Start(ctx); err != nil {
  182. t.Fatal(err)
  183. }
  184. t.Cleanup(client.Wait)
  185. txmp := setup(ctx, t, client, 0)
  186. txs := checkTxs(ctx, t, txmp, 100, 0)
  187. require.Equal(t, len(txs), txmp.Size())
  188. require.Equal(t, int64(5690), txmp.SizeBytes())
  189. rawTxs := make([]types.Tx, len(txs))
  190. for i, tx := range txs {
  191. rawTxs[i] = tx.tx
  192. }
  193. responses := make([]*abci.ExecTxResult, len(rawTxs[:50]))
  194. for i := 0; i < len(responses); i++ {
  195. responses[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
  196. }
  197. txmp.Lock()
  198. require.NoError(t, txmp.Update(ctx, 1, rawTxs[:50], responses, nil, nil))
  199. txmp.Unlock()
  200. txmp.Flush()
  201. require.Zero(t, txmp.Size())
  202. require.Equal(t, int64(0), txmp.SizeBytes())
  203. }
  204. func TestTxMempool_ReapMaxBytesMaxGas(t *testing.T) {
  205. ctx, cancel := context.WithCancel(context.Background())
  206. defer cancel()
  207. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  208. if err := client.Start(ctx); err != nil {
  209. t.Fatal(err)
  210. }
  211. t.Cleanup(client.Wait)
  212. txmp := setup(ctx, t, client, 0)
  213. tTxs := checkTxs(ctx, t, txmp, 100, 0) // all txs request 1 gas unit
  214. require.Equal(t, len(tTxs), txmp.Size())
  215. require.Equal(t, int64(5690), txmp.SizeBytes())
  216. txMap := make(map[types.TxKey]testTx)
  217. priorities := make([]int64, len(tTxs))
  218. for i, tTx := range tTxs {
  219. txMap[tTx.tx.Key()] = tTx
  220. priorities[i] = tTx.priority
  221. }
  222. sort.Slice(priorities, func(i, j int) bool {
  223. // sort by priority, i.e. decreasing order
  224. return priorities[i] > priorities[j]
  225. })
  226. ensurePrioritized := func(reapedTxs types.Txs) {
  227. reapedPriorities := make([]int64, len(reapedTxs))
  228. for i, rTx := range reapedTxs {
  229. reapedPriorities[i] = txMap[rTx.Key()].priority
  230. }
  231. require.Equal(t, priorities[:len(reapedPriorities)], reapedPriorities)
  232. }
  233. // reap by gas capacity only
  234. reapedTxs := txmp.ReapMaxBytesMaxGas(-1, 50)
  235. ensurePrioritized(reapedTxs)
  236. require.Equal(t, len(tTxs), txmp.Size())
  237. require.Equal(t, int64(5690), txmp.SizeBytes())
  238. require.Len(t, reapedTxs, 50)
  239. // reap by transaction bytes only
  240. reapedTxs = txmp.ReapMaxBytesMaxGas(1000, -1)
  241. ensurePrioritized(reapedTxs)
  242. require.Equal(t, len(tTxs), txmp.Size())
  243. require.Equal(t, int64(5690), txmp.SizeBytes())
  244. require.GreaterOrEqual(t, len(reapedTxs), 16)
  245. // Reap by both transaction bytes and gas, where the size yields 31 reaped
  246. // transactions and the gas limit reaps 25 transactions.
  247. reapedTxs = txmp.ReapMaxBytesMaxGas(1500, 30)
  248. ensurePrioritized(reapedTxs)
  249. require.Equal(t, len(tTxs), txmp.Size())
  250. require.Equal(t, int64(5690), txmp.SizeBytes())
  251. require.Len(t, reapedTxs, 25)
  252. }
  253. func TestTxMempool_ReapMaxTxs(t *testing.T) {
  254. ctx, cancel := context.WithCancel(context.Background())
  255. defer cancel()
  256. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  257. if err := client.Start(ctx); err != nil {
  258. t.Fatal(err)
  259. }
  260. t.Cleanup(client.Wait)
  261. txmp := setup(ctx, t, client, 0)
  262. tTxs := checkTxs(ctx, t, txmp, 100, 0)
  263. require.Equal(t, len(tTxs), txmp.Size())
  264. require.Equal(t, int64(5690), txmp.SizeBytes())
  265. txMap := make(map[types.TxKey]testTx)
  266. priorities := make([]int64, len(tTxs))
  267. for i, tTx := range tTxs {
  268. txMap[tTx.tx.Key()] = tTx
  269. priorities[i] = tTx.priority
  270. }
  271. sort.Slice(priorities, func(i, j int) bool {
  272. // sort by priority, i.e. decreasing order
  273. return priorities[i] > priorities[j]
  274. })
  275. ensurePrioritized := func(reapedTxs types.Txs) {
  276. reapedPriorities := make([]int64, len(reapedTxs))
  277. for i, rTx := range reapedTxs {
  278. reapedPriorities[i] = txMap[rTx.Key()].priority
  279. }
  280. require.Equal(t, priorities[:len(reapedPriorities)], reapedPriorities)
  281. }
  282. // reap all transactions
  283. reapedTxs := txmp.ReapMaxTxs(-1)
  284. ensurePrioritized(reapedTxs)
  285. require.Equal(t, len(tTxs), txmp.Size())
  286. require.Equal(t, int64(5690), txmp.SizeBytes())
  287. require.Len(t, reapedTxs, len(tTxs))
  288. // reap a single transaction
  289. reapedTxs = txmp.ReapMaxTxs(1)
  290. ensurePrioritized(reapedTxs)
  291. require.Equal(t, len(tTxs), txmp.Size())
  292. require.Equal(t, int64(5690), txmp.SizeBytes())
  293. require.Len(t, reapedTxs, 1)
  294. // reap half of the transactions
  295. reapedTxs = txmp.ReapMaxTxs(len(tTxs) / 2)
  296. ensurePrioritized(reapedTxs)
  297. require.Equal(t, len(tTxs), txmp.Size())
  298. require.Equal(t, int64(5690), txmp.SizeBytes())
  299. require.Len(t, reapedTxs, len(tTxs)/2)
  300. }
  301. func TestTxMempool_CheckTxExceedsMaxSize(t *testing.T) {
  302. ctx, cancel := context.WithCancel(context.Background())
  303. defer cancel()
  304. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  305. if err := client.Start(ctx); err != nil {
  306. t.Fatal(err)
  307. }
  308. t.Cleanup(client.Wait)
  309. txmp := setup(ctx, t, client, 0)
  310. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  311. tx := make([]byte, txmp.config.MaxTxBytes+1)
  312. _, err := rng.Read(tx)
  313. require.NoError(t, err)
  314. require.Error(t, txmp.CheckTx(ctx, tx, nil, TxInfo{SenderID: 0}))
  315. tx = make([]byte, txmp.config.MaxTxBytes-1)
  316. _, err = rng.Read(tx)
  317. require.NoError(t, err)
  318. require.NoError(t, txmp.CheckTx(ctx, tx, nil, TxInfo{SenderID: 0}))
  319. }
  320. func TestTxMempool_CheckTxSamePeer(t *testing.T) {
  321. ctx, cancel := context.WithCancel(context.Background())
  322. defer cancel()
  323. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  324. if err := client.Start(ctx); err != nil {
  325. t.Fatal(err)
  326. }
  327. t.Cleanup(client.Wait)
  328. txmp := setup(ctx, t, client, 100)
  329. peerID := uint16(1)
  330. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  331. prefix := make([]byte, 20)
  332. _, err := rng.Read(prefix)
  333. require.NoError(t, err)
  334. tx := []byte(fmt.Sprintf("sender-0=%X=%d", prefix, 50))
  335. require.NoError(t, txmp.CheckTx(ctx, tx, nil, TxInfo{SenderID: peerID}))
  336. require.Error(t, txmp.CheckTx(ctx, tx, nil, TxInfo{SenderID: peerID}))
  337. }
  338. func TestTxMempool_CheckTxSameSender(t *testing.T) {
  339. ctx, cancel := context.WithCancel(context.Background())
  340. defer cancel()
  341. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  342. if err := client.Start(ctx); err != nil {
  343. t.Fatal(err)
  344. }
  345. t.Cleanup(client.Wait)
  346. txmp := setup(ctx, t, client, 100)
  347. peerID := uint16(1)
  348. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  349. prefix1 := make([]byte, 20)
  350. _, err := rng.Read(prefix1)
  351. require.NoError(t, err)
  352. prefix2 := make([]byte, 20)
  353. _, err = rng.Read(prefix2)
  354. require.NoError(t, err)
  355. tx1 := []byte(fmt.Sprintf("sender-0=%X=%d", prefix1, 50))
  356. tx2 := []byte(fmt.Sprintf("sender-0=%X=%d", prefix2, 50))
  357. require.NoError(t, txmp.CheckTx(ctx, tx1, nil, TxInfo{SenderID: peerID}))
  358. require.Equal(t, 1, txmp.Size())
  359. require.NoError(t, txmp.CheckTx(ctx, tx2, nil, TxInfo{SenderID: peerID}))
  360. require.Equal(t, 1, txmp.Size())
  361. }
  362. func TestTxMempool_ConcurrentTxs(t *testing.T) {
  363. ctx, cancel := context.WithCancel(context.Background())
  364. defer cancel()
  365. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  366. if err := client.Start(ctx); err != nil {
  367. t.Fatal(err)
  368. }
  369. t.Cleanup(client.Wait)
  370. txmp := setup(ctx, t, client, 100)
  371. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  372. checkTxDone := make(chan struct{})
  373. var wg sync.WaitGroup
  374. wg.Add(1)
  375. go func() {
  376. for i := 0; i < 20; i++ {
  377. _ = checkTxs(ctx, t, txmp, 100, 0)
  378. dur := rng.Intn(1000-500) + 500
  379. time.Sleep(time.Duration(dur) * time.Millisecond)
  380. }
  381. wg.Done()
  382. close(checkTxDone)
  383. }()
  384. wg.Add(1)
  385. go func() {
  386. ticker := time.NewTicker(time.Second)
  387. defer ticker.Stop()
  388. defer wg.Done()
  389. var height int64 = 1
  390. for range ticker.C {
  391. reapedTxs := txmp.ReapMaxTxs(200)
  392. if len(reapedTxs) > 0 {
  393. responses := make([]*abci.ExecTxResult, len(reapedTxs))
  394. for i := 0; i < len(responses); i++ {
  395. var code uint32
  396. if i%10 == 0 {
  397. code = 100
  398. } else {
  399. code = abci.CodeTypeOK
  400. }
  401. responses[i] = &abci.ExecTxResult{Code: code}
  402. }
  403. txmp.Lock()
  404. require.NoError(t, txmp.Update(ctx, height, reapedTxs, responses, nil, nil))
  405. txmp.Unlock()
  406. height++
  407. } else {
  408. // only return once we know we finished the CheckTx loop
  409. select {
  410. case <-checkTxDone:
  411. return
  412. default:
  413. }
  414. }
  415. }
  416. }()
  417. wg.Wait()
  418. require.Zero(t, txmp.Size())
  419. require.Zero(t, txmp.SizeBytes())
  420. }
  421. func TestTxMempool_ExpiredTxs_NumBlocks(t *testing.T) {
  422. ctx, cancel := context.WithCancel(context.Background())
  423. defer cancel()
  424. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  425. if err := client.Start(ctx); err != nil {
  426. t.Fatal(err)
  427. }
  428. t.Cleanup(client.Wait)
  429. txmp := setup(ctx, t, client, 500)
  430. txmp.height = 100
  431. txmp.config.TTLNumBlocks = 10
  432. tTxs := checkTxs(ctx, t, txmp, 100, 0)
  433. require.Equal(t, len(tTxs), txmp.Size())
  434. require.Equal(t, 100, txmp.heightIndex.Size())
  435. // reap 5 txs at the next height -- no txs should expire
  436. reapedTxs := txmp.ReapMaxTxs(5)
  437. responses := make([]*abci.ExecTxResult, len(reapedTxs))
  438. for i := 0; i < len(responses); i++ {
  439. responses[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
  440. }
  441. txmp.Lock()
  442. require.NoError(t, txmp.Update(ctx, txmp.height+1, reapedTxs, responses, nil, nil))
  443. txmp.Unlock()
  444. require.Equal(t, 95, txmp.Size())
  445. require.Equal(t, 95, txmp.heightIndex.Size())
  446. // check more txs at height 101
  447. _ = checkTxs(ctx, t, txmp, 50, 1)
  448. require.Equal(t, 145, txmp.Size())
  449. require.Equal(t, 145, txmp.heightIndex.Size())
  450. // Reap 5 txs at a height that would expire all the transactions from before
  451. // the previous Update (height 100).
  452. //
  453. // NOTE: When we reap txs below, we do not know if we're picking txs from the
  454. // initial CheckTx calls or from the second round of CheckTx calls. Thus, we
  455. // cannot guarantee that all 95 txs are remaining that should be expired and
  456. // removed. However, we do know that that at most 95 txs can be expired and
  457. // removed.
  458. reapedTxs = txmp.ReapMaxTxs(5)
  459. responses = make([]*abci.ExecTxResult, len(reapedTxs))
  460. for i := 0; i < len(responses); i++ {
  461. responses[i] = &abci.ExecTxResult{Code: abci.CodeTypeOK}
  462. }
  463. txmp.Lock()
  464. require.NoError(t, txmp.Update(ctx, txmp.height+10, reapedTxs, responses, nil, nil))
  465. txmp.Unlock()
  466. require.GreaterOrEqual(t, txmp.Size(), 45)
  467. require.GreaterOrEqual(t, txmp.heightIndex.Size(), 45)
  468. }
  469. func TestTxMempool_CheckTxPostCheckError(t *testing.T) {
  470. ctx, cancel := context.WithCancel(context.Background())
  471. defer cancel()
  472. cases := []struct {
  473. name string
  474. err error
  475. }{
  476. {
  477. name: "error",
  478. err: errors.New("test error"),
  479. },
  480. {
  481. name: "no error",
  482. err: nil,
  483. },
  484. }
  485. for _, tc := range cases {
  486. testCase := tc
  487. t.Run(testCase.name, func(t *testing.T) {
  488. ctx, cancel := context.WithCancel(ctx)
  489. defer cancel()
  490. client := abciclient.NewLocalClient(log.NewNopLogger(), &application{Application: kvstore.NewApplication()})
  491. if err := client.Start(ctx); err != nil {
  492. t.Fatal(err)
  493. }
  494. t.Cleanup(client.Wait)
  495. postCheckFn := func(_ types.Tx, _ *abci.ResponseCheckTx) error {
  496. return testCase.err
  497. }
  498. txmp := setup(ctx, t, client, 0, WithPostCheck(postCheckFn))
  499. rng := rand.New(rand.NewSource(time.Now().UnixNano()))
  500. tx := make([]byte, txmp.config.MaxTxBytes-1)
  501. _, err := rng.Read(tx)
  502. require.NoError(t, err)
  503. callback := func(res *abci.ResponseCheckTx) {
  504. expectedErrString := ""
  505. if testCase.err != nil {
  506. expectedErrString = testCase.err.Error()
  507. }
  508. require.Equal(t, expectedErrString, res.MempoolError)
  509. }
  510. require.NoError(t, txmp.CheckTx(ctx, tx, callback, TxInfo{SenderID: 0}))
  511. })
  512. }
  513. }