diff --git a/README.md b/README.md index 27842008aa..45b80e86a6 100644 --- a/README.md +++ b/README.md @@ -54,14 +54,14 @@ on how you can run your own `geth` instance. Minimum: -* CPU with 2+ cores -* 4GB RAM +* CPU with 4+ cores +* 8GB RAM * 1TB free storage space to sync the Mainnet * 8 MBit/sec download Internet service Recommended: -* Fast CPU with 4+ cores +* Fast CPU with 8+ cores * 16GB+ RAM * High-performance SSD with at least 1TB of free space * 25+ MBit/sec download Internet service @@ -138,8 +138,6 @@ export your existing configuration: $ geth --your-favourite-flags dumpconfig ``` -*Note: This works only with `geth` v1.6.0 and above.* - #### Docker quick start One of the quickest ways to get Ethereum up and running on your machine is by using @@ -187,7 +185,6 @@ HTTP based JSON-RPC API options: * `--ws.api` API's offered over the WS-RPC interface (default: `eth,net,web3`) * `--ws.origins` Origins from which to accept WebSocket requests * `--ipcdisable` Disable the IPC-RPC server - * `--ipcapi` API's offered over the IPC-RPC interface (default: `admin,debug,eth,miner,net,personal,txpool,web3`) * `--ipcpath` Filename for IPC socket/pipe within the datadir (explicit paths escape it) You'll need to use your own programming environments' capabilities (libraries, tools, etc) to @@ -206,118 +203,14 @@ APIs!** Maintaining your own private network is more involved as a lot of configurations taken for granted in the official networks need to be manually set up. -#### Defining the private genesis state +Unfortunately since [the Merge](https://ethereum.org/en/roadmap/merge/) it is no longer possible +to easily set up a network of geth nodes without also setting up a corresponding beacon chain. -First, you'll need to create the genesis state of your networks, which all nodes need to be -aware of and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`): +There are three different solutions depending on your use case: -```json -{ - "config": { - "chainId": , - "homesteadBlock": 0, - "eip150Block": 0, - "eip155Block": 0, - "eip158Block": 0, - "byzantiumBlock": 0, - "constantinopleBlock": 0, - "petersburgBlock": 0, - "istanbulBlock": 0, - "berlinBlock": 0, - "londonBlock": 0 - }, - "alloc": {}, - "coinbase": "0x0000000000000000000000000000000000000000", - "difficulty": "0x20000", - "extraData": "", - "gasLimit": "0x2fefd8", - "nonce": "0x0000000000000042", - "mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000", - "timestamp": "0x00" -} -``` - -The above fields should be fine for most purposes, although we'd recommend changing -the `nonce` to some random value so you prevent unknown remote nodes from being able -to connect to you. If you'd like to pre-fund some accounts for easier testing, create -the accounts and populate the `alloc` field with their addresses. - -```json -"alloc": { - "0x0000000000000000000000000000000000000001": { - "balance": "111111111" - }, - "0x0000000000000000000000000000000000000002": { - "balance": "222222222" - } -} -``` - -With the genesis state defined in the above JSON file, you'll need to initialize **every** -`geth` node with it prior to starting it up to ensure all blockchain parameters are correctly -set: - -```shell -$ geth init path/to/genesis.json -``` - -#### Creating the rendezvous point - -With all nodes that you want to run initialized to the desired genesis state, you'll need to -start a bootstrap node that others can use to find each other in your network and/or over -the internet. The clean way is to configure and run a dedicated bootnode: - -```shell -# Use the devp2p tool to create a node file. -# The devp2p tool is also part of the 'alltools' distribution bundle. -$ devp2p key generate node1.key -# file node1.key is created. -$ devp2p key to-enr -ip 10.2.3.4 -udp 30303 -tcp 30303 node1.key -# Prints the ENR for use in --bootnode flag of other nodes. -# Note this method requires knowing the IP/ports ahead of time. -$ geth --nodekey=node1.key -``` - -With the bootnode online, it will display an [`enode` URL](https://ethereum.org/en/developers/docs/networking-layer/network-addresses/#enode) -that other nodes can use to connect to it and exchange peer information. Make sure to -replace the displayed IP address information (most probably `[::]`) with your externally -accessible IP to get the actual `enode` URL. - -*Note: You could previously use the `bootnode` utility to start a stripped down version of geth. This is not possible anymore.* - -#### Starting up your member nodes - -With the bootnode operational and externally reachable (you can try -`telnet ` to ensure it's indeed reachable), start every subsequent `geth` -node pointed to the bootnode for peer discovery via the `--bootnodes` flag. It will -probably also be desirable to keep the data directory of your private network separated, so -do also specify a custom `--datadir` flag. - -```shell -$ geth --datadir=path/to/custom/data/folder --bootnodes= -``` - -*Note: Since your network will be completely cut off from the main and test networks, you'll -also need to configure a miner to process transactions and create new blocks for you.* - -#### Running a private miner - - -In a private network setting a single CPU miner instance is more than enough for -practical purposes as it can produce a stable stream of blocks at the correct intervals -without needing heavy resources (consider running on a single thread, no need for multiple -ones either). To start a `geth` instance for mining, run it with all your usual flags, extended -by: - -```shell -$ geth --mine --miner.threads=1 --miner.etherbase=0x0000000000000000000000000000000000000000 -``` - -Which will start mining blocks and transactions on a single CPU thread, crediting all -proceedings to the account specified by `--miner.etherbase`. You can further tune the mining -by changing the default gas limit blocks converge to (`--miner.targetgaslimit`) and the price -transactions are accepted at (`--miner.gasprice`). + * If you are looking for a simple way to test smart contracts from go in your CI, you can use the [Simulated Backend](https://geth.ethereum.org/docs/developers/dapp-developer/native-bindings#blockchain-simulator). + * If you want a convenient single node environment for testing, you can use our [Dev Mode](https://geth.ethereum.org/docs/developers/dapp-developer/dev-mode). + * If you are looking for a multiple node test network, you can set one up quite easily with [Kurtosis](https://geth.ethereum.org/docs/fundamentals/kurtosis). ## Contribution diff --git a/cmd/clef/rules.md b/cmd/clef/rules.md index cc4a645596..3cd1bb52c6 100644 --- a/cmd/clef/rules.md +++ b/cmd/clef/rules.md @@ -7,7 +7,7 @@ It enables usecases like the following: * I want to auto-approve transactions with contract `CasinoDapp`, with up to `0.05 ether` in value to maximum `1 ether` per 24h period * I want to auto-approve transaction to contract `EthAlarmClock` with `data`=`0xdeadbeef`, if `value=0`, `gas < 44k` and `gasPrice < 40Gwei` -The two main features that are required for this to work well are; +The two main features that are required for this to work well are: 1. Rule Implementation: how to create, manage, and interpret rules in a flexible but secure manner 2. Credential management and credentials; how to provide auto-unlock without exposing keys unnecessarily. @@ -29,10 +29,10 @@ function asBig(str) { // Approve transactions to a certain contract if the value is below a certain limit function ApproveTx(req) { - var limit = big.Newint("0xb1a2bc2ec50000") + var limit = new BigNumber("0xb1a2bc2ec50000") var value = asBig(req.transaction.value); - if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9") && value.lt(limit)) { + if (req.transaction.to.toLowerCase() == "0xae967917c465db8578ca9024c205720b1a3651a9" && value.lt(limit)) { return "Approve" } // If we return "Reject", it will be rejected. diff --git a/cmd/devp2p/dns_route53.go b/cmd/devp2p/dns_route53.go index a6125b8263..86907688f3 100644 --- a/cmd/devp2p/dns_route53.go +++ b/cmd/devp2p/dns_route53.go @@ -17,6 +17,7 @@ package main import ( + "cmp" "context" "errors" "fmt" @@ -292,13 +293,7 @@ func sortChanges(changes []types.Change) { if a.Action == b.Action { return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name) } - if score[string(a.Action)] < score[string(b.Action)] { - return -1 - } - if score[string(a.Action)] > score[string(b.Action)] { - return 1 - } - return 0 + return cmp.Compare(score[string(a.Action)], score[string(b.Action)]) }) } diff --git a/cmd/devp2p/nodeset.go b/cmd/devp2p/nodeset.go index 4fa862de14..4a6df6cdfe 100644 --- a/cmd/devp2p/nodeset.go +++ b/cmd/devp2p/nodeset.go @@ -18,6 +18,7 @@ package main import ( "bytes" + "cmp" "encoding/json" "fmt" "os" @@ -104,13 +105,7 @@ func (ns nodeSet) topN(n int) nodeSet { byscore = append(byscore, v) } slices.SortFunc(byscore, func(a, b nodeJSON) int { - if a.Score > b.Score { - return -1 - } - if a.Score < b.Score { - return 1 - } - return 0 + return cmp.Compare(b.Score, a.Score) }) result := make(nodeSet, n) for _, v := range byscore[:n] { diff --git a/core/rawdb/freezer.go b/core/rawdb/freezer.go index d6370cee33..c5a72eff7e 100644 --- a/core/rawdb/freezer.go +++ b/core/rawdb/freezer.go @@ -87,6 +87,10 @@ func NewFreezer(datadir string, namespace string, readonly bool, maxTableSize ui ) // Ensure the datadir is not a symbolic link if it exists. if info, err := os.Lstat(datadir); !os.IsNotExist(err) { + if info == nil { + log.Warn("Could not Lstat the database", "path", datadir) + return nil, errors.New("lstat failed") + } if info.Mode()&os.ModeSymlink != 0 { log.Warn("Symbolic link ancient database is not supported", "path", datadir) return nil, errSymlinkDatadir diff --git a/core/state/snapshot/iterator_fast.go b/core/state/snapshot/iterator_fast.go index 7f7ba876ff..61fc434178 100644 --- a/core/state/snapshot/iterator_fast.go +++ b/core/state/snapshot/iterator_fast.go @@ -18,6 +18,7 @@ package snapshot import ( "bytes" + "cmp" "fmt" "slices" "sort" @@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int { return 1 } // Same account/storage-slot in multiple layers, split by priority - if it.priority < other.priority { - return -1 - } - if it.priority > other.priority { - return 1 - } - return 0 + return cmp.Compare(it.priority, other.priority) } // fastIterator is a more optimized multi-layer iterator which maintains a diff --git a/core/types/hashing_test.go b/core/types/hashing_test.go index a6949414f3..c846ecd0c5 100644 --- a/core/types/hashing_test.go +++ b/core/types/hashing_test.go @@ -111,7 +111,7 @@ func TestFuzzDeriveSha(t *testing.T) { exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) if !bytes.Equal(got[:], exp[:]) { - printList(newDummy(seed)) + printList(t, newDummy(seed)) t.Fatalf("seed %d: got %x exp %x", seed, got, exp) } } @@ -192,15 +192,21 @@ func (d *dummyDerivableList) EncodeIndex(i int, w *bytes.Buffer) { io.CopyN(w, mrand.New(src), size) } -func printList(l types.DerivableList) { - fmt.Printf("list length: %d\n", l.Len()) - fmt.Printf("{\n") +func printList(t *testing.T, l types.DerivableList) { + var buf bytes.Buffer + _, _ = fmt.Fprintf(&buf, "list length: %d, ", l.Len()) + buf.WriteString("list: [") for i := 0; i < l.Len(); i++ { - var buf bytes.Buffer - l.EncodeIndex(i, &buf) - fmt.Printf("\"%#x\",\n", buf.Bytes()) + var itemBuf bytes.Buffer + l.EncodeIndex(i, &itemBuf) + if i == l.Len()-1 { + _, _ = fmt.Fprintf(&buf, "\"%#x\"", itemBuf.Bytes()) + } else { + _, _ = fmt.Fprintf(&buf, "\"%#x\",", itemBuf.Bytes()) + } } - fmt.Printf("},\n") + buf.WriteString("]") + t.Log(buf.String()) } type flatList []string diff --git a/crypto/bn256/cloudflare/gfp12.go b/crypto/bn256/cloudflare/gfp12.go index 93fb368a7b..767350701f 100644 --- a/crypto/bn256/cloudflare/gfp12.go +++ b/crypto/bn256/cloudflare/gfp12.go @@ -105,8 +105,8 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { - e.x.Mul(&e.x, b) - e.y.Mul(&e.y, b) + e.x.Mul(&a.x, b) + e.y.Mul(&a.y, b) return e } diff --git a/crypto/bn256/google/gfp12.go b/crypto/bn256/google/gfp12.go index f084eddf21..2b0151ebcc 100644 --- a/crypto/bn256/google/gfp12.go +++ b/crypto/bn256/google/gfp12.go @@ -125,8 +125,8 @@ func (e *gfP12) Mul(a, b *gfP12, pool *bnPool) *gfP12 { } func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 { - e.x.Mul(e.x, b, pool) - e.y.Mul(e.y, b, pool) + e.x.Mul(a.x, b, pool) + e.y.Mul(a.y, b, pool) return e } diff --git a/eth/protocols/eth/dispatcher.go b/eth/protocols/eth/dispatcher.go index 146eec3f60..cba40596fc 100644 --- a/eth/protocols/eth/dispatcher.go +++ b/eth/protocols/eth/dispatcher.go @@ -174,6 +174,8 @@ func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) erro return <-res.Done // Response delivered, return any errors case <-res.Req.cancel: return nil // Request cancelled, silently discard response + case <-p.term: + return errDisconnected } } diff --git a/eth/sync_test.go b/eth/sync_test.go index 57eea73790..cad3a4732e 100644 --- a/eth/sync_test.go +++ b/eth/sync_test.go @@ -88,7 +88,7 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) { if err := empty.handler.downloader.BeaconSync(ethconfig.SnapSync, full.chain.CurrentBlock(), nil); err != nil { t.Fatal("sync failed:", err) } - empty.handler.enableSyncedFeatures() + time.Sleep(time.Second * 5) // Downloader internally has to wait a timer (3s) to be expired before exiting if empty.handler.snapSync.Load() { t.Fatalf("snap sync not disabled after successful synchronisation") diff --git a/eth/tracers/logger/logger.go b/eth/tracers/logger/logger.go index dc9e6e62b7..07de871f14 100644 --- a/eth/tracers/logger/logger.go +++ b/eth/tracers/logger/logger.go @@ -217,6 +217,7 @@ type StructLogger struct { interrupt atomic.Bool // Atomic flag to signal execution interruption reason error // Textual reason for the interruption + skip bool // skip processing hooks. } // NewStreamingStructLogger returns a new streaming logger. @@ -240,10 +241,12 @@ func NewStructLogger(cfg *Config) *StructLogger { func (l *StructLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: l.OnTxStart, - OnTxEnd: l.OnTxEnd, - OnExit: l.OnExit, - OnOpcode: l.OnOpcode, + OnTxStart: l.OnTxStart, + OnTxEnd: l.OnTxEnd, + OnSystemCallStartV2: l.OnSystemCallStart, + OnSystemCallEnd: l.OnSystemCallEnd, + OnExit: l.OnExit, + OnOpcode: l.OnOpcode, } } @@ -255,6 +258,10 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope if l.interrupt.Load() { return } + // Processing a system call. + if l.skip { + return + } // check if already accumulated the size of the response. if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit { return @@ -320,6 +327,9 @@ func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err erro if depth != 0 { return } + if l.skip { + return + } l.output = output l.err = err // TODO @holiman, should we output the per-scope output? @@ -360,6 +370,13 @@ func (l *StructLogger) Stop(err error) { func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { l.env = env } +func (l *StructLogger) OnSystemCallStart(env *tracing.VMContext) { + l.skip = true +} + +func (l *StructLogger) OnSystemCallEnd() { + l.skip = false +} func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { if err != nil { @@ -389,9 +406,10 @@ func WriteTrace(writer io.Writer, logs []StructLog) { } type mdLogger struct { - out io.Writer - cfg *Config - env *tracing.VMContext + out io.Writer + cfg *Config + env *tracing.VMContext + skip bool } // NewMarkdownLogger creates a logger which outputs information in a format adapted @@ -406,11 +424,13 @@ func NewMarkdownLogger(cfg *Config, writer io.Writer) *mdLogger { func (t *mdLogger) Hooks() *tracing.Hooks { return &tracing.Hooks{ - OnTxStart: t.OnTxStart, - OnEnter: t.OnEnter, - OnExit: t.OnExit, - OnOpcode: t.OnOpcode, - OnFault: t.OnFault, + OnTxStart: t.OnTxStart, + OnSystemCallStartV2: t.OnSystemCallStart, + OnSystemCallEnd: t.OnSystemCallEnd, + OnEnter: t.OnEnter, + OnExit: t.OnExit, + OnOpcode: t.OnOpcode, + OnFault: t.OnFault, } } @@ -418,7 +438,18 @@ func (t *mdLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from t.env = env } +func (t *mdLogger) OnSystemCallStart(env *tracing.VMContext) { + t.skip = true +} + +func (t *mdLogger) OnSystemCallEnd() { + t.skip = false +} + func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.Address, input []byte, gas uint64, value *big.Int) { + if t.skip { + return + } if depth != 0 { return } @@ -446,6 +477,9 @@ func (t *mdLogger) OnEnter(depth int, typ byte, from common.Address, to common.A } func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) { + if t.skip { + return + } if depth == 0 { fmt.Fprintf(t.out, "\nPost-execution info:\n"+ " - output: `%#x`\n"+ @@ -457,6 +491,9 @@ func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, r // OnOpcode also tracks SLOAD/SSTORE ops to track storage change. func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) { + if t.skip { + return + } stack := scope.StackData() fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(), cost, t.env.StateDB.GetRefund()) @@ -477,6 +514,9 @@ func (t *mdLogger) OnOpcode(pc uint64, op byte, gas, cost uint64, scope tracing. } func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, depth int, err error) { + if t.skip { + return + } fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 5bd0079a93..130eaa9724 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -45,7 +45,7 @@ const ( maxSimulateBlocks = 256 // timestampIncrement is the default increment between block timestamps. - timestampIncrement = 1 + timestampIncrement = 12 ) // simBlock is a batch of calls to be simulated sequentially. diff --git a/internal/ethapi/simulate_test.go b/internal/ethapi/simulate_test.go index 52ae40cad0..c747b76477 100644 --- a/internal/ethapi/simulate_test.go +++ b/internal/ethapi/simulate_test.go @@ -41,19 +41,19 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{}, {}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}}, }, { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(80)}}, {}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 80}, {number: 14, timestamp: 92}}, }, { baseNumber: 10, baseTimestamp: 50, blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}}, - expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 53}, {number: 14, timestamp: 54}, {number: 15, timestamp: 55}}, + expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 86}, {number: 14, timestamp: 98}, {number: 15, timestamp: 110}}, }, { baseNumber: 10, @@ -64,8 +64,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, - err: "block timestamps must be in order: 52 <= 52", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(74)}}}, + err: "block timestamps must be in order: 74 <= 74", }, { baseNumber: 10, @@ -76,8 +76,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) { { baseNumber: 10, baseTimestamp: 50, - blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(61)}}}, - err: "block timestamps must be in order: 61 <= 61", + blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(72)}}}, + err: "block timestamps must be in order: 72 <= 72", }, } { sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} diff --git a/internal/flags/helpers.go b/internal/flags/helpers.go index fd706869f1..170b67b310 100644 --- a/internal/flags/helpers.go +++ b/internal/flags/helpers.go @@ -40,7 +40,7 @@ func NewApp(usage string) *cli.App { app.EnableBashCompletion = true app.Version = version.WithCommit(git.Commit, git.Date) app.Usage = usage - app.Copyright = "Copyright 2013-2024 The go-ethereum Authors" + app.Copyright = "Copyright 2013-2025 The go-ethereum Authors" app.Before = func(ctx *cli.Context) error { MigrateGlobalFlags(ctx) return nil diff --git a/p2p/protocol.go b/p2p/protocol.go index 9bb6785a22..de3127e233 100644 --- a/p2p/protocol.go +++ b/p2p/protocol.go @@ -17,6 +17,7 @@ package p2p import ( + "cmp" "fmt" "strings" @@ -81,13 +82,7 @@ func (cap Cap) String() string { // Cmp defines the canonical sorting order of capabilities. func (cap Cap) Cmp(other Cap) int { if cap.Name == other.Name { - if cap.Version < other.Version { - return -1 - } - if cap.Version > other.Version { - return 1 - } - return 0 + return cmp.Compare(cap.Version, other.Version) } return strings.Compare(cap.Name, other.Name) } diff --git a/triedb/pathdb/database_test.go b/triedb/pathdb/database_test.go index 648230df15..3b35370c84 100644 --- a/triedb/pathdb/database_test.go +++ b/triedb/pathdb/database_test.go @@ -222,7 +222,12 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode dirties = make(map[common.Hash]struct{}) ) for i := 0; i < 20; i++ { - switch rand.Intn(opLen) { + // Start with account creation always + op := createAccountOp + if i > 0 { + op = rand.Intn(opLen) + } + switch op { case createAccountOp: // account creation addr := testrand.Address() diff --git a/triedb/pathdb/iterator_fast.go b/triedb/pathdb/iterator_fast.go index 217b211fcc..966e37a7cb 100644 --- a/triedb/pathdb/iterator_fast.go +++ b/triedb/pathdb/iterator_fast.go @@ -18,6 +18,7 @@ package pathdb import ( "bytes" + "cmp" "fmt" "slices" "sort" @@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int { return 1 } // Same account/storage-slot in multiple layers, split by priority - if it.priority < other.priority { - return -1 - } - if it.priority > other.priority { - return 1 - } - return 0 + return cmp.Compare(it.priority, other.priority) } // fastIterator is a more optimized multi-layer iterator which maintains a