mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-14 16:03:45 +00:00
Merge branch 'ethereum:master' into master
This commit is contained in:
commit
e5d5a3806a
18 changed files with 115 additions and 190 deletions
125
README.md
125
README.md
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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] {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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}}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue