github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/tendermint/mempool/exchain_pending_pool.go (about)

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