Skip to content

eth: use slices package for sorting #27490

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jun 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions common/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ 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[:] }

Expand Down
12 changes: 3 additions & 9 deletions eth/api_debug_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"fmt"
"math/big"
"reflect"
"sort"
"testing"

"github.com/davecgh/go-spew/spew"
Expand All @@ -31,6 +30,7 @@ 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: " "}
Expand Down Expand Up @@ -58,12 +58,6 @@ 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()

Expand Down Expand Up @@ -97,7 +91,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(resultHash, 0)
hList := make([]common.Hash, 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.
Expand All @@ -111,7 +105,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.
sort.Sort(hList)
slices.SortFunc(hList, common.Hash.Less)
middleH := hList[AccountRangeMaxResults/2]
middleResult := accountRangeTest(t, &trie, state, middleH, AccountRangeMaxResults, AccountRangeMaxResults)
missing, infirst, insecond := 0, 0, 0
Expand Down
25 changes: 8 additions & 17 deletions eth/gasprice/feehistory.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,14 @@ import (
"fmt"
"math"
"math/big"
"sort"
"sync/atomic"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus/misc"
"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 (
Expand Down Expand Up @@ -69,20 +69,9 @@ type processedFees struct {
}

// txGasAndReward is sorted in ascending order based on reward
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
type txGasAndReward struct {
gasUsed uint64
reward *big.Int
}

// processBlock takes a blockFees structure with the blockNumber, the header and optionally
Expand Down Expand Up @@ -117,12 +106,14 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
return
}

sorter := make(sortGasAndReward, len(bf.block.Transactions()))
sorter := make([]txGasAndReward, 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}
}
sort.Stable(sorter)
slices.SortStableFunc(sorter, func(a, b txGasAndReward) bool {
return a.reward.Cmp(b.reward) < 0
})

var txIndex int
sumGasUsed := sorter[0].gasUsed
Expand Down
53 changes: 15 additions & 38 deletions eth/gasprice/gasprice.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package gasprice
import (
"context"
"math/big"
"sort"
"sync"

"github.com/ethereum/go-ethereum/common"
Expand All @@ -30,6 +29,7 @@ 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
Expand Down Expand Up @@ -208,7 +208,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
}
price := lastPrice
if len(results) > 0 {
sort.Sort(bigIntArray(results))
slices.SortFunc(results, func(a, b *big.Int) bool { return a.Cmp(b) < 0 })
price = results[(len(results)-1)*oracle.percentile/100]
}
if price.Cmp(oracle.maxPrice) > 0 {
Expand All @@ -227,30 +227,6 @@ 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
Expand All @@ -267,14 +243,21 @@ 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 := make([]*types.Transaction, len(block.Transactions()))
copy(txs, block.Transactions())
sorter := newSorter(txs, block.BaseFee())
sort.Sort(sorter)
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
})

var prices []*big.Int
for _, tx := range sorter.txs {
tip, _ := tx.EffectiveGasTip(block.BaseFee())
for _, tx := range sortedTxs {
tip, _ := tx.EffectiveGasTip(baseFee)
if ignoreUnder != nil && tip.Cmp(ignoreUnder) == -1 {
continue
}
Expand All @@ -291,9 +274,3 @@ 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] }
Loading