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 }