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  }