diff --git a/core/blockchain.go b/core/blockchain.go index becd39a1fa..ec8b789c58 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -23,6 +23,7 @@ import ( "io" "math/big" "runtime" + "sort" "strings" "sync" "sync/atomic" @@ -47,7 +48,6 @@ import ( "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" - "golang.org/x/exp/slices" ) var ( @@ -1015,8 +1015,8 @@ func (bc *BlockChain) procFutureBlocks() { } } if len(blocks) > 0 { - slices.SortFunc(blocks, func(a, b *types.Block) bool { - return a.NumberU64() < b.NumberU64() + sort.Slice(blocks, func(i, j int) bool { + return blocks[i].NumberU64() < blocks[j].NumberU64() }) // Insert one by one as chain insertion needs contiguous ancestry between blocks for i := range blocks { diff --git a/core/forkid/forkid.go b/core/forkid/forkid.go index 8964558845..f536019dac 100644 --- a/core/forkid/forkid.go +++ b/core/forkid/forkid.go @@ -24,13 +24,13 @@ import ( "math" "math/big" "reflect" + "sort" "strings" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" - "golang.org/x/exp/slices" ) var ( @@ -270,8 +270,8 @@ func gatherForks(config *params.ChainConfig) ([]uint64, []uint64) { } } } - slices.Sort(forksByBlock) - slices.Sort(forksByTime) + sort.Slice(forksByBlock, func(i, j int) bool { return forksByBlock[i] < forksByBlock[j] }) + sort.Slice(forksByTime, func(i, j int) bool { return forksByTime[i] < forksByTime[j] }) // Deduplicate fork identifiers applying multiple forks for i := 1; i < len(forksByBlock); i++ { diff --git a/core/mkalloc.go b/core/mkalloc.go index 0e7355f631..e4c2ec0d83 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -30,28 +30,32 @@ import ( "fmt" "math/big" "os" + "sort" "strconv" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) type allocItem struct{ Addr, Balance *big.Int } -func makelist(g *core.Genesis) []allocItem { - items := make([]allocItem, 0, len(g.Alloc)) +type allocList []allocItem + +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 { if len(account.Storage) > 0 || len(account.Code) > 0 || account.Nonce != 0 { panic(fmt.Sprintf("can't encode account %x", addr)) } bigAddr := new(big.Int).SetBytes(addr.Bytes()) - items = append(items, allocItem{bigAddr, account.Balance}) + a = append(a, allocItem{bigAddr, account.Balance}) } - slices.SortFunc(items, func(a, b allocItem) bool { - return a.Addr.Cmp(b.Addr) < 0 - }) - return items + sort.Sort(a) + return a } func makealloc(g *core.Genesis) string { diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index dd5425eec7..b479655b0b 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -22,6 +22,7 @@ import ( "errors" "fmt" "math/big" + "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -30,7 +31,6 @@ import ( "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/exp/slices" ) // ReadCanonicalHash retrieves the hash assigned to a canonical block number. @@ -836,13 +836,23 @@ type badBlock struct { 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. func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { blob, err := db.Get(badBlockKey) if err != nil { return nil } - var badBlocks []*badBlock + var badBlocks badBlockList if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -861,7 +871,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { if err != nil { return nil } - var badBlocks []*badBlock + var badBlocks badBlockList if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -879,7 +889,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { if err != nil { log.Warn("Failed to load old bad blocks", "error", err) } - var badBlocks []*badBlock + var badBlocks badBlockList if len(blob) > 0 { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { log.Crit("Failed to decode old bad blocks", "error", err) @@ -895,10 +905,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { Header: block.Header(), Body: block.Body(), }) - slices.SortFunc(badBlocks, func(a, b *badBlock) bool { - // Note: sorting in descending number order. - return a.Header.Number.Uint64() >= b.Header.Number.Uint64() - }) + sort.Sort(sort.Reverse(badBlocks)) if len(badBlocks) > badBlockToKeep { badBlocks = badBlocks[:badBlockToKeep] } diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index fd405e9d69..e1f5159753 100644 --- a/core/rawdb/chain_iterator_test.go +++ b/core/rawdb/chain_iterator_test.go @@ -19,12 +19,12 @@ package rawdb import ( "math/big" "reflect" + "sort" "sync" "testing" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "golang.org/x/exp/slices" ) func TestChainIterator(t *testing.T) { @@ -92,11 +92,9 @@ func TestChainIterator(t *testing.T) { } } if !c.reverse { - slices.Sort(numbers) + sort.Ints(numbers) } else { - slices.SortFunc(numbers, func(a, b int) bool { - return a > b // Sort descending - }) + sort.Sort(sort.Reverse(sort.IntSlice(numbers))) } if !reflect.DeepEqual(numbers, c.expect) { t.Fatalf("Case %d failed, visit element mismatch, want %v, got %v", i, c.expect, numbers) diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index b10b43b1ae..8869a84716 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -21,6 +21,7 @@ import ( "fmt" "math" "math/rand" + "sort" "sync" "sync/atomic" "time" @@ -29,7 +30,6 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/rlp" bloomfilter "github.com/holiman/bloomfilter/v2" - "golang.org/x/exp/slices" ) var ( @@ -525,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash { dl.accountList = append(dl.accountList, hash) } } - slices.SortFunc(dl.accountList, common.Hash.Less) + sort.Sort(hashes(dl.accountList)) dl.memory += uint64(len(dl.accountList) * common.HashLength) return dl.accountList } @@ -563,7 +563,7 @@ func (dl *diffLayer) StorageList(accountHash common.Hash) ([]common.Hash, bool) for k := range storageMap { storageList = append(storageList, k) } - slices.SortFunc(storageList, common.Hash.Less) + sort.Sort(hashes(storageList)) dl.storageList[accountHash] = storageList dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) return storageList, destructed diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 339f930ffd..1a042c7cd3 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -22,7 +22,6 @@ import ( "sort" "github.com/ethereum/go-ethereum/common" - "golang.org/x/exp/slices" ) // weightedIterator is a iterator with an assigned weight. It is used to prioritise @@ -33,10 +32,18 @@ type weightedIterator struct { priority int } -func (it *weightedIterator) Less(other *weightedIterator) bool { +// weightedIterators is a set of iterators implementing the sort.Interface. +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 - hashI := it.it.Hash() - hashJ := other.it.Hash() + hashI := its[i].it.Hash() + hashJ := its[j].it.Hash() switch bytes.Compare(hashI[:], hashJ[:]) { case -1: @@ -45,7 +52,12 @@ func (it *weightedIterator) Less(other *weightedIterator) bool { return false } // Same account/storage-slot in multiple layers, split by priority - return it.priority < other.priority + return its[i].priority < its[j].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 @@ -57,7 +69,7 @@ type fastIterator struct { curAccount []byte curSlot []byte - iterators []*weightedIterator + iterators weightedIterators initiated bool account bool fail error @@ -155,9 +167,7 @@ func (fi *fastIterator) init() { } } // Re-sort the entire list - slices.SortFunc(fi.iterators, func(a, b *weightedIterator) bool { - return a.Less(b) - }) + sort.Sort(fi.iterators) fi.initiated = false } diff --git a/core/state/snapshot/sort.go b/core/state/snapshot/sort.go new file mode 100644 index 0000000000..88841231d9 --- /dev/null +++ b/core/state/snapshot/sort.go @@ -0,0 +1,36 @@ +// 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 . + +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] }