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 }