Compare commits

...

7 Commits

Author SHA1 Message Date
Felix Lange
bed8460658 params: release go-ethereum v1.12.2 2023-08-12 11:05:07 +02:00
Felix Lange
a867039c53 internal/build: apply -ubuntu to env (#27910) 2023-08-12 11:02:24 +02:00
Felix Lange
f298ec4fe1 go.mod, build: upgrade c-kzg-4844 (#27907)
This upgrades to the latest release of ckzg, and also attempts to fix some blst-related
build errors that occur on launchpad.net.
2023-08-12 00:23:19 +02:00
Péter Szilágyi
811a674059 all: update golang/x/ext and fix slice sorting fallout (#27909)
The Go authors updated golang/x/ext to change the function signature of the slices sort method. 
It's an entire shitshow now because x/ext is not tagged, so everyone's codebase just 
picked a new version that some other dep depends on, causing our code to fail building.

This PR updates the dep on our code too and does all the refactorings to follow upstream...
2023-08-12 00:19:12 +02:00
Delweng
770db145ab ethdb/leveldb: support more than 7 levels in metrics (#27904) 2023-08-12 00:18:23 +02:00
imulmat4
55863ce0d8 core/txpool/blobpool: fix metrics name for prometheus export (#27901) 2023-08-12 00:18:16 +02:00
dependabot[bot]
a0491a04b5 deps: update supranational/blst to 0.3.11 (#27890)
build(deps): bump github.com/supranational/blst

Bumps [github.com/supranational/blst](https://github.com/supranational/blst) from 0.3.11-0.20230406105308-e9dfc5ee724b to 0.3.11.
- [Release notes](https://github.com/supranational/blst/releases)
- [Commits](https://github.com/supranational/blst/commits/v0.3.11)

---
updated-dependencies:
- dependency-name: github.com/supranational/blst
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-12 00:18:11 +02:00
45 changed files with 197 additions and 154 deletions

View File

@@ -40,8 +40,8 @@ import (
const minReloadInterval = 2 * time.Second
// byURL defines the sorting order for accounts.
func byURL(a, b accounts.Account) bool {
return a.URL.Cmp(b.URL) < 0
func byURL(a, b accounts.Account) int {
return a.URL.Cmp(b.URL)
}
// AmbiguousAddrError is returned when attempting to unlock

View File

@@ -200,6 +200,7 @@ func doInstall(cmdline []string) {
staticlink = flag.Bool("static", false, "Create statically-linked executable")
)
flag.CommandLine.Parse(cmdline)
env := build.Env()
// Configure the toolchain.
tc := build.GoToolchain{GOARCH: *arch, CC: *cc}
@@ -207,12 +208,16 @@ func doInstall(cmdline []string) {
csdb := build.MustLoadChecksums("build/checksums.txt")
tc.Root = build.DownloadGo(csdb, dlgoVersion)
}
// Disable CLI markdown doc generation in release builds and enable linking
// the CKZG library since we can make it portable here.
buildTags := []string{"urfave_cli_no_docs", "ckzg"}
// Disable CLI markdown doc generation in release builds.
buildTags := []string{"urfave_cli_no_docs"}
// Enable linking the CKZG library since we can make it work with additional flags.
if env.UbuntuVersion != "trusty" {
buildTags = append(buildTags, "ckzg")
}
// Configure the build.
env := build.Env()
gobuild := tc.Go("build", buildFlags(env, *staticlink, buildTags)...)
// arm64 CI builders are memory-constrained and can't handle concurrent builds,
@@ -298,10 +303,14 @@ func doTest(cmdline []string) {
csdb := build.MustLoadChecksums("build/checksums.txt")
tc.Root = build.DownloadGo(csdb, dlgoVersion)
}
gotest := tc.Go("test", "-tags=ckzg")
gotest := tc.Go("test")
// CI needs a bit more time for the statetests (default 10m).
gotest.Args = append(gotest.Args, "-timeout=20m")
// Enable CKZG backend in CI.
gotest.Args = append(gotest.Args, "-tags=ckzg")
// Test a single package at a time. CI builders are slow
// and some tests run into timeouts under load.
gotest.Args = append(gotest.Args, "-p", "1")

View File

@@ -28,7 +28,7 @@ override_dh_auto_build:
mv .mod $(GOPATH)/pkg/mod
# A fresh Go was built, all dependency downloads faked, hope build works now
../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}}
../.go/bin/go run build/ci.go install -git-commit={{.Env.Commit}} -git-branch={{.Env.Branch}} -git-tag={{.Env.Tag}} -buildnum={{.Env.Buildnum}} -pull-request={{.Env.IsPullRequest}} -ubuntu {{.Distro}}
override_dh_auto_test:

View File

@@ -288,11 +288,17 @@ func makeDeletionChanges(records map[string]recordSet, keep map[string]string) [
// sortChanges ensures DNS changes are in leaf-added -> root-changed -> leaf-deleted order.
func sortChanges(changes []types.Change) {
score := map[string]int{"CREATE": 1, "UPSERT": 2, "DELETE": 3}
slices.SortFunc(changes, func(a, b types.Change) bool {
slices.SortFunc(changes, func(a, b types.Change) int {
if a.Action == b.Action {
return *a.ResourceRecordSet.Name < *b.ResourceRecordSet.Name
return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name)
}
return score[string(a.Action)] < score[string(b.Action)]
if score[string(a.Action)] < score[string(b.Action)] {
return -1
}
if score[string(a.Action)] > score[string(b.Action)] {
return 1
}
return 0
})
}

View File

@@ -77,8 +77,8 @@ func (ns nodeSet) nodes() []*enode.Node {
result = append(result, n.N)
}
// Sort by ID.
slices.SortFunc(result, func(a, b *enode.Node) bool {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) < 0
slices.SortFunc(result, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
return result
}
@@ -103,8 +103,14 @@ func (ns nodeSet) topN(n int) nodeSet {
for _, v := range ns {
byscore = append(byscore, v)
}
slices.SortFunc(byscore, func(a, b nodeJSON) bool {
return a.Score >= b.Score
slices.SortFunc(byscore, func(a, b nodeJSON) int {
if a.Score > b.Score {
return -1
}
if a.Score < b.Score {
return 1
}
return 0
})
result := make(nodeSet, n)
for _, v := range byscore[:n] {

View File

@@ -65,9 +65,9 @@ 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
// Cmp compares two hashes.
func (h Hash) Cmp(other Hash) int {
return bytes.Compare(h[:], other[:])
}
// Bytes gets the byte representation of the underlying hash.
@@ -231,9 +231,9 @@ func IsHexAddress(s string) bool {
return len(s) == 2*AddressLength && isHex(s)
}
// Less compares two addresses.
func (a Address) Less(other Address) bool {
return bytes.Compare(a[:], other[:]) < 0
// Cmp compares two addresses.
func (a Address) Cmp(other Address) int {
return bytes.Compare(a[:], other[:])
}
// Bytes gets the string representation of the underlying address.

View File

@@ -308,7 +308,7 @@ func (s *Snapshot) signers() []common.Address {
for sig := range s.Signers {
sigs = append(sigs, sig)
}
slices.SortFunc(sigs, common.Address.Less)
slices.SortFunc(sigs, common.Address.Cmp)
return sigs
}

View File

@@ -53,7 +53,7 @@ func (ap *testerAccountPool) checkpoint(header *types.Header, signers []string)
for i, signer := range signers {
auths[i] = ap.address(signer)
}
slices.SortFunc(auths, common.Address.Less)
slices.SortFunc(auths, common.Address.Cmp)
for i, auth := range auths {
copy(header.Extra[extraVanity+i*common.AddressLength:], auth.Bytes())
}

View File

@@ -996,8 +996,8 @@ func (bc *BlockChain) procFutureBlocks() {
}
}
if len(blocks) > 0 {
slices.SortFunc(blocks, func(a, b *types.Block) bool {
return a.NumberU64() < b.NumberU64()
slices.SortFunc(blocks, func(a, b *types.Block) int {
return a.Number().Cmp(b.Number())
})
// Insert one by one as chain insertion needs contiguous ancestry between blocks
for i := range blocks {

View File

@@ -902,9 +902,9 @@ func WriteBadBlock(db ethdb.KeyValueStore, block *types.Block) {
Header: block.Header(),
Body: block.Body(),
})
slices.SortFunc(badBlocks, func(a, b *badBlock) bool {
slices.SortFunc(badBlocks, func(a, b *badBlock) int {
// Note: sorting in descending number order.
return a.Header.Number.Uint64() >= b.Header.Number.Uint64()
return -a.Header.Number.Cmp(b.Header.Number)
})
if len(badBlocks) > badBlockToKeep {
badBlocks = badBlocks[:badBlockToKeep]

View File

@@ -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)

View File

@@ -525,7 +525,7 @@ func (dl *diffLayer) AccountList() []common.Hash {
dl.accountList = append(dl.accountList, hash)
}
}
slices.SortFunc(dl.accountList, common.Hash.Less)
slices.SortFunc(dl.accountList, common.Hash.Cmp)
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)
slices.SortFunc(storageList, common.Hash.Cmp)
dl.storageList[accountHash] = storageList
dl.memory += uint64(len(dl.storageList)*common.HashLength + common.HashLength)
return storageList, destructed

View File

@@ -33,19 +33,25 @@ type weightedIterator struct {
priority int
}
func (it *weightedIterator) Less(other *weightedIterator) bool {
func (it *weightedIterator) Cmp(other *weightedIterator) int {
// Order the iterators primarily by the account hashes
hashI := it.it.Hash()
hashJ := other.it.Hash()
switch bytes.Compare(hashI[:], hashJ[:]) {
case -1:
return true
return -1
case 1:
return false
return 1
}
// Same account/storage-slot in multiple layers, split by priority
return it.priority < other.priority
if it.priority < other.priority {
return -1
}
if it.priority > other.priority {
return 1
}
return 0
}
// fastIterator is a more optimized multi-layer iterator which maintains a
@@ -155,9 +161,7 @@ func (fi *fastIterator) init() {
}
}
// Re-sort the entire list
slices.SortFunc(fi.iterators, func(a, b *weightedIterator) bool {
return a.Less(b)
})
slices.SortFunc(fi.iterators, func(a, b *weightedIterator) int { return a.Cmp(b) })
fi.initiated = false
}

View File

@@ -35,15 +35,15 @@ var (
// The below metrics track the per-shelf metrics for the primary blob store
// and the temporary limbo store.
shelfDatausedGaugeName = "blobpool/shelf-%d/dataused"
shelfDatagapsGaugeName = "blobpool/shelf-%d/datagaps"
shelfSlotusedGaugeName = "blobpool/shelf-%d/slotused"
shelfSlotgapsGaugeName = "blobpool/shelf-%d/slotgaps"
shelfDatausedGaugeName = "blobpool/shelf_%d/dataused"
shelfDatagapsGaugeName = "blobpool/shelf_%d/datagaps"
shelfSlotusedGaugeName = "blobpool/shelf_%d/slotused"
shelfSlotgapsGaugeName = "blobpool/shelf_%d/slotgaps"
limboShelfDatausedGaugeName = "blobpool/limbo/shelf-%d/dataused"
limboShelfDatagapsGaugeName = "blobpool/limbo/shelf-%d/datagaps"
limboShelfSlotusedGaugeName = "blobpool/limbo/shelf-%d/slotused"
limboShelfSlotgapsGaugeName = "blobpool/limbo/shelf-%d/slotgaps"
limboShelfDatausedGaugeName = "blobpool/limbo/shelf_%d/dataused"
limboShelfDatagapsGaugeName = "blobpool/limbo/shelf_%d/datagaps"
limboShelfSlotusedGaugeName = "blobpool/limbo/shelf_%d/slotused"
limboShelfSlotgapsGaugeName = "blobpool/limbo/shelf_%d/slotgaps"
// The oversized metrics aggregate the shelf stats above the max blob count
// limits to track transactions that are just huge, but don't contain blobs.

View File

@@ -105,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.
slices.SortFunc(hList, common.Hash.Less)
slices.SortFunc(hList, common.Hash.Cmp)
middleH := hList[AccountRangeMaxResults/2]
middleResult := accountRangeTest(t, &trie, sdb, middleH, AccountRangeMaxResults, AccountRangeMaxResults)
missing, infirst, insecond := 0, 0, 0

View File

@@ -111,8 +111,8 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
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
slices.SortStableFunc(sorter, func(a, b txGasAndReward) int {
return a.reward.Cmp(b.reward)
})
var txIndex int

View File

@@ -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 })
slices.SortFunc(results, func(a, b *big.Int) int { return a.Cmp(b) })
price = results[(len(results)-1)*oracle.percentile/100]
}
if price.Cmp(oracle.maxPrice) > 0 {
@@ -247,12 +247,12 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, blockNum uint64, limit
sortedTxs := make([]*types.Transaction, len(txs))
copy(sortedTxs, txs)
baseFee := block.BaseFee()
slices.SortFunc(sortedTxs, func(a, b *types.Transaction) bool {
slices.SortFunc(sortedTxs, func(a, b *types.Transaction) int {
// 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
return tip1.Cmp(tip2)
})
var prices []*big.Int

View File

@@ -1321,8 +1321,8 @@ type kv struct {
k, v []byte
}
func (k *kv) less(other *kv) bool {
return bytes.Compare(k.k, other.k) < 0
func (k *kv) cmp(other *kv) int {
return bytes.Compare(k.k, other.k)
}
func key32(i uint64) []byte {
@@ -1382,7 +1382,7 @@ func makeAccountTrieNoStorage(n int) (string, *trie.Trie, []*kv) {
accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit the state changes into db and re-create the trie
// for accessing later.
@@ -1444,7 +1444,7 @@ func makeBoundaryAccountTrie(n int) (string, *trie.Trie, []*kv) {
accTrie.MustUpdate(elem.k, elem.v)
entries = append(entries, elem)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit the state changes into db and re-create the trie
// for accessing later.
@@ -1491,7 +1491,7 @@ func makeAccountTrieWithStorageWithUniqueStorage(accounts, slots int, code bool)
storageRoots[common.BytesToHash(key)] = stRoot
storageEntries[common.BytesToHash(key)] = stEntries
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Commit account trie
root, set, _ := accTrie.Commit(true)
@@ -1556,7 +1556,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)
slices.SortFunc(entries, (*kv).cmp)
// Commit account trie
root, set, _ := accTrie.Commit(true)
@@ -1600,7 +1600,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)
slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false)
return root, nodes, entries
}
@@ -1651,7 +1651,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)
slices.SortFunc(entries, (*kv).cmp)
root, nodes, _ := trie.Commit(false)
return root, nodes, entries
}

View File

@@ -790,7 +790,7 @@ func newAccounts(n int) (accounts []Account) {
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) })
slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
return accounts
}

View File

@@ -527,7 +527,7 @@ func makeDataset(size, ksize, vsize int, order bool) ([][]byte, [][]byte) {
vals = append(vals, randBytes(vsize))
}
if order {
slices.SortFunc(keys, func(a, b []byte) bool { return bytes.Compare(a, b) < 0 })
slices.SortFunc(keys, func(a, b []byte) int { return bytes.Compare(a, b) })
}
return keys, vals
}

View File

@@ -75,7 +75,7 @@ type Database struct {
seekCompGauge metrics.Gauge // Gauge for tracking the number of table compaction caused by read opt
manualMemAllocGauge metrics.Gauge // Gauge to track the amount of memory that has been manually allocated (not a part of runtime/GC)
levelsGauge [7]metrics.Gauge // Gauge for tracking the number of tables in levels
levelsGauge []metrics.Gauge // Gauge for tracking the number of tables in levels
quitLock sync.Mutex // Mutex protecting the quit channel access
quitChan chan chan error // Quit channel to stop the metrics collection before closing the database
@@ -146,13 +146,8 @@ func NewCustom(file string, namespace string, customize func(options *opt.Option
ldb.seekCompGauge = metrics.NewRegisteredGauge(namespace+"compact/seek", nil)
ldb.manualMemAllocGauge = metrics.NewRegisteredGauge(namespace+"memory/manualalloc", nil)
// leveldb has only up to 7 levels
for i := range ldb.levelsGauge {
ldb.levelsGauge[i] = metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil)
}
// Start up the metrics gathering and return
go ldb.meter(metricsGatheringInterval)
go ldb.meter(metricsGatheringInterval, namespace)
return ldb, nil
}
@@ -271,7 +266,7 @@ func (db *Database) Path() string {
// meter periodically retrieves internal leveldb counters and reports them to
// the metrics subsystem.
func (db *Database) meter(refresh time.Duration) {
func (db *Database) meter(refresh time.Duration, namespace string) {
// Create the counters to store current and previous compaction values
compactions := make([][]int64, 2)
for i := 0; i < 2; i++ {
@@ -360,8 +355,11 @@ func (db *Database) meter(refresh time.Duration) {
db.nonlevel0CompGauge.Update(int64(stats.NonLevel0Comp))
db.seekCompGauge.Update(int64(stats.SeekComp))
// update tables amount
for i, tables := range stats.LevelTablesCounts {
// Append metrics for additional layers
if i >= len(db.levelsGauge) {
db.levelsGauge = append(db.levelsGauge, metrics.NewRegisteredGauge(namespace+fmt.Sprintf("tables/level%v", i), nil))
}
db.levelsGauge[i].Update(int64(tables))
}

8
go.mod
View File

@@ -19,7 +19,7 @@ require (
github.com/deckarep/golang-set/v2 v2.1.0
github.com/docker/docker v1.6.2
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
github.com/ethereum/c-kzg-4844 v0.3.0
github.com/ethereum/c-kzg-4844 v0.3.1
github.com/fatih/color v1.7.0
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
github.com/fjl/memsize v0.0.0-20190710130421-bcb5799ab5e5
@@ -57,13 +57,13 @@ require (
github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible
github.com/status-im/keycard-go v0.2.0
github.com/stretchr/testify v1.8.1
github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b
github.com/supranational/blst v0.3.11
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7
github.com/tyler-smith/go-bip39 v1.1.0
github.com/urfave/cli/v2 v2.24.1
go.uber.org/automaxprocs v1.5.2
golang.org/x/crypto v0.9.0
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad
golang.org/x/sync v0.3.0
golang.org/x/sys v0.9.0
golang.org/x/text v0.9.0
@@ -125,7 +125,7 @@ require (
github.com/tklauser/go-sysconf v0.3.5 // indirect
github.com/tklauser/numcpus v0.2.2 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/mod v0.11.0 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/xerrors v0.0.0-20220517211312-f3a8303e98df // indirect
google.golang.org/protobuf v1.28.1 // indirect

16
go.sum
View File

@@ -125,8 +125,8 @@ github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.m
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/ethereum/c-kzg-4844 v0.3.0 h1:3Y3hD6l5i0dEYsBL50C+Om644kve3pNqoAcvE26o9zI=
github.com/ethereum/c-kzg-4844 v0.3.0/go.mod h1:WI2Nd82DMZAAZI1wV2neKGost9EKjvbpQR9OqE5Qqa8=
github.com/ethereum/c-kzg-4844 v0.3.1 h1:sR65+68+WdnMKxseNWxSJuAv2tsUrihTpVBTfM/U5Zg=
github.com/ethereum/c-kzg-4844 v0.3.1/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -426,8 +426,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b h1:u49mjRnygnB34h8OKbnNJFVUtWSKIKb1KukdV8bILUM=
github.com/supranational/blst v0.3.11-0.20230406105308-e9dfc5ee724b/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/supranational/blst v0.3.11 h1:LyU6FolezeWAhvQk0k6O/d49jqgO52MSDDfYgbeoEm4=
github.com/supranational/blst v0.3.11/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY=
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc=
github.com/tklauser/go-sysconf v0.3.5 h1:uu3Xl4nkLzQfXNsWn15rPc/HQCJKObbt1dKJeWp3vU4=
@@ -479,8 +479,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc h1:mCRnTeVUjcrhlRmO0VK8a6k6Rrf6TF9htwo2pJVSjIU=
golang.org/x/exp v0.0.0-20230515195305-f3d0a9c9a5cc/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad h1:g0bG7Z4uG+OgH2QDODnjp6ggkk1bJDsINcuWmJN1iJU=
golang.org/x/exp v0.0.0-20230810033253-352e893a4cad/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
@@ -490,8 +490,8 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU=
golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=

View File

@@ -28,12 +28,13 @@ import (
var (
// These flags override values in build env.
GitCommitFlag = flag.String("git-commit", "", `Overrides git commit hash embedded into executables`)
GitBranchFlag = flag.String("git-branch", "", `Overrides git branch being built`)
GitTagFlag = flag.String("git-tag", "", `Overrides git tag being built`)
BuildnumFlag = flag.String("buildnum", "", `Overrides CI build number`)
PullRequestFlag = flag.Bool("pull-request", false, `Overrides pull request status of the build`)
CronJobFlag = flag.Bool("cron-job", false, `Overrides cron job status of the build`)
GitCommitFlag = flag.String("git-commit", "", `Overrides git commit hash embedded into executables`)
GitBranchFlag = flag.String("git-branch", "", `Overrides git branch being built`)
GitTagFlag = flag.String("git-tag", "", `Overrides git tag being built`)
BuildnumFlag = flag.String("buildnum", "", `Overrides CI build number`)
PullRequestFlag = flag.Bool("pull-request", false, `Overrides pull request status of the build`)
CronJobFlag = flag.Bool("cron-job", false, `Overrides cron job status of the build`)
UbuntuVersionFlag = flag.String("ubuntu", "", `Sets the ubuntu version being built for`)
)
// Environment contains metadata provided by the build environment.
@@ -43,6 +44,7 @@ type Environment struct {
Repo string // name of GitHub repo
Commit, Date, Branch, Tag string // Git info
Buildnum string
UbuntuVersion string // Ubuntu version being built for
IsPullRequest bool
IsCronJob bool
}
@@ -168,5 +170,8 @@ func applyEnvFlags(env Environment) Environment {
if *CronJobFlag {
env.IsCronJob = true
}
if *UbuntuVersionFlag != "" {
env.UbuntuVersion = *UbuntuVersionFlag
}
return env
}

View File

@@ -54,8 +54,8 @@ func (g *GoToolchain) Go(command string, args ...string) *exec.Cmd {
tool.Env = append(tool.Env, "CC="+os.Getenv("CC"))
}
// CKZG by default is not portable, append the necessary build flags to make
// it not rely on modern CPU instructions and enable linking against
tool.Env = append(tool.Env, "CGO_CFLAGS=-D__BLST_PORTABLE__")
// it not rely on modern CPU instructions and enable linking against.
tool.Env = append(tool.Env, "CGO_CFLAGS=-O2 -g -D__BLST_PORTABLE__")
return tool
}

View File

@@ -817,7 +817,7 @@ func newAccounts(n int) (accounts []Account) {
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) })
slices.SortFunc(accounts, func(a, b Account) int { return a.addr.Cmp(b.addr) })
return accounts
}

View File

@@ -215,8 +215,14 @@ func (sq *servingQueue) freezePeers() {
tasks.list = append(tasks.list, task)
tasks.sumTime += task.expTime
}
slices.SortFunc(peerList, func(a, b *peerTasks) bool {
return a.priority < b.priority
slices.SortFunc(peerList, func(a, b *peerTasks) int {
if a.priority < b.priority {
return -1
}
if a.priority > b.priority {
return 1
}
return 0
})
drop := true
for _, tasks := range peerList {

View File

@@ -369,8 +369,14 @@ func (l *Limiter) dropRequests() {
priority: w / float64(nq.sumCost),
})
}
slices.SortFunc(list, func(a, b dropListItem) bool {
return a.priority < b.priority
slices.SortFunc(list, func(a, b dropListItem) int {
if a.priority < b.priority {
return -1
}
if a.priority < b.priority {
return 1
}
return 0
})
for _, item := range list {
for _, request := range item.nq.queue {

View File

@@ -3,6 +3,7 @@ package metrics
import (
"fmt"
"io"
"strings"
"time"
"golang.org/x/exp/slices"
@@ -23,8 +24,7 @@ func WriteOnce(r Registry, w io.Writer) {
r.Each(func(name string, i interface{}) {
namedMetrics = append(namedMetrics, namedMetric{name, i})
})
slices.SortFunc(namedMetrics, namedMetric.less)
slices.SortFunc(namedMetrics, namedMetric.cmp)
for _, namedMetric := range namedMetrics {
switch metric := namedMetric.m.(type) {
case Counter:
@@ -92,6 +92,6 @@ type namedMetric struct {
m interface{}
}
func (m namedMetric) less(other namedMetric) bool {
return m.name < other.name
func (m namedMetric) cmp(other namedMetric) int {
return strings.Compare(m.name, other.name)
}

View File

@@ -14,7 +14,7 @@ func TestMetricsSorting(t *testing.T) {
{name: "ggg"},
}
slices.SortFunc(namedMetrics, namedMetric.less)
slices.SortFunc(namedMetrics, namedMetric.cmp)
for i, name := range []string{"bbb", "fff", "ggg", "zzz"} {
if namedMetrics[i].name != name {
t.Fail()

View File

@@ -217,14 +217,14 @@ func nodeEqual(n1 *enode.Node, n2 *enode.Node) bool {
}
func sortByID(nodes []*enode.Node) {
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return string(a.ID().Bytes()) < string(b.ID().Bytes())
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
}
func sortedByDistanceTo(distbase enode.ID, slice []*node) bool {
return slices.IsSortedFunc(slice, func(a, b *node) bool {
return enode.DistCmp(distbase, a.ID(), b.ID()) < 0
return slices.IsSortedFunc(slice, func(a, b *node) int {
return enode.DistCmp(distbase, a.ID(), b.ID())
})
}

View File

@@ -302,8 +302,8 @@ func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) {
nodes = append(nodes, tn.node(d, i))
}
}
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return enode.DistCmp(tn.target.id(), a.ID(), b.ID()) < 0
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return enode.DistCmp(tn.target.id(), a.ID(), b.ID())
})
return nodes[:n]
}

View File

@@ -61,8 +61,8 @@ func TestUDPv5_lookupE2E(t *testing.T) {
for i := range nodes {
expectedResult[i] = nodes[i].Self()
}
slices.SortFunc(expectedResult, func(a, b *enode.Node) bool {
return enode.DistCmp(target.ID(), a.ID(), b.ID()) < 0
slices.SortFunc(expectedResult, func(a, b *enode.Node) int {
return enode.DistCmp(target.ID(), a.ID(), b.ID())
})
// Do the lookup.

View File

@@ -214,8 +214,8 @@ func (t *Tree) build(entries []entry) entry {
}
func sortByID(nodes []*enode.Node) []*enode.Node {
slices.SortFunc(nodes, func(a, b *enode.Node) bool {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes()) < 0
slices.SortFunc(nodes, func(a, b *enode.Node) int {
return bytes.Compare(a.ID().Bytes(), b.ID().Bytes())
})
return nodes
}

View File

@@ -386,7 +386,7 @@ func countMatchingProtocols(protocols []Protocol, caps []Cap) int {
// matchProtocols creates structures for matching named subprotocols.
func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW {
slices.SortFunc(caps, Cap.Less)
slices.SortFunc(caps, Cap.Cmp)
offset := baseProtocolLength
result := make(map[string]*protoRW)

View File

@@ -18,6 +18,7 @@ package p2p
import (
"fmt"
"strings"
"github.com/ethereum/go-ethereum/p2p/enode"
"github.com/ethereum/go-ethereum/p2p/enr"
@@ -77,10 +78,16 @@ func (cap Cap) String() string {
return fmt.Sprintf("%s/%d", cap.Name, cap.Version)
}
// Less defines the canonical sorting order of capabilities.
func (cap Cap) Less(other Cap) bool {
// Cmp defines the canonical sorting order of capabilities.
func (cap Cap) Cmp(other Cap) int {
if cap.Name == other.Name {
return cap.Version < other.Version
if cap.Version < other.Version {
return -1
}
if cap.Version > other.Version {
return 1
}
return 0
}
return cap.Name < other.Name
return strings.Compare(cap.Name, other.Name)
}

View File

@@ -510,7 +510,7 @@ func (srv *Server) setupLocalNode() error {
for _, p := range srv.Protocols {
srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap())
}
slices.SortFunc(srv.ourHandshake.Caps, Cap.Less)
slices.SortFunc(srv.ourHandshake.Caps, Cap.Cmp)
// Create the local node.
db, err := enode.OpenDB(srv.NodeDatabase)

View File

@@ -21,10 +21,10 @@ import (
)
const (
VersionMajor = 1 // Major version component of the current release
VersionMinor = 12 // Minor version component of the current release
VersionPatch = 2 // Patch version component of the current release
VersionMeta = "unstable" // Version metadata to append to the version string
VersionMajor = 1 // Major version component of the current release
VersionMinor = 12 // Minor version component of the current release
VersionPatch = 2 // Patch version component of the current release
VersionMeta = "stable" // Version metadata to append to the version string
)
// Version holds the textual version string.

View File

@@ -98,8 +98,8 @@ func (f *fuzzer) fuzz() int {
if len(entries) <= 1 {
return 0
}
slices.SortFunc(entries, func(a, b *kv) bool {
return bytes.Compare(a.k, b.k) < 0
slices.SortFunc(entries, func(a, b *kv) int {
return bytes.Compare(a.k, b.k)
})
var ok = 0

View File

@@ -182,8 +182,8 @@ func (f *fuzzer) fuzz() int {
dbA.Commit(rootA, false)
// Stacktrie requires sorted insertion
slices.SortFunc(vals, func(a, b kv) bool {
return bytes.Compare(a.k, b.k) < 0
slices.SortFunc(vals, func(a, b kv) int {
return bytes.Compare(a.k, b.k)
})
for _, kv := range vals {
if f.debugging {

View File

@@ -84,8 +84,8 @@ type kv struct {
t bool
}
func (k *kv) less(other *kv) bool {
return bytes.Compare(k.k, other.k) < 0
func (k *kv) cmp(other *kv) int {
return bytes.Compare(k.k, other.k)
}
func TestIteratorLargeData(t *testing.T) {

View File

@@ -173,7 +173,7 @@ func TestRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
end := mrand.Intn(len(entries)-start) + start + 1
@@ -206,7 +206,7 @@ func TestRangeProofWithNonExistentProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
end := mrand.Intn(len(entries)-start) + start + 1
@@ -278,7 +278,7 @@ func TestRangeProofWithInvalidNonExistentProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Case 1
start, end := 100, 200
@@ -335,7 +335,7 @@ func TestOneElementRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// One element with existent edge proof, both edge proofs
// point to the SAME key.
@@ -422,7 +422,7 @@ func TestAllElementsProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var k [][]byte
var v [][]byte
@@ -474,7 +474,7 @@ func TestSingleSideRangeProof(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1}
for _, pos := range cases {
@@ -509,7 +509,7 @@ func TestReverseSingleSideRangeProof(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []int{0, 1, 50, 100, 1000, 2000, len(entries) - 1}
for _, pos := range cases {
@@ -543,7 +543,7 @@ func TestBadRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
for i := 0; i < 500; i++ {
start := mrand.Intn(len(entries))
@@ -646,7 +646,7 @@ func TestSameSideProofs(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
pos := 1000
first := decreaseKey(common.CopyBytes(entries[pos].k))
@@ -690,7 +690,7 @@ func TestHasRightElement(t *testing.T) {
trie.MustUpdate(value.k, value.v)
entries = append(entries, value)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []struct {
start int
@@ -762,7 +762,7 @@ func TestEmptyRangeProof(t *testing.T) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var cases = []struct {
pos int
@@ -797,7 +797,7 @@ func TestBloatedProof(t *testing.T) {
for _, kv := range kvs {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var keys [][]byte
var vals [][]byte
@@ -831,7 +831,7 @@ func TestEmptyValueRangeProof(t *testing.T) {
for _, kv := range values {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Create a new entry with a slightly modified key
mid := len(entries) / 2
@@ -875,7 +875,7 @@ func TestAllElementsEmptyValueRangeProof(t *testing.T) {
for _, kv := range values {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
// Create a new entry with a slightly modified key
mid := len(entries) / 2
@@ -981,7 +981,7 @@ func benchmarkVerifyRangeProof(b *testing.B, size int) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
start := 2
end := start + size
@@ -1018,7 +1018,7 @@ func benchmarkVerifyRangeNoProof(b *testing.B, size int) {
for _, kv := range vals {
entries = append(entries, kv)
}
slices.SortFunc(entries, (*kv).less)
slices.SortFunc(entries, (*kv).cmp)
var keys [][]byte
var values [][]byte

View File

@@ -262,20 +262,20 @@ func newHistory(root common.Hash, parent common.Hash, block uint64, states *trie
for addr := range states.Accounts {
accountList = append(accountList, addr)
}
slices.SortFunc(accountList, func(a, b common.Address) bool { return a.Less(b) })
slices.SortFunc(accountList, common.Address.Cmp)
for addr, slots := range states.Storages {
slist := make([]common.Hash, 0, len(slots))
for slotHash := range slots {
slist = append(slist, slotHash)
}
slices.SortFunc(slist, func(a, b common.Hash) bool { return a.Less(b) })
slices.SortFunc(slist, common.Hash.Cmp)
storageList[addr] = slist
}
for addr := range states.Incomplete {
incomplete = append(incomplete, addr)
}
slices.SortFunc(incomplete, func(a, b common.Address) bool { return a.Less(b) })
slices.SortFunc(incomplete, common.Address.Cmp)
return &history{
meta: &meta{

View File

@@ -117,7 +117,7 @@ func hash(states map[common.Hash][]byte) (common.Hash, []byte) {
for hash := range states {
hs = append(hs, hash)
}
slices.SortFunc(hs, func(a, b common.Hash) bool { return a.Less(b) })
slices.SortFunc(hs, common.Hash.Cmp)
var input []byte
for _, hash := range hs {

View File

@@ -18,10 +18,10 @@ package trienode
import (
"fmt"
"sort"
"strings"
"github.com/ethereum/go-ethereum/common"
"golang.org/x/exp/slices"
)
// Node is a wrapper which contains the encoded blob of the trie node and its
@@ -83,9 +83,7 @@ func (set *NodeSet) ForEachWithOrder(callback func(path string, n *Node)) {
paths = append(paths, path)
}
// Bottom-up, the longest path first
slices.SortFunc(paths, func(a, b string) bool {
return a > b // Sort in reverse order
})
sort.Sort(sort.Reverse(sort.StringSlice(paths)))
for _, path := range paths {
callback(path, set.Nodes[path])
}