From f591579ecb3c2135c3381ff2e3620f39366769a3 Mon Sep 17 00:00:00 2001 From: Dan Laine Date: Fri, 16 Jun 2023 09:37:02 -0400 Subject: [PATCH 1/6] core; use slices package for sorting --- core/blockchain.go | 6 +++--- core/forkid/forkid.go | 6 +++--- core/mkalloc.go | 14 +++++--------- core/rawdb/accessors_chain.go | 22 +++++++++------------- core/rawdb/chain_iterator_test.go | 8 +++++--- core/state/snapshot/difflayer.go | 6 +++--- core/state/snapshot/iterator_fast.go | 28 +++++++++------------------- core/state/snapshot/sort.go | 15 +++------------ core/vm/eips.go | 4 ++-- 9 files changed, 42 insertions(+), 67 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index ec8b789c586b..becd39a1fa04 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -23,7 +23,6 @@ import ( "io" "math/big" "runtime" - "sort" "strings" "sync" "sync/atomic" @@ -48,6 +47,7 @@ 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 { - sort.Slice(blocks, func(i, j int) bool { - return blocks[i].NumberU64() < blocks[j].NumberU64() + slices.SortFunc(blocks, func(a, b *types.Block) bool { + return a.NumberU64() < b.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 f536019dac12..8964558845d3 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) { } } } - 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] }) + slices.Sort(forksByBlock) + slices.Sort(forksByTime) // Deduplicate fork identifiers applying multiple forks for i := 1; i < len(forksByBlock); i++ { diff --git a/core/mkalloc.go b/core/mkalloc.go index e4c2ec0d83e9..277b00e3577c 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -39,14 +39,8 @@ import ( type allocItem struct{ Addr, Balance *big.Int } -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)) +func makelist(g *core.Genesis) []allocItem { + a := make([]allocItem, 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)) @@ -54,7 +48,9 @@ func makelist(g *core.Genesis) allocList { bigAddr := new(big.Int).SetBytes(addr.Bytes()) a = append(a, allocItem{bigAddr, account.Balance}) } - sort.Sort(a) + slices.SortFunc(a, func(b, c allocItem) bool { + return b.Addr.Cmp(c.Addr) < 0 + }) return a } diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index b479655b0b74..dd418abd4070 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -22,7 +22,6 @@ import ( "errors" "fmt" "math/big" - "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" @@ -31,6 +30,7 @@ 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,15 +836,9 @@ 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 (b *badBlock) Less(other *badBlock) bool { + return b.Header.Number.Uint64() < other.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 { @@ -852,7 +846,7 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block { if err != nil { return nil } - var badBlocks badBlockList + var badBlocks []*badBlock if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -871,7 +865,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block { if err != nil { return nil } - var badBlocks badBlockList + var badBlocks []*badBlock if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { return nil } @@ -889,7 +883,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { if err != nil { log.Warn("Failed to load old bad blocks", "error", err) } - var badBlocks badBlockList + var badBlocks []*badBlock if len(blob) > 0 { if err := rlp.DecodeBytes(blob, &badBlocks); err != nil { log.Crit("Failed to decode old bad blocks", "error", err) @@ -905,7 +899,9 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { Header: block.Header(), Body: block.Body(), }) - sort.Sort(sort.Reverse(badBlocks)) + slices.SortFunc(badBlocks, func(a, b *badBlock) bool { + return !a.Less(b) // Sort reverse order + }) if len(badBlocks) > badBlockToKeep { badBlocks = badBlocks[:badBlockToKeep] } diff --git a/core/rawdb/chain_iterator_test.go b/core/rawdb/chain_iterator_test.go index e1f5159753f0..fd405e9d6997 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,9 +92,11 @@ func TestChainIterator(t *testing.T) { } } if !c.reverse { - sort.Ints(numbers) + slices.Sort(numbers) } 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) { 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 8869a8471672..293c85115067 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -21,7 +21,6 @@ import ( "fmt" "math" "math/rand" - "sort" "sync" "sync/atomic" "time" @@ -30,6 +29,7 @@ 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) } } - sort.Sort(hashes(dl.accountList)) + slices.SortFunc(dl.accountList, hashesLess) 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) } - sort.Sort(hashes(storageList)) + slices.SortFunc(storageList, hashesLess) 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 1a042c7cd3c0..339f930ffd81 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -22,6 +22,7 @@ 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 @@ -32,18 +33,10 @@ type weightedIterator struct { priority int } -// 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 { +func (it *weightedIterator) Less(other *weightedIterator) bool { // Order the iterators primarily by the account hashes - hashI := its[i].it.Hash() - hashJ := its[j].it.Hash() + hashI := it.it.Hash() + hashJ := other.it.Hash() switch bytes.Compare(hashI[:], hashJ[:]) { case -1: @@ -52,12 +45,7 @@ func (its weightedIterators) Less(i, j int) bool { return false } // Same account/storage-slot in multiple layers, split by 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] + return it.priority < other.priority } // fastIterator is a more optimized multi-layer iterator which maintains a @@ -69,7 +57,7 @@ type fastIterator struct { curAccount []byte curSlot []byte - iterators weightedIterators + iterators []*weightedIterator initiated bool account bool fail error @@ -167,7 +155,9 @@ func (fi *fastIterator) init() { } } // 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 } diff --git a/core/state/snapshot/sort.go b/core/state/snapshot/sort.go index 88841231d917..10d544d26941 100644 --- a/core/state/snapshot/sort.go +++ b/core/state/snapshot/sort.go @@ -22,15 +22,6 @@ import ( "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] } +func hashesLess(a, b common.Hash) bool { + return bytes.Compare(a[:], b[:]) < 0 +} diff --git a/core/vm/eips.go b/core/vm/eips.go index ff1f132cb355..5510ddb1d28a 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -18,11 +18,11 @@ package vm import ( "fmt" - "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" + "golang.org/x/exp/slices" ) var activators = map[int]func(*JumpTable){ @@ -58,7 +58,7 @@ func ActivateableEips() []string { for k := range activators { nums = append(nums, fmt.Sprintf("%d", k)) } - sort.Strings(nums) + slices.Sort(nums) return nums } From 7765f11034a37a12f48400fd1431da52d0b3e4ac Mon Sep 17 00:00:00 2001 From: Dan Laine Date: Fri, 16 Jun 2023 14:57:15 -0400 Subject: [PATCH 2/6] core; use sort.Strings for strings --- core/vm/eips.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 5510ddb1d28a..ff1f132cb355 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -18,11 +18,11 @@ package vm import ( "fmt" + "sort" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" - "golang.org/x/exp/slices" ) var activators = map[int]func(*JumpTable){ @@ -58,7 +58,7 @@ func ActivateableEips() []string { for k := range activators { nums = append(nums, fmt.Sprintf("%d", k)) } - slices.Sort(nums) + sort.Strings(nums) return nums } From 1ff46a796b79cc92a288e68f62e017821004d876 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 19 Jun 2023 23:43:06 +0200 Subject: [PATCH 3/6] core/state/snapshot: use Hash.Less --- core/state/snapshot/difflayer.go | 4 ++-- core/state/snapshot/sort.go | 27 --------------------------- 2 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 core/state/snapshot/sort.go diff --git a/core/state/snapshot/difflayer.go b/core/state/snapshot/difflayer.go index 293c85115067..b10b43b1ae58 100644 --- a/core/state/snapshot/difflayer.go +++ b/core/state/snapshot/difflayer.go @@ -525,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash { dl.accountList = append(dl.accountList, hash) } } - slices.SortFunc(dl.accountList, hashesLess) + slices.SortFunc(dl.accountList, common.Hash.Less) 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, hashesLess) + slices.SortFunc(storageList, common.Hash.Less) dl.storageList[accountHash] = storageList dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength) return storageList, destructed diff --git a/core/state/snapshot/sort.go b/core/state/snapshot/sort.go deleted file mode 100644 index 10d544d26941..000000000000 --- a/core/state/snapshot/sort.go +++ /dev/null @@ -1,27 +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 . - -package snapshot - -import ( - "bytes" - - "github.com/ethereum/go-ethereum/common" -) - -func hashesLess(a, b common.Hash) bool { - return bytes.Compare(a[:], b[:]) < 0 -} From 4ef5a1cac63e3d12a77c83d8afd364223079d209 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 19 Jun 2023 23:44:45 +0200 Subject: [PATCH 4/6] core: fix mkalloc --- core/mkalloc.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/mkalloc.go b/core/mkalloc.go index 277b00e3577c..0e7355f6313a 100644 --- a/core/mkalloc.go +++ b/core/mkalloc.go @@ -30,28 +30,28 @@ 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 { - a := make([]allocItem, 0, len(g.Alloc)) + items := make([]allocItem, 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()) - a = append(a, allocItem{bigAddr, account.Balance}) + items = append(items, allocItem{bigAddr, account.Balance}) } - slices.SortFunc(a, func(b, c allocItem) bool { - return b.Addr.Cmp(c.Addr) < 0 + slices.SortFunc(items, func(a, b allocItem) bool { + return a.Addr.Cmp(b.Addr) < 0 }) - return a + return items } func makealloc(g *core.Genesis) string { From 363b8d2c6d6a11e23092606069c0ceadabc1a5b4 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 19 Jun 2023 23:46:54 +0200 Subject: [PATCH 5/6] core/rawdb: remove method --- core/rawdb/accessors_chain.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index dd418abd4070..2e5d486e9cf4 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -836,10 +836,6 @@ type badBlock struct { Body *types.Body } -func (b *badBlock) Less(other *badBlock) bool { - return b.Header.Number.Uint64() < other.Header.Number.Uint64() -} - // 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) @@ -900,7 +896,8 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { Body: block.Body(), }) slices.SortFunc(badBlocks, func(a, b *badBlock) bool { - return !a.Less(b) // Sort reverse order + // Note: sorting in ascending order. + return a.Header.Number.Uint64() >= b.Header.Number.Uint64() }) if len(badBlocks) > badBlockToKeep { badBlocks = badBlocks[:badBlockToKeep] From e1e540652561ec08c761febb01a6158455bc73d4 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 20 Jun 2023 11:55:39 +0200 Subject: [PATCH 6/6] core/rawdb: fix comment --- core/rawdb/accessors_chain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/rawdb/accessors_chain.go b/core/rawdb/accessors_chain.go index 2e5d486e9cf4..dd5425eec754 100644 --- a/core/rawdb/accessors_chain.go +++ b/core/rawdb/accessors_chain.go @@ -896,7 +896,7 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) { Body: block.Body(), }) slices.SortFunc(badBlocks, func(a, b *badBlock) bool { - // Note: sorting in ascending order. + // Note: sorting in descending number order. return a.Header.Number.Uint64() >= b.Header.Number.Uint64() }) if len(badBlocks) > badBlockToKeep {