github.com/insight-chain/inb-go@v1.1.3-0.20191221022159-da049980ae38/core/tx_list.go (about)

     1  // Copyright 2016 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package core
    18  
    19  import (
    20  	"container/heap"
    21  	"math"
    22  	"math/big"
    23  	"sort"
    24  
    25  	"github.com/insight-chain/inb-go/common"
    26  	"github.com/insight-chain/inb-go/core/types"
    27  	"github.com/insight-chain/inb-go/log"
    28  )
    29  
    30  // nonceHeap is a heap.Interface implementation over 64bit unsigned integers for
    31  // retrieving sorted transactions from the possibly gapped future queue.
    32  type nonceHeap []uint64
    33  
    34  func (h nonceHeap) Len() int           { return len(h) }
    35  func (h nonceHeap) Less(i, j int) bool { return h[i] < h[j] }
    36  func (h nonceHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }
    37  
    38  func (h *nonceHeap) Push(x interface{}) {
    39  	*h = append(*h, x.(uint64))
    40  }
    41  
    42  func (h *nonceHeap) Pop() interface{} {
    43  	old := *h
    44  	n := len(old)
    45  	x := old[n-1]
    46  	*h = old[0 : n-1]
    47  	return x
    48  }
    49  
    50  // txSortedMap is a nonce->transaction hash map with a heap based index to allow
    51  // iterating over the contents in a nonce-incrementing way.
    52  type txSortedMap struct {
    53  	items map[uint64]*types.Transaction // Hash map storing the transaction data
    54  	index *nonceHeap                    // Heap of nonces of all the stored transactions (non-strict mode)
    55  	cache types.Transactions            // Cache of the transactions already sorted
    56  }
    57  
    58  // newTxSortedMap creates a new nonce-sorted transaction map.
    59  func newTxSortedMap() *txSortedMap {
    60  	return &txSortedMap{
    61  		items: make(map[uint64]*types.Transaction),
    62  		index: new(nonceHeap),
    63  	}
    64  }
    65  
    66  // Get retrieves the current transactions associated with the given nonce.
    67  func (m *txSortedMap) Get(nonce uint64) *types.Transaction {
    68  	return m.items[nonce]
    69  }
    70  
    71  // Put inserts a new transaction into the map, also updating the map's nonce
    72  // index. If a transaction already exists with the same nonce, it's overwritten.
    73  func (m *txSortedMap) Put(tx *types.Transaction) {
    74  	nonce := tx.Nonce()
    75  	if m.items[nonce] == nil {
    76  		heap.Push(m.index, nonce)
    77  	}
    78  	m.items[nonce], m.cache = tx, nil
    79  }
    80  
    81  // Forward removes all transactions from the map with a nonce lower than the
    82  // provided threshold. Every removed transaction is returned for any post-removal
    83  // maintenance.
    84  func (m *txSortedMap) Forward(threshold uint64) types.Transactions {
    85  	var removed types.Transactions
    86  
    87  	// Pop off heap items until the threshold is reached
    88  	for m.index.Len() > 0 && (*m.index)[0] < threshold {
    89  		nonce := heap.Pop(m.index).(uint64)
    90  		removed = append(removed, m.items[nonce])
    91  		delete(m.items, nonce)
    92  	}
    93  	// If we had a cached order, shift the front
    94  	if m.cache != nil {
    95  		m.cache = m.cache[len(removed):]
    96  	}
    97  	return removed
    98  }
    99  
   100  // Filter iterates over the list of transactions and removes all of them for which
   101  // the specified function evaluates to true.
   102  func (m *txSortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions {
   103  	var removed types.Transactions
   104  
   105  	// Collect all the transactions to filter out
   106  	for nonce, tx := range m.items {
   107  		if filter(tx) {
   108  			removed = append(removed, tx)
   109  			delete(m.items, nonce)
   110  		}
   111  	}
   112  	// If transactions were removed, the heap and cache are ruined
   113  	if len(removed) > 0 {
   114  		*m.index = make([]uint64, 0, len(m.items))
   115  		for nonce := range m.items {
   116  			*m.index = append(*m.index, nonce)
   117  		}
   118  		heap.Init(m.index)
   119  
   120  		m.cache = nil
   121  	}
   122  	return removed
   123  }
   124  
   125  // Cap places a hard limit on the number of items, returning all transactions
   126  // exceeding that limit.
   127  func (m *txSortedMap) Cap(threshold int) types.Transactions {
   128  	// Short circuit if the number of items is under the limit
   129  	if len(m.items) <= threshold {
   130  		return nil
   131  	}
   132  	// Otherwise gather and drop the highest nonce'd transactions
   133  	var drops types.Transactions
   134  
   135  	sort.Sort(*m.index)
   136  	for size := len(m.items); size > threshold; size-- {
   137  		drops = append(drops, m.items[(*m.index)[size-1]])
   138  		delete(m.items, (*m.index)[size-1])
   139  	}
   140  	*m.index = (*m.index)[:threshold]
   141  	heap.Init(m.index)
   142  
   143  	// If we had a cache, shift the back
   144  	if m.cache != nil {
   145  		m.cache = m.cache[:len(m.cache)-len(drops)]
   146  	}
   147  	return drops
   148  }
   149  
   150  // Remove deletes a transaction from the maintained map, returning whether the
   151  // transaction was found.
   152  func (m *txSortedMap) Remove(nonce uint64) bool {
   153  	// Short circuit if no transaction is present
   154  	_, ok := m.items[nonce]
   155  	if !ok {
   156  		return false
   157  	}
   158  	// Otherwise delete the transaction and fix the heap index
   159  	for i := 0; i < m.index.Len(); i++ {
   160  		if (*m.index)[i] == nonce {
   161  			heap.Remove(m.index, i)
   162  			break
   163  		}
   164  	}
   165  	delete(m.items, nonce)
   166  	m.cache = nil
   167  
   168  	return true
   169  }
   170  
   171  // Ready retrieves a sequentially increasing list of transactions starting at the
   172  // provided nonce that is ready for processing. The returned transactions will be
   173  // removed from the list.
   174  //
   175  // Note, all transactions with nonces lower than start will also be returned to
   176  // prevent getting into and invalid state. This is not something that should ever
   177  // happen but better to be self correcting than failing!
   178  func (m *txSortedMap) Ready(start uint64) types.Transactions {
   179  	// Short circuit if no transactions are available
   180  	if m.index.Len() == 0 || (*m.index)[0] > start {
   181  		return nil
   182  	}
   183  	// Otherwise start accumulating incremental transactions
   184  	var ready types.Transactions
   185  	for next := (*m.index)[0]; m.index.Len() > 0 && (*m.index)[0] == next; next++ {
   186  		ready = append(ready, m.items[next])
   187  		delete(m.items, next)
   188  		heap.Pop(m.index)
   189  	}
   190  	m.cache = nil
   191  
   192  	return ready
   193  }
   194  
   195  // Len returns the length of the transaction map.
   196  func (m *txSortedMap) Len() int {
   197  	return len(m.items)
   198  }
   199  
   200  // Flatten creates a nonce-sorted slice of transactions based on the loosely
   201  // sorted internal representation. The result of the sorting is cached in case
   202  // it's requested again before any modifications are made to the contents.
   203  func (m *txSortedMap) Flatten() types.Transactions {
   204  	// If the sorting was not cached yet, create and cache it
   205  	if m.cache == nil {
   206  		m.cache = make(types.Transactions, 0, len(m.items))
   207  		for _, tx := range m.items {
   208  			m.cache = append(m.cache, tx)
   209  		}
   210  		sort.Sort(types.TxByNonce(m.cache))
   211  	}
   212  	// Copy the cache to prevent accidental modifications
   213  	txs := make(types.Transactions, len(m.cache))
   214  	copy(txs, m.cache)
   215  	return txs
   216  }
   217  
   218  // txList is a "list" of transactions belonging to an account, sorted by account
   219  // nonce. The same type can be used both for storing contiguous transactions for
   220  // the executable/pending queue; and for storing gapped transactions for the non-
   221  // executable/future queue, with minor behavioral changes.
   222  type txList struct {
   223  	strict bool         // Whether nonces are strictly continuous or not
   224  	txs    *txSortedMap // Heap indexed sorted hash map of the transactions
   225  
   226  	costcap *big.Int // Price of the highest costing transaction (reset only if exceeds balance)
   227  	gascap  uint64   // Gas limit of the highest spending transaction (reset only if exceeds block limit)
   228  }
   229  
   230  // newTxList create a new transaction list for maintaining nonce-indexable fast,
   231  // gapped, sortable transaction lists.
   232  func newTxList(strict bool) *txList {
   233  	return &txList{
   234  		strict:  strict,
   235  		txs:     newTxSortedMap(),
   236  		costcap: new(big.Int),
   237  	}
   238  }
   239  
   240  // Overlaps returns whether the transaction specified has the same nonce as one
   241  // already contained within the list.
   242  func (l *txList) Overlaps(tx *types.Transaction) bool {
   243  	return l.txs.Get(tx.Nonce()) != nil
   244  }
   245  
   246  // Add tries to insert a new transaction into the list, returning whether the
   247  // transaction was accepted, and if yes, any previous transaction it replaced.
   248  //
   249  // If the new transaction is accepted into the list, the lists' cost and gas
   250  // thresholds are also potentially updated.
   251  func (l *txList) Add(tx *types.Transaction, priceBump uint64) (bool, *types.Transaction) {
   252  	// If there's an older better transaction, abort
   253  	old := l.txs.Get(tx.Nonce())
   254  	if old != nil {
   255  		//achilles0711 remove gas
   256  		//threshold := new(big.Int).Div(new(big.Int).Mul(old.GasPrice(), big.NewInt(100+int64(priceBump))), big.NewInt(100))
   257  		//// Have to ensure that the new gas price is higher than the old gas
   258  		//// price as well as checking the percentage threshold to ensure that
   259  		//// this is accurate for low (Wei-level) gas price replacements
   260  		//if old.GasPrice().Cmp(tx.GasPrice()) >= 0 || threshold.Cmp(tx.GasPrice()) > 0 {
   261  		//	return false, nil
   262  		//}
   263  	}
   264  	// Otherwise overwrite the old transaction with the current one
   265  	l.txs.Put(tx)
   266  	if cost := tx.Cost(); l.costcap.Cmp(cost) < 0 {
   267  		l.costcap = cost
   268  	}
   269  	//achilles0711 remove gas
   270  	//if gas := tx.Gas(); l.gascap < gas {
   271  	//	l.gascap = gas
   272  	//}
   273  	return true, old
   274  }
   275  
   276  // Forward removes all transactions from the list with a nonce lower than the
   277  // provided threshold. Every removed transaction is returned for any post-removal
   278  // maintenance.
   279  func (l *txList) Forward(threshold uint64) types.Transactions {
   280  	return l.txs.Forward(threshold)
   281  }
   282  
   283  // Filter removes all transactions from the list with a cost or gas limit higher
   284  // than the provided thresholds. Every removed transaction is returned for any
   285  // post-removal maintenance. Strict-mode invalidated transactions are also
   286  // returned.
   287  //
   288  // This method uses the cached costcap and gascap to quickly decide if there's even
   289  // a point in calculating all the costs or if the balance covers all. If the threshold
   290  // is lower than the costgas cap, the caps will be reset to a new high after removing
   291  // the newly invalidated transactions.
   292  func (l *txList) Filter(costLimit *big.Int, gasLimit uint64) (types.Transactions, types.Transactions) {
   293  	// If all transactions are below the threshold, short circuit
   294  	//achilles0711 remove gas
   295  	//if l.costcap.Cmp(costLimit) <= 0 && l.gascap <= gasLimit {
   296  	if l.costcap.Cmp(costLimit) <= 0 {
   297  		return nil, nil
   298  	}
   299  	l.costcap = new(big.Int).Set(costLimit) // Lower the caps to the thresholds
   300  	l.gascap = gasLimit
   301  
   302  	// Filter out all the transactions above the account's funds
   303  	//achilles0711
   304  	//removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 || tx.Gas() > gasLimit })
   305  	removed := l.txs.Filter(func(tx *types.Transaction) bool { return tx.Cost().Cmp(costLimit) > 0 })
   306  
   307  	// If the list was strict, filter anything above the lowest nonce
   308  	var invalids types.Transactions
   309  
   310  	if l.strict && len(removed) > 0 {
   311  		lowest := uint64(math.MaxUint64)
   312  		for _, tx := range removed {
   313  			if nonce := tx.Nonce(); lowest > nonce {
   314  				lowest = nonce
   315  			}
   316  		}
   317  		invalids = l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > lowest })
   318  	}
   319  	return removed, invalids
   320  }
   321  
   322  // Cap places a hard limit on the number of items, returning all transactions
   323  // exceeding that limit.
   324  func (l *txList) Cap(threshold int) types.Transactions {
   325  	return l.txs.Cap(threshold)
   326  }
   327  
   328  // Remove deletes a transaction from the maintained list, returning whether the
   329  // transaction was found, and also returning any transaction invalidated due to
   330  // the deletion (strict mode only).
   331  func (l *txList) Remove(tx *types.Transaction) (bool, types.Transactions) {
   332  	// Remove the transaction from the set
   333  	nonce := tx.Nonce()
   334  	if removed := l.txs.Remove(nonce); !removed {
   335  		return false, nil
   336  	}
   337  	// In strict mode, filter out non-executable transactions
   338  	if l.strict {
   339  		return true, l.txs.Filter(func(tx *types.Transaction) bool { return tx.Nonce() > nonce })
   340  	}
   341  	return true, nil
   342  }
   343  
   344  // Ready retrieves a sequentially increasing list of transactions starting at the
   345  // provided nonce that is ready for processing. The returned transactions will be
   346  // removed from the list.
   347  //
   348  // Note, all transactions with nonces lower than start will also be returned to
   349  // prevent getting into and invalid state. This is not something that should ever
   350  // happen but better to be self correcting than failing!
   351  func (l *txList) Ready(start uint64) types.Transactions {
   352  	return l.txs.Ready(start)
   353  }
   354  
   355  // Len returns the length of the transaction list.
   356  func (l *txList) Len() int {
   357  	return l.txs.Len()
   358  }
   359  
   360  // Empty returns whether the list of transactions is empty or not.
   361  func (l *txList) Empty() bool {
   362  	return l.Len() == 0
   363  }
   364  
   365  // Flatten creates a nonce-sorted slice of transactions based on the loosely
   366  // sorted internal representation. The result of the sorting is cached in case
   367  // it's requested again before any modifications are made to the contents.
   368  func (l *txList) Flatten() types.Transactions {
   369  	return l.txs.Flatten()
   370  }
   371  
   372  // priceHeap is a heap.Interface implementation over transactions for retrieving
   373  // price-sorted transactions to discard when the pool fills up.
   374  type priceHeap []*types.Transaction
   375  
   376  func (h priceHeap) Len() int      { return len(h) }
   377  func (h priceHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
   378  
   379  func (h priceHeap) Less(i, j int) bool {
   380  	// Sort primarily by price, returning the cheaper one
   381  	//achilles190806 todo replace with net
   382  	//switch h[i].GasPrice().Cmp(h[j].GasPrice()) {
   383  	//case -1:
   384  	//	return true
   385  	//case 1:
   386  	//	return false
   387  	//}
   388  	// If the prices match, stabilize via nonces (high nonce is worse)
   389  	return h[i].Nonce() > h[j].Nonce()
   390  }
   391  
   392  func (h *priceHeap) Push(x interface{}) {
   393  	*h = append(*h, x.(*types.Transaction))
   394  }
   395  
   396  func (h *priceHeap) Pop() interface{} {
   397  	old := *h
   398  	n := len(old)
   399  	x := old[n-1]
   400  	*h = old[0 : n-1]
   401  	return x
   402  }
   403  
   404  // txPricedList is a price-sorted heap to allow operating on transactions pool
   405  // contents in a price-incrementing way.
   406  type txPricedList struct {
   407  	all    *txLookup  // Pointer to the map of all transactions
   408  	items  *priceHeap // Heap of prices of all the stored transactions
   409  	stales int        // Number of stale price points to (re-heap trigger)
   410  }
   411  
   412  // newTxPricedList creates a new price-sorted transaction heap.
   413  func newTxPricedList(all *txLookup) *txPricedList {
   414  	return &txPricedList{
   415  		all:   all,
   416  		items: new(priceHeap),
   417  	}
   418  }
   419  
   420  // Put inserts a new transaction into the heap.
   421  func (l *txPricedList) Put(tx *types.Transaction) {
   422  	heap.Push(l.items, tx)
   423  }
   424  
   425  // Removed notifies the prices transaction list that an old transaction dropped
   426  // from the pool. The list will just keep a counter of stale objects and update
   427  // the heap if a large enough ratio of transactions go stale.
   428  func (l *txPricedList) Removed() {
   429  	// Bump the stale counter, but exit if still too low (< 25%)
   430  	l.stales++
   431  	if l.stales <= len(*l.items)/4 {
   432  		return
   433  	}
   434  	// Seems we've reached a critical number of stale transactions, reheap
   435  	reheap := make(priceHeap, 0, l.all.Count())
   436  
   437  	l.stales, l.items = 0, &reheap
   438  	l.all.Range(func(hash common.Hash, tx *types.Transaction) bool {
   439  		*l.items = append(*l.items, tx)
   440  		return true
   441  	})
   442  	heap.Init(l.items)
   443  }
   444  
   445  // Cap finds all the transactions below the given price threshold, drops them
   446  // from the priced list and returns them for further removal from the entire pool.
   447  func (l *txPricedList) Cap(threshold *big.Int, local *accountSet) types.Transactions {
   448  	drop := make(types.Transactions, 0, 128) // Remote underpriced transactions to drop
   449  	save := make(types.Transactions, 0, 64)  // Local underpriced transactions to keep
   450  
   451  	for len(*l.items) > 0 {
   452  		// Discard stale transactions if found during cleanup
   453  		tx := heap.Pop(l.items).(*types.Transaction)
   454  		if l.all.Get(tx.Hash()) == nil {
   455  			l.stales--
   456  			continue
   457  		}
   458  		// Stop the discards if we've reached the threshold
   459  		//achilles190806 todo replace with net
   460  		//if tx.GasPrice().Cmp(threshold) >= 0 {
   461  		//	save = append(save, tx)
   462  		//	break
   463  		//}
   464  		// Non stale transaction found, discard unless local
   465  		if local.containsTx(tx) {
   466  			save = append(save, tx)
   467  		} else {
   468  			drop = append(drop, tx)
   469  		}
   470  	}
   471  	for _, tx := range save {
   472  		heap.Push(l.items, tx)
   473  	}
   474  	return drop
   475  }
   476  
   477  // Underpriced checks whether a transaction is cheaper than (or as cheap as) the
   478  // lowest priced transaction currently being tracked.
   479  func (l *txPricedList) Underpriced(tx *types.Transaction, local *accountSet) bool {
   480  	// Local transactions cannot be underpriced
   481  	if local.containsTx(tx) {
   482  		return false
   483  	}
   484  	// Discard stale price points if found at the heap start
   485  	for len(*l.items) > 0 {
   486  		head := []*types.Transaction(*l.items)[0]
   487  		if l.all.Get(head.Hash()) == nil {
   488  			l.stales--
   489  			heap.Pop(l.items)
   490  			continue
   491  		}
   492  		break
   493  	}
   494  	// Check if the transaction is underpriced or not
   495  	if len(*l.items) == 0 {
   496  		log.Error("Pricing query for empty pool") // This cannot happen, print to catch programming errors
   497  		return false
   498  	}
   499  	//achilles0711 remove gas
   500  	//cheapest := []*types.Transaction(*l.items)[0]
   501  	//return cheapest.GasPrice().Cmp(tx.GasPrice()) >= 0
   502  	return false
   503  }
   504  
   505  // Discard finds a number of most underpriced transactions, removes them from the
   506  // priced list and returns them for further removal from the entire pool.
   507  func (l *txPricedList) Discard(count int, local *accountSet) types.Transactions {
   508  	drop := make(types.Transactions, 0, count) // Remote underpriced transactions to drop
   509  	save := make(types.Transactions, 0, 64)    // Local underpriced transactions to keep
   510  
   511  	for len(*l.items) > 0 && count > 0 {
   512  		// Discard stale transactions if found during cleanup
   513  		tx := heap.Pop(l.items).(*types.Transaction)
   514  		if l.all.Get(tx.Hash()) == nil {
   515  			l.stales--
   516  			continue
   517  		}
   518  		// Non stale transaction found, discard unless local
   519  		if local.containsTx(tx) {
   520  			save = append(save, tx)
   521  		} else {
   522  			drop = append(drop, tx)
   523  			count--
   524  		}
   525  	}
   526  	for _, tx := range save {
   527  		heap.Push(l.items, tx)
   528  	}
   529  	return drop
   530  }