|
|
@ -17,11 +17,13 @@ |
|
|
|
package types |
|
|
|
package types |
|
|
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
import ( |
|
|
|
|
|
|
|
"container/heap" |
|
|
|
"crypto/ecdsa" |
|
|
|
"crypto/ecdsa" |
|
|
|
"errors" |
|
|
|
"errors" |
|
|
|
"fmt" |
|
|
|
"fmt" |
|
|
|
"io" |
|
|
|
"io" |
|
|
|
"math/big" |
|
|
|
"math/big" |
|
|
|
|
|
|
|
"sort" |
|
|
|
"sync/atomic" |
|
|
|
"sync/atomic" |
|
|
|
|
|
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
|
"github.com/ethereum/go-ethereum/common" |
|
|
@ -302,27 +304,78 @@ func TxDifference(a, b Transactions) (keep Transactions) { |
|
|
|
return keep |
|
|
|
return keep |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type TxByNonce struct{ Transactions } |
|
|
|
// TxByNonce implements the sort interface to allow sorting a list of transactions
|
|
|
|
|
|
|
|
// by their nonces. This is usually only useful for sorting transactions from a
|
|
|
|
|
|
|
|
// single account, otherwise a nonce comparison doesn't make much sense.
|
|
|
|
|
|
|
|
type TxByNonce Transactions |
|
|
|
|
|
|
|
|
|
|
|
func (s TxByNonce) Less(i, j int) bool { |
|
|
|
func (s TxByNonce) Len() int { return len(s) } |
|
|
|
return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce |
|
|
|
func (s TxByNonce) Less(i, j int) bool { return s[i].data.AccountNonce < s[j].data.AccountNonce } |
|
|
|
} |
|
|
|
func (s TxByNonce) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TxByPrice implements both the sort and the heap interface, making it useful
|
|
|
|
|
|
|
|
// for all at once sorting as well as individually adding and removing elements.
|
|
|
|
|
|
|
|
type TxByPrice Transactions |
|
|
|
|
|
|
|
|
|
|
|
type TxByPrice struct{ Transactions } |
|
|
|
func (s TxByPrice) Len() int { return len(s) } |
|
|
|
|
|
|
|
func (s TxByPrice) Less(i, j int) bool { return s[i].data.Price.Cmp(s[j].data.Price) > 0 } |
|
|
|
|
|
|
|
func (s TxByPrice) Swap(i, j int) { s[i], s[j] = s[j], s[i] } |
|
|
|
|
|
|
|
|
|
|
|
func (s TxByPrice) Less(i, j int) bool { |
|
|
|
func (s *TxByPrice) Push(x interface{}) { |
|
|
|
return s.Transactions[i].data.Price.Cmp(s.Transactions[j].data.Price) > 0 |
|
|
|
*s = append(*s, x.(*Transaction)) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
type TxByPriceAndNonce struct{ Transactions } |
|
|
|
func (s *TxByPrice) Pop() interface{} { |
|
|
|
|
|
|
|
old := *s |
|
|
|
|
|
|
|
n := len(old) |
|
|
|
|
|
|
|
x := old[n-1] |
|
|
|
|
|
|
|
*s = old[0 : n-1] |
|
|
|
|
|
|
|
return x |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (s TxByPriceAndNonce) Less(i, j int) bool { |
|
|
|
// SortByPriceAndNonce sorts the transactions by price in such a way that the
|
|
|
|
// we can ignore the error here. Sorting shouldn't care about validness
|
|
|
|
// nonce orderings within a single account are maintained.
|
|
|
|
ifrom, _ := s.Transactions[i].From() |
|
|
|
//
|
|
|
|
jfrom, _ := s.Transactions[j].From() |
|
|
|
// Note, this is not as trivial as it seems from the first look as there are three
|
|
|
|
// favour nonce if they are from the same recipient
|
|
|
|
// different criteria that need to be taken into account (price, nonce, account
|
|
|
|
if ifrom == jfrom { |
|
|
|
// match), which cannot be done with any plain sorting method, as certain items
|
|
|
|
return s.Transactions[i].data.AccountNonce < s.Transactions[j].data.AccountNonce |
|
|
|
// cannot be compared without context.
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// This method first sorts the separates the list of transactions into individual
|
|
|
|
|
|
|
|
// sender accounts and sorts them by nonce. After the account nonce ordering is
|
|
|
|
|
|
|
|
// satisfied, the results are merged back together by price, always comparing only
|
|
|
|
|
|
|
|
// the head transaction from each account. This is done via a heap to keep it fast.
|
|
|
|
|
|
|
|
func SortByPriceAndNonce(txs []*Transaction) { |
|
|
|
|
|
|
|
// Separate the transactions by account and sort by nonce
|
|
|
|
|
|
|
|
byNonce := make(map[common.Address][]*Transaction) |
|
|
|
|
|
|
|
for _, tx := range txs { |
|
|
|
|
|
|
|
acc, _ := tx.From() // we only sort valid txs so this cannot fail
|
|
|
|
|
|
|
|
byNonce[acc] = append(byNonce[acc], tx) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for _, accTxs := range byNonce { |
|
|
|
|
|
|
|
sort.Sort(TxByNonce(accTxs)) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Initialize a price based heap with the head transactions
|
|
|
|
|
|
|
|
byPrice := make(TxByPrice, 0, len(byNonce)) |
|
|
|
|
|
|
|
for acc, accTxs := range byNonce { |
|
|
|
|
|
|
|
byPrice = append(byPrice, accTxs[0]) |
|
|
|
|
|
|
|
byNonce[acc] = accTxs[1:] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
heap.Init(&byPrice) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Merge by replacing the best with the next from the same account
|
|
|
|
|
|
|
|
txs = txs[:0] |
|
|
|
|
|
|
|
for len(byPrice) > 0 { |
|
|
|
|
|
|
|
// Retrieve the next best transaction by price
|
|
|
|
|
|
|
|
best := heap.Pop(&byPrice).(*Transaction) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Push in its place the next transaction from the same account
|
|
|
|
|
|
|
|
acc, _ := best.From() // we only sort valid txs so this cannot fail
|
|
|
|
|
|
|
|
if accTxs, ok := byNonce[acc]; ok && len(accTxs) > 0 { |
|
|
|
|
|
|
|
heap.Push(&byPrice, accTxs[0]) |
|
|
|
|
|
|
|
byNonce[acc] = accTxs[1:] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// Accumulate the best priced transaction
|
|
|
|
|
|
|
|
txs = append(txs, best) |
|
|
|
} |
|
|
|
} |
|
|
|
return s.Transactions[i].data.Price.Cmp(s.Transactions[j].data.Price) > 0 |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|