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.

135 lines
3.6 KiB

9 years ago
  1. /*
  2. Mempool receives new transactions and applies them to the latest committed state.
  3. If the transaction is acceptable, then it broadcasts the tx to peers.
  4. When this node happens to be the next proposer, it simply uses the recently
  5. modified state (and the associated transactions) to construct a proposal.
  6. */
  7. package mempool
  8. import (
  9. "sync"
  10. sm "github.com/tendermint/tendermint/state"
  11. "github.com/tendermint/tendermint/types"
  12. )
  13. type Mempool struct {
  14. mtx sync.Mutex
  15. state *sm.State
  16. txs []types.Tx // TODO: we need to add a map to facilitate replace-by-fee
  17. }
  18. func NewMempool(state *sm.State) *Mempool {
  19. return &Mempool{
  20. state: state,
  21. }
  22. }
  23. func (mem *Mempool) GetState() *sm.State {
  24. return mem.state
  25. }
  26. func (mem *Mempool) GetHeight() int {
  27. mem.mtx.Lock()
  28. defer mem.mtx.Unlock()
  29. return mem.state.LastBlockHeight
  30. }
  31. // Apply tx to the state and remember it.
  32. func (mem *Mempool) AddTx(tx types.Tx) (err error) {
  33. mem.mtx.Lock()
  34. defer mem.mtx.Unlock()
  35. err = sm.ExecTx(mem.state, tx, nil)
  36. if err != nil {
  37. log.Info("AddTx() error", "tx", tx, "error", err)
  38. return err
  39. } else {
  40. log.Info("AddTx() success", "tx", tx)
  41. mem.txs = append(mem.txs, tx)
  42. return nil
  43. }
  44. }
  45. func (mem *Mempool) GetProposalTxs() []types.Tx {
  46. mem.mtx.Lock()
  47. defer mem.mtx.Unlock()
  48. log.Info("GetProposalTxs:", "txs", mem.txs)
  49. return mem.txs
  50. }
  51. // We use this to inform peer routines of how the mempool has been updated
  52. type ResetInfo struct {
  53. Height int
  54. Included []Range
  55. Invalid []Range
  56. }
  57. type Range struct {
  58. Start int
  59. Length int
  60. }
  61. // "block" is the new block being committed.
  62. // "state" is the result of state.AppendBlock("block").
  63. // Txs that are present in "block" are discarded from mempool.
  64. // Txs that have become invalid in the new "state" are also discarded.
  65. func (mem *Mempool) ResetForBlockAndState(block *types.Block, state *sm.State) ResetInfo {
  66. mem.mtx.Lock()
  67. defer mem.mtx.Unlock()
  68. mem.state = state.Copy()
  69. // First, create a lookup map of txns in new block.
  70. blockTxsMap := make(map[string]struct{})
  71. for _, tx := range block.Data.Txs {
  72. blockTxsMap[string(tx)] = struct{}{}
  73. }
  74. // Now we filter all txs from mem.txs that are in blockTxsMap,
  75. // and ExecTx on what remains. Only valid txs are kept.
  76. // We track the ranges of txs included in the block and invalidated by it
  77. // so we can tell peer routines
  78. var ri = ResetInfo{Height: block.Height}
  79. var validTxs []types.Tx
  80. includedStart, invalidStart := -1, -1
  81. for i, tx := range mem.txs {
  82. if _, ok := blockTxsMap[string(tx)]; ok {
  83. startRange(&includedStart, i) // start counting included txs
  84. endRange(&invalidStart, i, &ri.Invalid) // stop counting invalid txs
  85. log.Info("Filter out, already committed", "tx", tx)
  86. } else {
  87. endRange(&includedStart, i, &ri.Included) // stop counting included txs
  88. err := sm.ExecTx(mem.state, tx, nil)
  89. if err != nil {
  90. startRange(&invalidStart, i) // start counting invalid txs
  91. log.Info("Filter out, no longer valid", "tx", tx, "error", err)
  92. } else {
  93. endRange(&invalidStart, i, &ri.Invalid) // stop counting invalid txs
  94. log.Info("Filter in, new, valid", "tx", tx)
  95. validTxs = append(validTxs, tx)
  96. }
  97. }
  98. }
  99. endRange(&includedStart, len(mem.txs)-1, &ri.Included) // stop counting included txs
  100. endRange(&invalidStart, len(mem.txs)-1, &ri.Invalid) // stop counting invalid txs
  101. // We're done!
  102. log.Info("New txs", "txs", validTxs, "oldTxs", mem.txs)
  103. mem.txs = validTxs
  104. return ri
  105. }
  106. func startRange(start *int, i int) {
  107. if *start < 0 {
  108. *start = i
  109. }
  110. }
  111. func endRange(start *int, i int, ranger *[]Range) {
  112. if *start >= 0 {
  113. length := i - *start
  114. *ranger = append(*ranger, Range{*start, length})
  115. *start = -1
  116. }
  117. }