github.com/okex/exchain@v1.8.0/libs/tendermint/mempool/address_record.go (about) 1 package mempool 2 3 import ( 4 "sync" 5 6 "github.com/okex/exchain/libs/tendermint/libs/clist" 7 "github.com/okex/exchain/libs/tendermint/types" 8 ) 9 10 type elementManager interface { 11 removeElement(*clist.CElement) 12 removeElementByKey(key [32]byte) *clist.CElement 13 reorganizeElements([]*clist.CElement) 14 } 15 16 type AddressRecord struct { 17 addrTxs sync.Map // address -> *addrMap 18 19 elementManager 20 } 21 22 type addrMap struct { 23 sync.RWMutex 24 25 items map[uint64]*clist.CElement // nonce -> *mempoolTx 26 maxNonce uint64 27 } 28 29 func newAddressRecord(em elementManager) *AddressRecord { 30 return &AddressRecord{elementManager: em} 31 } 32 33 func (ar *AddressRecord) AddItem(address string, cElement *clist.CElement) { 34 v, ok := ar.addrTxs.Load(address) 35 if !ok { 36 // LoadOrStore to prevent double storing 37 v, ok = ar.addrTxs.LoadOrStore(address, &addrMap{items: make(map[uint64]*clist.CElement)}) 38 } 39 am := v.(*addrMap) 40 am.Lock() 41 defer am.Unlock() 42 am.items[cElement.Nonce] = cElement 43 if cElement.Nonce > am.maxNonce { 44 am.maxNonce = cElement.Nonce 45 } 46 } 47 48 func (ar *AddressRecord) checkRepeatedAndAddItem(memTx *mempoolTx, txPriceBump int64, cb func(*clist.CElement) *clist.CElement) *clist.CElement { 49 gasPrice := memTx.realTx.GetGasPrice() 50 nonce := memTx.realTx.GetNonce() 51 newElement := clist.NewCElement(memTx, memTx.from, gasPrice, nonce) 52 53 v, ok := ar.addrTxs.Load(memTx.from) 54 if !ok { 55 v, ok = ar.addrTxs.LoadOrStore(memTx.from, &addrMap{items: make(map[uint64]*clist.CElement)}) 56 } 57 am := v.(*addrMap) 58 am.Lock() 59 defer am.Unlock() 60 // do not need to check element nonce 61 if newElement.Nonce > am.maxNonce { 62 cb(newElement) 63 am.maxNonce = newElement.Nonce 64 am.items[newElement.Nonce] = newElement 65 return newElement 66 } 67 68 for _, e := range am.items { 69 if e.Nonce == nonce { 70 // only replace tx for bigger gas price 71 expectedGasPrice := MultiPriceBump(e.GasPrice, txPriceBump) 72 if gasPrice.Cmp(expectedGasPrice) <= 0 { 73 return nil 74 } 75 76 // delete the old element and reorganize the elements whose nonce is greater the the new element 77 ar.removeElement(e) 78 items := []*clist.CElement{newElement} 79 for _, item := range am.items { 80 if item.Nonce > nonce { 81 items = append(items, item) 82 } 83 } 84 ar.reorganizeElements(items) 85 am.items[newElement.Nonce] = newElement 86 return newElement 87 } 88 } 89 90 cb(newElement) 91 am.items[newElement.Nonce] = newElement 92 93 return newElement 94 } 95 96 func (ar *AddressRecord) CleanItems(address string, nonce uint64, cb func(element *clist.CElement)) { 97 v, ok := ar.addrTxs.Load(address) 98 if !ok { 99 return 100 } 101 am := v.(*addrMap) 102 am.Lock() 103 defer am.Unlock() 104 for k, v := range am.items { 105 if v.Nonce <= nonce { 106 cb(v) 107 delete(am.items, k) 108 } 109 } 110 if len(am.items) == 0 { 111 ar.addrTxs.Delete(address) 112 } 113 } 114 115 func (ar *AddressRecord) GetItems(address string) []*clist.CElement { 116 v, ok := ar.addrTxs.Load(address) 117 if !ok { 118 return nil 119 } 120 am := v.(*addrMap) 121 var l []*clist.CElement 122 am.RLock() 123 defer am.RUnlock() 124 for _, v := range am.items { 125 l = append(l, v) 126 } 127 return l 128 } 129 130 func (ar *AddressRecord) DeleteItem(e *clist.CElement) { 131 if v, ok := ar.addrTxs.Load(e.Address); ok { 132 am := v.(*addrMap) 133 am.Lock() 134 defer am.Unlock() 135 delete(am.items, e.Nonce) 136 //calculate max Nonce 137 am.maxNonce = calculateMaxNonce(am) 138 if len(am.items) == 0 { 139 ar.addrTxs.Delete(e.Address) 140 } 141 } 142 } 143 144 func (ar *AddressRecord) GetAddressList() []string { 145 var addrList []string 146 ar.addrTxs.Range(func(k, v interface{}) bool { 147 addrList = append(addrList, k.(string)) 148 return true 149 }) 150 return addrList 151 } 152 153 func (ar *AddressRecord) GetAddressTxsCnt(address string) int { 154 v, ok := ar.addrTxs.Load(address) 155 if !ok { 156 return 0 157 } 158 am := v.(*addrMap) 159 am.RLock() 160 defer am.RUnlock() 161 return len(am.items) 162 } 163 164 func (ar *AddressRecord) GetAddressNonce(address string) (uint64, bool) { 165 v, ok := ar.addrTxs.Load(address) 166 if !ok { 167 return 0, false 168 } 169 am := v.(*addrMap) 170 am.RLock() 171 defer am.RUnlock() 172 return am.maxNonce, true 173 } 174 175 func (ar *AddressRecord) GetAddressTxs(address string, max int) types.Txs { 176 v, ok := ar.addrTxs.Load(address) 177 if !ok { 178 return nil 179 } 180 am := v.(*addrMap) 181 am.RLock() 182 defer am.RUnlock() 183 if max <= 0 || max > len(am.items) { 184 max = len(am.items) 185 } 186 txs := make([]types.Tx, 0, max) 187 for _, e := range am.items { 188 if len(txs) == max { 189 break 190 } 191 txs = append(txs, e.Value.(*mempoolTx).tx) 192 } 193 return txs 194 } 195 196 func calculateMaxNonce(data *addrMap) uint64 { 197 maxNonce := uint64(0) 198 for k, _ := range data.items { 199 if k > maxNonce { 200 maxNonce = k 201 } 202 } 203 return maxNonce 204 } 205 206 type AddressNonce struct { 207 addr string 208 nonce uint64 209 } 210 211 var addressNoncePool = sync.Pool{ 212 New: func() interface{} { 213 return &AddressNonce{} 214 }, 215 }