github.com/okex/exchain@v1.8.0/libs/tendermint/mempool/exchain_pending_pool.go (about)

     1  package mempool
     2  
     3  import (
     4  	"strconv"
     5  	"strings"
     6  	"sync"
     7  
     8  	cfg "github.com/okex/exchain/libs/tendermint/config"
     9  	"github.com/okex/exchain/libs/tendermint/types"
    10  )
    11  
    12  const (
    13  	FlagEnablePendingPool = "mempool.enable_pending_pool"
    14  )
    15  
    16  type PendingPool struct {
    17  	maxSize         int
    18  	addressTxsMap   map[string]map[uint64]*mempoolTx
    19  	txsMap          map[string]*mempoolTx
    20  	mtx             sync.RWMutex
    21  	period          int
    22  	reserveBlocks   int
    23  	periodCounter   map[string]int // address with period count
    24  	maxTxPerAddress int
    25  }
    26  
    27  func newPendingPool(maxSize int, period int, reserveBlocks int, maxTxPerAddress int) *PendingPool {
    28  	return &PendingPool{
    29  		maxSize:         maxSize,
    30  		addressTxsMap:   make(map[string]map[uint64]*mempoolTx),
    31  		txsMap:          make(map[string]*mempoolTx),
    32  		period:          period,
    33  		reserveBlocks:   reserveBlocks,
    34  		periodCounter:   make(map[string]int),
    35  		maxTxPerAddress: maxTxPerAddress,
    36  	}
    37  }
    38  
    39  func (p *PendingPool) Size() int {
    40  	p.mtx.RLock()
    41  	defer p.mtx.RUnlock()
    42  	return len(p.txsMap)
    43  }
    44  
    45  func (p *PendingPool) GetWrappedAddressTxsMap() map[string]map[string]types.WrappedMempoolTx {
    46  	p.mtx.RLock()
    47  	defer p.mtx.RUnlock()
    48  	wrappedAddressTxsMap := make(map[string]map[string]types.WrappedMempoolTx)
    49  	for address, subMap := range p.addressTxsMap {
    50  		nonceTxsMap := make(map[string]types.WrappedMempoolTx)
    51  		for nonce, memTxPtr := range subMap {
    52  			nonceStr := strconv.Itoa(int(nonce))
    53  			nonceTxsMap[nonceStr] = memTxPtr.ToWrappedMempoolTx()
    54  		}
    55  		wrappedAddressTxsMap[address] = nonceTxsMap
    56  	}
    57  	return wrappedAddressTxsMap
    58  }
    59  
    60  func (p *PendingPool) txCount(address string) int {
    61  	p.mtx.RLock()
    62  	defer p.mtx.RUnlock()
    63  	if _, ok := p.addressTxsMap[address]; !ok {
    64  		return 0
    65  	}
    66  	return len(p.addressTxsMap[address])
    67  }
    68  
    69  func (p *PendingPool) getTx(address string, nonce uint64) *mempoolTx {
    70  	p.mtx.RLock()
    71  	defer p.mtx.RUnlock()
    72  	if _, ok := p.addressTxsMap[address]; ok {
    73  		return p.addressTxsMap[address][nonce]
    74  	}
    75  	return nil
    76  }
    77  
    78  func (p *PendingPool) hasTx(tx types.Tx, height int64) bool {
    79  	p.mtx.RLock()
    80  	defer p.mtx.RUnlock()
    81  	_, exist := p.txsMap[txID(tx, height)]
    82  	return exist
    83  }
    84  
    85  func (p *PendingPool) addTx(pendingTx *mempoolTx) {
    86  	p.mtx.Lock()
    87  	defer p.mtx.Unlock()
    88  	blacklist := strings.Split(cfg.DynamicConfig.GetPendingPoolBlacklist(), ",")
    89  	// When cfg.DynamicConfig.GetPendingPoolBlacklist() == "", blacklist == []string{""} and len(blacklist) == 1.
    90  	// Above case should be avoided.
    91  	for _, address := range blacklist {
    92  		if address != "" && pendingTx.from == address {
    93  			return
    94  		}
    95  	}
    96  	if _, ok := p.addressTxsMap[pendingTx.from]; !ok {
    97  		p.addressTxsMap[pendingTx.from] = make(map[uint64]*mempoolTx)
    98  	}
    99  	p.addressTxsMap[pendingTx.from][pendingTx.realTx.GetNonce()] = pendingTx
   100  	p.txsMap[txID(pendingTx.tx, pendingTx.height)] = pendingTx
   101  }
   102  
   103  func (p *PendingPool) removeTx(address string, nonce uint64) {
   104  	p.mtx.Lock()
   105  	defer p.mtx.Unlock()
   106  	if _, ok := p.addressTxsMap[address]; ok {
   107  		if pendingTx, ok := p.addressTxsMap[address][nonce]; ok {
   108  			delete(p.addressTxsMap[address], nonce)
   109  			delete(p.txsMap, txID(pendingTx.tx, pendingTx.height))
   110  		}
   111  		if len(p.addressTxsMap[address]) == 0 {
   112  			delete(p.addressTxsMap, address)
   113  			delete(p.periodCounter, address)
   114  		}
   115  		// update period counter
   116  		if count, ok := p.periodCounter[address]; ok && count > 0 {
   117  			p.periodCounter[address] = count - 1
   118  		}
   119  
   120  	}
   121  
   122  }
   123  
   124  func (p *PendingPool) removeTxByHash(txHash string) {
   125  	p.mtx.Lock()
   126  	defer p.mtx.Unlock()
   127  	if pendingTx, ok := p.txsMap[txHash]; ok {
   128  		delete(p.txsMap, txHash)
   129  		if _, ok := p.addressTxsMap[pendingTx.from]; ok {
   130  			delete(p.addressTxsMap[pendingTx.from], pendingTx.realTx.GetNonce())
   131  			if len(p.addressTxsMap[pendingTx.from]) == 0 {
   132  				delete(p.addressTxsMap, pendingTx.from)
   133  				delete(p.periodCounter, pendingTx.from)
   134  			}
   135  			// update period counter
   136  			if count, ok := p.periodCounter[pendingTx.from]; ok && count > 0 {
   137  				p.periodCounter[pendingTx.from] = count - 1
   138  			}
   139  		}
   140  	}
   141  }
   142  
   143  func (p *PendingPool) handlePendingTx(addressNonce map[string]uint64) map[string]uint64 {
   144  	p.mtx.Lock()
   145  	defer p.mtx.Unlock()
   146  	addrMap := make(map[string]uint64)
   147  	for addr, accountNonce := range addressNonce {
   148  		if txsMap, ok := p.addressTxsMap[addr]; ok {
   149  			for nonce, pendingTx := range txsMap {
   150  				// remove invalid pending tx
   151  				if nonce <= accountNonce {
   152  					delete(p.addressTxsMap[addr], nonce)
   153  					delete(p.txsMap, txID(pendingTx.tx, pendingTx.height))
   154  				} else if nonce == accountNonce+1 {
   155  					addrMap[addr] = nonce
   156  				}
   157  			}
   158  			if len(p.addressTxsMap[addr]) == 0 {
   159  				delete(p.addressTxsMap, addr)
   160  			}
   161  		}
   162  	}
   163  	return addrMap
   164  }
   165  
   166  func (p *PendingPool) handlePeriodCounter() {
   167  	p.mtx.Lock()
   168  	defer p.mtx.Unlock()
   169  	for addr, txMap := range p.addressTxsMap {
   170  		count := p.periodCounter[addr]
   171  		if count >= p.reserveBlocks {
   172  			delete(p.addressTxsMap, addr)
   173  			for _, pendingTx := range txMap {
   174  				delete(p.txsMap, txID(pendingTx.tx, pendingTx.height))
   175  			}
   176  			delete(p.periodCounter, addr)
   177  		} else {
   178  			p.periodCounter[addr] = count + 1
   179  		}
   180  	}
   181  }
   182  
   183  func (p *PendingPool) validate(address string, tx types.Tx, height int64) error {
   184  	// tx already in pending pool
   185  	if p.hasTx(tx, height) {
   186  		return ErrTxAlreadyInPendingPool{
   187  			txHash: txID(tx, height),
   188  		}
   189  	}
   190  
   191  	poolSize := p.Size()
   192  	if poolSize >= p.maxSize {
   193  		return ErrPendingPoolIsFull{
   194  			size:    poolSize,
   195  			maxSize: p.maxSize,
   196  		}
   197  	}
   198  	txCount := p.txCount(address)
   199  	if txCount >= p.maxTxPerAddress {
   200  		return ErrPendingPoolAddressLimit{
   201  			address: address,
   202  			size:    txCount,
   203  			maxSize: p.maxTxPerAddress,
   204  		}
   205  	}
   206  	return nil
   207  }
   208  
   209  type AccountRetriever interface {
   210  	GetAccountNonce(address string) uint64
   211  }