core: use slices package for sorting (#27489)

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
Dan Laine 2023-06-20 05:58:47 -04:00 committed by GitHub
parent 84b05d4f34
commit 154b016b6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 39 additions and 94 deletions

View File

@ -23,7 +23,6 @@ import (
"io" "io"
"math/big" "math/big"
"runtime" "runtime"
"sort"
"strings" "strings"
"sync" "sync"
"sync/atomic" "sync/atomic"
@ -48,6 +47,7 @@ import (
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
"golang.org/x/exp/slices"
) )
var ( var (
@ -1015,8 +1015,8 @@ func (bc *BlockChain) procFutureBlocks() {
} }
} }
if len(blocks) > 0 { if len(blocks) > 0 {
sort.Slice(blocks, func(i, j int) bool { slices.SortFunc(blocks, func(a, b *types.Block) bool {
return blocks[i].NumberU64() < blocks[j].NumberU64() return a.NumberU64() < b.NumberU64()
}) })
// Insert one by one as chain insertion needs contiguous ancestry between blocks // Insert one by one as chain insertion needs contiguous ancestry between blocks
for i := range blocks { for i := range blocks {

View File

@ -24,13 +24,13 @@ import (
"math" "math"
"math/big" "math/big"
"reflect" "reflect"
"sort"
"strings" "strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"golang.org/x/exp/slices"
) )
var ( var (
@ -270,8 +270,8 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) {
} }
} }
} }
sort.Slice(forksByBlock, func(i, j int) bool { return forksByBlock[i] < forksByBlock[j] }) slices.Sort(forksByBlock)
sort.Slice(forksByTime, func(i, j int) bool { return forksByTime[i] < forksByTime[j] }) slices.Sort(forksByTime)
// Deduplicate fork identifiers applying multiple forks // Deduplicate fork identifiers applying multiple forks
for i := 1; i < len(forksByBlock); i++ { for i := 1; i < len(forksByBlock); i++ {

View File

@ -30,32 +30,28 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"os" "os"
"sort"
"strconv" "strconv"
"github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/exp/slices"
) )
type allocItem struct{ Addr, Balance *big.Int } type allocItem struct{ Addr, Balance *big.Int }
type allocList []allocItem func makelist(g *core.Genesis) []allocItem {
items := make([]allocItem, 0, len(g.Alloc))
func (a allocList) Len() int { return len(a) }
func (a allocList) Less(i, j int) bool { return a[i].Addr.Cmp(a[j].Addr) < 0 }
func (a allocList) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
func makelist(g *core.Genesis) allocList {
a := make(allocList, 0, len(g.Alloc))
for addr, account := range g.Alloc { for addr, account := range g.Alloc {
if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 { if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 {
panic(fmt.Sprintf("can't encode account %x", addr)) panic(fmt.Sprintf("can't encode account %x", addr))
} }
bigAddr := new(big.Int).SetBytes(addr.Bytes()) bigAddr := new(big.Int).SetBytes(addr.Bytes())
a = append(a, allocItem{bigAddr, account.Balance}) items = append(items, allocItem{bigAddr, account.Balance})
} }
sort.Sort(a) slices.SortFunc(items, func(a, b allocItem) bool {
return a return a.Addr.Cmp(b.Addr) < 0
})
return items
} }
func makealloc(g *core.Genesis) string { func makealloc(g *core.Genesis) string {

View File

@ -22,7 +22,6 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"sort"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -31,6 +30,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"golang.org/x/exp/slices"
) )
// ReadCanonicalHash retrieves the hash assigned to a canonical block number. // ReadCanonicalHash retrieves the hash assigned to a canonical block number.
@ -836,23 +836,13 @@ type badBlock struct {
Body *types.Body Body *types.Body
} }
// badBlockList implements the sort interface to allow sorting a list of
// bad blocks by their number in the reverse order.
type badBlockList []*badBlock
func (s badBlockList) Len() int { return len(s) }
func (s badBlockList) Less(i, j int) bool {
return s[i].Header.Number.Uint64() < s[j].Header.Number.Uint64()
}
func (s badBlockList) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// ReadBadBlock retrieves the bad block with the corresponding block hash. // ReadBadBlock retrieves the bad block with the corresponding block hash.
func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block {
blob, err := db.Get(badBlockKey) blob, err := db.Get(badBlockKey)
if err != nil { if err != nil {
return nil return nil
} }
var badBlocks badBlockList var badBlocks []*badBlock
if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil {
return nil return nil
} }
@ -871,7 +861,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block {
if err != nil { if err != nil {
return nil return nil
} }
var badBlocks badBlockList var badBlocks []*badBlock
if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil {
return nil return nil
} }
@ -889,7 +879,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) {
if err != nil { if err != nil {
log.Warn("Failed to load old bad blocks", "error", err) log.Warn("Failed to load old bad blocks", "error", err)
} }
var badBlocks badBlockList var badBlocks []*badBlock
if len(blob) > 0 { if len(blob) > 0 {
if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil {
log.Crit("Failed to decode old bad blocks", "error", err) log.Crit("Failed to decode old bad blocks", "error", err)
@ -905,7 +895,10 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) {
Header: block.Header(), Header: block.Header(),
Body: block.Body(), Body: block.Body(),
}) })
sort.Sort(sort.Reverse(badBlocks)) slices.SortFunc(badBlocks, func(a, b *badBlock) bool {
// Note: sorting in descending number order.
return a.Header.Number.Uint64() >= b.Header.Number.Uint64()
})
if len(badBlocks) > badBlockToKeep { if len(badBlocks) > badBlockToKeep {
badBlocks = badBlocks[:badBlockToKeep] badBlocks = badBlocks[:badBlockToKeep]
} }

View File

@ -19,12 +19,12 @@ package rawdb
import ( import (
"math/big" "math/big"
"reflect" "reflect"
"sort"
"sync" "sync"
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"golang.org/x/exp/slices"
) )
func TestChainIterator(t *testing.T) { func TestChainIterator(t *testing.T) {
@ -92,9 +92,11 @@ func TestChainIterator(t *testing.T) {
} }
} }
if !c.reverse { if !c.reverse {
sort.Ints(numbers) slices.Sort(numbers)
} else { } else {
sort.Sort(sort.Reverse(sort.IntSlice(numbers))) slices.SortFunc(numbers, func(a, b int) bool {
return a > b // Sort descending
})
} }
if !reflect.DeepEqual(numbers, c.expect) { if !reflect.DeepEqual(numbers, c.expect) {
t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers) t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers)

View File

@ -21,7 +21,6 @@ import (
"fmt" "fmt"
"math" "math"
"math/rand" "math/rand"
"sort"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -30,6 +29,7 @@ import (
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
bloomfilter "github.com/holiman/bloomfilter/v2" bloomfilter "github.com/holiman/bloomfilter/v2"
"golang.org/x/exp/slices"
) )
var ( var (
@ -525,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash {
dl.accountList = append(dl.accountList, hash) dl.accountList = append(dl.accountList, hash)
} }
} }
sort.Sort(hashes(dl.accountList)) slices.SortFunc(dl.accountList, common.Hash.Less)
dl.memory += uint64(len(dl.accountList) * common.HashLength) dl.memory += uint64(len(dl.accountList) * common.HashLength)
return dl.accountList return dl.accountList
} }
@ -563,7 +563,7 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool)
for k := range storageMap { for k := range storageMap {
storageList = append(storageList, k) storageList = append(storageList, k)
} }
sort.Sort(hashes(storageList)) slices.SortFunc(storageList, common.Hash.Less)
dl.storageList[accountHash] = storageList dl.storageList[accountHash] = storageList
dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength)
return storageList, destructed return storageList, destructed

View File

@ -22,6 +22,7 @@ import (
"sort" "sort"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/slices"
) )
// weightedIterator is a iterator with an assigned weight. It is used to prioritise // weightedIterator is a iterator with an assigned weight. It is used to prioritise
@ -32,18 +33,10 @@ type weightedIterator struct {
priority int priority int
} }
// weightedIterators is a set of iterators implementing the sort.Interface. func (it *weightedIterator) Less(other *weightedIterator) bool {
type weightedIterators []*weightedIterator
// Len implements sort.Interface, returning the number of active iterators.
func (its weightedIterators) Len() int { return len(its) }
// Less implements sort.Interface, returning which of two iterators in the stack
// is before the other.
func (its weightedIterators) Less(i, j int) bool {
// Order the iterators primarily by the account hashes // Order the iterators primarily by the account hashes
hashI := its[i].it.Hash() hashI := it.it.Hash()
hashJ := its[j].it.Hash() hashJ := other.it.Hash()
switch bytes.Compare(hashI[:], hashJ[:]) { switch bytes.Compare(hashI[:], hashJ[:]) {
case -1: case -1:
@ -52,12 +45,7 @@ func (its weightedIterators) Less(i, j int) bool {
return false return false
} }
// Same account/storage-slot in multiple layers, split by priority // Same account/storage-slot in multiple layers, split by priority
return its[i].priority < its[j].priority return it.priority < other.priority
}
// Swap implements sort.Interface, swapping two entries in the iterator stack.
func (its weightedIterators) Swap(i, j int) {
its[i], its[j] = its[j], its[i]
} }
// fastIterator is a more optimized multi-layer iterator which maintains a // fastIterator is a more optimized multi-layer iterator which maintains a
@ -69,7 +57,7 @@ type fastIterator struct {
curAccount []byte curAccount []byte
curSlot []byte curSlot []byte
iterators weightedIterators iterators []*weightedIterator
initiated bool initiated bool
account bool account bool
fail error fail error
@ -167,7 +155,9 @@ func (fi *fastIterator) init() {
} }
} }
// Re-sort the entire list // Re-sort the entire list
sort.Sort(fi.iterators) slices.SortFunc(fi.iterators, func(a, b *weightedIterator) bool {
return a.Less(b)
})
fi.initiated = false fi.initiated = false
} }

View File

@ -1,36 +0,0 @@
// Copyright 2019 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package snapshot
import (
"bytes"
"github.com/ethereum/go-ethereum/common"
)
// hashes is a helper to implement sort.Interface.
type hashes []common.Hash
// Len is the number of elements in the collection.
func (hs hashes) Len() int { return len(hs) }
// Less reports whether the element with index i should sort before the element
// with index j.
func (hs hashes) Less(i, j int) bool { return bytes.Compare(hs[i][:], hs[j][:]) < 0 }
// Swap swaps the elements with indexes i and j.
func (hs hashes) Swap(i, j int) { hs[i], hs[j] = hs[j], hs[i] }