|
|
|
@ -52,31 +52,31 @@ func (h *nonceHeap) Pop() interface{} { |
|
|
|
|
return x |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// sortedMap is a nonce->transaction hash map with a heap based index to allow
|
|
|
|
|
// SortedMap is a nonce->transaction hash map with a heap based index to allow
|
|
|
|
|
// iterating over the contents in a nonce-incrementing way.
|
|
|
|
|
type sortedMap struct { |
|
|
|
|
type SortedMap struct { |
|
|
|
|
items map[uint64]*types.Transaction // Hash map storing the transaction data
|
|
|
|
|
index *nonceHeap // Heap of nonces of all the stored transactions (non-strict mode)
|
|
|
|
|
cache types.Transactions // Cache of the transactions already sorted
|
|
|
|
|
cacheMu sync.Mutex // Mutex covering the cache
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// newSortedMap creates a new nonce-sorted transaction map.
|
|
|
|
|
func newSortedMap() *sortedMap { |
|
|
|
|
return &sortedMap{ |
|
|
|
|
// NewSortedMap creates a new nonce-sorted transaction map.
|
|
|
|
|
func NewSortedMap() *SortedMap { |
|
|
|
|
return &SortedMap{ |
|
|
|
|
items: make(map[uint64]*types.Transaction), |
|
|
|
|
index: new(nonceHeap), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Get retrieves the current transactions associated with the given nonce.
|
|
|
|
|
func (m *sortedMap) Get(nonce uint64) *types.Transaction { |
|
|
|
|
func (m *SortedMap) Get(nonce uint64) *types.Transaction { |
|
|
|
|
return m.items[nonce] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Put inserts a new transaction into the map, also updating the map's nonce
|
|
|
|
|
// index. If a transaction already exists with the same nonce, it's overwritten.
|
|
|
|
|
func (m *sortedMap) Put(tx *types.Transaction) { |
|
|
|
|
func (m *SortedMap) Put(tx *types.Transaction) { |
|
|
|
|
nonce := tx.Nonce() |
|
|
|
|
if m.items[nonce] == nil { |
|
|
|
|
heap.Push(m.index, nonce) |
|
|
|
@ -89,7 +89,7 @@ func (m *sortedMap) Put(tx *types.Transaction) { |
|
|
|
|
// Forward removes all transactions from the map with a nonce lower than the
|
|
|
|
|
// provided threshold. Every removed transaction is returned for any post-removal
|
|
|
|
|
// maintenance.
|
|
|
|
|
func (m *sortedMap) Forward(threshold uint64) types.Transactions { |
|
|
|
|
func (m *SortedMap) Forward(threshold uint64) types.Transactions { |
|
|
|
|
var removed types.Transactions |
|
|
|
|
|
|
|
|
|
// Pop off heap items until the threshold is reached
|
|
|
|
@ -112,7 +112,7 @@ func (m *sortedMap) Forward(threshold uint64) types.Transactions { |
|
|
|
|
// Filter, as opposed to 'filter', re-initialises the heap after the operation is done.
|
|
|
|
|
// If you want to do several consecutive filterings, it's therefore better to first
|
|
|
|
|
// do a .filter(func1) followed by .Filter(func2) or reheap()
|
|
|
|
|
func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { |
|
|
|
|
func (m *SortedMap) Filter(filter func(*types.Transaction) bool) types.Transactions { |
|
|
|
|
removed := m.filter(filter) |
|
|
|
|
// If transactions were removed, the heap and cache are ruined
|
|
|
|
|
if len(removed) > 0 { |
|
|
|
@ -121,7 +121,7 @@ func (m *sortedMap) Filter(filter func(*types.Transaction) bool) types.Transacti |
|
|
|
|
return removed |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m *sortedMap) reheap() { |
|
|
|
|
func (m *SortedMap) reheap() { |
|
|
|
|
*m.index = make([]uint64, 0, len(m.items)) |
|
|
|
|
for nonce := range m.items { |
|
|
|
|
*m.index = append(*m.index, nonce) |
|
|
|
@ -134,7 +134,7 @@ func (m *sortedMap) reheap() { |
|
|
|
|
|
|
|
|
|
// filter is identical to Filter, but **does not** regenerate the heap. This method
|
|
|
|
|
// should only be used if followed immediately by a call to Filter or reheap()
|
|
|
|
|
func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { |
|
|
|
|
func (m *SortedMap) filter(filter func(*types.Transaction) bool) types.Transactions { |
|
|
|
|
var removed types.Transactions |
|
|
|
|
|
|
|
|
|
// Collect all the transactions to filter out
|
|
|
|
@ -154,7 +154,7 @@ func (m *sortedMap) filter(filter func(*types.Transaction) bool) types.Transacti |
|
|
|
|
|
|
|
|
|
// Cap places a hard limit on the number of items, returning all transactions
|
|
|
|
|
// exceeding that limit.
|
|
|
|
|
func (m *sortedMap) Cap(threshold int) types.Transactions { |
|
|
|
|
func (m *SortedMap) Cap(threshold int) types.Transactions { |
|
|
|
|
// Short circuit if the number of items is under the limit
|
|
|
|
|
if len(m.items) <= threshold { |
|
|
|
|
return nil |
|
|
|
@ -181,7 +181,7 @@ func (m *sortedMap) Cap(threshold int) types.Transactions { |
|
|
|
|
|
|
|
|
|
// Remove deletes a transaction from the maintained map, returning whether the
|
|
|
|
|
// transaction was found.
|
|
|
|
|
func (m *sortedMap) Remove(nonce uint64) bool { |
|
|
|
|
func (m *SortedMap) Remove(nonce uint64) bool { |
|
|
|
|
// Short circuit if no transaction is present
|
|
|
|
|
_, ok := m.items[nonce] |
|
|
|
|
if !ok { |
|
|
|
@ -209,7 +209,7 @@ func (m *sortedMap) Remove(nonce uint64) bool { |
|
|
|
|
// Note, all transactions with nonces lower than start will also be returned to
|
|
|
|
|
// prevent getting into an invalid state. This is not something that should ever
|
|
|
|
|
// happen but better to be self correcting than failing!
|
|
|
|
|
func (m *sortedMap) Ready(start uint64) types.Transactions { |
|
|
|
|
func (m *SortedMap) Ready(start uint64) types.Transactions { |
|
|
|
|
// Short circuit if no transactions are available
|
|
|
|
|
if m.index.Len() == 0 || (*m.index)[0] > start { |
|
|
|
|
return nil |
|
|
|
@ -229,11 +229,11 @@ func (m *sortedMap) Ready(start uint64) types.Transactions { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Len returns the length of the transaction map.
|
|
|
|
|
func (m *sortedMap) Len() int { |
|
|
|
|
func (m *SortedMap) Len() int { |
|
|
|
|
return len(m.items) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (m *sortedMap) flatten() types.Transactions { |
|
|
|
|
func (m *SortedMap) flatten() types.Transactions { |
|
|
|
|
m.cacheMu.Lock() |
|
|
|
|
defer m.cacheMu.Unlock() |
|
|
|
|
// If the sorting was not cached yet, create and cache it
|
|
|
|
@ -250,7 +250,7 @@ func (m *sortedMap) flatten() types.Transactions { |
|
|
|
|
// Flatten creates a nonce-sorted slice of transactions based on the loosely
|
|
|
|
|
// sorted internal representation. The result of the sorting is cached in case
|
|
|
|
|
// it's requested again before any modifications are made to the contents.
|
|
|
|
|
func (m *sortedMap) Flatten() types.Transactions { |
|
|
|
|
func (m *SortedMap) Flatten() types.Transactions { |
|
|
|
|
cache := m.flatten() |
|
|
|
|
// Copy the cache to prevent accidental modification
|
|
|
|
|
txs := make(types.Transactions, len(cache)) |
|
|
|
@ -260,7 +260,7 @@ func (m *sortedMap) Flatten() types.Transactions { |
|
|
|
|
|
|
|
|
|
// LastElement returns the last element of a flattened list, thus, the
|
|
|
|
|
// transaction with the highest nonce
|
|
|
|
|
func (m *sortedMap) LastElement() *types.Transaction { |
|
|
|
|
func (m *SortedMap) LastElement() *types.Transaction { |
|
|
|
|
cache := m.flatten() |
|
|
|
|
return cache[len(cache)-1] |
|
|
|
|
} |
|
|
|
@ -271,7 +271,7 @@ func (m *sortedMap) LastElement() *types.Transaction { |
|
|
|
|
// executable/future queue, with minor behavioral changes.
|
|
|
|
|
type list struct { |
|
|
|
|
strict bool // Whether nonces are strictly continuous or not
|
|
|
|
|
txs *sortedMap // Heap indexed sorted hash map of the transactions
|
|
|
|
|
txs *SortedMap // Heap indexed sorted hash map of the transactions
|
|
|
|
|
|
|
|
|
|
costcap *uint256.Int // Price of the highest costing transaction (reset only if exceeds balance)
|
|
|
|
|
gascap uint64 // Gas limit of the highest spending transaction (reset only if exceeds block limit)
|
|
|
|
@ -283,7 +283,7 @@ type list struct { |
|
|
|
|
func newList(strict bool) *list { |
|
|
|
|
return &list{ |
|
|
|
|
strict: strict, |
|
|
|
|
txs: newSortedMap(), |
|
|
|
|
txs: NewSortedMap(), |
|
|
|
|
costcap: new(uint256.Int), |
|
|
|
|
totalcost: new(uint256.Int), |
|
|
|
|
} |
|
|
|
|