Merge branch 'ethereum:master' into master

This commit is contained in:
Mikhail Wall 2025-01-10 14:06:08 +08:00 committed by GitHub
commit e5d5a3806a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 115 additions and 190 deletions

125
README.md
View file

@ -54,14 +54,14 @@ on how you can run your own `geth` instance.
Minimum: Minimum:
* CPU with 2+ cores * CPU with 4+ cores
* 4GB RAM * 8GB RAM
* 1TB free storage space to sync the Mainnet * 1TB free storage space to sync the Mainnet
* 8 MBit/sec download Internet service * 8 MBit/sec download Internet service
Recommended: Recommended:
* Fast CPU with 4+ cores * Fast CPU with 8+ cores
* 16GB+ RAM * 16GB+ RAM
* High-performance SSD with at least 1TB of free space * High-performance SSD with at least 1TB of free space
* 25+ MBit/sec download Internet service * 25+ MBit/sec download Internet service
@ -138,8 +138,6 @@ export your existing configuration:
$ geth --your-favourite-flags dumpconfig $ geth --your-favourite-flags dumpconfig
``` ```
*Note: This works only with `geth` v1.6.0 and above.*
#### Docker quick start #### Docker quick start
One of the quickest ways to get Ethereum up and running on your machine is by using 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.api` API's offered over the WS-RPC interface (default: `eth,net,web3`)
* `--ws.origins` Origins from which to accept WebSocket requests * `--ws.origins` Origins from which to accept WebSocket requests
* `--ipcdisable` Disable the IPC-RPC server * `--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) * `--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 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 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. 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 There are three different solutions depending on your use case:
aware of and agree upon. This consists of a small JSON file (e.g. call it `genesis.json`):
```json * 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).
"config": { * 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).
"chainId": <arbitrary positive integer>,
"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 <ip> <port>` 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=<bootnode-enode-url-from-above>
```
*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 <usual-flags> --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`).
## Contribution ## Contribution

View file

@ -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 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` * 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 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. 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 // Approve transactions to a certain contract if the value is below a certain limit
function ApproveTx(req) { function ApproveTx(req) {
var limit = big.Newint("0xb1a2bc2ec50000") var limit = new BigNumber("0xb1a2bc2ec50000")
var value = asBig(req.transaction.value); 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" return "Approve"
} }
// If we return "Reject", it will be rejected. // If we return "Reject", it will be rejected.

View file

@ -17,6 +17,7 @@
package main package main
import ( import (
"cmp"
"context" "context"
"errors" "errors"
"fmt" "fmt"
@ -292,13 +293,7 @@ func sortChanges(changes []types.Change) {
if a.Action == b.Action { if a.Action == b.Action {
return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name) return strings.Compare(*a.ResourceRecordSet.Name, *b.ResourceRecordSet.Name)
} }
if score[string(a.Action)] < score[string(b.Action)] { return cmp.Compare(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

@ -18,6 +18,7 @@ package main
import ( import (
"bytes" "bytes"
"cmp"
"encoding/json" "encoding/json"
"fmt" "fmt"
"os" "os"
@ -104,13 +105,7 @@ func (ns nodeSet) topN(n int) nodeSet {
byscore = append(byscore, v) byscore = append(byscore, v)
} }
slices.SortFunc(byscore, func(a, b nodeJSON) int { slices.SortFunc(byscore, func(a, b nodeJSON) int {
if a.Score > b.Score { return cmp.Compare(b.Score, a.Score)
return -1
}
if a.Score < b.Score {
return 1
}
return 0
}) })
result := make(nodeSet, n) result := make(nodeSet, n)
for _, v := range byscore[:n] { for _, v := range byscore[:n] {

View file

@ -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. // Ensure the datadir is not a symbolic link if it exists.
if info, err := os.Lstat(datadir); !os.IsNotExist(err) { 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 { if info.Mode()&os.ModeSymlink != 0 {
log.Warn("Symbolic link ancient database is not supported", "path", datadir) log.Warn("Symbolic link ancient database is not supported", "path", datadir)
return nil, errSymlinkDatadir return nil, errSymlinkDatadir

View file

@ -18,6 +18,7 @@ package snapshot
import ( import (
"bytes" "bytes"
"cmp"
"fmt" "fmt"
"slices" "slices"
"sort" "sort"
@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int {
return 1 return 1
} }
// Same account/storage-slot in multiple layers, split by priority // Same account/storage-slot in multiple layers, split by priority
if it.priority < other.priority { return cmp.Compare(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 // fastIterator is a more optimized multi-layer iterator which maintains a

View file

@ -111,7 +111,7 @@ func TestFuzzDeriveSha(t *testing.T) {
exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil))) exp := types.DeriveSha(newDummy(i), trie.NewEmpty(triedb.NewDatabase(rawdb.NewMemoryDatabase(), nil)))
got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil)) got := types.DeriveSha(newDummy(i), trie.NewStackTrie(nil))
if !bytes.Equal(got[:], exp[:]) { if !bytes.Equal(got[:], exp[:]) {
printList(newDummy(seed)) printList(t, newDummy(seed))
t.Fatalf("seed %d: got %x exp %x", seed, got, exp) 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) io.CopyN(w, mrand.New(src), size)
} }
func printList(l types.DerivableList) { func printList(t *testing.T, l types.DerivableList) {
fmt.Printf("list length: %d\n", l.Len()) var buf bytes.Buffer
fmt.Printf("{\n") _, _ = fmt.Fprintf(&buf, "list length: %d, ", l.Len())
buf.WriteString("list: [")
for i := 0; i < l.Len(); i++ { for i := 0; i < l.Len(); i++ {
var buf bytes.Buffer var itemBuf bytes.Buffer
l.EncodeIndex(i, &buf) l.EncodeIndex(i, &itemBuf)
fmt.Printf("\"%#x\",\n", buf.Bytes()) 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 type flatList []string

View file

@ -105,8 +105,8 @@ func (e *gfP12) Mul(a, b *gfP12) *gfP12 {
} }
func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 { func (e *gfP12) MulScalar(a *gfP12, b *gfP6) *gfP12 {
e.x.Mul(&e.x, b) e.x.Mul(&a.x, b)
e.y.Mul(&e.y, b) e.y.Mul(&a.y, b)
return e return e
} }

View file

@ -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 { func (e *gfP12) MulScalar(a *gfP12, b *gfP6, pool *bnPool) *gfP12 {
e.x.Mul(e.x, b, pool) e.x.Mul(a.x, b, pool)
e.y.Mul(e.y, b, pool) e.y.Mul(a.y, b, pool)
return e return e
} }

View file

@ -174,6 +174,8 @@ func (p *Peer) dispatchResponse(res *Response, metadata func() interface{}) erro
return <-res.Done // Response delivered, return any errors return <-res.Done // Response delivered, return any errors
case <-res.Req.cancel: case <-res.Req.cancel:
return nil // Request cancelled, silently discard response return nil // Request cancelled, silently discard response
case <-p.term:
return errDisconnected
} }
} }

View file

@ -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 { if err := empty.handler.downloader.BeaconSync(ethconfig.SnapSync, full.chain.CurrentBlock(), nil); err != nil {
t.Fatal("sync failed:", err) 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() { if empty.handler.snapSync.Load() {
t.Fatalf("snap sync not disabled after successful synchronisation") t.Fatalf("snap sync not disabled after successful synchronisation")

View file

@ -217,6 +217,7 @@ type StructLogger struct {
interrupt atomic.Bool // Atomic flag to signal execution interruption interrupt atomic.Bool // Atomic flag to signal execution interruption
reason error // Textual reason for the interruption reason error // Textual reason for the interruption
skip bool // skip processing hooks.
} }
// NewStreamingStructLogger returns a new streaming logger. // NewStreamingStructLogger returns a new streaming logger.
@ -240,10 +241,12 @@ func NewStructLogger(cfg *Config) *StructLogger {
func (l *StructLogger) Hooks() *tracing.Hooks { func (l *StructLogger) Hooks() *tracing.Hooks {
return &tracing.Hooks{ return &tracing.Hooks{
OnTxStart: l.OnTxStart, OnTxStart: l.OnTxStart,
OnTxEnd: l.OnTxEnd, OnTxEnd: l.OnTxEnd,
OnExit: l.OnExit, OnSystemCallStartV2: l.OnSystemCallStart,
OnOpcode: l.OnOpcode, 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() { if l.interrupt.Load() {
return return
} }
// Processing a system call.
if l.skip {
return
}
// check if already accumulated the size of the response. // check if already accumulated the size of the response.
if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit { if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit {
return return
@ -320,6 +327,9 @@ func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err erro
if depth != 0 { if depth != 0 {
return return
} }
if l.skip {
return
}
l.output = output l.output = output
l.err = err l.err = err
// TODO @holiman, should we output the per-scope output? // 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) { func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
l.env = env 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) { func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) {
if err != nil { if err != nil {
@ -389,9 +406,10 @@ func WriteTrace(writer io.Writer, logs []StructLog) {
} }
type mdLogger struct { type mdLogger struct {
out io.Writer out io.Writer
cfg *Config cfg *Config
env *tracing.VMContext env *tracing.VMContext
skip bool
} }
// NewMarkdownLogger creates a logger which outputs information in a format adapted // 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 { func (t *mdLogger) Hooks() *tracing.Hooks {
return &tracing.Hooks{ return &tracing.Hooks{
OnTxStart: t.OnTxStart, OnTxStart: t.OnTxStart,
OnEnter: t.OnEnter, OnSystemCallStartV2: t.OnSystemCallStart,
OnExit: t.OnExit, OnSystemCallEnd: t.OnSystemCallEnd,
OnOpcode: t.OnOpcode, OnEnter: t.OnEnter,
OnFault: t.OnFault, 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 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) { 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 { if depth != 0 {
return 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) { func (t *mdLogger) OnExit(depth int, output []byte, gasUsed uint64, err error, reverted bool) {
if t.skip {
return
}
if depth == 0 { if depth == 0 {
fmt.Fprintf(t.out, "\nPost-execution info:\n"+ fmt.Fprintf(t.out, "\nPost-execution info:\n"+
" - output: `%#x`\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. // 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) { 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() stack := scope.StackData()
fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(), fmt.Fprintf(t.out, "| %4d | %10v | %3d |%10v |", pc, vm.OpCode(op).String(),
cost, t.env.StateDB.GetRefund()) 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) { 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) fmt.Fprintf(t.out, "\nError: at pc=%d, op=%v: %v\n", pc, op, err)
} }

View file

@ -45,7 +45,7 @@ const (
maxSimulateBlocks = 256 maxSimulateBlocks = 256
// timestampIncrement is the default increment between block timestamps. // timestampIncrement is the default increment between block timestamps.
timestampIncrement = 1 timestampIncrement = 12
) )
// simBlock is a batch of calls to be simulated sequentially. // simBlock is a batch of calls to be simulated sequentially.

View file

@ -41,19 +41,19 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
baseNumber: 10, baseNumber: 10,
baseTimestamp: 50, baseTimestamp: 50,
blocks: []simBlock{{}, {}, {}}, 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, baseNumber: 10,
baseTimestamp: 50, baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(70)}}, {}}, blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(80)}}, {}},
expected: []result{{number: 11, timestamp: 51}, {number: 12, timestamp: 52}, {number: 13, timestamp: 70}, {number: 14, timestamp: 71}}, expected: []result{{number: 11, timestamp: 62}, {number: 12, timestamp: 74}, {number: 13, timestamp: 80}, {number: 14, timestamp: 92}},
}, },
{ {
baseNumber: 10, baseNumber: 10,
baseTimestamp: 50, baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(14)}}, {}}, 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, baseNumber: 10,
@ -64,8 +64,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
{ {
baseNumber: 10, baseNumber: 10,
baseTimestamp: 50, baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(52)}}}, blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(74)}}},
err: "block timestamps must be in order: 52 <= 52", err: "block timestamps must be in order: 74 <= 74",
}, },
{ {
baseNumber: 10, baseNumber: 10,
@ -76,8 +76,8 @@ func TestSimulateSanitizeBlockOrder(t *testing.T) {
{ {
baseNumber: 10, baseNumber: 10,
baseTimestamp: 50, baseTimestamp: 50,
blocks: []simBlock{{BlockOverrides: &override.BlockOverrides{Number: newInt(11), Time: newUint64(60)}}, {BlockOverrides: &override.BlockOverrides{Number: newInt(13), Time: newUint64(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: 61 <= 61", err: "block timestamps must be in order: 72 <= 72",
}, },
} { } {
sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}} sim := &simulator{base: &types.Header{Number: big.NewInt(int64(tc.baseNumber)), Time: tc.baseTimestamp}}

View file

@ -40,7 +40,7 @@ func NewApp(usage string) *cli.App {
app.EnableBashCompletion = true app.EnableBashCompletion = true
app.Version = version.WithCommit(git.Commit, git.Date) app.Version = version.WithCommit(git.Commit, git.Date)
app.Usage = usage 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 { app.Before = func(ctx *cli.Context) error {
MigrateGlobalFlags(ctx) MigrateGlobalFlags(ctx)
return nil return nil

View file

@ -17,6 +17,7 @@
package p2p package p2p
import ( import (
"cmp"
"fmt" "fmt"
"strings" "strings"
@ -81,13 +82,7 @@ func (cap Cap) String() string {
// Cmp defines the canonical sorting order of capabilities. // Cmp defines the canonical sorting order of capabilities.
func (cap Cap) Cmp(other Cap) int { func (cap Cap) Cmp(other Cap) int {
if cap.Name == other.Name { if cap.Name == other.Name {
if cap.Version < other.Version { return cmp.Compare(cap.Version, other.Version)
return -1
}
if cap.Version > other.Version {
return 1
}
return 0
} }
return strings.Compare(cap.Name, other.Name) return strings.Compare(cap.Name, other.Name)
} }

View file

@ -222,7 +222,12 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode
dirties = make(map[common.Hash]struct{}) dirties = make(map[common.Hash]struct{})
) )
for i := 0; i < 20; i++ { 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: case createAccountOp:
// account creation // account creation
addr := testrand.Address() addr := testrand.Address()

View file

@ -18,6 +18,7 @@ package pathdb
import ( import (
"bytes" "bytes"
"cmp"
"fmt" "fmt"
"slices" "slices"
"sort" "sort"
@ -45,13 +46,7 @@ func (it *weightedIterator) Cmp(other *weightedIterator) int {
return 1 return 1
} }
// Same account/storage-slot in multiple layers, split by priority // Same account/storage-slot in multiple layers, split by priority
if it.priority < other.priority { return cmp.Compare(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 // fastIterator is a more optimized multi-layer iterator which maintains a