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.

143 lines
3.9 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. cache *sm.BlockCache
  17. txs []types.Tx // TODO: we need to add a map to facilitate replace-by-fee
  18. }
  19. func NewMempool(state *sm.State) *Mempool {
  20. return &Mempool{
  21. state: state,
  22. cache: sm.NewBlockCache(state),
  23. }
  24. }
  25. func (mem *Mempool) GetState() *sm.State {
  26. return mem.state
  27. }
  28. func (mem *Mempool) GetCache() *sm.BlockCache {
  29. return mem.cache
  30. }
  31. func (mem *Mempool) GetHeight() int {
  32. mem.mtx.Lock()
  33. defer mem.mtx.Unlock()
  34. return mem.state.LastBlockHeight
  35. }
  36. // Apply tx to the state and remember it.
  37. func (mem *Mempool) AddTx(tx types.Tx) (err error) {
  38. mem.mtx.Lock()
  39. defer mem.mtx.Unlock()
  40. err = sm.ExecTx(mem.cache, tx, false, nil)
  41. if err != nil {
  42. log.Info("AddTx() error", "tx", tx, "error", err)
  43. return err
  44. } else {
  45. log.Info("AddTx() success", "tx", tx)
  46. mem.txs = append(mem.txs, tx)
  47. return nil
  48. }
  49. }
  50. func (mem *Mempool) GetProposalTxs() []types.Tx {
  51. mem.mtx.Lock()
  52. defer mem.mtx.Unlock()
  53. log.Info("GetProposalTxs:", "txs", mem.txs)
  54. return mem.txs
  55. }
  56. // We use this to inform peer routines of how the mempool has been updated
  57. type ResetInfo struct {
  58. Height int
  59. Included []Range
  60. Invalid []Range
  61. }
  62. type Range struct {
  63. Start int
  64. Length int
  65. }
  66. // "block" is the new block being committed.
  67. // "state" is the result of state.AppendBlock("block").
  68. // Txs that are present in "block" are discarded from mempool.
  69. // Txs that have become invalid in the new "state" are also discarded.
  70. func (mem *Mempool) ResetForBlockAndState(block *types.Block, state *sm.State) ResetInfo {
  71. mem.mtx.Lock()
  72. defer mem.mtx.Unlock()
  73. mem.state = state.Copy()
  74. mem.cache = sm.NewBlockCache(mem.state)
  75. // First, create a lookup map of txns in new block.
  76. blockTxsMap := make(map[string]struct{})
  77. for _, tx := range block.Data.Txs {
  78. blockTxsMap[string(types.TxID(state.ChainID, tx))] = struct{}{}
  79. }
  80. // Now we filter all txs from mem.txs that are in blockTxsMap,
  81. // and ExecTx on what remains. Only valid txs are kept.
  82. // We track the ranges of txs included in the block and invalidated by it
  83. // so we can tell peer routines
  84. var ri = ResetInfo{Height: block.Height}
  85. var validTxs []types.Tx
  86. includedStart, invalidStart := -1, -1
  87. for i, tx := range mem.txs {
  88. txID := types.TxID(state.ChainID, tx)
  89. if _, ok := blockTxsMap[string(txID)]; ok {
  90. startRange(&includedStart, i) // start counting included txs
  91. endRange(&invalidStart, i, &ri.Invalid) // stop counting invalid txs
  92. log.Info("Filter out, already committed", "tx", tx, "txID", txID)
  93. } else {
  94. endRange(&includedStart, i, &ri.Included) // stop counting included txs
  95. err := sm.ExecTx(mem.cache, tx, false, nil)
  96. if err != nil {
  97. startRange(&invalidStart, i) // start counting invalid txs
  98. log.Info("Filter out, no longer valid", "tx", tx, "error", err)
  99. } else {
  100. endRange(&invalidStart, i, &ri.Invalid) // stop counting invalid txs
  101. log.Info("Filter in, new, valid", "tx", tx, "txID", txID)
  102. validTxs = append(validTxs, tx)
  103. }
  104. }
  105. }
  106. endRange(&includedStart, len(mem.txs)-1, &ri.Included) // stop counting included txs
  107. endRange(&invalidStart, len(mem.txs)-1, &ri.Invalid) // stop counting invalid txs
  108. // We're done!
  109. log.Info("New txs", "txs", validTxs, "oldTxs", mem.txs)
  110. mem.txs = validTxs
  111. return ri
  112. }
  113. func startRange(start *int, i int) {
  114. if *start < 0 {
  115. *start = i
  116. }
  117. }
  118. func endRange(start *int, i int, ranger *[]Range) {
  119. if *start >= 0 {
  120. length := i - *start
  121. *ranger = append(*ranger, Range{*start, length})
  122. *start = -1
  123. }
  124. }