From aff49f7b3e2d9072c7c0f91f869aedd3f6cb66e0 Mon Sep 17 00:00:00 2001 From: devopsbo3 <69951731+devopsbo3@users.noreply.github.com> Date: Fri, 10 Nov 2023 12:27:53 -0600 Subject: [PATCH] Revert "eth: use slices package for sorting (#27490)" This reverts commit 53e07ce2e6344cbc9a282c8c743c5993af205098. --- common/types.go | 5 --- eth/api_debug_test.go | 12 +++++-- eth/gasprice/feehistory.go | 25 ++++++++++----- eth/gasprice/gasprice.go | 53 +++++++++++++++++++++--------- eth/protocols/snap/sync_test.go | 57 +++++++++++++++++---------------- eth/tracers/api_test.go | 13 ++++++-- 6 files changed, 104 insertions(+), 61 deletions(-) diff --git a/common/types.go b/common/types.go index 93fb090454..31515f52fa 100644 --- a/common/types.go +++ b/common/types.go @@ -65,11 +65,6 @@ func BigToHash(b *big.Int) Hash { return BytesToHash(b.Bytes()) } // If b is larger than len(h), b will be cropped from the left. func HexToHash(s string) Hash { return BytesToHash(FromHex(s)) } -// Less compares two hashes. -func (h Hash) Less(other Hash) bool { - return bytes.Compare(h[:], other[:]) < 0 -} - // Bytes gets the byte representation of the underlying hash. func (h Hash) Bytes() []byte { return h[:] } diff --git a/eth/api_debug_test.go b/eth/api_debug_test.go index c7f0d4ac90..dec1b34ddc 100644 --- a/eth/api_debug_test.go +++ b/eth/api_debug_test.go @@ -21,6 +21,7 @@ import ( "fmt" "math/big" "reflect" + "sort" "testing" "github.com/davecgh/go-spew/spew" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/trie" - "golang.org/x/exp/slices" ) var dumper = spew.ConfigState{Indent: " "} @@ -58,6 +58,12 @@ func accountRangeTest(t *testing.T, trie *state.Trie, statedb *state.StateDB, st return result } +type resultHash []common.Hash + +func (h resultHash) Len() int { return len(h) } +func (h resultHash) Swap(i, j int) { h[i], h[j] = h[j], h[i] } +func (h resultHash) Less(i, j int) bool { return bytes.Compare(h[i].Bytes(), h[j].Bytes()) < 0 } + func TestAccountRange(t *testing.T) { t.Parallel() @@ -91,7 +97,7 @@ func TestAccountRange(t *testing.T) { firstResult := accountRangeTest(t, &trie, state, common.Hash{}, AccountRangeMaxResults, AccountRangeMaxResults) secondResult := accountRangeTest(t, &trie, state, common.BytesToHash(firstResult.Next), AccountRangeMaxResults, AccountRangeMaxResults) - hList := make([]common.Hash, 0) + hList := make(resultHash, 0) for addr1 := range firstResult.Accounts { // If address is empty, then it makes no sense to compare // them as they might be two different accounts. @@ -105,7 +111,7 @@ func TestAccountRange(t *testing.T) { } // Test to see if it's possible to recover from the middle of the previous // set and get an even split between the first and second sets. - slices.SortFunc(hList, common.Hash.Less) + sort.Sort(hList) middleH := hList[AccountRangeMaxResults/2] middleResult := accountRangeTest(t, &trie, state, middleH, AccountRangeMaxResults, AccountRangeMaxResults) missing, infirst, insecond := 0, 0, 0 diff --git a/eth/gasprice/feehistory.go b/eth/gasprice/feehistory.go index c048377062..ee0b0ebcca 100644 --- a/eth/gasprice/feehistory.go +++ b/eth/gasprice/feehistory.go @@ -23,6 +23,7 @@ import ( "fmt" "math" "math/big" + "sort" "sync/atomic" "github.com/ethereum/go-ethereum/common" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) var ( @@ -69,9 +69,20 @@ type processedFees struct { } // txGasAndReward is sorted in ascending order based on reward -type txGasAndReward struct { - gasUsed uint64 - reward *big.Int +type ( + txGasAndReward struct { + gasUsed uint64 + reward *big.Int + } + sortGasAndReward []txGasAndReward +) + +func (s sortGasAndReward) Len() int { return len(s) } +func (s sortGasAndReward) Swap(i, j int) { + s[i], s[j] = s[j], s[i] +} +func (s sortGasAndReward) Less(i, j int) bool { + return s[i].reward.Cmp(s[j].reward) < 0 } // processBlock takes a blockFees structure with the blockNumber, the header and optionally @@ -106,14 +117,12 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) { return } - sorter := make([]txGasAndReward, len(bf.block.Transactions())) + sorter := make(sortGasAndReward, len(bf.block.Transactions())) for i, tx := range bf.block.Transactions() { reward, _ := tx.EffectiveGasTip(bf.block.BaseFee()) sorter[i] = txGasAndReward{gasUsed: bf.receipts[i].GasUsed, reward: reward} } - slices.SortStableFunc(sorter, func(a, b txGasAndReward) bool { - return a.reward.Cmp(b.reward) < 0 - }) + sort.Stable(sorter) var txIndex int sumGasUsed := sorter[0].gasUsed diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index 9eccd72428..a3dd83d79f 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -19,6 +19,7 @@ package gasprice import ( "context" "math/big" + "sort" "sync" "github.com/ethereum/go-ethereum/common" @@ -29,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) const sampleNumber = 3 // Number of transactions sampled in a block @@ -208,7 +208,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) { } price := lastPrice if len(results) > 0 { - slices.SortFunc(results, func(a, b *big.Int) bool { return a.Cmp(b) < 0 }) + sort.Sort(bigIntArray(results)) price = results[(len(results)-1)*oracle.percentile/100] } if price.Cmp(oracle.maxPrice) > 0 { @@ -227,6 +227,30 @@ type results struct { err error } +type txSorter struct { + txs []*types.Transaction + baseFee *big.Int +} + +func newSorter(txs []*types.Transaction, baseFee *big.Int) *txSorter { + return &txSorter{ + txs: txs, + baseFee: baseFee, + } +} + +func (s *txSorter) Len() int { return len(s.txs) } +func (s *txSorter) Swap(i, j int) { + s.txs[i], s.txs[j] = s.txs[j], s.txs[i] +} +func (s *txSorter) Less(i, j int) bool { + // It's okay to discard the error because a tx would never be + // accepted into a block with an invalid effective tip. + tip1, _ := s.txs[i].EffectiveGasTip(s.baseFee) + tip2, _ := s.txs[j].EffectiveGasTip(s.baseFee) + return tip1.Cmp(tip2) < 0 +} + // getBlockValues calculates the lowest transaction gas price in a given block // and sends it to the result channel. If the block is empty or all transactions // are sent by the miner itself(it doesn't make any sense to include this kind of @@ -243,21 +267,14 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit signer := types.MakeSigner(oracle.backend.ChainConfig(), block.Number(), block.Time()) // Sort the transaction by effective tip in ascending sort. - txs := block.Transactions() - sortedTxs := make([]*types.Transaction, len(txs)) - copy(sortedTxs, txs) - baseFee := block.BaseFee() - slices.SortFunc(sortedTxs, func(a, b *types.Transaction) bool { - // It's okay to discard the error because a tx would never be - // accepted into a block with an invalid effective tip. - tip1, _ := a.EffectiveGasTip(baseFee) - tip2, _ := b.EffectiveGasTip(baseFee) - return tip1.Cmp(tip2) < 0 - }) + txs := make([]*types.Transaction, len(block.Transactions())) + copy(txs, block.Transactions()) + sorter := newSorter(txs, block.BaseFee()) + sort.Sort(sorter) var prices []*big.Int - for _, tx := range sortedTxs { - tip, _ := tx.EffectiveGasTip(baseFee) + for _, tx := range sorter.txs { + tip, _ := tx.EffectiveGasTip(block.BaseFee()) if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 { continue } @@ -274,3 +291,9 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit case <-quit: } } + +type bigIntArray []*big.Int + +func (s bigIntArray) Len() int { return len(s) } +func (s bigIntArray) Less(i, j int) bool { return s[i].Cmp(s[j]) < 0 } +func (s bigIntArray) Swap(i, j int) { s[i], s[j] = s[j], s[i] } diff --git a/eth/protocols/snap/sync_test.go b/eth/protocols/snap/sync_test.go index 6efe0c8325..23af204162 100644 --- a/eth/protocols/snap/sync_test.go +++ b/eth/protocols/snap/sync_test.go @@ -22,6 +22,7 @@ import ( "encoding/binary" "fmt" "math/big" + "sort" "sync" "testing" "time" @@ -37,7 +38,6 @@ import ( "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" "golang.org/x/crypto/sha3" - "golang.org/x/exp/slices" ) func TestHashing(t *testing.T) { @@ -127,9 +127,9 @@ type testPeer struct { remote *Syncer logger log.Logger accountTrie *trie.Trie - accountValues []*kv + accountValues entrySlice storageTries map[common.Hash]*trie.Trie - storageValues map[common.Hash][]*kv + storageValues map[common.Hash]entrySlice accountRequestHandler accountHandlerFunc storageRequestHandler storageHandlerFunc @@ -1321,9 +1321,12 @@ type kv struct { k, v []byte } -func (k *kv) less(other *kv) bool { - return bytes.Compare(k.k, other.k) < 0 -} +// Some helpers for sorting +type entrySlice []*kv + +func (p entrySlice) Len() int { return len(p) } +func (p entrySlice) Less(i, j int) bool { return bytes.Compare(p[i].k, p[j].k) < 0 } +func (p entrySlice) Swap(i, j int) { p[i], p[j] = p[j], p[i] } func key32(i uint64) []byte { key := make([]byte, 32) @@ -1364,11 +1367,11 @@ func getCodeByHash(hash common.Hash) []byte { } // makeAccountTrieNoStorage spits out a trie, along with the leafs -func makeAccountTrieNoStorage(n int) (string, *trie.Trie, []*kv) { +func makeAccountTrieNoStorage(n int) (string, *trie.Trie, entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) - entries []*kv + entries entrySlice ) for i := uint64(1); i <= uint64(n); i++ { value, _ := rlp.EncodeToBytes(&types.StateAccount{ @@ -1382,7 +1385,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, []*kv) { accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) // Commit the state changes into db and re-create the trie // for accessing later. @@ -1396,9 +1399,9 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, []*kv) { // makeBoundaryAccountTrie constructs an account trie. Instead of filling // accounts normally, this function will fill a few accounts which have // boundary hash. -func makeBoundaryAccountTrie(n int) (string, *trie.Trie, []*kv) { +func makeBoundaryAccountTrie(n int) (string, *trie.Trie, entrySlice) { var ( - entries []*kv + entries entrySlice boundaries []common.Hash db = trie.NewDatabase(rawdb.NewMemoryDatabase()) @@ -1444,7 +1447,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, []*kv) { accTrie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) // Commit the state changes into db and re-create the trie // for accessing later. @@ -1457,14 +1460,14 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, []*kv) { // makeAccountTrieWithStorageWithUniqueStorage creates an account trie where each accounts // has a unique storage set. -func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { +func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) - entries []*kv + entries entrySlice storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) - storageEntries = make(map[common.Hash][]*kv) + storageEntries = make(map[common.Hash]entrySlice) nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie @@ -1491,7 +1494,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) // Commit account trie root, set := accTrie.Commit(true) @@ -1512,14 +1515,14 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool) } // makeAccountTrieWithStorage spits out a trie, along with the leafs -func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (string, *trie.Trie, []*kv, map[common.Hash]*trie.Trie, map[common.Hash][]*kv) { +func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (string, *trie.Trie, entrySlice, map[common.Hash]*trie.Trie, map[common.Hash]entrySlice) { var ( db = trie.NewDatabase(rawdb.NewMemoryDatabase()) accTrie = trie.NewEmpty(db) - entries []*kv + entries entrySlice storageRoots = make(map[common.Hash]common.Hash) storageTries = make(map[common.Hash]*trie.Trie) - storageEntries = make(map[common.Hash][]*kv) + storageEntries = make(map[common.Hash]entrySlice) nodes = trienode.NewMergedNodeSet() ) // Create n accounts in the trie @@ -1533,7 +1536,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin var ( stRoot common.Hash stNodes *trienode.NodeSet - stEntries []*kv + stEntries entrySlice ) if boundary { stRoot, stNodes, stEntries = makeBoundaryStorageTrie(common.BytesToHash(key), slots, db) @@ -1556,7 +1559,7 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin storageRoots[common.BytesToHash(key)] = stRoot storageEntries[common.BytesToHash(key)] = stEntries } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) // Commit account trie root, set := accTrie.Commit(true) @@ -1585,9 +1588,9 @@ func makeAccountTrieWithStorage(accounts, slots int, code, boundary bool) (strin // makeStorageTrieWithSeed fills a storage trie with n items, returning the // not-yet-committed trie and the sorted entries. The seeds can be used to ensure // that tries are unique. -func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, []*kv) { +func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { trie, _ := trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) - var entries []*kv + var entries entrySlice for i := uint64(1); i <= n; i++ { // store 'x' at slot 'x' slotValue := key32(i + seed) @@ -1600,7 +1603,7 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) root, nodes := trie.Commit(false) return root, nodes, entries } @@ -1608,9 +1611,9 @@ func makeStorageTrieWithSeed(owner common.Hash, n, seed uint64, db *trie.Databas // makeBoundaryStorageTrie constructs a storage trie. Instead of filling // storage slots normally, this function will fill a few slots which have // boundary hash. -func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, []*kv) { +func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (common.Hash, *trienode.NodeSet, entrySlice) { var ( - entries []*kv + entries entrySlice boundaries []common.Hash trie, _ = trie.New(trie.StorageTrieID(types.EmptyRootHash, owner, types.EmptyRootHash), db) ) @@ -1651,7 +1654,7 @@ func makeBoundaryStorageTrie(owner common.Hash, n int, db *trie.Database) (commo trie.MustUpdate(elem.k, elem.v) entries = append(entries, elem) } - slices.SortFunc(entries, (*kv).less) + sort.Sort(entries) root, nodes := trie.Commit(false) return root, nodes, entries } diff --git a/eth/tracers/api_test.go b/eth/tracers/api_test.go index 11d7ff4b69..fdb02b1895 100644 --- a/eth/tracers/api_test.go +++ b/eth/tracers/api_test.go @@ -17,6 +17,7 @@ package tracers import ( + "bytes" "context" "crypto/ecdsa" "encoding/json" @@ -24,6 +25,7 @@ import ( "fmt" "math/big" "reflect" + "sort" "sync/atomic" "testing" "time" @@ -43,7 +45,6 @@ import ( "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" - "golang.org/x/exp/slices" ) var ( @@ -784,13 +785,19 @@ type Account struct { addr common.Address } -func newAccounts(n int) (accounts []Account) { +type Accounts []Account + +func (a Accounts) Len() int { return len(a) } +func (a Accounts) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a Accounts) Less(i, j int) bool { return bytes.Compare(a[i].addr.Bytes(), a[j].addr.Bytes()) < 0 } + +func newAccounts(n int) (accounts Accounts) { for i := 0; i < n; i++ { key, _ := crypto.GenerateKey() addr := crypto.PubkeyToAddress(key.PublicKey) accounts = append(accounts, Account{key: key, addr: addr}) } - slices.SortFunc(accounts, func(a, b Account) bool { return a.addr.Less(b.addr) }) + sort.Sort(accounts) return accounts }