github.com/Finschia/ostracon@v1.1.5/mempool/v1/mempool.go (about)

     1  //go:build deprecated
     2  
     3  package v1
     4  
     5  import (
     6  	"fmt"
     7  	"runtime"
     8  	"sort"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/creachadair/taskgroup"
    14  
    15  	abci "github.com/tendermint/tendermint/abci/types"
    16  	"github.com/tendermint/tendermint/config"
    17  	"github.com/tendermint/tendermint/libs/clist"
    18  	"github.com/tendermint/tendermint/libs/log"
    19  	"github.com/tendermint/tendermint/mempool"
    20  	"github.com/tendermint/tendermint/proxy"
    21  	"github.com/tendermint/tendermint/types"
    22  )
    23  
    24  var _ mempool.Mempool = (*TxMempool)(nil)
    25  
    26  // TxMempoolOption sets an optional parameter on the TxMempool.
    27  type TxMempoolOption func(*TxMempool)
    28  
    29  // TxMempool implemements the Mempool interface and allows the application to
    30  // set priority values on transactions in the CheckTx response. When selecting
    31  // transactions to include in a block, higher-priority transactions are chosen
    32  // first.  When evicting transactions from the mempool for size constraints,
    33  // lower-priority transactions are evicted sooner.
    34  //
    35  // Within the mempool, transactions are ordered by time of arrival, and are
    36  // gossiped to the rest of the network based on that order (gossip order does
    37  // not take priority into account).
    38  type TxMempool struct {
    39  	// Immutable fields
    40  	logger       log.Logger
    41  	config       *config.MempoolConfig
    42  	proxyAppConn proxy.AppConnMempool
    43  	metrics      *mempool.Metrics
    44  	cache        mempool.TxCache // seen transactions
    45  
    46  	// Atomically-updated fields
    47  	txsBytes int64 // atomic: the total size of all transactions in the mempool, in bytes
    48  
    49  	// Synchronized fields, protected by mtx.
    50  	mtx                  *sync.RWMutex
    51  	notifiedTxsAvailable bool
    52  	txsAvailable         chan struct{} // one value sent per height when mempool is not empty
    53  	preCheck             mempool.PreCheckFunc
    54  	postCheck            mempool.PostCheckFunc
    55  	height               int64 // the latest height passed to Update
    56  
    57  	txs        *clist.CList // valid transactions (passed CheckTx)
    58  	txByKey    map[types.TxKey]*clist.CElement
    59  	txBySender map[string]*clist.CElement // for sender != ""
    60  }
    61  
    62  // NewTxMempool constructs a new, empty priority mempool at the specified
    63  // initial height and using the given config and options.
    64  func NewTxMempool(
    65  	logger log.Logger,
    66  	cfg *config.MempoolConfig,
    67  	proxyAppConn proxy.AppConnMempool,
    68  	height int64,
    69  	options ...TxMempoolOption,
    70  ) *TxMempool {
    71  
    72  	txmp := &TxMempool{
    73  		logger:       logger,
    74  		config:       cfg,
    75  		proxyAppConn: proxyAppConn,
    76  		metrics:      mempool.NopMetrics(),
    77  		cache:        mempool.NopTxCache{},
    78  		txs:          clist.New(),
    79  		mtx:          new(sync.RWMutex),
    80  		height:       height,
    81  		txByKey:      make(map[types.TxKey]*clist.CElement),
    82  		txBySender:   make(map[string]*clist.CElement),
    83  	}
    84  	if cfg.CacheSize > 0 {
    85  		txmp.cache = mempool.NewLRUTxCache(cfg.CacheSize)
    86  	}
    87  
    88  	for _, opt := range options {
    89  		opt(txmp)
    90  	}
    91  
    92  	return txmp
    93  }
    94  
    95  // WithPreCheck sets a filter for the mempool to reject a transaction if f(tx)
    96  // returns an error. This is executed before CheckTx. It only applies to the
    97  // first created block. After that, Update() overwrites the existing value.
    98  func WithPreCheck(f mempool.PreCheckFunc) TxMempoolOption {
    99  	return func(txmp *TxMempool) { txmp.preCheck = f }
   100  }
   101  
   102  // WithPostCheck sets a filter for the mempool to reject a transaction if
   103  // f(tx, resp) returns an error. This is executed after CheckTx. It only applies
   104  // to the first created block. After that, Update overwrites the existing value.
   105  func WithPostCheck(f mempool.PostCheckFunc) TxMempoolOption {
   106  	return func(txmp *TxMempool) { txmp.postCheck = f }
   107  }
   108  
   109  // WithMetrics sets the mempool's metrics collector.
   110  func WithMetrics(metrics *mempool.Metrics) TxMempoolOption {
   111  	return func(txmp *TxMempool) { txmp.metrics = metrics }
   112  }
   113  
   114  // Lock obtains a write-lock on the mempool. A caller must be sure to explicitly
   115  // release the lock when finished.
   116  func (txmp *TxMempool) Lock() { txmp.mtx.Lock() }
   117  
   118  // Unlock releases a write-lock on the mempool.
   119  func (txmp *TxMempool) Unlock() { txmp.mtx.Unlock() }
   120  
   121  // Size returns the number of valid transactions in the mempool. It is
   122  // thread-safe.
   123  func (txmp *TxMempool) Size() int { return txmp.txs.Len() }
   124  
   125  // SizeBytes return the total sum in bytes of all the valid transactions in the
   126  // mempool. It is thread-safe.
   127  func (txmp *TxMempool) SizeBytes() int64 { return atomic.LoadInt64(&txmp.txsBytes) }
   128  
   129  // FlushAppConn executes FlushSync on the mempool's proxyAppConn.
   130  //
   131  // The caller must hold an exclusive mempool lock (by calling txmp.Lock) before
   132  // calling FlushAppConn.
   133  func (txmp *TxMempool) FlushAppConn() error {
   134  	// N.B.: We have to issue the call outside the lock so that its callback can
   135  	// fire.  It's safe to do this, the flush will block until complete.
   136  	//
   137  	// We could just not require the caller to hold the lock at all, but the
   138  	// semantics of the Mempool interface require the caller to hold it, and we
   139  	// can't change that without disrupting existing use.
   140  	txmp.mtx.Unlock()
   141  	defer txmp.mtx.Lock()
   142  
   143  	return txmp.proxyAppConn.FlushSync()
   144  }
   145  
   146  // EnableTxsAvailable enables the mempool to trigger events when transactions
   147  // are available on a block by block basis.
   148  func (txmp *TxMempool) EnableTxsAvailable() {
   149  	txmp.mtx.Lock()
   150  	defer txmp.mtx.Unlock()
   151  
   152  	txmp.txsAvailable = make(chan struct{}, 1)
   153  }
   154  
   155  // TxsAvailable returns a channel which fires once for every height, and only
   156  // when transactions are available in the mempool. It is thread-safe.
   157  func (txmp *TxMempool) TxsAvailable() <-chan struct{} { return txmp.txsAvailable }
   158  
   159  // CheckTx adds the given transaction to the mempool if it fits and passes the
   160  // application's ABCI CheckTx method.
   161  //
   162  // CheckTx reports an error without adding tx if:
   163  //
   164  // - The size of tx exceeds the configured maximum transaction size.
   165  // - The pre-check hook is defined and reports an error for tx.
   166  // - The transaction already exists in the cache.
   167  // - The proxy connection to the application fails.
   168  //
   169  // If tx passes all of the above conditions, it is passed (asynchronously) to
   170  // the application's ABCI CheckTx method and this CheckTx method returns nil.
   171  // If cb != nil, it is called when the ABCI request completes to report the
   172  // application response.
   173  //
   174  // If the application accepts the transaction and the mempool is full, the
   175  // mempool evicts one or more of the lowest-priority transaction whose priority
   176  // is (strictly) lower than the priority of tx and whose size together exceeds
   177  // the size of tx, and adds tx instead. If no such transactions exist, tx is
   178  // discarded.
   179  func (txmp *TxMempool) CheckTx(tx types.Tx, cb func(*abci.Response), txInfo mempool.TxInfo) error {
   180  
   181  	// During the initial phase of CheckTx, we do not need to modify any state.
   182  	// A transaction will not actually be added to the mempool until it survives
   183  	// a call to the ABCI CheckTx method and size constraint checks.
   184  	height, err := func() (int64, error) {
   185  		txmp.mtx.RLock()
   186  		defer txmp.mtx.RUnlock()
   187  
   188  		// Reject transactions in excess of the configured maximum transaction size.
   189  		if len(tx) > txmp.config.MaxTxBytes {
   190  			return 0, mempool.ErrTxTooLarge{Max: txmp.config.MaxTxBytes, Actual: len(tx)}
   191  		}
   192  
   193  		// If a precheck hook is defined, call it before invoking the application.
   194  		if txmp.preCheck != nil {
   195  			if err := txmp.preCheck(tx); err != nil {
   196  				return 0, mempool.ErrPreCheck{Reason: err}
   197  			}
   198  		}
   199  
   200  		// Early exit if the proxy connection has an error.
   201  		if err := txmp.proxyAppConn.Error(); err != nil {
   202  			return 0, err
   203  		}
   204  
   205  		txKey := tx.Key()
   206  
   207  		// Check for the transaction in the cache.
   208  		if !txmp.cache.Push(tx) {
   209  			// If the cached transaction is also in the pool, record its sender.
   210  			if elt, ok := txmp.txByKey[txKey]; ok {
   211  				w := elt.Value.(*WrappedTx)
   212  				w.SetPeer(txInfo.SenderID)
   213  			}
   214  			return 0, mempool.ErrTxInCache
   215  		}
   216  		return txmp.height, nil
   217  	}()
   218  	if err != nil {
   219  		return err
   220  	}
   221  
   222  	// Invoke an ABCI CheckTx for this transaction.
   223  	rsp, err := txmp.proxyAppConn.CheckTxSync(abci.RequestCheckTx{Tx: tx})
   224  	if err != nil {
   225  		txmp.cache.Remove(tx)
   226  		return err
   227  	}
   228  	wtx := &WrappedTx{
   229  		tx:        tx,
   230  		hash:      tx.Key(),
   231  		timestamp: time.Now().UTC(),
   232  		height:    height,
   233  	}
   234  	wtx.SetPeer(txInfo.SenderID)
   235  	txmp.addNewTransaction(wtx, rsp)
   236  	if cb != nil {
   237  		cb(&abci.Response{Value: &abci.Response_CheckTx{CheckTx: rsp}})
   238  	}
   239  	return nil
   240  }
   241  
   242  // RemoveTxByKey removes the transaction with the specified key from the
   243  // mempool. It reports an error if no such transaction exists.  This operation
   244  // does not remove the transaction from the cache.
   245  func (txmp *TxMempool) RemoveTxByKey(txKey types.TxKey) error {
   246  	txmp.mtx.Lock()
   247  	defer txmp.mtx.Unlock()
   248  	return txmp.removeTxByKey(txKey)
   249  }
   250  
   251  // removeTxByKey removes the specified transaction key from the mempool.
   252  // The caller must hold txmp.mtx excluxively.
   253  func (txmp *TxMempool) removeTxByKey(key types.TxKey) error {
   254  	if elt, ok := txmp.txByKey[key]; ok {
   255  		w := elt.Value.(*WrappedTx)
   256  		delete(txmp.txByKey, key)
   257  		delete(txmp.txBySender, w.sender)
   258  		txmp.txs.Remove(elt)
   259  		elt.DetachPrev()
   260  		elt.DetachNext()
   261  		atomic.AddInt64(&txmp.txsBytes, -w.Size())
   262  		return nil
   263  	}
   264  	return fmt.Errorf("transaction %x not found", key)
   265  }
   266  
   267  // removeTxByElement removes the specified transaction element from the mempool.
   268  // The caller must hold txmp.mtx exclusively.
   269  func (txmp *TxMempool) removeTxByElement(elt *clist.CElement) {
   270  	w := elt.Value.(*WrappedTx)
   271  	delete(txmp.txByKey, w.tx.Key())
   272  	delete(txmp.txBySender, w.sender)
   273  	txmp.txs.Remove(elt)
   274  	elt.DetachPrev()
   275  	elt.DetachNext()
   276  	atomic.AddInt64(&txmp.txsBytes, -w.Size())
   277  }
   278  
   279  // Flush purges the contents of the mempool and the cache, leaving both empty.
   280  // The current height is not modified by this operation.
   281  func (txmp *TxMempool) Flush() {
   282  	txmp.mtx.Lock()
   283  	defer txmp.mtx.Unlock()
   284  
   285  	// Remove all the transactions in the list explicitly, so that the sizes
   286  	// and indexes get updated properly.
   287  	cur := txmp.txs.Front()
   288  	for cur != nil {
   289  		next := cur.Next()
   290  		txmp.removeTxByElement(cur)
   291  		cur = next
   292  	}
   293  	txmp.cache.Reset()
   294  }
   295  
   296  // allEntriesSorted returns a slice of all the transactions currently in the
   297  // mempool, sorted in nonincreasing order by priority with ties broken by
   298  // increasing order of arrival time.
   299  func (txmp *TxMempool) allEntriesSorted() []*WrappedTx {
   300  	txmp.mtx.RLock()
   301  	defer txmp.mtx.RUnlock()
   302  
   303  	all := make([]*WrappedTx, 0, len(txmp.txByKey))
   304  	for _, tx := range txmp.txByKey {
   305  		all = append(all, tx.Value.(*WrappedTx))
   306  	}
   307  	sort.Slice(all, func(i, j int) bool {
   308  		if all[i].priority == all[j].priority {
   309  			return all[i].timestamp.Before(all[j].timestamp)
   310  		}
   311  		return all[i].priority > all[j].priority // N.B. higher priorities first
   312  	})
   313  	return all
   314  }
   315  
   316  // ReapMaxBytesMaxGas returns a slice of valid transactions that fit within the
   317  // size and gas constraints. The results are ordered by nonincreasing priority,
   318  // with ties broken by increasing order of arrival.  Reaping transactions does
   319  // not remove them from the mempool.
   320  //
   321  // If maxBytes < 0, no limit is set on the total size in bytes.
   322  // If maxGas < 0, no limit is set on the total gas cost.
   323  //
   324  // If the mempool is empty or has no transactions fitting within the given
   325  // constraints, the result will also be empty.
   326  func (txmp *TxMempool) ReapMaxBytesMaxGas(maxBytes, maxGas int64) types.Txs {
   327  	var totalGas, totalBytes int64
   328  
   329  	var keep []types.Tx //nolint:prealloc
   330  	for _, w := range txmp.allEntriesSorted() {
   331  		// N.B. When computing byte size, we need to include the overhead for
   332  		// encoding as protobuf to send to the application.
   333  		totalGas += w.gasWanted
   334  		totalBytes += types.ComputeProtoSizeForTxs([]types.Tx{w.tx})
   335  		if (maxGas >= 0 && totalGas > maxGas) || (maxBytes >= 0 && totalBytes > maxBytes) {
   336  			break
   337  		}
   338  		keep = append(keep, w.tx)
   339  	}
   340  	return keep
   341  }
   342  
   343  // TxsWaitChan returns a channel that is closed when there is at least one
   344  // transaction available to be gossiped.
   345  func (txmp *TxMempool) TxsWaitChan() <-chan struct{} { return txmp.txs.WaitChan() }
   346  
   347  // TxsFront returns the frontmost element of the pending transaction list.
   348  // It will be nil if the mempool is empty.
   349  func (txmp *TxMempool) TxsFront() *clist.CElement { return txmp.txs.Front() }
   350  
   351  // ReapMaxTxs returns up to max transactions from the mempool. The results are
   352  // ordered by nonincreasing priority with ties broken by increasing order of
   353  // arrival. Reaping transactions does not remove them from the mempool.
   354  //
   355  // If max < 0, all transactions in the mempool are reaped.
   356  //
   357  // The result may have fewer than max elements (possibly zero) if the mempool
   358  // does not have that many transactions available.
   359  func (txmp *TxMempool) ReapMaxTxs(max int) types.Txs {
   360  	var keep []types.Tx //nolint:prealloc
   361  
   362  	for _, w := range txmp.allEntriesSorted() {
   363  		if max >= 0 && len(keep) >= max {
   364  			break
   365  		}
   366  		keep = append(keep, w.tx)
   367  	}
   368  	return keep
   369  }
   370  
   371  // Update removes all the given transactions from the mempool and the cache,
   372  // and updates the current block height. The blockTxs and deliverTxResponses
   373  // must have the same length with each response corresponding to the tx at the
   374  // same offset.
   375  //
   376  // If the configuration enables recheck, Update sends each remaining
   377  // transaction after removing blockTxs to the ABCI CheckTx method.  Any
   378  // transactions marked as invalid during recheck are also removed.
   379  //
   380  // The caller must hold an exclusive mempool lock (by calling txmp.Lock) before
   381  // calling Update.
   382  func (txmp *TxMempool) Update(
   383  	blockHeight int64,
   384  	blockTxs types.Txs,
   385  	deliverTxResponses []*abci.ResponseDeliverTx,
   386  	newPreFn mempool.PreCheckFunc,
   387  	newPostFn mempool.PostCheckFunc,
   388  ) error {
   389  	// Safety check: Transactions and responses must match in number.
   390  	if len(blockTxs) != len(deliverTxResponses) {
   391  		panic(fmt.Sprintf("mempool: got %d transactions but %d DeliverTx responses",
   392  			len(blockTxs), len(deliverTxResponses)))
   393  	}
   394  
   395  	txmp.height = blockHeight
   396  	txmp.notifiedTxsAvailable = false
   397  
   398  	if newPreFn != nil {
   399  		txmp.preCheck = newPreFn
   400  	}
   401  	if newPostFn != nil {
   402  		txmp.postCheck = newPostFn
   403  	}
   404  
   405  	for i, tx := range blockTxs {
   406  		// Add successful committed transactions to the cache (if they are not
   407  		// already present).  Transactions that failed to commit are removed from
   408  		// the cache unless the operator has explicitly requested we keep them.
   409  		if deliverTxResponses[i].Code == abci.CodeTypeOK {
   410  			_ = txmp.cache.Push(tx)
   411  		} else if !txmp.config.KeepInvalidTxsInCache {
   412  			txmp.cache.Remove(tx)
   413  		}
   414  
   415  		// Regardless of success, remove the transaction from the mempool.
   416  		_ = txmp.removeTxByKey(tx.Key())
   417  	}
   418  
   419  	txmp.purgeExpiredTxs(blockHeight)
   420  
   421  	// If there any uncommitted transactions left in the mempool, we either
   422  	// initiate re-CheckTx per remaining transaction or notify that remaining
   423  	// transactions are left.
   424  	size := txmp.Size()
   425  	txmp.metrics.Size.Set(float64(size))
   426  	if size > 0 {
   427  		if txmp.config.Recheck {
   428  			txmp.recheckTransactions()
   429  		} else {
   430  			txmp.notifyTxsAvailable()
   431  		}
   432  	}
   433  	return nil
   434  }
   435  
   436  // addNewTransaction handles the ABCI CheckTx response for the first time a
   437  // transaction is added to the mempool.  A recheck after a block is committed
   438  // goes to handleRecheckResult.
   439  //
   440  // If either the application rejected the transaction or a post-check hook is
   441  // defined and rejects the transaction, it is discarded.
   442  //
   443  // Otherwise, if the mempool is full, check for lower-priority transactions
   444  // that can be evicted to make room for the new one. If no such transactions
   445  // exist, this transaction is logged and dropped; otherwise the selected
   446  // transactions are evicted.
   447  //
   448  // Finally, the new transaction is added and size stats updated.
   449  func (txmp *TxMempool) addNewTransaction(wtx *WrappedTx, checkTxRes *abci.ResponseCheckTx) {
   450  	txmp.mtx.Lock()
   451  	defer txmp.mtx.Unlock()
   452  
   453  	var err error
   454  	if txmp.postCheck != nil {
   455  		err = txmp.postCheck(wtx.tx, checkTxRes)
   456  	}
   457  
   458  	if err != nil || checkTxRes.Code != abci.CodeTypeOK {
   459  		txmp.logger.Info(
   460  			"rejected bad transaction",
   461  			"priority", wtx.Priority(),
   462  			"tx", fmt.Sprintf("%X", wtx.tx.Hash()),
   463  			"peer_id", wtx.peers,
   464  			"code", checkTxRes.Code,
   465  			"post_check_err", err,
   466  		)
   467  
   468  		txmp.metrics.FailedTxs.Add(1)
   469  
   470  		// Remove the invalid transaction from the cache, unless the operator has
   471  		// instructed us to keep invalid transactions.
   472  		if !txmp.config.KeepInvalidTxsInCache {
   473  			txmp.cache.Remove(wtx.tx)
   474  		}
   475  
   476  		// If there was a post-check error, record its text in the result for
   477  		// debugging purposes.
   478  		if err != nil {
   479  			checkTxRes.MempoolError = err.Error()
   480  		}
   481  		return
   482  	}
   483  
   484  	priority := checkTxRes.Priority
   485  	sender := checkTxRes.Sender
   486  
   487  	// Disallow multiple concurrent transactions from the same sender assigned
   488  	// by the ABCI application. As a special case, an empty sender is not
   489  	// restricted.
   490  	if sender != "" {
   491  		elt, ok := txmp.txBySender[sender]
   492  		if ok {
   493  			w := elt.Value.(*WrappedTx)
   494  			txmp.logger.Debug(
   495  				"rejected valid incoming transaction; tx already exists for sender",
   496  				"tx", fmt.Sprintf("%X", w.tx.Hash()),
   497  				"sender", sender,
   498  			)
   499  			checkTxRes.MempoolError =
   500  				fmt.Sprintf("rejected valid incoming transaction; tx already exists for sender %q (%X)",
   501  					sender, w.tx.Hash())
   502  			txmp.metrics.RejectedTxs.Add(1)
   503  			return
   504  		}
   505  	}
   506  
   507  	// At this point the application has ruled the transaction valid, but the
   508  	// mempool might be full. If so, find the lowest-priority items with lower
   509  	// priority than the application assigned to this new one, and evict as many
   510  	// of them as necessary to make room for tx. If no such items exist, we
   511  	// discard tx.
   512  
   513  	if err := txmp.canAddTx(wtx); err != nil {
   514  		var victims []*clist.CElement // eligible transactions for eviction
   515  		var victimBytes int64         // total size of victims
   516  		for cur := txmp.txs.Front(); cur != nil; cur = cur.Next() {
   517  			cw := cur.Value.(*WrappedTx)
   518  			if cw.priority < priority {
   519  				victims = append(victims, cur)
   520  				victimBytes += cw.Size()
   521  			}
   522  		}
   523  
   524  		// If there are no suitable eviction candidates, or the total size of
   525  		// those candidates is not enough to make room for the new transaction,
   526  		// drop the new one.
   527  		if len(victims) == 0 || victimBytes < wtx.Size() {
   528  			txmp.cache.Remove(wtx.tx)
   529  			txmp.logger.Error(
   530  				"rejected valid incoming transaction; mempool is full",
   531  				"tx", fmt.Sprintf("%X", wtx.tx.Hash()),
   532  				"err", err.Error(),
   533  			)
   534  			checkTxRes.MempoolError =
   535  				fmt.Sprintf("rejected valid incoming transaction; mempool is full (%X)",
   536  					wtx.tx.Hash())
   537  			txmp.metrics.RejectedTxs.Add(1)
   538  			return
   539  		}
   540  
   541  		txmp.logger.Debug("evicting lower-priority transactions",
   542  			"new_tx", fmt.Sprintf("%X", wtx.tx.Hash()),
   543  			"new_priority", priority,
   544  		)
   545  
   546  		// Sort lowest priority items first so they will be evicted first.  Break
   547  		// ties in favor of newer items (to maintain FIFO semantics in a group).
   548  		sort.Slice(victims, func(i, j int) bool {
   549  			iw := victims[i].Value.(*WrappedTx)
   550  			jw := victims[j].Value.(*WrappedTx)
   551  			if iw.Priority() == jw.Priority() {
   552  				return iw.timestamp.After(jw.timestamp)
   553  			}
   554  			return iw.Priority() < jw.Priority()
   555  		})
   556  
   557  		// Evict as many of the victims as necessary to make room.
   558  		var evictedBytes int64
   559  		for _, vic := range victims {
   560  			w := vic.Value.(*WrappedTx)
   561  
   562  			txmp.logger.Debug(
   563  				"evicted valid existing transaction; mempool full",
   564  				"old_tx", fmt.Sprintf("%X", w.tx.Hash()),
   565  				"old_priority", w.priority,
   566  			)
   567  			txmp.removeTxByElement(vic)
   568  			txmp.cache.Remove(w.tx)
   569  			txmp.metrics.EvictedTxs.Add(1)
   570  
   571  			// We may not need to evict all the eligible transactions.  Bail out
   572  			// early if we have made enough room.
   573  			evictedBytes += w.Size()
   574  			if evictedBytes >= wtx.Size() {
   575  				break
   576  			}
   577  		}
   578  	}
   579  
   580  	wtx.SetGasWanted(checkTxRes.GasWanted)
   581  	wtx.SetPriority(priority)
   582  	wtx.SetSender(sender)
   583  	txmp.insertTx(wtx)
   584  
   585  	txmp.metrics.TxSizeBytes.Observe(float64(wtx.Size()))
   586  	txmp.metrics.Size.Set(float64(txmp.Size()))
   587  	txmp.logger.Debug(
   588  		"inserted new valid transaction",
   589  		"priority", wtx.Priority(),
   590  		"tx", fmt.Sprintf("%X", wtx.tx.Hash()),
   591  		"height", txmp.height,
   592  		"num_txs", txmp.Size(),
   593  	)
   594  	txmp.notifyTxsAvailable()
   595  }
   596  
   597  func (txmp *TxMempool) insertTx(wtx *WrappedTx) {
   598  	elt := txmp.txs.PushBack(wtx)
   599  	txmp.txByKey[wtx.tx.Key()] = elt
   600  	if s := wtx.Sender(); s != "" {
   601  		txmp.txBySender[s] = elt
   602  	}
   603  
   604  	atomic.AddInt64(&txmp.txsBytes, wtx.Size())
   605  }
   606  
   607  // handleRecheckResult handles the responses from ABCI CheckTx calls issued
   608  // during the recheck phase of a block Update.  It removes any transactions
   609  // invalidated by the application.
   610  //
   611  // This method is NOT executed for the initial CheckTx on a new transaction;
   612  // that case is handled by addNewTransaction instead.
   613  func (txmp *TxMempool) handleRecheckResult(tx types.Tx, checkTxRes *abci.ResponseCheckTx) {
   614  	txmp.metrics.RecheckTimes.Add(1)
   615  	txmp.mtx.Lock()
   616  	defer txmp.mtx.Unlock()
   617  
   618  	// Find the transaction reported by the ABCI callback. It is possible the
   619  	// transaction was evicted during the recheck, in which case the transaction
   620  	// will be gone.
   621  	elt, ok := txmp.txByKey[tx.Key()]
   622  	if !ok {
   623  		return
   624  	}
   625  	wtx := elt.Value.(*WrappedTx)
   626  
   627  	// If a postcheck hook is defined, call it before checking the result.
   628  	var err error
   629  	if txmp.postCheck != nil {
   630  		err = txmp.postCheck(tx, checkTxRes)
   631  	}
   632  
   633  	if checkTxRes.Code == abci.CodeTypeOK && err == nil {
   634  		wtx.SetPriority(checkTxRes.Priority)
   635  		return // N.B. Size of mempool did not change
   636  	}
   637  
   638  	txmp.logger.Debug(
   639  		"existing transaction no longer valid; failed re-CheckTx callback",
   640  		"priority", wtx.Priority(),
   641  		"tx", fmt.Sprintf("%X", wtx.tx.Hash()),
   642  		"err", err,
   643  		"code", checkTxRes.Code,
   644  	)
   645  	txmp.removeTxByElement(elt)
   646  	txmp.metrics.FailedTxs.Add(1)
   647  	if !txmp.config.KeepInvalidTxsInCache {
   648  		txmp.cache.Remove(wtx.tx)
   649  	}
   650  	txmp.metrics.Size.Set(float64(txmp.Size()))
   651  }
   652  
   653  // recheckTransactions initiates re-CheckTx ABCI calls for all the transactions
   654  // currently in the mempool. It reports the number of recheck calls that were
   655  // successfully initiated.
   656  //
   657  // Precondition: The mempool is not empty.
   658  // The caller must hold txmp.mtx exclusively.
   659  func (txmp *TxMempool) recheckTransactions() {
   660  	if txmp.Size() == 0 {
   661  		panic("mempool: cannot run recheck on an empty mempool")
   662  	}
   663  	txmp.logger.Debug(
   664  		"executing re-CheckTx for all remaining transactions",
   665  		"num_txs", txmp.Size(),
   666  		"height", txmp.height,
   667  	)
   668  
   669  	// Collect transactions currently in the mempool requiring recheck.
   670  	wtxs := make([]*WrappedTx, 0, txmp.txs.Len())
   671  	for e := txmp.txs.Front(); e != nil; e = e.Next() {
   672  		wtxs = append(wtxs, e.Value.(*WrappedTx))
   673  	}
   674  
   675  	// Issue CheckTx calls for each remaining transaction, and when all the
   676  	// rechecks are complete signal watchers that transactions may be available.
   677  	go func() {
   678  		g, start := taskgroup.New(nil).Limit(2 * runtime.NumCPU())
   679  
   680  		for _, wtx := range wtxs {
   681  			wtx := wtx
   682  			start(func() error {
   683  				// The response for this CheckTx is handled by the default recheckTxCallback.
   684  				rsp, err := txmp.proxyAppConn.CheckTxSync(abci.RequestCheckTx{
   685  					Tx:   wtx.tx,
   686  					Type: abci.CheckTxType_Recheck,
   687  				})
   688  				if err != nil {
   689  					txmp.logger.Error("failed to execute CheckTx during recheck",
   690  						"err", err, "hash", fmt.Sprintf("%x", wtx.tx.Hash()))
   691  				} else {
   692  					txmp.handleRecheckResult(wtx.tx, rsp)
   693  				}
   694  				return nil
   695  			})
   696  		}
   697  		_ = txmp.proxyAppConn.FlushAsync()
   698  
   699  		// When recheck is complete, trigger a notification for more transactions.
   700  		_ = g.Wait()
   701  		txmp.mtx.Lock()
   702  		defer txmp.mtx.Unlock()
   703  		txmp.notifyTxsAvailable()
   704  	}()
   705  }
   706  
   707  // canAddTx returns an error if we cannot insert the provided *WrappedTx into
   708  // the mempool due to mempool configured constraints. Otherwise, nil is
   709  // returned and the transaction can be inserted into the mempool.
   710  func (txmp *TxMempool) canAddTx(wtx *WrappedTx) error {
   711  	numTxs := txmp.Size()
   712  	txBytes := txmp.SizeBytes()
   713  
   714  	if numTxs >= txmp.config.Size || wtx.Size()+txBytes > txmp.config.MaxTxsBytes {
   715  		return mempool.ErrMempoolIsFull{
   716  			NumTxs:      numTxs,
   717  			MaxTxs:      txmp.config.Size,
   718  			TxsBytes:    txBytes,
   719  			MaxTxsBytes: txmp.config.MaxTxsBytes,
   720  		}
   721  	}
   722  
   723  	return nil
   724  }
   725  
   726  // purgeExpiredTxs removes all transactions from the mempool that have exceeded
   727  // their respective height or time-based limits as of the given blockHeight.
   728  // Transactions removed by this operation are not removed from the cache.
   729  //
   730  // The caller must hold txmp.mtx exclusively.
   731  func (txmp *TxMempool) purgeExpiredTxs(blockHeight int64) {
   732  	if txmp.config.TTLNumBlocks == 0 && txmp.config.TTLDuration == 0 {
   733  		return // nothing to do
   734  	}
   735  
   736  	now := time.Now()
   737  	cur := txmp.txs.Front()
   738  	for cur != nil {
   739  		// N.B. Grab the next element first, since if we remove cur its successor
   740  		// will be invalidated.
   741  		next := cur.Next()
   742  
   743  		w := cur.Value.(*WrappedTx)
   744  		if txmp.config.TTLNumBlocks > 0 && (blockHeight-w.height) > txmp.config.TTLNumBlocks {
   745  			txmp.removeTxByElement(cur)
   746  			txmp.cache.Remove(w.tx)
   747  			txmp.metrics.EvictedTxs.Add(1)
   748  		} else if txmp.config.TTLDuration > 0 && now.Sub(w.timestamp) > txmp.config.TTLDuration {
   749  			txmp.removeTxByElement(cur)
   750  			txmp.cache.Remove(w.tx)
   751  			txmp.metrics.EvictedTxs.Add(1)
   752  		}
   753  		cur = next
   754  	}
   755  }
   756  
   757  func (txmp *TxMempool) notifyTxsAvailable() {
   758  	if txmp.Size() == 0 {
   759  		return // nothing to do
   760  	}
   761  
   762  	if txmp.txsAvailable != nil && !txmp.notifiedTxsAvailable {
   763  		// channel cap is 1, so this will send once
   764  		txmp.notifiedTxsAvailable = true
   765  
   766  		select {
   767  		case txmp.txsAvailable <- struct{}{}:
   768  		default:
   769  		}
   770  	}
   771  }