mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 14:46:42 +00:00
Merge branch 'gethmaster' into gethintegration
This commit is contained in:
commit
b209acdc7d
106 changed files with 2491 additions and 1432 deletions
39
.github/CODEOWNERS
vendored
39
.github/CODEOWNERS
vendored
|
|
@ -1,25 +1,36 @@
|
||||||
# Lines starting with '#' are comments.
|
# Lines starting with '#' are comments.
|
||||||
# Each line is a file pattern followed by one or more owners.
|
# Each line is a file pattern followed by one or more owners.
|
||||||
|
|
||||||
accounts/usbwallet @karalabe
|
accounts/usbwallet/ @gballet
|
||||||
accounts/scwallet @gballet
|
accounts/scwallet/ @gballet
|
||||||
accounts/abi @gballet @MariusVanDerWijden
|
accounts/abi/ @gballet @MariusVanDerWijden
|
||||||
beacon/engine @lightclient
|
beacon/engine/ @MariusVanDerWijden @lightclient @fjl
|
||||||
cmd/clef @holiman
|
beacon/light/ @zsfelfoldi
|
||||||
cmd/evm @holiman @MariusVanDerWijden @lightclient
|
beacon/merkle/ @zsfelfoldi
|
||||||
consensus @karalabe
|
beacon/types/ @zsfelfoldi @fjl
|
||||||
core/ @karalabe @holiman @rjl493456442
|
beacon/params/ @zsfelfoldi @fjl
|
||||||
eth/ @karalabe @holiman @rjl493456442
|
cmd/clef/ @holiman
|
||||||
eth/catalyst/ @gballet @lightclient
|
cmd/evm/ @holiman @MariusVanDerWijden @lightclient
|
||||||
|
core/state/ @rjl493456442 @holiman
|
||||||
|
crypto/ @gballet @jwasinger @holiman @fjl
|
||||||
|
core/ @holiman @rjl493456442
|
||||||
|
eth/ @holiman @rjl493456442
|
||||||
|
eth/catalyst/ @MariusVanDerWijden @lightclient @fjl @jwasinger
|
||||||
eth/tracers/ @s1na
|
eth/tracers/ @s1na
|
||||||
|
ethclient/ @fjl
|
||||||
|
ethdb/ @rjl493456442
|
||||||
|
event/ @fjl
|
||||||
|
trie/ @rjl493456442
|
||||||
|
triedb/ @rjl493456442
|
||||||
core/tracing/ @s1na
|
core/tracing/ @s1na
|
||||||
graphql/ @s1na
|
graphql/ @s1na
|
||||||
internal/ethapi @lightclient
|
internal/ethapi/ @fjl @s1na @lightclient
|
||||||
internal/era @lightclient
|
internal/era/ @lightclient
|
||||||
les/ @zsfelfoldi @rjl493456442
|
metrics/ @holiman
|
||||||
light/ @zsfelfoldi @rjl493456442
|
miner/ @MariusVanDerWijden @holiman @fjl @rjl493456442
|
||||||
node/ @fjl
|
node/ @fjl
|
||||||
p2p/ @fjl @zsfelfoldi
|
p2p/ @fjl @zsfelfoldi
|
||||||
|
rlp/ @fjl
|
||||||
params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi
|
params/ @fjl @holiman @karalabe @gballet @rjl493456442 @zsfelfoldi
|
||||||
rpc/ @fjl @holiman
|
rpc/ @fjl @holiman
|
||||||
signer/ @holiman
|
signer/ @holiman
|
||||||
|
|
|
||||||
|
|
@ -265,15 +265,7 @@ func ExecutableDataToBlockNoHash(data ExecutableData, versionedHashes []common.H
|
||||||
|
|
||||||
var requestsHash *common.Hash
|
var requestsHash *common.Hash
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
// Put back request type byte.
|
h := types.CalcRequestsHash(requests)
|
||||||
typedRequests := make([][]byte, len(requests))
|
|
||||||
for i, reqdata := range requests {
|
|
||||||
typedReqdata := make([]byte, len(reqdata)+1)
|
|
||||||
typedReqdata[0] = byte(i)
|
|
||||||
copy(typedReqdata[1:], reqdata)
|
|
||||||
typedRequests[i] = typedReqdata
|
|
||||||
}
|
|
||||||
h := types.CalcRequestsHash(typedRequests)
|
|
||||||
requestsHash = &h
|
requestsHash = &h
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -343,20 +335,11 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove type byte in requests.
|
|
||||||
var plainRequests [][]byte
|
|
||||||
if requests != nil {
|
|
||||||
plainRequests = make([][]byte, len(requests))
|
|
||||||
for i, reqdata := range requests {
|
|
||||||
plainRequests[i] = reqdata[1:]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &ExecutionPayloadEnvelope{
|
return &ExecutionPayloadEnvelope{
|
||||||
ExecutionPayload: data,
|
ExecutionPayload: data,
|
||||||
BlockValue: fees,
|
BlockValue: fees,
|
||||||
BlobsBundle: &bundle,
|
BlobsBundle: &bundle,
|
||||||
Requests: plainRequests,
|
Requests: requests,
|
||||||
Override: false,
|
Override: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ var (
|
||||||
allToolsArchiveFiles = []string{
|
allToolsArchiveFiles = []string{
|
||||||
"COPYING",
|
"COPYING",
|
||||||
executablePath("abigen"),
|
executablePath("abigen"),
|
||||||
executablePath("bootnode"),
|
|
||||||
executablePath("evm"),
|
executablePath("evm"),
|
||||||
executablePath("geth"),
|
executablePath("geth"),
|
||||||
executablePath("rlpdump"),
|
executablePath("rlpdump"),
|
||||||
|
|
@ -87,10 +86,6 @@ var (
|
||||||
BinaryName: "abigen",
|
BinaryName: "abigen",
|
||||||
Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.",
|
Description: "Source code generator to convert Ethereum contract definitions into easy to use, compile-time type-safe Go packages.",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
BinaryName: "bootnode",
|
|
||||||
Description: "Ethereum bootnode.",
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
BinaryName: "evm",
|
BinaryName: "evm",
|
||||||
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
|
Description: "Developer utility version of the EVM (Ethereum Virtual Machine) that is capable of running bytecode snippets within a configurable environment and execution mode.",
|
||||||
|
|
|
||||||
|
|
@ -1,209 +0,0 @@
|
||||||
// Copyright 2015 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
// bootnode runs a bootstrap node for the Ethereum Discovery Protocol.
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/ecdsa"
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/discover"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/nat"
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/netutil"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var (
|
|
||||||
listenAddr = flag.String("addr", ":30301", "listen address")
|
|
||||||
genKey = flag.String("genkey", "", "generate a node key")
|
|
||||||
writeAddr = flag.Bool("writeaddress", false, "write out the node's public key and quit")
|
|
||||||
nodeKeyFile = flag.String("nodekey", "", "private key filename")
|
|
||||||
nodeKeyHex = flag.String("nodekeyhex", "", "private key as hex (for testing)")
|
|
||||||
natdesc = flag.String("nat", "none", "port mapping mechanism (any|none|upnp|pmp|pmp:<IP>|extip:<IP>)")
|
|
||||||
netrestrict = flag.String("netrestrict", "", "restrict network communication to the given IP networks (CIDR masks)")
|
|
||||||
runv5 = flag.Bool("v5", false, "run a v5 topic discovery bootnode")
|
|
||||||
verbosity = flag.Int("verbosity", 3, "log verbosity (0-5)")
|
|
||||||
vmodule = flag.String("vmodule", "", "log verbosity pattern")
|
|
||||||
|
|
||||||
nodeKey *ecdsa.PrivateKey
|
|
||||||
err error
|
|
||||||
)
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
glogger := log.NewGlogHandler(log.NewTerminalHandler(os.Stderr, false))
|
|
||||||
slogVerbosity := log.FromLegacyLevel(*verbosity)
|
|
||||||
glogger.Verbosity(slogVerbosity)
|
|
||||||
glogger.Vmodule(*vmodule)
|
|
||||||
log.SetDefault(log.NewLogger(glogger))
|
|
||||||
|
|
||||||
natm, err := nat.Parse(*natdesc)
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("-nat: %v", err)
|
|
||||||
}
|
|
||||||
switch {
|
|
||||||
case *genKey != "":
|
|
||||||
nodeKey, err = crypto.GenerateKey()
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("could not generate key: %v", err)
|
|
||||||
}
|
|
||||||
if err = crypto.SaveECDSA(*genKey, nodeKey); err != nil {
|
|
||||||
utils.Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
if !*writeAddr {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
case *nodeKeyFile == "" && *nodeKeyHex == "":
|
|
||||||
utils.Fatalf("Use -nodekey or -nodekeyhex to specify a private key")
|
|
||||||
case *nodeKeyFile != "" && *nodeKeyHex != "":
|
|
||||||
utils.Fatalf("Options -nodekey and -nodekeyhex are mutually exclusive")
|
|
||||||
case *nodeKeyFile != "":
|
|
||||||
if nodeKey, err = crypto.LoadECDSA(*nodeKeyFile); err != nil {
|
|
||||||
utils.Fatalf("-nodekey: %v", err)
|
|
||||||
}
|
|
||||||
case *nodeKeyHex != "":
|
|
||||||
if nodeKey, err = crypto.HexToECDSA(*nodeKeyHex); err != nil {
|
|
||||||
utils.Fatalf("-nodekeyhex: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if *writeAddr {
|
|
||||||
fmt.Printf("%x\n", crypto.FromECDSAPub(&nodeKey.PublicKey)[1:])
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
var restrictList *netutil.Netlist
|
|
||||||
if *netrestrict != "" {
|
|
||||||
restrictList, err = netutil.ParseNetlist(*netrestrict)
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("-netrestrict: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addr, err := net.ResolveUDPAddr("udp", *listenAddr)
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("-ResolveUDPAddr: %v", err)
|
|
||||||
}
|
|
||||||
conn, err := net.ListenUDP("udp", addr)
|
|
||||||
if err != nil {
|
|
||||||
utils.Fatalf("-ListenUDP: %v", err)
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
|
|
||||||
db, _ := enode.OpenDB("")
|
|
||||||
ln := enode.NewLocalNode(db, nodeKey)
|
|
||||||
|
|
||||||
listenerAddr := conn.LocalAddr().(*net.UDPAddr)
|
|
||||||
if natm != nil && !listenerAddr.IP.IsLoopback() {
|
|
||||||
natAddr := doPortMapping(natm, ln, listenerAddr)
|
|
||||||
if natAddr != nil {
|
|
||||||
listenerAddr = natAddr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printNotice(&nodeKey.PublicKey, *listenerAddr)
|
|
||||||
cfg := discover.Config{
|
|
||||||
PrivateKey: nodeKey,
|
|
||||||
NetRestrict: restrictList,
|
|
||||||
}
|
|
||||||
if *runv5 {
|
|
||||||
if _, err := discover.ListenV5(conn, ln, cfg); err != nil {
|
|
||||||
utils.Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if _, err := discover.ListenUDP(conn, ln, cfg); err != nil {
|
|
||||||
utils.Fatalf("%v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
select {}
|
|
||||||
}
|
|
||||||
|
|
||||||
func printNotice(nodeKey *ecdsa.PublicKey, addr net.UDPAddr) {
|
|
||||||
if addr.IP.IsUnspecified() {
|
|
||||||
addr.IP = net.IP{127, 0, 0, 1}
|
|
||||||
}
|
|
||||||
n := enode.NewV4(nodeKey, addr.IP, 0, addr.Port)
|
|
||||||
fmt.Println(n.URLv4())
|
|
||||||
fmt.Println("Note: you're using cmd/bootnode, a developer tool.")
|
|
||||||
fmt.Println("We recommend using a regular node as bootstrap node for production deployments.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func doPortMapping(natm nat.Interface, ln *enode.LocalNode, addr *net.UDPAddr) *net.UDPAddr {
|
|
||||||
const (
|
|
||||||
protocol = "udp"
|
|
||||||
name = "ethereum discovery"
|
|
||||||
)
|
|
||||||
newLogger := func(external int, internal int) log.Logger {
|
|
||||||
return log.New("proto", protocol, "extport", external, "intport", internal, "interface", natm)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
intport = addr.Port
|
|
||||||
extaddr = &net.UDPAddr{IP: addr.IP, Port: addr.Port}
|
|
||||||
mapTimeout = nat.DefaultMapTimeout
|
|
||||||
log = newLogger(addr.Port, intport)
|
|
||||||
)
|
|
||||||
addMapping := func() {
|
|
||||||
// Get the external address.
|
|
||||||
var err error
|
|
||||||
extaddr.IP, err = natm.ExternalIP()
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Couldn't get external IP", "err", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Create the mapping.
|
|
||||||
p, err := natm.AddMapping(protocol, extaddr.Port, intport, name, mapTimeout)
|
|
||||||
if err != nil {
|
|
||||||
log.Debug("Couldn't add port mapping", "err", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if p != uint16(extaddr.Port) {
|
|
||||||
extaddr.Port = int(p)
|
|
||||||
log = newLogger(extaddr.Port, intport)
|
|
||||||
log.Info("NAT mapped alternative port")
|
|
||||||
} else {
|
|
||||||
log.Info("NAT mapped port")
|
|
||||||
}
|
|
||||||
// Update IP/port information of the local node.
|
|
||||||
ln.SetStaticIP(extaddr.IP)
|
|
||||||
ln.SetFallbackUDP(extaddr.Port)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Perform mapping once, synchronously.
|
|
||||||
log.Info("Attempting port mapping")
|
|
||||||
addMapping()
|
|
||||||
|
|
||||||
// Refresh the mapping periodically.
|
|
||||||
go func() {
|
|
||||||
refresh := time.NewTimer(mapTimeout)
|
|
||||||
defer refresh.Stop()
|
|
||||||
for range refresh.C {
|
|
||||||
addMapping()
|
|
||||||
refresh.Reset(mapTimeout)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
return extaddr
|
|
||||||
}
|
|
||||||
|
|
@ -22,79 +22,84 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
"golang.org/x/exp/maps"
|
||||||
)
|
)
|
||||||
|
|
||||||
var RunFlag = &cli.StringFlag{
|
|
||||||
Name: "run",
|
|
||||||
Value: ".*",
|
|
||||||
Usage: "Run only those tests matching the regular expression.",
|
|
||||||
}
|
|
||||||
|
|
||||||
var blockTestCommand = &cli.Command{
|
var blockTestCommand = &cli.Command{
|
||||||
Action: blockTestCmd,
|
Action: blockTestCmd,
|
||||||
Name: "blocktest",
|
Name: "blocktest",
|
||||||
Usage: "Executes the given blockchain tests",
|
Usage: "Executes the given blockchain tests",
|
||||||
ArgsUsage: "<file>",
|
ArgsUsage: "<path>",
|
||||||
Flags: []cli.Flag{RunFlag},
|
Flags: slices.Concat([]cli.Flag{
|
||||||
|
DumpFlag,
|
||||||
|
HumanReadableFlag,
|
||||||
|
RunFlag,
|
||||||
|
WitnessCrossCheckFlag,
|
||||||
|
}, traceFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
func blockTestCmd(ctx *cli.Context) error {
|
func blockTestCmd(ctx *cli.Context) error {
|
||||||
if len(ctx.Args().First()) == 0 {
|
path := ctx.Args().First()
|
||||||
return errors.New("path-to-test argument required")
|
if len(path) == 0 {
|
||||||
|
return errors.New("path argument required")
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
collected = collectJSONFiles(path)
|
||||||
|
results []testResult
|
||||||
|
)
|
||||||
|
for _, fname := range collected {
|
||||||
|
r, err := runBlockTest(ctx, fname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
results = append(results, r...)
|
||||||
|
}
|
||||||
|
report(ctx, results)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var tracer *tracing.Hooks
|
func runBlockTest(ctx *cli.Context, fname string) ([]testResult, error) {
|
||||||
// Configure the EVM logger
|
src, err := os.ReadFile(fname)
|
||||||
if ctx.Bool(MachineFlag.Name) {
|
|
||||||
tracer = logger.NewJSONLogger(&logger.Config{
|
|
||||||
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
|
||||||
DisableStack: ctx.Bool(DisableStackFlag.Name),
|
|
||||||
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
|
|
||||||
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
|
|
||||||
}, os.Stderr)
|
|
||||||
}
|
|
||||||
// Load the test content from the input file
|
|
||||||
src, err := os.ReadFile(ctx.Args().First())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
var tests map[string]tests.BlockTest
|
var tests map[string]*tests.BlockTest
|
||||||
if err = json.Unmarshal(src, &tests); err != nil {
|
if err = json.Unmarshal(src, &tests); err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
re, err := regexp.Compile(ctx.String(RunFlag.Name))
|
re, err := regexp.Compile(ctx.String(RunFlag.Name))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err)
|
return nil, fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err)
|
||||||
}
|
}
|
||||||
|
tracer := tracerFromFlags(ctx)
|
||||||
|
|
||||||
// Run them in order
|
// Pull out keys to sort and ensure tests are run in order.
|
||||||
var keys []string
|
keys := maps.Keys(tests)
|
||||||
for key := range tests {
|
slices.Sort(keys)
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
// Run all the tests.
|
||||||
sort.Strings(keys)
|
var results []testResult
|
||||||
for _, name := range keys {
|
for _, name := range keys {
|
||||||
if !re.MatchString(name) {
|
if !re.MatchString(name) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
test := tests[name]
|
result := &testResult{Name: name, Pass: true}
|
||||||
if err := test.Run(false, rawdb.HashScheme, false, tracer, func(res error, chain *core.BlockChain) {
|
if err := tests[name].Run(false, rawdb.HashScheme, ctx.Bool(WitnessCrossCheckFlag.Name), tracer, func(res error, chain *core.BlockChain) {
|
||||||
if ctx.Bool(DumpFlag.Name) {
|
if ctx.Bool(DumpFlag.Name) {
|
||||||
if state, _ := chain.State(); state != nil {
|
if s, _ := chain.State(); s != nil {
|
||||||
fmt.Println(string(state.Dump(nil)))
|
result.State = dump(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return fmt.Errorf("test %v: %w", name, err)
|
result.Pass, result.Error = false, err.Error()
|
||||||
}
|
}
|
||||||
|
results = append(results, *result)
|
||||||
}
|
}
|
||||||
return nil
|
return results, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
|
|
||||||
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var compileCommand = &cli.Command{
|
|
||||||
Action: compileCmd,
|
|
||||||
Name: "compile",
|
|
||||||
Usage: "Compiles easm source to evm binary",
|
|
||||||
ArgsUsage: "<file>",
|
|
||||||
}
|
|
||||||
|
|
||||||
func compileCmd(ctx *cli.Context) error {
|
|
||||||
debug := ctx.Bool(DebugFlag.Name)
|
|
||||||
|
|
||||||
if len(ctx.Args().First()) == 0 {
|
|
||||||
return errors.New("filename required")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := ctx.Args().First()
|
|
||||||
src, err := os.ReadFile(fn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
bin, err := compiler.Compile(fn, src, debug)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Println(bin)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/asm"
|
|
||||||
"github.com/urfave/cli/v2"
|
|
||||||
)
|
|
||||||
|
|
||||||
var disasmCommand = &cli.Command{
|
|
||||||
Action: disasmCmd,
|
|
||||||
Name: "disasm",
|
|
||||||
Usage: "Disassembles evm binary",
|
|
||||||
ArgsUsage: "<file>",
|
|
||||||
}
|
|
||||||
|
|
||||||
func disasmCmd(ctx *cli.Context) error {
|
|
||||||
var in string
|
|
||||||
switch {
|
|
||||||
case len(ctx.Args().First()) > 0:
|
|
||||||
fn := ctx.Args().First()
|
|
||||||
input, err := os.ReadFile(fn)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
in = string(input)
|
|
||||||
case ctx.IsSet(InputFlag.Name):
|
|
||||||
in = ctx.String(InputFlag.Name)
|
|
||||||
default:
|
|
||||||
return errors.New("missing filename or --input value")
|
|
||||||
}
|
|
||||||
|
|
||||||
code := strings.TrimSpace(in)
|
|
||||||
fmt.Printf("%v\n", code)
|
|
||||||
return asm.PrintDisassembled(code)
|
|
||||||
}
|
|
||||||
49
cmd/evm/eest.go
Normal file
49
cmd/evm/eest.go
Normal file
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "regexp"
|
||||||
|
|
||||||
|
// testMetadata provides more granular access to the test information encoded
|
||||||
|
// within its filename by the execution spec test (EEST).
|
||||||
|
type testMetadata struct {
|
||||||
|
fork string
|
||||||
|
module string // which python module gnerated the test, e.g. eip7702
|
||||||
|
file string // exact file the test came from, e.g. test_gas.py
|
||||||
|
function string // func that created the test, e.g. test_valid_mcopy_operations
|
||||||
|
parameters string // the name of the parameters which were used to fill the test, e.g. zero_inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseTestMetadata reads a test name and parses out more specific information
|
||||||
|
// about the test.
|
||||||
|
func parseTestMetadata(s string) *testMetadata {
|
||||||
|
var (
|
||||||
|
pattern = `tests\/([^\/]+)\/([^\/]+)\/([^:]+)::([^[]+)\[fork_([^-\]]+)-[^-]+-(.+)\]`
|
||||||
|
re = regexp.MustCompile(pattern)
|
||||||
|
)
|
||||||
|
match := re.FindStringSubmatch(s)
|
||||||
|
if len(match) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &testMetadata{
|
||||||
|
fork: match[5],
|
||||||
|
module: match[2],
|
||||||
|
file: match[3],
|
||||||
|
function: match[4],
|
||||||
|
parameters: match[6],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,13 +31,41 @@ import (
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var jt vm.JumpTable
|
||||||
|
|
||||||
|
const initcode = "INITCODE"
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
jt = vm.NewPragueEOFInstructionSetForTesting()
|
jt = vm.NewPragueEOFInstructionSetForTesting()
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
jt vm.JumpTable
|
hexFlag = &cli.StringFlag{
|
||||||
initcode = "INITCODE"
|
Name: "hex",
|
||||||
|
Usage: "Single container data parse and validation",
|
||||||
|
}
|
||||||
|
refTestFlag = &cli.StringFlag{
|
||||||
|
Name: "test",
|
||||||
|
Usage: "Path to EOF validation reference test.",
|
||||||
|
}
|
||||||
|
eofParseCommand = &cli.Command{
|
||||||
|
Name: "eofparse",
|
||||||
|
Aliases: []string{"eof"},
|
||||||
|
Usage: "Parses hex eof container and returns validation errors (if any)",
|
||||||
|
Action: eofParseAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
hexFlag,
|
||||||
|
refTestFlag,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
eofDumpCommand = &cli.Command{
|
||||||
|
Name: "eofdump",
|
||||||
|
Usage: "Parses hex eof container and prints out human-readable representation of the container.",
|
||||||
|
Action: eofDumpAction,
|
||||||
|
Flags: []cli.Flag{
|
||||||
|
hexFlag,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func eofParseAction(ctx *cli.Context) error {
|
func eofParseAction(ctx *cli.Context) error {
|
||||||
|
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
// Copyright 2017 The go-ethereum Authors
|
|
||||||
// This file is part of go-ethereum.
|
|
||||||
//
|
|
||||||
// go-ethereum is free software: you can redistribute it and/or modify
|
|
||||||
// it under the terms of the GNU General Public License as published by
|
|
||||||
// the Free Software Foundation, either version 3 of the License, or
|
|
||||||
// (at your option) any later version.
|
|
||||||
//
|
|
||||||
// go-ethereum is distributed in the hope that it will be useful,
|
|
||||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
// GNU General Public License for more details.
|
|
||||||
//
|
|
||||||
// You should have received a copy of the GNU General Public License
|
|
||||||
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
package compiler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/core/asm"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Compile(fn string, src []byte, debug bool) (string, error) {
|
|
||||||
compiler := asm.NewCompiler(debug)
|
|
||||||
compiler.Feed(asm.Lex(src, debug))
|
|
||||||
|
|
||||||
bin, compileErrors := compiler.Compile()
|
|
||||||
if len(compileErrors) > 0 {
|
|
||||||
// report errors
|
|
||||||
for _, err := range compileErrors {
|
|
||||||
fmt.Printf("%s:%v\n", fn, err)
|
|
||||||
}
|
|
||||||
return "", errors.New("compiling failed")
|
|
||||||
}
|
|
||||||
return bin, nil
|
|
||||||
}
|
|
||||||
|
|
@ -253,16 +253,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
statedb.SetTxContext(tx.Hash(), txIndex)
|
statedb.SetTxContext(tx.Hash(), txIndex)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
txContext = core.NewEVMTxContext(msg)
|
snapshot = statedb.Snapshot()
|
||||||
snapshot = statedb.Snapshot()
|
prevGas = gaspool.Gas()
|
||||||
prevGas = gaspool.Gas()
|
|
||||||
)
|
)
|
||||||
if tracer != nil && tracer.OnTxStart != nil {
|
if tracer != nil && tracer.OnTxStart != nil {
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
}
|
}
|
||||||
// (ret []byte, usedGas uint64, failed bool, err error)
|
// (ret []byte, usedGas uint64, failed bool, err error)
|
||||||
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statedb.RevertToSnapshot(snapshot)
|
statedb.RevertToSnapshot(snapshot)
|
||||||
|
|
@ -366,21 +363,19 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
// Gather the execution-layer triggered requests.
|
// Gather the execution-layer triggered requests.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
|
if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) {
|
||||||
// EIP-6110 deposits
|
requests = [][]byte{}
|
||||||
|
// EIP-6110
|
||||||
var allLogs []*types.Log
|
var allLogs []*types.Log
|
||||||
for _, receipt := range receipts {
|
for _, receipt := range receipts {
|
||||||
allLogs = append(allLogs, receipt.Logs...)
|
allLogs = append(allLogs, receipt.Logs...)
|
||||||
}
|
}
|
||||||
depositRequests, err := core.ParseDepositLogs(allLogs, chainConfig)
|
if err := core.ParseDepositLogs(&requests, allLogs, chainConfig); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err))
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
// EIP-7002
|
||||||
|
core.ProcessWithdrawalQueue(&requests, evm)
|
||||||
// EIP-7002 withdrawals
|
// EIP-7251
|
||||||
requests = append(requests, core.ProcessWithdrawalQueue(evm))
|
core.ProcessConsolidationQueue(&requests, evm)
|
||||||
// EIP-7251 consolidations
|
|
||||||
requests = append(requests, core.ProcessConsolidationQueue(evm))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Commit block
|
// Commit block
|
||||||
|
|
|
||||||
298
cmd/evm/main.go
298
cmd/evm/main.go
|
|
@ -19,11 +19,14 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"io/fs"
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"path/filepath"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
|
"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
"github.com/ethereum/go-ethereum/internal/debug"
|
"github.com/ethereum/go-ethereum/internal/debug"
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
@ -33,122 +36,100 @@ import (
|
||||||
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
|
_ "github.com/ethereum/go-ethereum/eth/tracers/native"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Some other nice-to-haves:
|
||||||
|
// * accumulate traces into an object to bundle with test
|
||||||
|
// * write tx identifier for trace before hand (blocktest only)
|
||||||
|
// * combine blocktest and statetest runner logic using unified test interface
|
||||||
|
|
||||||
|
const traceCategory = "TRACING"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
DebugFlag = &cli.BoolFlag{
|
// Test running flags.
|
||||||
Name: "debug",
|
RunFlag = &cli.StringFlag{
|
||||||
Usage: "output full trace logs",
|
Name: "run",
|
||||||
Category: flags.VMCategory,
|
Value: ".*",
|
||||||
}
|
Usage: "Run only those tests matching the regular expression.",
|
||||||
StatDumpFlag = &cli.BoolFlag{
|
|
||||||
Name: "statdump",
|
|
||||||
Usage: "displays stack and heap memory information",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
CodeFlag = &cli.StringFlag{
|
|
||||||
Name: "code",
|
|
||||||
Usage: "EVM code",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
CodeFileFlag = &cli.StringFlag{
|
|
||||||
Name: "codefile",
|
|
||||||
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
GasFlag = &cli.Uint64Flag{
|
|
||||||
Name: "gas",
|
|
||||||
Usage: "gas limit for the evm",
|
|
||||||
Value: 10000000000,
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
PriceFlag = &flags.BigFlag{
|
|
||||||
Name: "price",
|
|
||||||
Usage: "price set for the evm",
|
|
||||||
Value: new(big.Int),
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
ValueFlag = &flags.BigFlag{
|
|
||||||
Name: "value",
|
|
||||||
Usage: "value set for the evm",
|
|
||||||
Value: new(big.Int),
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
DumpFlag = &cli.BoolFlag{
|
|
||||||
Name: "dump",
|
|
||||||
Usage: "dumps the state after the run",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
InputFlag = &cli.StringFlag{
|
|
||||||
Name: "input",
|
|
||||||
Usage: "input for the EVM",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
InputFileFlag = &cli.StringFlag{
|
|
||||||
Name: "inputfile",
|
|
||||||
Usage: "file containing input for the EVM",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
}
|
||||||
BenchFlag = &cli.BoolFlag{
|
BenchFlag = &cli.BoolFlag{
|
||||||
Name: "bench",
|
Name: "bench",
|
||||||
Usage: "benchmark the execution",
|
Usage: "benchmark the execution",
|
||||||
Category: flags.VMCategory,
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
CreateFlag = &cli.BoolFlag{
|
WitnessCrossCheckFlag = &cli.BoolFlag{
|
||||||
Name: "create",
|
Name: "cross-check",
|
||||||
Usage: "indicates the action should be create rather than call",
|
Aliases: []string{"xc"},
|
||||||
Category: flags.VMCategory,
|
Usage: "Cross-check stateful execution against stateless, verifying the witness generation.",
|
||||||
}
|
}
|
||||||
GenesisFlag = &cli.StringFlag{
|
|
||||||
Name: "prestate",
|
// Debugging flags.
|
||||||
Usage: "JSON file with prestate (genesis) config",
|
DumpFlag = &cli.BoolFlag{
|
||||||
Category: flags.VMCategory,
|
Name: "dump",
|
||||||
|
Usage: "dumps the state after the run",
|
||||||
|
}
|
||||||
|
HumanReadableFlag = &cli.BoolFlag{
|
||||||
|
Name: "human",
|
||||||
|
Usage: "\"Human-readable\" output",
|
||||||
|
}
|
||||||
|
StatDumpFlag = &cli.BoolFlag{
|
||||||
|
Name: "statdump",
|
||||||
|
Usage: "displays stack and heap memory information",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tracing flags.
|
||||||
|
TraceFlag = &cli.BoolFlag{
|
||||||
|
Name: "trace",
|
||||||
|
Usage: "Enable tracing and output trace log.",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
TraceFormatFlag = &cli.StringFlag{
|
||||||
|
Name: "trace.format",
|
||||||
|
Usage: "Trace output format to use (struct|json)",
|
||||||
|
Value: "struct",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
TraceDisableMemoryFlag = &cli.BoolFlag{
|
||||||
|
Name: "trace.nomemory",
|
||||||
|
Aliases: []string{"nomemory"},
|
||||||
|
Value: true,
|
||||||
|
Usage: "disable memory output",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
TraceDisableStackFlag = &cli.BoolFlag{
|
||||||
|
Name: "trace.nostack",
|
||||||
|
Aliases: []string{"nostack"},
|
||||||
|
Usage: "disable stack output",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
TraceDisableStorageFlag = &cli.BoolFlag{
|
||||||
|
Name: "trace.nostorage",
|
||||||
|
Aliases: []string{"nostorage"},
|
||||||
|
Usage: "disable storage output",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
TraceDisableReturnDataFlag = &cli.BoolFlag{
|
||||||
|
Name: "trace.noreturndata",
|
||||||
|
Aliases: []string{"noreturndata"},
|
||||||
|
Value: true,
|
||||||
|
Usage: "enable return data output",
|
||||||
|
Category: traceCategory,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated flags.
|
||||||
|
DebugFlag = &cli.BoolFlag{
|
||||||
|
Name: "debug",
|
||||||
|
Usage: "output full trace logs (deprecated)",
|
||||||
|
Hidden: true,
|
||||||
|
Category: traceCategory,
|
||||||
}
|
}
|
||||||
MachineFlag = &cli.BoolFlag{
|
MachineFlag = &cli.BoolFlag{
|
||||||
Name: "json",
|
Name: "json",
|
||||||
Usage: "output trace logs in machine readable format (json)",
|
Usage: "output trace logs in machine readable format, json (deprecated)",
|
||||||
Category: flags.VMCategory,
|
Hidden: true,
|
||||||
}
|
Category: traceCategory,
|
||||||
SenderFlag = &cli.StringFlag{
|
|
||||||
Name: "sender",
|
|
||||||
Usage: "The transaction origin",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
ReceiverFlag = &cli.StringFlag{
|
|
||||||
Name: "receiver",
|
|
||||||
Usage: "The transaction receiver (execution context)",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
DisableMemoryFlag = &cli.BoolFlag{
|
|
||||||
Name: "nomemory",
|
|
||||||
Value: true,
|
|
||||||
Usage: "disable memory output",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
DisableStackFlag = &cli.BoolFlag{
|
|
||||||
Name: "nostack",
|
|
||||||
Usage: "disable stack output",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
DisableStorageFlag = &cli.BoolFlag{
|
|
||||||
Name: "nostorage",
|
|
||||||
Usage: "disable storage output",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
DisableReturnDataFlag = &cli.BoolFlag{
|
|
||||||
Name: "noreturndata",
|
|
||||||
Value: true,
|
|
||||||
Usage: "enable return data output",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
refTestFlag = &cli.StringFlag{
|
|
||||||
Name: "test",
|
|
||||||
Usage: "Path to EOF validation reference test.",
|
|
||||||
}
|
|
||||||
hexFlag = &cli.StringFlag{
|
|
||||||
Name: "hex",
|
|
||||||
Usage: "single container data parse and validation",
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Command definitions.
|
||||||
var (
|
var (
|
||||||
stateTransitionCommand = &cli.Command{
|
stateTransitionCommand = &cli.Command{
|
||||||
Name: "transition",
|
Name: "transition",
|
||||||
|
|
@ -175,7 +156,6 @@ var (
|
||||||
t8ntool.RewardFlag,
|
t8ntool.RewardFlag,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
transactionCommand = &cli.Command{
|
transactionCommand = &cli.Command{
|
||||||
Name: "transaction",
|
Name: "transaction",
|
||||||
Aliases: []string{"t9n"},
|
Aliases: []string{"t9n"},
|
||||||
|
|
@ -203,62 +183,27 @@ var (
|
||||||
t8ntool.SealCliqueFlag,
|
t8ntool.SealCliqueFlag,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
eofParseCommand = &cli.Command{
|
|
||||||
Name: "eofparse",
|
|
||||||
Aliases: []string{"eof"},
|
|
||||||
Usage: "Parses hex eof container and returns validation errors (if any)",
|
|
||||||
Action: eofParseAction,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
hexFlag,
|
|
||||||
refTestFlag,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
eofDumpCommand = &cli.Command{
|
|
||||||
Name: "eofdump",
|
|
||||||
Usage: "Parses hex eof container and prints out human-readable representation of the container.",
|
|
||||||
Action: eofDumpAction,
|
|
||||||
Flags: []cli.Flag{
|
|
||||||
hexFlag,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// vmFlags contains flags related to running the EVM.
|
|
||||||
var vmFlags = []cli.Flag{
|
|
||||||
CodeFlag,
|
|
||||||
CodeFileFlag,
|
|
||||||
CreateFlag,
|
|
||||||
GasFlag,
|
|
||||||
PriceFlag,
|
|
||||||
ValueFlag,
|
|
||||||
InputFlag,
|
|
||||||
InputFileFlag,
|
|
||||||
GenesisFlag,
|
|
||||||
SenderFlag,
|
|
||||||
ReceiverFlag,
|
|
||||||
}
|
|
||||||
|
|
||||||
// traceFlags contains flags that configure tracing output.
|
// traceFlags contains flags that configure tracing output.
|
||||||
var traceFlags = []cli.Flag{
|
var traceFlags = []cli.Flag{
|
||||||
BenchFlag,
|
TraceFlag,
|
||||||
|
TraceFormatFlag,
|
||||||
|
TraceDisableStackFlag,
|
||||||
|
TraceDisableMemoryFlag,
|
||||||
|
TraceDisableStorageFlag,
|
||||||
|
TraceDisableReturnDataFlag,
|
||||||
|
|
||||||
|
// deprecated
|
||||||
DebugFlag,
|
DebugFlag,
|
||||||
DumpFlag,
|
|
||||||
MachineFlag,
|
MachineFlag,
|
||||||
StatDumpFlag,
|
|
||||||
DisableMemoryFlag,
|
|
||||||
DisableStackFlag,
|
|
||||||
DisableStorageFlag,
|
|
||||||
DisableReturnDataFlag,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var app = flags.NewApp("the evm command line interface")
|
var app = flags.NewApp("the evm command line interface")
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
app.Flags = slices.Concat(vmFlags, traceFlags, debug.Flags)
|
app.Flags = debug.Flags
|
||||||
app.Commands = []*cli.Command{
|
app.Commands = []*cli.Command{
|
||||||
compileCommand,
|
|
||||||
disasmCommand,
|
|
||||||
runCommand,
|
runCommand,
|
||||||
blockTestCommand,
|
blockTestCommand,
|
||||||
stateTestCommand,
|
stateTestCommand,
|
||||||
|
|
@ -280,11 +225,56 @@ func init() {
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if err := app.Run(os.Args); err != nil {
|
if err := app.Run(os.Args); err != nil {
|
||||||
code := 1
|
|
||||||
if ec, ok := err.(*t8ntool.NumberedError); ok {
|
|
||||||
code = ec.ExitCode()
|
|
||||||
}
|
|
||||||
fmt.Fprintln(os.Stderr, err)
|
fmt.Fprintln(os.Stderr, err)
|
||||||
os.Exit(code)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// tracerFromFlags parses the cli flags and returns the specified tracer.
|
||||||
|
func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
|
||||||
|
config := &logger.Config{
|
||||||
|
EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name),
|
||||||
|
DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
|
||||||
|
DisableStorage: ctx.Bool(TraceDisableStorageFlag.Name),
|
||||||
|
EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name),
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "struct":
|
||||||
|
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
|
||||||
|
case ctx.Bool(TraceFlag.Name) && ctx.String(TraceFormatFlag.Name) == "json":
|
||||||
|
return logger.NewJSONLogger(config, os.Stderr)
|
||||||
|
case ctx.Bool(MachineFlag.Name):
|
||||||
|
return logger.NewJSONLogger(config, os.Stderr)
|
||||||
|
case ctx.Bool(DebugFlag.Name):
|
||||||
|
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
|
||||||
|
default:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collectJSONFiles walks the given path and accumulates all files with json
|
||||||
|
// extension.
|
||||||
|
func collectJSONFiles(path string) []string {
|
||||||
|
var out []string
|
||||||
|
err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if !info.IsDir() && filepath.Ext(info.Name()) == ".json" {
|
||||||
|
out = append(out, path)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, err)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// dump returns a state dump for the most current trie.
|
||||||
|
func dump(s *state.StateDB) *state.Dump {
|
||||||
|
root := s.IntermediateRoot(false)
|
||||||
|
cpy, _ := state.New(root, s.Database())
|
||||||
|
dump := cpy.RawDump(nil)
|
||||||
|
return &dump
|
||||||
|
}
|
||||||
|
|
|
||||||
87
cmd/evm/reporter.go
Normal file
87
cmd/evm/reporter.go
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
// Copyright 2024 The go-ethereum Authors
|
||||||
|
// This file is part of go-ethereum.
|
||||||
|
//
|
||||||
|
// go-ethereum is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// go-ethereum is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/urfave/cli/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PASS = "\033[32mPASS\033[0m"
|
||||||
|
FAIL = "\033[31mFAIL\033[0m"
|
||||||
|
)
|
||||||
|
|
||||||
|
// testResult contains the execution status after running a state test, any
|
||||||
|
// error that might have occurred and a dump of the final state if requested.
|
||||||
|
type testResult struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Pass bool `json:"pass"`
|
||||||
|
Root *common.Hash `json:"stateRoot,omitempty"`
|
||||||
|
Fork string `json:"fork"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
State *state.Dump `json:"state,omitempty"`
|
||||||
|
Stats *execStats `json:"benchStats,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r testResult) String() string {
|
||||||
|
var status string
|
||||||
|
if r.Pass {
|
||||||
|
status = fmt.Sprintf("[%s]", PASS)
|
||||||
|
} else {
|
||||||
|
status = fmt.Sprintf("[%s]", FAIL)
|
||||||
|
}
|
||||||
|
info := r.Name
|
||||||
|
m := parseTestMetadata(r.Name)
|
||||||
|
if m != nil {
|
||||||
|
info = fmt.Sprintf("%s %s, param=%s", m.module, m.function, m.parameters)
|
||||||
|
}
|
||||||
|
var extra string
|
||||||
|
if !r.Pass {
|
||||||
|
extra = fmt.Sprintf(", err=%v, fork=%s", r.Error, r.Fork)
|
||||||
|
}
|
||||||
|
out := fmt.Sprintf("%s %s%s", status, info, extra)
|
||||||
|
if r.State != nil {
|
||||||
|
state, _ := json.MarshalIndent(r.State, "", " ")
|
||||||
|
out += "\n" + string(state)
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// report prints the after-test summary.
|
||||||
|
func report(ctx *cli.Context, results []testResult) {
|
||||||
|
if ctx.Bool(HumanReadableFlag.Name) {
|
||||||
|
pass := 0
|
||||||
|
for _, r := range results {
|
||||||
|
if r.Pass {
|
||||||
|
pass++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, r := range results {
|
||||||
|
fmt.Println(r)
|
||||||
|
}
|
||||||
|
fmt.Println("--")
|
||||||
|
fmt.Printf("%d tests passed, %d tests failed.\n", pass, len(results)-pass)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
out, _ := json.MarshalIndent(results, "", " ")
|
||||||
|
fmt.Println(string(out))
|
||||||
|
}
|
||||||
|
|
@ -18,6 +18,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
@ -25,16 +26,17 @@ import (
|
||||||
"os"
|
"os"
|
||||||
goruntime "runtime"
|
goruntime "runtime"
|
||||||
"slices"
|
"slices"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/evm/internal/compiler"
|
|
||||||
"github.com/ethereum/go-ethereum/cmd/utils"
|
"github.com/ethereum/go-ethereum/cmd/utils"
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
"github.com/ethereum/go-ethereum/core/vm/runtime"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
||||||
|
|
@ -51,14 +53,82 @@ var runCommand = &cli.Command{
|
||||||
Usage: "Run arbitrary evm binary",
|
Usage: "Run arbitrary evm binary",
|
||||||
ArgsUsage: "<code>",
|
ArgsUsage: "<code>",
|
||||||
Description: `The run command runs arbitrary EVM code.`,
|
Description: `The run command runs arbitrary EVM code.`,
|
||||||
Flags: slices.Concat(vmFlags, traceFlags),
|
Flags: slices.Concat([]cli.Flag{
|
||||||
|
BenchFlag,
|
||||||
|
CodeFileFlag,
|
||||||
|
CreateFlag,
|
||||||
|
GasFlag,
|
||||||
|
GenesisFlag,
|
||||||
|
InputFlag,
|
||||||
|
InputFileFlag,
|
||||||
|
PriceFlag,
|
||||||
|
ReceiverFlag,
|
||||||
|
SenderFlag,
|
||||||
|
ValueFlag,
|
||||||
|
StatDumpFlag,
|
||||||
|
}, traceFlags),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
CodeFileFlag = &cli.StringFlag{
|
||||||
|
Name: "codefile",
|
||||||
|
Usage: "File containing EVM code. If '-' is specified, code is read from stdin ",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
CreateFlag = &cli.BoolFlag{
|
||||||
|
Name: "create",
|
||||||
|
Usage: "Indicates the action should be create rather than call",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
GasFlag = &cli.Uint64Flag{
|
||||||
|
Name: "gas",
|
||||||
|
Usage: "Gas limit for the evm",
|
||||||
|
Value: 10000000000,
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
GenesisFlag = &cli.StringFlag{
|
||||||
|
Name: "prestate",
|
||||||
|
Usage: "JSON file with prestate (genesis) config",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
InputFlag = &cli.StringFlag{
|
||||||
|
Name: "input",
|
||||||
|
Usage: "Input for the EVM",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
InputFileFlag = &cli.StringFlag{
|
||||||
|
Name: "inputfile",
|
||||||
|
Usage: "File containing input for the EVM",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
PriceFlag = &flags.BigFlag{
|
||||||
|
Name: "price",
|
||||||
|
Usage: "Price set for the evm",
|
||||||
|
Value: new(big.Int),
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
ReceiverFlag = &cli.StringFlag{
|
||||||
|
Name: "receiver",
|
||||||
|
Usage: "The transaction receiver (execution context)",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
SenderFlag = &cli.StringFlag{
|
||||||
|
Name: "sender",
|
||||||
|
Usage: "The transaction origin",
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
ValueFlag = &flags.BigFlag{
|
||||||
|
Name: "value",
|
||||||
|
Usage: "Value set for the evm",
|
||||||
|
Value: new(big.Int),
|
||||||
|
Category: flags.VMCategory,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// readGenesis will read the given JSON format genesis file and return
|
// readGenesis will read the given JSON format genesis file and return
|
||||||
// the initialized Genesis structure
|
// the initialized Genesis structure
|
||||||
func readGenesis(genesisPath string) *core.Genesis {
|
func readGenesis(genesisPath string) *core.Genesis {
|
||||||
// Make sure we have a valid genesis JSON
|
// Make sure we have a valid genesis JSON
|
||||||
//genesisPath := ctx.Args().First()
|
|
||||||
if len(genesisPath) == 0 {
|
if len(genesisPath) == 0 {
|
||||||
utils.Fatalf("Must supply path to genesis JSON file")
|
utils.Fatalf("Must supply path to genesis JSON file")
|
||||||
}
|
}
|
||||||
|
|
@ -128,16 +198,15 @@ func timedExec(bench bool, execFunc func() ([]byte, uint64, error)) ([]byte, exe
|
||||||
|
|
||||||
func runCmd(ctx *cli.Context) error {
|
func runCmd(ctx *cli.Context) error {
|
||||||
logconfig := &logger.Config{
|
logconfig := &logger.Config{
|
||||||
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
EnableMemory: !ctx.Bool(TraceDisableMemoryFlag.Name),
|
||||||
DisableStack: ctx.Bool(DisableStackFlag.Name),
|
DisableStack: ctx.Bool(TraceDisableStackFlag.Name),
|
||||||
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
|
DisableStorage: ctx.Bool(TraceDisableStorageFlag.Name),
|
||||||
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
|
EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name),
|
||||||
Debug: ctx.Bool(DebugFlag.Name),
|
Debug: ctx.Bool(DebugFlag.Name),
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
tracer *tracing.Hooks
|
tracer *tracing.Hooks
|
||||||
debugLogger *logger.StructLogger
|
|
||||||
prestate *state.StateDB
|
prestate *state.StateDB
|
||||||
chainConfig *params.ChainConfig
|
chainConfig *params.ChainConfig
|
||||||
sender = common.BytesToAddress([]byte("sender"))
|
sender = common.BytesToAddress([]byte("sender"))
|
||||||
|
|
@ -149,10 +218,7 @@ func runCmd(ctx *cli.Context) error {
|
||||||
if ctx.Bool(MachineFlag.Name) {
|
if ctx.Bool(MachineFlag.Name) {
|
||||||
tracer = logger.NewJSONLogger(logconfig, os.Stdout)
|
tracer = logger.NewJSONLogger(logconfig, os.Stdout)
|
||||||
} else if ctx.Bool(DebugFlag.Name) {
|
} else if ctx.Bool(DebugFlag.Name) {
|
||||||
debugLogger = logger.NewStructLogger(logconfig)
|
tracer = logger.NewStreamingStructLogger(logconfig, os.Stderr).Hooks()
|
||||||
tracer = debugLogger.Hooks()
|
|
||||||
} else {
|
|
||||||
debugLogger = logger.NewStructLogger(logconfig)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initialGas := ctx.Uint64(GasFlag.Name)
|
initialGas := ctx.Uint64(GasFlag.Name)
|
||||||
|
|
@ -188,48 +254,35 @@ func runCmd(ctx *cli.Context) error {
|
||||||
|
|
||||||
var code []byte
|
var code []byte
|
||||||
codeFileFlag := ctx.String(CodeFileFlag.Name)
|
codeFileFlag := ctx.String(CodeFileFlag.Name)
|
||||||
codeFlag := ctx.String(CodeFlag.Name)
|
hexcode := ctx.Args().First()
|
||||||
|
|
||||||
// The '--code' or '--codefile' flag overrides code in state
|
// The '--codefile' flag overrides code in state
|
||||||
if codeFileFlag != "" || codeFlag != "" {
|
if codeFileFlag == "-" {
|
||||||
var hexcode []byte
|
// If - is specified, it means that code comes from stdin
|
||||||
if codeFileFlag != "" {
|
// Try reading from stdin
|
||||||
var err error
|
input, err := io.ReadAll(os.Stdin)
|
||||||
// If - is specified, it means that code comes from stdin
|
if err != nil {
|
||||||
if codeFileFlag == "-" {
|
fmt.Printf("Could not load code from stdin: %v\n", err)
|
||||||
//Try reading from stdin
|
|
||||||
if hexcode, err = io.ReadAll(os.Stdin); err != nil {
|
|
||||||
fmt.Printf("Could not load code from stdin: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Codefile with hex assembly
|
|
||||||
if hexcode, err = os.ReadFile(codeFileFlag); err != nil {
|
|
||||||
fmt.Printf("Could not load code from file: %v\n", err)
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
hexcode = []byte(codeFlag)
|
|
||||||
}
|
|
||||||
hexcode = bytes.TrimSpace(hexcode)
|
|
||||||
if len(hexcode)%2 != 0 {
|
|
||||||
fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode))
|
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
code = common.FromHex(string(hexcode))
|
hexcode = string(input)
|
||||||
} else if fn := ctx.Args().First(); len(fn) > 0 {
|
} else if codeFileFlag != "" {
|
||||||
// EASM-file to compile
|
// Codefile with hex assembly
|
||||||
src, err := os.ReadFile(fn)
|
input, err := os.ReadFile(codeFileFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
fmt.Printf("Could not load code from file: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
bin, err := compiler.Compile(fn, src, false)
|
hexcode = string(input)
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
code = common.Hex2Bytes(bin)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hexcode = strings.TrimSpace(hexcode)
|
||||||
|
if len(hexcode)%2 != 0 {
|
||||||
|
fmt.Printf("Invalid input length for hex data (%d)\n", len(hexcode))
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
code = common.FromHex(hexcode)
|
||||||
|
|
||||||
runtimeConfig := runtime.Config{
|
runtimeConfig := runtime.Config{
|
||||||
Origin: sender,
|
Origin: sender,
|
||||||
State: prestate,
|
State: prestate,
|
||||||
|
|
@ -310,12 +363,10 @@ func runCmd(ctx *cli.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.Bool(DebugFlag.Name) {
|
if ctx.Bool(DebugFlag.Name) {
|
||||||
if debugLogger != nil {
|
if logs := runtimeConfig.State.Logs(); len(logs) > 0 {
|
||||||
fmt.Fprintln(os.Stderr, "#### TRACE ####")
|
fmt.Fprintln(os.Stderr, "### LOGS")
|
||||||
logger.WriteTrace(os.Stderr, debugLogger.StructLogs())
|
writeLogs(os.Stderr, logs)
|
||||||
}
|
}
|
||||||
fmt.Fprintln(os.Stderr, "#### LOGS ####")
|
|
||||||
logger.WriteLogs(os.Stderr, runtimeConfig.State.Logs())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if bench || ctx.Bool(StatDumpFlag.Name) {
|
if bench || ctx.Bool(StatDumpFlag.Name) {
|
||||||
|
|
@ -334,3 +385,16 @@ allocated bytes: %d
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeLogs writes vm logs in a readable format to the given writer
|
||||||
|
func writeLogs(writer io.Writer, logs []*types.Log) {
|
||||||
|
for _, log := range logs {
|
||||||
|
fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex)
|
||||||
|
|
||||||
|
for i, topic := range log.Topics {
|
||||||
|
fmt.Fprintf(writer, "%08d %x\n", i, topic)
|
||||||
|
}
|
||||||
|
fmt.Fprint(writer, hex.Dump(log.Data))
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,12 +21,12 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
|
"slices"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/tracers/logger"
|
|
||||||
"github.com/ethereum/go-ethereum/internal/flags"
|
"github.com/ethereum/go-ethereum/internal/flags"
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
"github.com/urfave/cli/v2"
|
"github.com/urfave/cli/v2"
|
||||||
|
|
@ -35,157 +35,124 @@ import (
|
||||||
var (
|
var (
|
||||||
forkFlag = &cli.StringFlag{
|
forkFlag = &cli.StringFlag{
|
||||||
Name: "statetest.fork",
|
Name: "statetest.fork",
|
||||||
Usage: "The hard-fork to run the test against",
|
Usage: "Only run tests for the specified fork.",
|
||||||
Category: flags.VMCategory,
|
Category: flags.VMCategory,
|
||||||
}
|
}
|
||||||
idxFlag = &cli.IntFlag{
|
idxFlag = &cli.IntFlag{
|
||||||
Name: "statetest.index",
|
Name: "statetest.index",
|
||||||
Usage: "The index of the subtest to run",
|
Usage: "The index of the subtest to run.",
|
||||||
Category: flags.VMCategory,
|
Category: flags.VMCategory,
|
||||||
Value: -1, // default to select all subtest indices
|
Value: -1, // default to select all subtest indices
|
||||||
}
|
}
|
||||||
testNameFlag = &cli.StringFlag{
|
|
||||||
Name: "statetest.name",
|
|
||||||
Usage: "The name of the state test to run",
|
|
||||||
Category: flags.VMCategory,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
var stateTestCommand = &cli.Command{
|
var stateTestCommand = &cli.Command{
|
||||||
Action: stateTestCmd,
|
Action: stateTestCmd,
|
||||||
Name: "statetest",
|
Name: "statetest",
|
||||||
Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
|
Usage: "Executes the given state tests. Filenames can be fed via standard input (batch mode) or as an argument (one-off execution).",
|
||||||
ArgsUsage: "<file>",
|
ArgsUsage: "<file>",
|
||||||
Flags: []cli.Flag{
|
Flags: slices.Concat([]cli.Flag{
|
||||||
forkFlag,
|
DumpFlag,
|
||||||
idxFlag,
|
HumanReadableFlag,
|
||||||
testNameFlag,
|
RunFlag,
|
||||||
},
|
}, traceFlags),
|
||||||
}
|
|
||||||
|
|
||||||
// StatetestResult contains the execution status after running a state test, any
|
|
||||||
// error that might have occurred and a dump of the final state if requested.
|
|
||||||
type StatetestResult struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Pass bool `json:"pass"`
|
|
||||||
Root *common.Hash `json:"stateRoot,omitempty"`
|
|
||||||
Fork string `json:"fork"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
State *state.Dump `json:"state,omitempty"`
|
|
||||||
BenchStats *execStats `json:"benchStats,omitempty"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stateTestCmd(ctx *cli.Context) error {
|
func stateTestCmd(ctx *cli.Context) error {
|
||||||
// Configure the EVM logger
|
path := ctx.Args().First()
|
||||||
config := &logger.Config{
|
|
||||||
EnableMemory: !ctx.Bool(DisableMemoryFlag.Name),
|
|
||||||
DisableStack: ctx.Bool(DisableStackFlag.Name),
|
|
||||||
DisableStorage: ctx.Bool(DisableStorageFlag.Name),
|
|
||||||
EnableReturnData: !ctx.Bool(DisableReturnDataFlag.Name),
|
|
||||||
}
|
|
||||||
var cfg vm.Config
|
|
||||||
switch {
|
|
||||||
case ctx.Bool(MachineFlag.Name):
|
|
||||||
cfg.Tracer = logger.NewJSONLogger(config, os.Stderr)
|
|
||||||
|
|
||||||
case ctx.Bool(DebugFlag.Name):
|
// If path is provided, run the tests at that path.
|
||||||
cfg.Tracer = logger.NewStructLogger(config).Hooks()
|
if len(path) != 0 {
|
||||||
|
var (
|
||||||
|
collected = collectJSONFiles(path)
|
||||||
|
results []testResult
|
||||||
|
)
|
||||||
|
for _, fname := range collected {
|
||||||
|
r, err := runStateTest(ctx, fname)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
results = append(results, r...)
|
||||||
|
}
|
||||||
|
report(ctx, results)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
// Load the test content from the input file
|
// Otherwise, read filenames from stdin and execute back-to-back.
|
||||||
if len(ctx.Args().First()) != 0 {
|
|
||||||
return runStateTest(ctx, ctx.Args().First(), cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name))
|
|
||||||
}
|
|
||||||
// Read filenames from stdin and execute back-to-back
|
|
||||||
scanner := bufio.NewScanner(os.Stdin)
|
scanner := bufio.NewScanner(os.Stdin)
|
||||||
for scanner.Scan() {
|
for scanner.Scan() {
|
||||||
fname := scanner.Text()
|
fname := scanner.Text()
|
||||||
if len(fname) == 0 {
|
if len(fname) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if err := runStateTest(ctx, fname, cfg, ctx.Bool(DumpFlag.Name), ctx.Bool(BenchFlag.Name)); err != nil {
|
results, err := runStateTest(ctx, fname)
|
||||||
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
report(ctx, results)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type stateTestCase struct {
|
|
||||||
name string
|
|
||||||
test tests.StateTest
|
|
||||||
st tests.StateSubtest
|
|
||||||
}
|
|
||||||
|
|
||||||
// collectMatchedSubtests returns test cases which match against provided filtering CLI parameters
|
|
||||||
func collectMatchedSubtests(ctx *cli.Context, testsByName map[string]tests.StateTest) []stateTestCase {
|
|
||||||
var res []stateTestCase
|
|
||||||
subtestName := ctx.String(testNameFlag.Name)
|
|
||||||
if subtestName != "" {
|
|
||||||
if subtest, ok := testsByName[subtestName]; ok {
|
|
||||||
testsByName := make(map[string]tests.StateTest)
|
|
||||||
testsByName[subtestName] = subtest
|
|
||||||
}
|
|
||||||
}
|
|
||||||
idx := ctx.Int(idxFlag.Name)
|
|
||||||
fork := ctx.String(forkFlag.Name)
|
|
||||||
|
|
||||||
for key, test := range testsByName {
|
|
||||||
for _, st := range test.Subtests() {
|
|
||||||
if idx != -1 && st.Index != idx {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if fork != "" && st.Fork != fork {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
res = append(res, stateTestCase{name: key, st: st, test: test})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
|
||||||
|
|
||||||
// runStateTest loads the state-test given by fname, and executes the test.
|
// runStateTest loads the state-test given by fname, and executes the test.
|
||||||
func runStateTest(ctx *cli.Context, fname string, cfg vm.Config, dump bool, bench bool) error {
|
func runStateTest(ctx *cli.Context, fname string) ([]testResult, error) {
|
||||||
src, err := os.ReadFile(fname)
|
src, err := os.ReadFile(fname)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return nil, err
|
||||||
}
|
}
|
||||||
var testsByName map[string]tests.StateTest
|
var testsByName map[string]tests.StateTest
|
||||||
if err := json.Unmarshal(src, &testsByName); err != nil {
|
if err := json.Unmarshal(src, &testsByName); err != nil {
|
||||||
return err
|
return nil, fmt.Errorf("unable to read test file %s: %w", fname, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
matchingTests := collectMatchedSubtests(ctx, testsByName)
|
cfg := vm.Config{Tracer: tracerFromFlags(ctx)}
|
||||||
|
re, err := regexp.Compile(ctx.String(RunFlag.Name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("invalid regex -%s: %v", RunFlag.Name, err)
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate over all the tests, run them and aggregate the results
|
// Iterate over all the tests, run them and aggregate the results
|
||||||
var results []StatetestResult
|
results := make([]testResult, 0, len(testsByName))
|
||||||
for _, test := range matchingTests {
|
for key, test := range testsByName {
|
||||||
// Run the test and aggregate the result
|
if !re.MatchString(key) {
|
||||||
result := &StatetestResult{Name: test.name, Fork: test.st.Fork, Pass: true}
|
continue
|
||||||
test.test.Run(test.st, cfg, false, rawdb.HashScheme, func(err error, tstate *tests.StateTestState) {
|
}
|
||||||
var root common.Hash
|
for i, st := range test.Subtests() {
|
||||||
if tstate.StateDB != nil {
|
if idx := ctx.Int(idxFlag.Name); idx != -1 && idx != i {
|
||||||
root = tstate.StateDB.IntermediateRoot(false)
|
// If specific index requested, skip all tests that do not match.
|
||||||
result.Root = &root
|
continue
|
||||||
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
}
|
||||||
if dump { // Dump any state to aid debugging
|
if fork := ctx.String(forkFlag.Name); fork != "" && st.Fork != fork {
|
||||||
cpy, _ := state.New(root, tstate.StateDB.Database())
|
// If specific fork requested, skip all tests that do not match.
|
||||||
dump := cpy.RawDump(nil)
|
continue
|
||||||
result.State = &dump
|
}
|
||||||
}
|
// Run the test and aggregate the result
|
||||||
}
|
result := &testResult{Name: key, Fork: st.Fork, Pass: true}
|
||||||
if err != nil {
|
test.Run(st, cfg, false, rawdb.HashScheme, func(err error, state *tests.StateTestState) {
|
||||||
// Test failed, mark as so
|
var root common.Hash
|
||||||
result.Pass, result.Error = false, err.Error()
|
if state.StateDB != nil {
|
||||||
}
|
root = state.StateDB.IntermediateRoot(false)
|
||||||
})
|
result.Root = &root
|
||||||
if bench {
|
fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%#x\"}\n", root)
|
||||||
_, stats, _ := timedExec(true, func() ([]byte, uint64, error) {
|
// Dump any state to aid debugging.
|
||||||
_, _, gasUsed, _ := test.test.RunNoVerify(test.st, cfg, false, rawdb.HashScheme)
|
if ctx.Bool(DumpFlag.Name) {
|
||||||
return nil, gasUsed, nil
|
result.State = dump(state.StateDB)
|
||||||
})
|
}
|
||||||
result.BenchStats = &stats
|
}
|
||||||
|
// Collect bench stats if requested.
|
||||||
|
if ctx.Bool(BenchFlag.Name) {
|
||||||
|
_, stats, _ := timedExec(true, func() ([]byte, uint64, error) {
|
||||||
|
_, _, gasUsed, _ := test.RunNoVerify(st, cfg, false, rawdb.HashScheme)
|
||||||
|
return nil, gasUsed, nil
|
||||||
|
})
|
||||||
|
result.Stats = &stats
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
// Test failed, mark as so.
|
||||||
|
result.Pass, result.Error = false, err.Error()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
results = append(results, *result)
|
||||||
}
|
}
|
||||||
results = append(results, *result)
|
|
||||||
}
|
}
|
||||||
out, _ := json.MarshalIndent(results, "", " ")
|
return results, nil
|
||||||
fmt.Println(string(out))
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
|
|
@ -1687,7 +1686,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
godebug.SetGCPercent(int(gogc))
|
godebug.SetGCPercent(int(gogc))
|
||||||
|
|
||||||
if ctx.IsSet(SyncTargetFlag.Name) {
|
if ctx.IsSet(SyncTargetFlag.Name) {
|
||||||
cfg.SyncMode = downloader.FullSync // dev sync target forces full sync
|
cfg.SyncMode = ethconfig.FullSync // dev sync target forces full sync
|
||||||
} else if ctx.IsSet(SyncModeFlag.Name) {
|
} else if ctx.IsSet(SyncModeFlag.Name) {
|
||||||
if err = cfg.SyncMode.UnmarshalText([]byte(ctx.String(SyncModeFlag.Name))); err != nil {
|
if err = cfg.SyncMode.UnmarshalText([]byte(ctx.String(SyncModeFlag.Name))); err != nil {
|
||||||
Fatalf("invalid --syncmode flag: %v", err)
|
Fatalf("invalid --syncmode flag: %v", err)
|
||||||
|
|
@ -1758,7 +1757,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
}
|
}
|
||||||
if !ctx.Bool(SnapshotFlag.Name) || cfg.SnapshotCache == 0 {
|
if !ctx.Bool(SnapshotFlag.Name) || cfg.SnapshotCache == 0 {
|
||||||
// If snap-sync is requested, this flag is also required
|
// If snap-sync is requested, this flag is also required
|
||||||
if cfg.SyncMode == downloader.SnapSync {
|
if cfg.SyncMode == ethconfig.SnapSync {
|
||||||
if !ctx.Bool(SnapshotFlag.Name) {
|
if !ctx.Bool(SnapshotFlag.Name) {
|
||||||
log.Warn("Snap sync requested, enabling --snapshot")
|
log.Warn("Snap sync requested, enabling --snapshot")
|
||||||
}
|
}
|
||||||
|
|
@ -1824,7 +1823,7 @@ func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) {
|
||||||
if !ctx.IsSet(NetworkIdFlag.Name) {
|
if !ctx.IsSet(NetworkIdFlag.Name) {
|
||||||
cfg.NetworkId = 1337
|
cfg.NetworkId = 1337
|
||||||
}
|
}
|
||||||
cfg.SyncMode = downloader.FullSync
|
cfg.SyncMode = ethconfig.FullSync
|
||||||
// Create new developer account or reuse existing one
|
// Create new developer account or reuse existing one
|
||||||
var (
|
var (
|
||||||
developer accounts.Account
|
developer accounts.Account
|
||||||
|
|
|
||||||
|
|
@ -93,7 +93,7 @@ func (v *BlockValidator) ValidateBody(block *types.Block) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// The individual checks for blob validity (version-check + not empty)
|
// The individual checks for blob validity (version-check + not empty)
|
||||||
// happens in StateTransition.
|
// happens in state transition.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check blob gas usage.
|
// Check blob gas usage.
|
||||||
|
|
|
||||||
|
|
@ -1926,7 +1926,7 @@ func (bc *BlockChain) processBlock(block *types.Block, statedb *state.StateDB, s
|
||||||
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
task := types.NewBlockWithHeader(context).WithBody(*block.Body())
|
||||||
|
|
||||||
// Run the stateless self-cross-validation
|
// Run the stateless self-cross-validation
|
||||||
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, task, witness)
|
crossStateRoot, crossReceiptRoot, err := ExecuteStateless(bc.chainConfig, bc.vmConfig, task, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
return nil, fmt.Errorf("stateless self-validation failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -344,10 +344,7 @@ func (bc *BlockChain) stateRecoverable(root common.Hash) bool {
|
||||||
|
|
||||||
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
|
// ContractCodeWithPrefix retrieves a blob of data associated with a contract
|
||||||
// hash either from ephemeral in-memory cache, or from persistent storage.
|
// hash either from ephemeral in-memory cache, or from persistent storage.
|
||||||
//
|
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) []byte {
|
||||||
// If the code doesn't exist in the in-memory cache, check the storage with
|
|
||||||
// new code scheme.
|
|
||||||
func (bc *BlockChain) ContractCodeWithPrefix(hash common.Hash) ([]byte, error) {
|
|
||||||
// TODO(rjl493456442) The associated account address is also required
|
// TODO(rjl493456442) The associated account address is also required
|
||||||
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
// in Verkle scheme. Fix it once snap-sync is supported for Verkle.
|
||||||
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
return bc.statedb.ContractCodeWithPrefix(common.Address{}, hash)
|
||||||
|
|
|
||||||
|
|
@ -349,25 +349,22 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse
|
||||||
|
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if config.IsPrague(b.header.Number, b.header.Time) {
|
if config.IsPrague(b.header.Number, b.header.Time) {
|
||||||
|
requests = [][]byte{}
|
||||||
// EIP-6110 deposits
|
// EIP-6110 deposits
|
||||||
var blockLogs []*types.Log
|
var blockLogs []*types.Log
|
||||||
for _, r := range b.receipts {
|
for _, r := range b.receipts {
|
||||||
blockLogs = append(blockLogs, r.Logs...)
|
blockLogs = append(blockLogs, r.Logs...)
|
||||||
}
|
}
|
||||||
depositRequests, err := ParseDepositLogs(blockLogs, config)
|
if err := ParseDepositLogs(&requests, blockLogs, config); err != nil {
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
panic(fmt.Sprintf("failed to parse deposit log: %v", err))
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
|
||||||
// create EVM for system calls
|
// create EVM for system calls
|
||||||
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
blockContext := NewEVMBlockContext(b.header, cm, &b.header.Coinbase)
|
||||||
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
evm := vm.NewEVM(blockContext, statedb, cm.config, vm.Config{})
|
||||||
// EIP-7002 withdrawals
|
// EIP-7002
|
||||||
withdrawalRequests := ProcessWithdrawalQueue(evm)
|
ProcessWithdrawalQueue(&requests, evm)
|
||||||
requests = append(requests, withdrawalRequests)
|
// EIP-7251
|
||||||
// EIP-7251 consolidations
|
ProcessConsolidationQueue(&requests, evm)
|
||||||
consolidationRequests := ProcessConsolidationQueue(evm)
|
|
||||||
requests = append(requests, consolidationRequests)
|
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
reqHash := types.CalcRequestsHash(requests)
|
||||||
|
|
|
||||||
|
|
@ -472,9 +472,7 @@ func (g *Genesis) toBlockWithRoot(root common.Hash) *types.Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if conf.IsPrague(num, g.Timestamp) {
|
if conf.IsPrague(num, g.Timestamp) {
|
||||||
emptyRequests := [][]byte{{0x00}, {0x01}, {0x02}}
|
head.RequestsHash = &types.EmptyRequestsHash
|
||||||
rhash := types.CalcRequestsHash(emptyRequests)
|
|
||||||
head.RequestsHash = &rhash
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
return types.NewBlock(head, &types.Body{Withdrawals: withdrawals}, nil, trie.NewStackTrie(nil))
|
||||||
|
|
|
||||||
|
|
@ -293,7 +293,7 @@ func TestVerkleGenesisCommit(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := common.FromHex("4a83dc39eb688dbcfaf581d60e82de18f875e38786ebce5833342011d6fef37b")
|
expected := common.FromHex("018d20eebb130b5e2b796465fe36aafab650650729a92435aec071bf2386f080")
|
||||||
got := genesis.ToBlock().Root().Bytes()
|
got := genesis.ToBlock().Root().Bytes()
|
||||||
if !bytes.Equal(got, expected) {
|
if !bytes.Equal(got, expected) {
|
||||||
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -55,12 +54,6 @@ type Database interface {
|
||||||
// OpenStorageTrie opens the storage trie of an account.
|
// OpenStorageTrie opens the storage trie of an account.
|
||||||
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
|
OpenStorageTrie(stateRoot common.Hash, address common.Address, root common.Hash, trie Trie) (Trie, error)
|
||||||
|
|
||||||
// ContractCode retrieves a particular contract's code.
|
|
||||||
ContractCode(addr common.Address, codeHash common.Hash) ([]byte, error)
|
|
||||||
|
|
||||||
// ContractCodeSize retrieves a particular contracts code's size.
|
|
||||||
ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
|
||||||
|
|
||||||
// PointCache returns the cache holding points used in verkle tree key computation
|
// PointCache returns the cache holding points used in verkle tree key computation
|
||||||
PointCache() *utils.PointCache
|
PointCache() *utils.PointCache
|
||||||
|
|
||||||
|
|
@ -180,7 +173,7 @@ func NewDatabaseForTesting() *CachingDB {
|
||||||
|
|
||||||
// Reader returns a state reader associated with the specified state root.
|
// Reader returns a state reader associated with the specified state root.
|
||||||
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
var readers []Reader
|
var readers []StateReader
|
||||||
|
|
||||||
// Set up the state snapshot reader if available. This feature
|
// Set up the state snapshot reader if available. This feature
|
||||||
// is optional and may be partially useful if it's not fully
|
// is optional and may be partially useful if it's not fully
|
||||||
|
|
@ -188,7 +181,7 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
if db.snap != nil {
|
if db.snap != nil {
|
||||||
snap := db.snap.Snapshot(stateRoot)
|
snap := db.snap.Snapshot(stateRoot)
|
||||||
if snap != nil {
|
if snap != nil {
|
||||||
readers = append(readers, newStateReader(snap)) // snap reader is optional
|
readers = append(readers, newFlatReader(snap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set up the trie reader, which is expected to always be available
|
// Set up the trie reader, which is expected to always be available
|
||||||
|
|
@ -199,7 +192,11 @@ func (db *CachingDB) Reader(stateRoot common.Hash) (Reader, error) {
|
||||||
}
|
}
|
||||||
readers = append(readers, tr)
|
readers = append(readers, tr)
|
||||||
|
|
||||||
return newMultiReader(readers...)
|
combined, err := newMultiStateReader(readers...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newReader(newCachingCodeReader(db.disk, db.codeCache, db.codeSizeCache), combined), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenTrie opens the main account trie at a specific root hash.
|
// OpenTrie opens the main account trie at a specific root hash.
|
||||||
|
|
@ -229,45 +226,20 @@ func (db *CachingDB) OpenStorageTrie(stateRoot common.Hash, address common.Addre
|
||||||
return tr, nil
|
return tr, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContractCode retrieves a particular contract's code.
|
|
||||||
func (db *CachingDB) ContractCode(address common.Address, codeHash common.Hash) ([]byte, error) {
|
|
||||||
code, _ := db.codeCache.Get(codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
code = rawdb.ReadCode(db.disk, codeHash)
|
|
||||||
if len(code) > 0 {
|
|
||||||
db.codeCache.Add(codeHash, code)
|
|
||||||
db.codeSizeCache.Add(codeHash, len(code))
|
|
||||||
return code, nil
|
|
||||||
}
|
|
||||||
return nil, errors.New("not found")
|
|
||||||
}
|
|
||||||
|
|
||||||
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
// ContractCodeWithPrefix retrieves a particular contract's code. If the
|
||||||
// code can't be found in the cache, then check the existence with **new**
|
// code can't be found in the cache, then check the existence with **new**
|
||||||
// db scheme.
|
// db scheme.
|
||||||
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) ([]byte, error) {
|
func (db *CachingDB) ContractCodeWithPrefix(address common.Address, codeHash common.Hash) []byte {
|
||||||
code, _ := db.codeCache.Get(codeHash)
|
code, _ := db.codeCache.Get(codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
return code, nil
|
return code
|
||||||
}
|
}
|
||||||
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
|
code = rawdb.ReadCodeWithPrefix(db.disk, codeHash)
|
||||||
if len(code) > 0 {
|
if len(code) > 0 {
|
||||||
db.codeCache.Add(codeHash, code)
|
db.codeCache.Add(codeHash, code)
|
||||||
db.codeSizeCache.Add(codeHash, len(code))
|
db.codeSizeCache.Add(codeHash, len(code))
|
||||||
return code, nil
|
|
||||||
}
|
}
|
||||||
return nil, errors.New("not found")
|
return code
|
||||||
}
|
|
||||||
|
|
||||||
// ContractCodeSize retrieves a particular contracts code's size.
|
|
||||||
func (db *CachingDB) ContractCodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
|
||||||
if cached, ok := db.codeSizeCache.Get(codeHash); ok {
|
|
||||||
return cached, nil
|
|
||||||
}
|
|
||||||
code, err := db.ContractCode(addr, codeHash)
|
|
||||||
return len(code), err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TrieDB retrieves any intermediate trie-node caching layer.
|
// TrieDB retrieves any intermediate trie-node caching layer.
|
||||||
|
|
|
||||||
|
|
@ -136,10 +136,13 @@ func (it *nodeIterator) step() error {
|
||||||
}
|
}
|
||||||
if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
|
if !bytes.Equal(account.CodeHash, types.EmptyCodeHash.Bytes()) {
|
||||||
it.codeHash = common.BytesToHash(account.CodeHash)
|
it.codeHash = common.BytesToHash(account.CodeHash)
|
||||||
it.code, err = it.state.db.ContractCode(address, common.BytesToHash(account.CodeHash))
|
it.code, err = it.state.reader.Code(address, common.BytesToHash(account.CodeHash))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("code %x: %v", account.CodeHash, err)
|
return fmt.Errorf("code %x: %v", account.CodeHash, err)
|
||||||
}
|
}
|
||||||
|
if len(it.code) == 0 {
|
||||||
|
return fmt.Errorf("code is not found: %x", account.CodeHash)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
it.accountHash = it.stateIt.Parent()
|
it.accountHash = it.stateIt.Parent()
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,13 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"maps"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/common/lru"
|
||||||
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/utils"
|
"github.com/ethereum/go-ethereum/trie/utils"
|
||||||
|
|
@ -30,9 +32,26 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/triedb/database"
|
"github.com/ethereum/go-ethereum/triedb/database"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Reader defines the interface for accessing accounts and storage slots
|
// ContractCodeReader defines the interface for accessing contract code.
|
||||||
|
type ContractCodeReader interface {
|
||||||
|
// Code retrieves a particular contract's code.
|
||||||
|
//
|
||||||
|
// - Returns nil code along with nil error if the requested contract code
|
||||||
|
// doesn't exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
Code(addr common.Address, codeHash common.Hash) ([]byte, error)
|
||||||
|
|
||||||
|
// CodeSize retrieves a particular contracts code's size.
|
||||||
|
//
|
||||||
|
// - Returns zero code size along with nil error if the requested contract code
|
||||||
|
// doesn't exist
|
||||||
|
// - Returns an error only if an unexpected issue occurs
|
||||||
|
CodeSize(addr common.Address, codeHash common.Hash) (int, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// StateReader defines the interface for accessing accounts and storage slots
|
||||||
// associated with a specific state.
|
// associated with a specific state.
|
||||||
type Reader interface {
|
type StateReader interface {
|
||||||
// Account retrieves the account associated with a particular address.
|
// Account retrieves the account associated with a particular address.
|
||||||
//
|
//
|
||||||
// - Returns a nil account if it does not exist
|
// - Returns a nil account if it does not exist
|
||||||
|
|
@ -47,32 +66,84 @@ type Reader interface {
|
||||||
// - Returns an error only if an unexpected issue occurs
|
// - Returns an error only if an unexpected issue occurs
|
||||||
// - The returned storage slot is safe to modify after the call
|
// - The returned storage slot is safe to modify after the call
|
||||||
Storage(addr common.Address, slot common.Hash) (common.Hash, error)
|
Storage(addr common.Address, slot common.Hash) (common.Hash, error)
|
||||||
|
|
||||||
// Copy returns a deep-copied state reader.
|
|
||||||
Copy() Reader
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stateReader wraps a database state reader.
|
// Reader defines the interface for accessing accounts, storage slots and contract
|
||||||
type stateReader struct {
|
// code associated with a specific state.
|
||||||
|
type Reader interface {
|
||||||
|
ContractCodeReader
|
||||||
|
StateReader
|
||||||
|
}
|
||||||
|
|
||||||
|
// cachingCodeReader implements ContractCodeReader, accessing contract code either in
|
||||||
|
// local key-value store or the shared code cache.
|
||||||
|
type cachingCodeReader struct {
|
||||||
|
db ethdb.KeyValueReader
|
||||||
|
|
||||||
|
// These caches could be shared by multiple code reader instances,
|
||||||
|
// they are natively thread-safe.
|
||||||
|
codeCache *lru.SizeConstrainedCache[common.Hash, []byte]
|
||||||
|
codeSizeCache *lru.Cache[common.Hash, int]
|
||||||
|
}
|
||||||
|
|
||||||
|
// newCachingCodeReader constructs the code reader.
|
||||||
|
func newCachingCodeReader(db ethdb.KeyValueReader, codeCache *lru.SizeConstrainedCache[common.Hash, []byte], codeSizeCache *lru.Cache[common.Hash, int]) *cachingCodeReader {
|
||||||
|
return &cachingCodeReader{
|
||||||
|
db: db,
|
||||||
|
codeCache: codeCache,
|
||||||
|
codeSizeCache: codeSizeCache,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Code implements ContractCodeReader, retrieving a particular contract's code.
|
||||||
|
// If the contract code doesn't exist, no error will be returned.
|
||||||
|
func (r *cachingCodeReader) Code(addr common.Address, codeHash common.Hash) ([]byte, error) {
|
||||||
|
code, _ := r.codeCache.Get(codeHash)
|
||||||
|
if len(code) > 0 {
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
code = rawdb.ReadCode(r.db, codeHash)
|
||||||
|
if len(code) > 0 {
|
||||||
|
r.codeCache.Add(codeHash, code)
|
||||||
|
r.codeSizeCache.Add(codeHash, len(code))
|
||||||
|
}
|
||||||
|
return code, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeSize implements ContractCodeReader, retrieving a particular contracts code's size.
|
||||||
|
// If the contract code doesn't exist, no error will be returned.
|
||||||
|
func (r *cachingCodeReader) CodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||||
|
if cached, ok := r.codeSizeCache.Get(codeHash); ok {
|
||||||
|
return cached, nil
|
||||||
|
}
|
||||||
|
code, err := r.Code(addr, codeHash)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return len(code), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// flatReader wraps a database state reader.
|
||||||
|
type flatReader struct {
|
||||||
reader database.StateReader
|
reader database.StateReader
|
||||||
buff crypto.KeccakState
|
buff crypto.KeccakState
|
||||||
}
|
}
|
||||||
|
|
||||||
// newStateReader constructs a state reader with on the given state root.
|
// newFlatReader constructs a state reader with on the given state root.
|
||||||
func newStateReader(reader database.StateReader) *stateReader {
|
func newFlatReader(reader database.StateReader) *flatReader {
|
||||||
return &stateReader{
|
return &flatReader{
|
||||||
reader: reader,
|
reader: reader,
|
||||||
buff: crypto.NewKeccakState(),
|
buff: crypto.NewKeccakState(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements Reader, retrieving the account specified by the address.
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
//
|
//
|
||||||
// An error will be returned if the associated snapshot is already stale or
|
// An error will be returned if the associated snapshot is already stale or
|
||||||
// the requested account is not yet covered by the snapshot.
|
// the requested account is not yet covered by the snapshot.
|
||||||
//
|
//
|
||||||
// The returned account might be nil if it's not existent.
|
// The returned account might be nil if it's not existent.
|
||||||
func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes()))
|
account, err := r.reader.Account(crypto.HashData(r.buff, addr.Bytes()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -95,14 +166,14 @@ func (r *stateReader) Account(addr common.Address) (*types.StateAccount, error)
|
||||||
return acct, nil
|
return acct, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage implements Reader, retrieving the storage slot specified by the
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
// address and slot key.
|
// address and slot key.
|
||||||
//
|
//
|
||||||
// An error will be returned if the associated snapshot is already stale or
|
// An error will be returned if the associated snapshot is already stale or
|
||||||
// the requested storage slot is not yet covered by the snapshot.
|
// the requested storage slot is not yet covered by the snapshot.
|
||||||
//
|
//
|
||||||
// The returned storage slot might be empty if it's not existent.
|
// The returned storage slot might be empty if it's not existent.
|
||||||
func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) {
|
||||||
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
addrHash := crypto.HashData(r.buff, addr.Bytes())
|
||||||
slotHash := crypto.HashData(r.buff, key.Bytes())
|
slotHash := crypto.HashData(r.buff, key.Bytes())
|
||||||
ret, err := r.reader.Storage(addrHash, slotHash)
|
ret, err := r.reader.Storage(addrHash, slotHash)
|
||||||
|
|
@ -123,15 +194,7 @@ func (r *stateReader) Storage(addr common.Address, key common.Hash) (common.Hash
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy implements Reader, returning a deep-copied snap reader.
|
// trieReader implements the StateReader interface, providing functions to access
|
||||||
func (r *stateReader) Copy() Reader {
|
|
||||||
return &stateReader{
|
|
||||||
reader: r.reader,
|
|
||||||
buff: crypto.NewKeccakState(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// trieReader implements the Reader interface, providing functions to access
|
|
||||||
// state from the referenced trie.
|
// state from the referenced trie.
|
||||||
type trieReader struct {
|
type trieReader struct {
|
||||||
root common.Hash // State root which uniquely represent a state
|
root common.Hash // State root which uniquely represent a state
|
||||||
|
|
@ -167,7 +230,7 @@ func newTrieReader(root common.Hash, db *triedb.Database, cache *utils.PointCach
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implements Reader, retrieving the account specified by the address.
|
// Account implements StateReader, retrieving the account specified by the address.
|
||||||
//
|
//
|
||||||
// An error will be returned if the trie state is corrupted. An nil account
|
// An error will be returned if the trie state is corrupted. An nil account
|
||||||
// will be returned if it's not existent in the trie.
|
// will be returned if it's not existent in the trie.
|
||||||
|
|
@ -184,7 +247,7 @@ func (r *trieReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
return account, nil
|
return account, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage implements Reader, retrieving the storage slot specified by the
|
// Storage implements StateReader, retrieving the storage slot specified by the
|
||||||
// address and slot key.
|
// address and slot key.
|
||||||
//
|
//
|
||||||
// An error will be returned if the trie state is corrupted. An empty storage
|
// An error will be returned if the trie state is corrupted. An empty storage
|
||||||
|
|
@ -227,48 +290,32 @@ func (r *trieReader) Storage(addr common.Address, key common.Hash) (common.Hash,
|
||||||
return value, nil
|
return value, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy implements Reader, returning a deep-copied trie reader.
|
// multiStateReader is the aggregation of a list of StateReader interface,
|
||||||
func (r *trieReader) Copy() Reader {
|
// providing state access by leveraging all readers. The checking priority
|
||||||
tries := make(map[common.Address]Trie)
|
// is determined by the position in the reader list.
|
||||||
for addr, tr := range r.subTries {
|
type multiStateReader struct {
|
||||||
tries[addr] = mustCopyTrie(tr)
|
readers []StateReader // List of state readers, sorted by checking priority
|
||||||
}
|
|
||||||
return &trieReader{
|
|
||||||
root: r.root,
|
|
||||||
db: r.db,
|
|
||||||
buff: crypto.NewKeccakState(),
|
|
||||||
mainTrie: mustCopyTrie(r.mainTrie),
|
|
||||||
subRoots: maps.Clone(r.subRoots),
|
|
||||||
subTries: tries,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// multiReader is the aggregation of a list of Reader interface, providing state
|
// newMultiStateReader constructs a multiStateReader instance with the given
|
||||||
// access by leveraging all readers. The checking priority is determined by the
|
// readers. The priority among readers is assumed to be sorted. Note, it must
|
||||||
// position in the reader list.
|
// contain at least one reader for constructing a multiStateReader.
|
||||||
type multiReader struct {
|
func newMultiStateReader(readers ...StateReader) (*multiStateReader, error) {
|
||||||
readers []Reader // List of readers, sorted by checking priority
|
|
||||||
}
|
|
||||||
|
|
||||||
// newMultiReader constructs a multiReader instance with the given readers. The
|
|
||||||
// priority among readers is assumed to be sorted. Note, it must contain at least
|
|
||||||
// one reader for constructing a multiReader.
|
|
||||||
func newMultiReader(readers ...Reader) (*multiReader, error) {
|
|
||||||
if len(readers) == 0 {
|
if len(readers) == 0 {
|
||||||
return nil, errors.New("empty reader set")
|
return nil, errors.New("empty reader set")
|
||||||
}
|
}
|
||||||
return &multiReader{
|
return &multiStateReader{
|
||||||
readers: readers,
|
readers: readers,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Account implementing Reader interface, retrieving the account associated with
|
// Account implementing StateReader interface, retrieving the account associated
|
||||||
// a particular address.
|
// with a particular address.
|
||||||
//
|
//
|
||||||
// - Returns a nil account if it does not exist
|
// - Returns a nil account if it does not exist
|
||||||
// - Returns an error only if an unexpected issue occurs
|
// - Returns an error only if an unexpected issue occurs
|
||||||
// - The returned account is safe to modify after the call
|
// - The returned account is safe to modify after the call
|
||||||
func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error) {
|
func (r *multiStateReader) Account(addr common.Address) (*types.StateAccount, error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, reader := range r.readers {
|
for _, reader := range r.readers {
|
||||||
acct, err := reader.Account(addr)
|
acct, err := reader.Account(addr)
|
||||||
|
|
@ -280,13 +327,13 @@ func (r *multiReader) Account(addr common.Address) (*types.StateAccount, error)
|
||||||
return nil, errors.Join(errs...)
|
return nil, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Storage implementing Reader interface, retrieving the storage slot associated
|
// Storage implementing StateReader interface, retrieving the storage slot
|
||||||
// with a particular account address and slot key.
|
// associated with a particular account address and slot key.
|
||||||
//
|
//
|
||||||
// - Returns an empty slot if it does not exist
|
// - Returns an empty slot if it does not exist
|
||||||
// - Returns an error only if an unexpected issue occurs
|
// - Returns an error only if an unexpected issue occurs
|
||||||
// - The returned storage slot is safe to modify after the call
|
// - The returned storage slot is safe to modify after the call
|
||||||
func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
||||||
var errs []error
|
var errs []error
|
||||||
for _, reader := range r.readers {
|
for _, reader := range r.readers {
|
||||||
slot, err := reader.Storage(addr, slot)
|
slot, err := reader.Storage(addr, slot)
|
||||||
|
|
@ -298,11 +345,16 @@ func (r *multiReader) Storage(addr common.Address, slot common.Hash) (common.Has
|
||||||
return common.Hash{}, errors.Join(errs...)
|
return common.Hash{}, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy implementing Reader interface, returning a deep-copied state reader.
|
// reader is the wrapper of ContractCodeReader and StateReader interface.
|
||||||
func (r *multiReader) Copy() Reader {
|
type reader struct {
|
||||||
var readers []Reader
|
ContractCodeReader
|
||||||
for _, reader := range r.readers {
|
StateReader
|
||||||
readers = append(readers, reader.Copy())
|
}
|
||||||
}
|
|
||||||
return &multiReader{readers: readers}
|
// newReader constructs a reader with the supplied code reader and state reader.
|
||||||
|
func newReader(codeReader ContractCodeReader, stateReader StateReader) *reader {
|
||||||
|
return &reader{
|
||||||
|
ContractCodeReader: codeReader,
|
||||||
|
StateReader: stateReader,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,9 +33,11 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/triedb"
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 0: initial version
|
const (
|
||||||
// 1: destruct flag in diff layer is removed
|
journalV0 uint64 = 0 // initial version
|
||||||
const journalVersion uint64 = 1
|
journalV1 uint64 = 1 // current version, with destruct flag (in diff layers) removed
|
||||||
|
journalCurrentVersion = journalV1
|
||||||
|
)
|
||||||
|
|
||||||
// journalGenerator is a disk layer entry containing the generator progress marker.
|
// journalGenerator is a disk layer entry containing the generator progress marker.
|
||||||
type journalGenerator struct {
|
type journalGenerator struct {
|
||||||
|
|
@ -50,6 +52,11 @@ type journalGenerator struct {
|
||||||
Storage uint64
|
Storage uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// journalDestruct is an account deletion entry in a diffLayer's disk journal.
|
||||||
|
type journalDestruct struct {
|
||||||
|
Hash common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
// journalAccount is an account entry in a diffLayer's disk journal.
|
// journalAccount is an account entry in a diffLayer's disk journal.
|
||||||
type journalAccount struct {
|
type journalAccount struct {
|
||||||
Hash common.Hash
|
Hash common.Hash
|
||||||
|
|
@ -285,8 +292,8 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
|
||||||
log.Warn("Failed to resolve the journal version", "error", err)
|
log.Warn("Failed to resolve the journal version", "error", err)
|
||||||
return errors.New("failed to resolve journal version")
|
return errors.New("failed to resolve journal version")
|
||||||
}
|
}
|
||||||
if version != journalVersion {
|
if version != journalV0 && version != journalCurrentVersion {
|
||||||
log.Warn("Discarded the snapshot journal with wrong version", "required", journalVersion, "got", version)
|
log.Warn("Discarded journal with wrong version", "required", journalCurrentVersion, "got", version)
|
||||||
return errors.New("wrong journal version")
|
return errors.New("wrong journal version")
|
||||||
}
|
}
|
||||||
// Secondly, resolve the disk layer root, ensure it's continuous
|
// Secondly, resolve the disk layer root, ensure it's continuous
|
||||||
|
|
@ -316,6 +323,36 @@ func iterateJournal(db ethdb.KeyValueReader, callback journalCallback) error {
|
||||||
}
|
}
|
||||||
return fmt.Errorf("load diff root: %v", err)
|
return fmt.Errorf("load diff root: %v", err)
|
||||||
}
|
}
|
||||||
|
// If a legacy journal is detected, decode the destruct set from the stream.
|
||||||
|
// The destruct set has been deprecated. If the journal contains non-empty
|
||||||
|
// destruct set, then it is deemed incompatible.
|
||||||
|
//
|
||||||
|
// Since self-destruction has been deprecated following the cancun fork,
|
||||||
|
// the destruct set is expected to be nil for layers above the fork block.
|
||||||
|
// However, an exception occurs during contract deployment: pre-funded accounts
|
||||||
|
// may self-destruct, causing accounts with non-zero balances to be removed
|
||||||
|
// from the state. For example,
|
||||||
|
// https://etherscan.io/tx/0xa087333d83f0cd63b96bdafb686462e1622ce25f40bd499e03efb1051f31fe49).
|
||||||
|
//
|
||||||
|
// For nodes with a fully synced state, the legacy journal is likely compatible
|
||||||
|
// with the updated definition, eliminating the need for regeneration. Unfortunately,
|
||||||
|
// nodes performing a full sync of historical chain segments or encountering
|
||||||
|
// pre-funded account deletions may face incompatibilities, leading to automatic
|
||||||
|
// snapshot regeneration.
|
||||||
|
//
|
||||||
|
// This approach minimizes snapshot regeneration for Geth nodes upgrading from a
|
||||||
|
// legacy version that are already synced. The workaround can be safely removed
|
||||||
|
// after the next hard fork.
|
||||||
|
if version == journalV0 {
|
||||||
|
var destructs []journalDestruct
|
||||||
|
if err := r.Decode(&destructs); err != nil {
|
||||||
|
return fmt.Errorf("load diff destructs: %v", err)
|
||||||
|
}
|
||||||
|
if len(destructs) > 0 {
|
||||||
|
log.Warn("Incompatible legacy journal detected", "version", journalV0)
|
||||||
|
return fmt.Errorf("incompatible legacy journal detected")
|
||||||
|
}
|
||||||
|
}
|
||||||
if err := r.Decode(&accounts); err != nil {
|
if err := r.Decode(&accounts); err != nil {
|
||||||
return fmt.Errorf("load diff accounts: %v", err)
|
return fmt.Errorf("load diff accounts: %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -664,7 +664,7 @@ func (t *Tree) Journal(root common.Hash) (common.Hash, error) {
|
||||||
|
|
||||||
// Firstly write out the metadata of journal
|
// Firstly write out the metadata of journal
|
||||||
journal := new(bytes.Buffer)
|
journal := new(bytes.Buffer)
|
||||||
if err := rlp.Encode(journal, journalVersion); err != nil {
|
if err := rlp.Encode(journal, journalCurrentVersion); err != nil {
|
||||||
return common.Hash{}, err
|
return common.Hash{}, err
|
||||||
}
|
}
|
||||||
diskroot := t.diskRoot()
|
diskroot := t.diskRoot()
|
||||||
|
|
|
||||||
|
|
@ -510,10 +510,13 @@ func (s *stateObject) Code() []byte {
|
||||||
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
code, err := s.db.db.ContractCode(s.address, common.BytesToHash(s.CodeHash()))
|
code, err := s.db.reader.Code(s.address, common.BytesToHash(s.CodeHash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
|
s.db.setError(fmt.Errorf("can't load code hash %x: %v", s.CodeHash(), err))
|
||||||
}
|
}
|
||||||
|
if len(code) == 0 {
|
||||||
|
s.db.setError(fmt.Errorf("code is not found %x", s.CodeHash()))
|
||||||
|
}
|
||||||
s.code = code
|
s.code = code
|
||||||
return code
|
return code
|
||||||
}
|
}
|
||||||
|
|
@ -528,10 +531,13 @@ func (s *stateObject) CodeSize() int {
|
||||||
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
if bytes.Equal(s.CodeHash(), types.EmptyCodeHash.Bytes()) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
size, err := s.db.db.ContractCodeSize(s.address, common.BytesToHash(s.CodeHash()))
|
size, err := s.db.reader.CodeSize(s.address, common.BytesToHash(s.CodeHash()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
|
s.db.setError(fmt.Errorf("can't load code size %x: %v", s.CodeHash(), err))
|
||||||
}
|
}
|
||||||
|
if size == 0 {
|
||||||
|
s.db.setError(fmt.Errorf("code is not found %x", s.CodeHash()))
|
||||||
|
}
|
||||||
return size
|
return size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -650,10 +650,11 @@ func (s *StateDB) CreateContract(addr common.Address) {
|
||||||
// Snapshots of the copied state cannot be applied to the copy.
|
// Snapshots of the copied state cannot be applied to the copy.
|
||||||
func (s *StateDB) Copy() *StateDB {
|
func (s *StateDB) Copy() *StateDB {
|
||||||
// Copy all the basic fields, initialize the memory ones
|
// Copy all the basic fields, initialize the memory ones
|
||||||
|
reader, _ := s.db.Reader(s.originalRoot) // impossible to fail
|
||||||
state := &StateDB{
|
state := &StateDB{
|
||||||
db: s.db,
|
db: s.db,
|
||||||
trie: mustCopyTrie(s.trie),
|
trie: mustCopyTrie(s.trie),
|
||||||
reader: s.reader.Copy(),
|
reader: reader,
|
||||||
originalRoot: s.originalRoot,
|
originalRoot: s.originalRoot,
|
||||||
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
stateObjects: make(map[common.Address]*stateObject, len(s.stateObjects)),
|
||||||
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
stateObjectsDestruct: make(map[common.Address]*stateObject, len(s.stateObjectsDestruct)),
|
||||||
|
|
|
||||||
|
|
@ -210,14 +210,18 @@ func testIterativeStateSync(t *testing.T, count int, commit bool, bypath bool, s
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("state is not existent, %#x", srcRoot)
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
}
|
}
|
||||||
|
cReader, err := srcDb.Reader(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
|
}
|
||||||
for len(nodeElements)+len(codeElements) > 0 {
|
for len(nodeElements)+len(codeElements) > 0 {
|
||||||
var (
|
var (
|
||||||
nodeResults = make([]trie.NodeSyncResult, len(nodeElements))
|
nodeResults = make([]trie.NodeSyncResult, len(nodeElements))
|
||||||
codeResults = make([]trie.CodeSyncResult, len(codeElements))
|
codeResults = make([]trie.CodeSyncResult, len(codeElements))
|
||||||
)
|
)
|
||||||
for i, element := range codeElements {
|
for i, element := range codeElements {
|
||||||
data, err := srcDb.ContractCode(common.Address{}, element.code)
|
data, err := cReader.Code(common.Address{}, element.code)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code)
|
t.Fatalf("failed to retrieve contract bytecode for hash %x", element.code)
|
||||||
}
|
}
|
||||||
codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
|
codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
|
||||||
|
|
@ -329,6 +333,10 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("state is not existent, %#x", srcRoot)
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
}
|
}
|
||||||
|
cReader, err := srcDb.Reader(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
|
}
|
||||||
for len(nodeElements)+len(codeElements) > 0 {
|
for len(nodeElements)+len(codeElements) > 0 {
|
||||||
// Sync only half of the scheduled nodes
|
// Sync only half of the scheduled nodes
|
||||||
var nodeProcessed int
|
var nodeProcessed int
|
||||||
|
|
@ -336,8 +344,8 @@ func testIterativeDelayedStateSync(t *testing.T, scheme string) {
|
||||||
if len(codeElements) > 0 {
|
if len(codeElements) > 0 {
|
||||||
codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1)
|
codeResults := make([]trie.CodeSyncResult, len(codeElements)/2+1)
|
||||||
for i, element := range codeElements[:len(codeResults)] {
|
for i, element := range codeElements[:len(codeResults)] {
|
||||||
data, err := srcDb.ContractCode(common.Address{}, element.code)
|
data, err := cReader.Code(common.Address{}, element.code)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
t.Fatalf("failed to retrieve contract bytecode for %x", element.code)
|
t.Fatalf("failed to retrieve contract bytecode for %x", element.code)
|
||||||
}
|
}
|
||||||
codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
|
codeResults[i] = trie.CodeSyncResult{Hash: element.code, Data: data}
|
||||||
|
|
@ -433,13 +441,17 @@ func testIterativeRandomStateSync(t *testing.T, count int, scheme string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("state is not existent, %#x", srcRoot)
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
}
|
}
|
||||||
|
cReader, err := srcDb.Reader(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
|
}
|
||||||
for len(nodeQueue)+len(codeQueue) > 0 {
|
for len(nodeQueue)+len(codeQueue) > 0 {
|
||||||
// Fetch all the queued nodes in a random order
|
// Fetch all the queued nodes in a random order
|
||||||
if len(codeQueue) > 0 {
|
if len(codeQueue) > 0 {
|
||||||
results := make([]trie.CodeSyncResult, 0, len(codeQueue))
|
results := make([]trie.CodeSyncResult, 0, len(codeQueue))
|
||||||
for hash := range codeQueue {
|
for hash := range codeQueue {
|
||||||
data, err := srcDb.ContractCode(common.Address{}, hash)
|
data, err := cReader.Code(common.Address{}, hash)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
t.Fatalf("failed to retrieve node data for %x", hash)
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
}
|
}
|
||||||
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
||||||
|
|
@ -526,6 +538,10 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("state is not existent, %#x", srcRoot)
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
}
|
}
|
||||||
|
cReader, err := srcDb.Reader(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
|
}
|
||||||
for len(nodeQueue)+len(codeQueue) > 0 {
|
for len(nodeQueue)+len(codeQueue) > 0 {
|
||||||
// Sync only half of the scheduled nodes, even those in random order
|
// Sync only half of the scheduled nodes, even those in random order
|
||||||
if len(codeQueue) > 0 {
|
if len(codeQueue) > 0 {
|
||||||
|
|
@ -533,8 +549,8 @@ func testIterativeRandomDelayedStateSync(t *testing.T, scheme string) {
|
||||||
for hash := range codeQueue {
|
for hash := range codeQueue {
|
||||||
delete(codeQueue, hash)
|
delete(codeQueue, hash)
|
||||||
|
|
||||||
data, err := srcDb.ContractCode(common.Address{}, hash)
|
data, err := cReader.Code(common.Address{}, hash)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
t.Fatalf("failed to retrieve node data for %x", hash)
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
}
|
}
|
||||||
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
||||||
|
|
@ -631,6 +647,10 @@ func testIncompleteStateSync(t *testing.T, scheme string) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("state is not available %x", srcRoot)
|
t.Fatalf("state is not available %x", srcRoot)
|
||||||
}
|
}
|
||||||
|
cReader, err := srcDb.Reader(srcRoot)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("state is not existent, %#x", srcRoot)
|
||||||
|
}
|
||||||
nodeQueue := make(map[string]stateElement)
|
nodeQueue := make(map[string]stateElement)
|
||||||
codeQueue := make(map[common.Hash]struct{})
|
codeQueue := make(map[common.Hash]struct{})
|
||||||
paths, nodes, codes := sched.Missing(1)
|
paths, nodes, codes := sched.Missing(1)
|
||||||
|
|
@ -649,8 +669,8 @@ func testIncompleteStateSync(t *testing.T, scheme string) {
|
||||||
if len(codeQueue) > 0 {
|
if len(codeQueue) > 0 {
|
||||||
results := make([]trie.CodeSyncResult, 0, len(codeQueue))
|
results := make([]trie.CodeSyncResult, 0, len(codeQueue))
|
||||||
for hash := range codeQueue {
|
for hash := range codeQueue {
|
||||||
data, err := srcDb.ContractCode(common.Address{}, hash)
|
data, err := cReader.Code(common.Address{}, hash)
|
||||||
if err != nil {
|
if err != nil || len(data) == 0 {
|
||||||
t.Fatalf("failed to retrieve node data for %x", hash)
|
t.Fatalf("failed to retrieve node data for %x", hash)
|
||||||
}
|
}
|
||||||
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
results = append(results, trie.CodeSyncResult{Hash: hash, Data: data})
|
||||||
|
|
@ -713,6 +733,11 @@ func testIncompleteStateSync(t *testing.T, scheme string) {
|
||||||
// Sanity check that removing any node from the database is detected
|
// Sanity check that removing any node from the database is detected
|
||||||
for _, node := range addedCodes {
|
for _, node := range addedCodes {
|
||||||
val := rawdb.ReadCode(dstDb, node)
|
val := rawdb.ReadCode(dstDb, node)
|
||||||
|
if len(val) == 0 {
|
||||||
|
t.Logf("no code: %v", node)
|
||||||
|
} else {
|
||||||
|
t.Logf("has code: %v", node)
|
||||||
|
}
|
||||||
rawdb.DeleteCode(dstDb, node)
|
rawdb.DeleteCode(dstDb, node)
|
||||||
if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil {
|
if err := checkStateConsistency(dstDb, ndb.Scheme(), srcRoot); err == nil {
|
||||||
t.Errorf("trie inconsistency not caught, missing: %x", node)
|
t.Errorf("trie inconsistency not caught, missing: %x", node)
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,10 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
return // Also invalid block, bail out
|
return // Also invalid block, bail out
|
||||||
}
|
}
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if err := precacheTransaction(msg, gaspool, evm); err != nil {
|
|
||||||
|
// We attempt to apply a transaction. The goal is not to execute
|
||||||
|
// the transaction successfully, rather to warm up touched data slots.
|
||||||
|
if _, err := ApplyMessage(evm, msg, gaspool); err != nil {
|
||||||
return // Ugh, something went horribly wrong, bail out
|
return // Ugh, something went horribly wrong, bail out
|
||||||
}
|
}
|
||||||
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
|
// If we're pre-byzantium, pre-load trie nodes for the intermediate root
|
||||||
|
|
@ -78,14 +81,3 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
|
||||||
statedb.IntermediateRoot(true)
|
statedb.IntermediateRoot(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// precacheTransaction attempts to apply a transaction to the given state database
|
|
||||||
// and uses the input parameters for its environment. The goal is not to execute
|
|
||||||
// the transaction successfully, rather to warm up touched data slots.
|
|
||||||
func precacheTransaction(msg *Message, gaspool *GasPool, evm *vm.EVM) error {
|
|
||||||
// Update the evm with the new transaction context.
|
|
||||||
evm.SetTxContext(NewEVMTxContext(msg))
|
|
||||||
// Add addresses to access list if applicable
|
|
||||||
_, err := ApplyMessage(evm, msg, gaspool)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc"
|
"github.com/ethereum/go-ethereum/consensus/misc"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -106,18 +107,15 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
// Read requests if Prague is enabled.
|
// Read requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if p.config.IsPrague(block.Number(), block.Time()) {
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
// EIP-6110 deposits
|
requests = [][]byte{}
|
||||||
depositRequests, err := ParseDepositLogs(allLogs, p.config)
|
// EIP-6110
|
||||||
if err != nil {
|
if err := ParseDepositLogs(&requests, allLogs, p.config); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
// EIP-7002
|
||||||
// EIP-7002 withdrawals
|
ProcessWithdrawalQueue(&requests, evm)
|
||||||
withdrawalRequests := ProcessWithdrawalQueue(evm)
|
// EIP-7251
|
||||||
requests = append(requests, withdrawalRequests)
|
ProcessConsolidationQueue(&requests, evm)
|
||||||
// EIP-7251 consolidations
|
|
||||||
consolidationRequests := ProcessConsolidationQueue(evm)
|
|
||||||
requests = append(requests, consolidationRequests)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
// Finalize the block, applying any consensus engine specific extras (e.g. block rewards)
|
||||||
|
|
@ -143,17 +141,11 @@ func ApplyTransactionWithEVM(msg *Message, gp *GasPool, statedb *state.StateDB,
|
||||||
defer func() { hooks.OnTxEnd(receipt, err) }()
|
defer func() { hooks.OnTxEnd(receipt, err) }()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a new context to be used in the EVM environment.
|
|
||||||
txContext := NewEVMTxContext(msg)
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
|
|
||||||
// Apply the transaction to the current state (included in the env).
|
// Apply the transaction to the current state (included in the env).
|
||||||
result, err := ApplyMessage(evm, msg, gp)
|
result, err := ApplyMessage(evm, msg, gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the state with pending changes.
|
// Update the state with pending changes.
|
||||||
var root []byte
|
var root []byte
|
||||||
if evm.ChainConfig().IsByzantium(blockNumber) {
|
if evm.ChainConfig().IsByzantium(blockNumber) {
|
||||||
|
|
@ -221,9 +213,7 @@ func ApplyTransaction(evm *vm.EVM, gp *GasPool, statedb *state.StateDB, header *
|
||||||
// contract. This method is exported to be used in tests.
|
// contract. This method is exported to be used in tests.
|
||||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
|
func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
|
||||||
if tracer := evm.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStart != nil {
|
onSystemCallStart(tracer, evm.GetVMContext())
|
||||||
tracer.OnSystemCallStart()
|
|
||||||
}
|
|
||||||
if tracer.OnSystemCallEnd != nil {
|
if tracer.OnSystemCallEnd != nil {
|
||||||
defer tracer.OnSystemCallEnd()
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
|
|
@ -247,9 +237,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) {
|
||||||
// as per EIP-2935.
|
// as per EIP-2935.
|
||||||
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
|
func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
|
||||||
if tracer := evm.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStart != nil {
|
onSystemCallStart(tracer, evm.GetVMContext())
|
||||||
tracer.OnSystemCallStart()
|
|
||||||
}
|
|
||||||
if tracer.OnSystemCallEnd != nil {
|
if tracer.OnSystemCallEnd != nil {
|
||||||
defer tracer.OnSystemCallEnd()
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
|
|
@ -271,21 +259,19 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) {
|
||||||
|
|
||||||
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
|
// ProcessWithdrawalQueue calls the EIP-7002 withdrawal queue contract.
|
||||||
// It returns the opaque request data returned by the contract.
|
// It returns the opaque request data returned by the contract.
|
||||||
func ProcessWithdrawalQueue(evm *vm.EVM) []byte {
|
func ProcessWithdrawalQueue(requests *[][]byte, evm *vm.EVM) {
|
||||||
return processRequestsSystemCall(evm, 0x01, params.WithdrawalQueueAddress)
|
processRequestsSystemCall(requests, evm, 0x01, params.WithdrawalQueueAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
|
// ProcessConsolidationQueue calls the EIP-7251 consolidation queue contract.
|
||||||
// It returns the opaque request data returned by the contract.
|
// It returns the opaque request data returned by the contract.
|
||||||
func ProcessConsolidationQueue(evm *vm.EVM) []byte {
|
func ProcessConsolidationQueue(requests *[][]byte, evm *vm.EVM) {
|
||||||
return processRequestsSystemCall(evm, 0x02, params.ConsolidationQueueAddress)
|
processRequestsSystemCall(requests, evm, 0x02, params.ConsolidationQueueAddress)
|
||||||
}
|
}
|
||||||
|
|
||||||
func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Address) []byte {
|
func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte, addr common.Address) {
|
||||||
if tracer := evm.Config.Tracer; tracer != nil {
|
if tracer := evm.Config.Tracer; tracer != nil {
|
||||||
if tracer.OnSystemCallStart != nil {
|
onSystemCallStart(tracer, evm.GetVMContext())
|
||||||
tracer.OnSystemCallStart()
|
|
||||||
}
|
|
||||||
if tracer.OnSystemCallEnd != nil {
|
if tracer.OnSystemCallEnd != nil {
|
||||||
defer tracer.OnSystemCallEnd()
|
defer tracer.OnSystemCallEnd()
|
||||||
}
|
}
|
||||||
|
|
@ -302,26 +288,40 @@ func processRequestsSystemCall(evm *vm.EVM, requestType byte, addr common.Addres
|
||||||
evm.StateDB.AddAddressToAccessList(addr)
|
evm.StateDB.AddAddressToAccessList(addr)
|
||||||
ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
ret, _, _ := evm.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
evm.StateDB.Finalise(true)
|
evm.StateDB.Finalise(true)
|
||||||
|
if len(ret) == 0 {
|
||||||
|
return // skip empty output
|
||||||
|
}
|
||||||
|
|
||||||
// Create withdrawals requestsData with prefix 0x01
|
// Append prefixed requestsData to the requests list.
|
||||||
requestsData := make([]byte, len(ret)+1)
|
requestsData := make([]byte, len(ret)+1)
|
||||||
requestsData[0] = requestType
|
requestsData[0] = requestType
|
||||||
copy(requestsData[1:], ret)
|
copy(requestsData[1:], ret)
|
||||||
return requestsData
|
*requests = append(*requests, requestsData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
// ParseDepositLogs extracts the EIP-6110 deposit values from logs emitted by
|
||||||
// BeaconDepositContract.
|
// BeaconDepositContract.
|
||||||
func ParseDepositLogs(logs []*types.Log, config *params.ChainConfig) ([]byte, error) {
|
func ParseDepositLogs(requests *[][]byte, logs []*types.Log, config *params.ChainConfig) error {
|
||||||
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
|
deposits := make([]byte, 1) // note: first byte is 0x00 (== deposit request type)
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
if log.Address == config.DepositContractAddress {
|
if log.Address == config.DepositContractAddress {
|
||||||
request, err := types.DepositLogToRequest(log.Data)
|
request, err := types.DepositLogToRequest(log.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("unable to parse deposit data: %v", err)
|
return fmt.Errorf("unable to parse deposit data: %v", err)
|
||||||
}
|
}
|
||||||
deposits = append(deposits, request...)
|
deposits = append(deposits, request...)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return deposits, nil
|
if len(deposits) > 1 {
|
||||||
|
*requests = append(*requests, deposits)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) {
|
||||||
|
if tracer.OnSystemCallStartV2 != nil {
|
||||||
|
tracer.OnSystemCallStartV2(ctx)
|
||||||
|
} else if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,10 +187,11 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
|
||||||
// indicates a core error meaning that the message would always fail for that particular
|
// indicates a core error meaning that the message would always fail for that particular
|
||||||
// state and would never be accepted within a block.
|
// state and would never be accepted within a block.
|
||||||
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, error) {
|
||||||
return NewStateTransition(evm, msg, gp).TransitionDb()
|
evm.SetTxContext(NewEVMTxContext(msg))
|
||||||
|
return newStateTransition(evm, msg, gp).execute()
|
||||||
}
|
}
|
||||||
|
|
||||||
// StateTransition represents a state transition.
|
// stateTransition represents a state transition.
|
||||||
//
|
//
|
||||||
// == The State Transitioning Model
|
// == The State Transitioning Model
|
||||||
//
|
//
|
||||||
|
|
@ -212,7 +213,7 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err
|
||||||
//
|
//
|
||||||
// 5. Run Script section
|
// 5. Run Script section
|
||||||
// 6. Derive new state root
|
// 6. Derive new state root
|
||||||
type StateTransition struct {
|
type stateTransition struct {
|
||||||
gp *GasPool
|
gp *GasPool
|
||||||
msg *Message
|
msg *Message
|
||||||
gasRemaining uint64
|
gasRemaining uint64
|
||||||
|
|
@ -221,9 +222,9 @@ type StateTransition struct {
|
||||||
evm *vm.EVM
|
evm *vm.EVM
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStateTransition initialises and returns a new state transition object.
|
// newStateTransition initialises and returns a new state transition object.
|
||||||
func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition {
|
func newStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *stateTransition {
|
||||||
return &StateTransition{
|
return &stateTransition{
|
||||||
gp: gp,
|
gp: gp,
|
||||||
evm: evm,
|
evm: evm,
|
||||||
msg: msg,
|
msg: msg,
|
||||||
|
|
@ -232,14 +233,14 @@ func NewStateTransition(evm *vm.EVM, msg *Message, gp *GasPool) *StateTransition
|
||||||
}
|
}
|
||||||
|
|
||||||
// to returns the recipient of the message.
|
// to returns the recipient of the message.
|
||||||
func (st *StateTransition) to() common.Address {
|
func (st *stateTransition) to() common.Address {
|
||||||
if st.msg == nil || st.msg.To == nil /* contract creation */ {
|
if st.msg == nil || st.msg.To == nil /* contract creation */ {
|
||||||
return common.Address{}
|
return common.Address{}
|
||||||
}
|
}
|
||||||
return *st.msg.To
|
return *st.msg.To
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) buyGas() error {
|
func (st *stateTransition) buyGas() error {
|
||||||
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
mgval := new(big.Int).SetUint64(st.msg.GasLimit)
|
||||||
mgval.Mul(mgval, st.msg.GasPrice)
|
mgval.Mul(mgval, st.msg.GasPrice)
|
||||||
balanceCheck := new(big.Int).Set(mgval)
|
balanceCheck := new(big.Int).Set(mgval)
|
||||||
|
|
@ -283,7 +284,7 @@ func (st *StateTransition) buyGas() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) preCheck() error {
|
func (st *stateTransition) preCheck() error {
|
||||||
// Only check transactions that are not fake
|
// Only check transactions that are not fake
|
||||||
msg := st.msg
|
msg := st.msg
|
||||||
if !msg.SkipNonceChecks {
|
if !msg.SkipNonceChecks {
|
||||||
|
|
@ -368,7 +369,7 @@ func (st *StateTransition) preCheck() error {
|
||||||
return st.buyGas()
|
return st.buyGas()
|
||||||
}
|
}
|
||||||
|
|
||||||
// TransitionDb will transition the state by applying the current message and
|
// execute will transition the state by applying the current message and
|
||||||
// returning the evm execution result with following fields.
|
// returning the evm execution result with following fields.
|
||||||
//
|
//
|
||||||
// - used gas: total gas used (including gas being refunded)
|
// - used gas: total gas used (including gas being refunded)
|
||||||
|
|
@ -378,7 +379,7 @@ func (st *StateTransition) preCheck() error {
|
||||||
//
|
//
|
||||||
// However if any consensus issue encountered, return the error directly with
|
// However if any consensus issue encountered, return the error directly with
|
||||||
// nil evm execution result.
|
// nil evm execution result.
|
||||||
func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
func (st *stateTransition) execute() (*ExecutionResult, error) {
|
||||||
// First check this message satisfies all consensus rules before
|
// First check this message satisfies all consensus rules before
|
||||||
// applying the message. The rules include these clauses
|
// applying the message. The rules include these clauses
|
||||||
//
|
//
|
||||||
|
|
@ -493,7 +494,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
|
func (st *stateTransition) refundGas(refundQuotient uint64) uint64 {
|
||||||
// Apply refund counter, capped to a refund quotient
|
// Apply refund counter, capped to a refund quotient
|
||||||
refund := st.gasUsed() / refundQuotient
|
refund := st.gasUsed() / refundQuotient
|
||||||
if refund > st.state.GetRefund() {
|
if refund > st.state.GetRefund() {
|
||||||
|
|
@ -523,11 +524,11 @@ func (st *StateTransition) refundGas(refundQuotient uint64) uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// gasUsed returns the amount of gas used up by the state transition.
|
// gasUsed returns the amount of gas used up by the state transition.
|
||||||
func (st *StateTransition) gasUsed() uint64 {
|
func (st *stateTransition) gasUsed() uint64 {
|
||||||
return st.initialGas - st.gasRemaining
|
return st.initialGas - st.gasRemaining
|
||||||
}
|
}
|
||||||
|
|
||||||
// blobGasUsed returns the amount of blob gas used by the message.
|
// blobGasUsed returns the amount of blob gas used by the message.
|
||||||
func (st *StateTransition) blobGasUsed() uint64 {
|
func (st *stateTransition) blobGasUsed() uint64 {
|
||||||
return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob)
|
return uint64(len(st.msg.BlobHashes) * params.BlobTxBlobGasPerBlob)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ import (
|
||||||
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
// - It cannot be placed outside of core, because it needs to construct a dud headerchain
|
||||||
//
|
//
|
||||||
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
// TODO(karalabe): Would be nice to resolve both issues above somehow and move it.
|
||||||
func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
func ExecuteStateless(config *params.ChainConfig, vmconfig vm.Config, block *types.Block, witness *stateless.Witness) (common.Hash, common.Hash, error) {
|
||||||
// Sanity check if the supplied block accidentally contains a set root or
|
// Sanity check if the supplied block accidentally contains a set root or
|
||||||
// receipt hash. If so, be very loud, but still continue.
|
// receipt hash. If so, be very loud, but still continue.
|
||||||
if block.Root() != (common.Hash{}) {
|
if block.Root() != (common.Hash{}) {
|
||||||
|
|
@ -66,7 +66,7 @@ func ExecuteStateless(config *params.ChainConfig, block *types.Block, witness *s
|
||||||
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
validator := NewBlockValidator(config, nil) // No chain, we only validate the state, not the block
|
||||||
|
|
||||||
// Run the stateless blocks processing and self-validate certain fields
|
// Run the stateless blocks processing and self-validate certain fields
|
||||||
res, err := processor.Process(block, db, vm.Config{})
|
res, err := processor.Process(block, db, vmconfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return common.Hash{}, common.Hash{}, err
|
return common.Hash{}, common.Hash{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,8 @@ type VMContext struct {
|
||||||
BlockNumber *big.Int
|
BlockNumber *big.Int
|
||||||
Time uint64
|
Time uint64
|
||||||
Random *common.Hash
|
Random *common.Hash
|
||||||
// Effective tx gas price
|
BaseFee *big.Int
|
||||||
GasPrice *big.Int
|
StateDB StateDB
|
||||||
StateDB StateDB
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockEvent is emitted upon tracing an incoming block.
|
// BlockEvent is emitted upon tracing an incoming block.
|
||||||
|
|
@ -146,6 +145,10 @@ type (
|
||||||
// will not be invoked.
|
// will not be invoked.
|
||||||
OnSystemCallStartHook = func()
|
OnSystemCallStartHook = func()
|
||||||
|
|
||||||
|
// OnSystemCallStartHookV2 is called when a system call is about to be executed. Refer
|
||||||
|
// to `OnSystemCallStartHook` for more information.
|
||||||
|
OnSystemCallStartHookV2 = func(vm *VMContext)
|
||||||
|
|
||||||
// OnSystemCallEndHook is called when a system call has finished executing. Today,
|
// OnSystemCallEndHook is called when a system call has finished executing. Today,
|
||||||
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
|
// this hook is invoked when the EIP-4788 system call is about to be executed to set the
|
||||||
// beacon block root.
|
// beacon block root.
|
||||||
|
|
@ -181,14 +184,15 @@ type Hooks struct {
|
||||||
OnFault FaultHook
|
OnFault FaultHook
|
||||||
OnGasChange GasChangeHook
|
OnGasChange GasChangeHook
|
||||||
// Chain events
|
// Chain events
|
||||||
OnBlockchainInit BlockchainInitHook
|
OnBlockchainInit BlockchainInitHook
|
||||||
OnClose CloseHook
|
OnClose CloseHook
|
||||||
OnBlockStart BlockStartHook
|
OnBlockStart BlockStartHook
|
||||||
OnBlockEnd BlockEndHook
|
OnBlockEnd BlockEndHook
|
||||||
OnSkippedBlock SkippedBlockHook
|
OnSkippedBlock SkippedBlockHook
|
||||||
OnGenesisBlock GenesisBlockHook
|
OnGenesisBlock GenesisBlockHook
|
||||||
OnSystemCallStart OnSystemCallStartHook
|
OnSystemCallStart OnSystemCallStartHook
|
||||||
OnSystemCallEnd OnSystemCallEndHook
|
OnSystemCallStartV2 OnSystemCallStartHookV2
|
||||||
|
OnSystemCallEnd OnSystemCallEndHook
|
||||||
// State events
|
// State events
|
||||||
OnBalanceChange BalanceChangeHook
|
OnBalanceChange BalanceChangeHook
|
||||||
OnNonceChange NonceChangeHook
|
OnNonceChange NonceChangeHook
|
||||||
|
|
|
||||||
|
|
@ -463,9 +463,11 @@ func CalcRequestsHash(requests [][]byte) common.Hash {
|
||||||
h1, h2 := sha256.New(), sha256.New()
|
h1, h2 := sha256.New(), sha256.New()
|
||||||
var buf common.Hash
|
var buf common.Hash
|
||||||
for _, item := range requests {
|
for _, item := range requests {
|
||||||
h1.Reset()
|
if len(item) > 1 { // skip items with only requestType and no data.
|
||||||
h1.Write(item)
|
h1.Reset()
|
||||||
h2.Write(h1.Sum(buf[:0]))
|
h1.Write(item)
|
||||||
|
h2.Write(h1.Sum(buf[:0]))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
h2.Sum(buf[:0])
|
h2.Sum(buf[:0])
|
||||||
return buf
|
return buf
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ var (
|
||||||
// EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
|
// EmptyWithdrawalsHash is the known hash of the empty withdrawal set.
|
||||||
EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
EmptyWithdrawalsHash = common.HexToHash("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421")
|
||||||
|
|
||||||
|
// EmptyRequestsHash is the known hash of an empty request set, sha256("").
|
||||||
|
EmptyRequestsHash = common.HexToHash("e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
|
||||||
|
|
||||||
// EmptyVerkleHash is the known hash of an empty verkle trie.
|
// EmptyVerkleHash is the known hash of an empty verkle trie.
|
||||||
EmptyVerkleHash = common.Hash{}
|
EmptyVerkleHash = common.Hash{}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -605,7 +605,7 @@ func (evm *EVM) GetVMContext() *tracing.VMContext {
|
||||||
BlockNumber: evm.Context.BlockNumber,
|
BlockNumber: evm.Context.BlockNumber,
|
||||||
Time: evm.Context.Time,
|
Time: evm.Context.Time,
|
||||||
Random: evm.Context.Random,
|
Random: evm.Context.Random,
|
||||||
GasPrice: evm.TxContext.GasPrice,
|
BaseFee: evm.Context.BaseFee,
|
||||||
StateDB: evm.StateDB,
|
StateDB: evm.StateDB,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/asm"
|
"github.com/ethereum/go-ethereum/core/asm"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/core/vm/program"
|
"github.com/ethereum/go-ethereum/core/vm/program"
|
||||||
|
|
@ -670,17 +671,23 @@ func TestColdAccountAccessCost(t *testing.T) {
|
||||||
want: 7600,
|
want: 7600,
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
tracer := logger.NewStructLogger(nil)
|
var step = 0
|
||||||
|
var have = uint64(0)
|
||||||
Execute(tc.code, nil, &Config{
|
Execute(tc.code, nil, &Config{
|
||||||
EVMConfig: vm.Config{
|
EVMConfig: vm.Config{
|
||||||
Tracer: tracer.Hooks(),
|
Tracer: &tracing.Hooks{
|
||||||
|
OnOpcode: func(pc uint64, op byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||||
|
// Uncomment to investigate failures:
|
||||||
|
//t.Logf("%d: %v %d", step, vm.OpCode(op).String(), cost)
|
||||||
|
if step == tc.step {
|
||||||
|
have = cost
|
||||||
|
}
|
||||||
|
step++
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
have := tracer.StructLogs()[tc.step].GasCost
|
|
||||||
if want := tc.want; have != want {
|
if want := tc.want; have != want {
|
||||||
for ii, op := range tracer.StructLogs() {
|
|
||||||
t.Logf("%d: %v %d", ii, op.OpName(), op.GasCost)
|
|
||||||
}
|
|
||||||
t.Fatalf("testcase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want)
|
t.Fatalf("testcase %d, gas report wrong, step %d, have %d want %d", i, tc.step, have, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -424,17 +424,17 @@ func (s *Ethereum) Stop() error {
|
||||||
|
|
||||||
// SyncMode retrieves the current sync mode, either explicitly set, or derived
|
// SyncMode retrieves the current sync mode, either explicitly set, or derived
|
||||||
// from the chain status.
|
// from the chain status.
|
||||||
func (s *Ethereum) SyncMode() downloader.SyncMode {
|
func (s *Ethereum) SyncMode() ethconfig.SyncMode {
|
||||||
// If we're in snap sync mode, return that directly
|
// If we're in snap sync mode, return that directly
|
||||||
if s.handler.snapSync.Load() {
|
if s.handler.snapSync.Load() {
|
||||||
return downloader.SnapSync
|
return ethconfig.SnapSync
|
||||||
}
|
}
|
||||||
// We are probably in full sync, but we might have rewound to before the
|
// We are probably in full sync, but we might have rewound to before the
|
||||||
// snap sync pivot, check if we should re-enable snap sync.
|
// snap sync pivot, check if we should re-enable snap sync.
|
||||||
head := s.blockchain.CurrentBlock()
|
head := s.blockchain.CurrentBlock()
|
||||||
if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil {
|
if pivot := rawdb.ReadLastPivotNumber(s.chainDb); pivot != nil {
|
||||||
if head.Number.Uint64() < *pivot {
|
if head.Number.Uint64() < *pivot {
|
||||||
return downloader.SnapSync
|
return ethconfig.SnapSync
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We are in a full sync, but the associated head state is missing. To complete
|
// We are in a full sync, but the associated head state is missing. To complete
|
||||||
|
|
@ -442,8 +442,8 @@ func (s *Ethereum) SyncMode() downloader.SyncMode {
|
||||||
// persistent state is corrupted, just mismatch with the head block.
|
// persistent state is corrupted, just mismatch with the head block.
|
||||||
if !s.blockchain.HasState(head.Root) {
|
if !s.blockchain.HasState(head.Root) {
|
||||||
log.Info("Reenabled snap sync as chain is stateless")
|
log.Info("Reenabled snap sync as chain is stateless")
|
||||||
return downloader.SnapSync
|
return ethconfig.SnapSync
|
||||||
}
|
}
|
||||||
// Nope, we're really full syncing
|
// Nope, we're really full syncing
|
||||||
return downloader.FullSync
|
return ethconfig.FullSync
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,9 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/stateless"
|
"github.com/ethereum/go-ethereum/core/stateless"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
|
@ -917,7 +918,7 @@ func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashe
|
||||||
// tries to make it import a block. That should be denied as pushing something
|
// tries to make it import a block. That should be denied as pushing something
|
||||||
// into the database directly will conflict with the assumptions of snap sync
|
// into the database directly will conflict with the assumptions of snap sync
|
||||||
// that it has an empty db that it can fill itself.
|
// that it has an empty db that it can fill itself.
|
||||||
if api.eth.SyncMode() != downloader.FullSync {
|
if api.eth.SyncMode() != ethconfig.FullSync {
|
||||||
return api.delayPayloadImport(block), nil
|
return api.delayPayloadImport(block), nil
|
||||||
}
|
}
|
||||||
if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
if !api.eth.BlockChain().HasBlockAndState(block.ParentHash(), block.NumberU64()-1) {
|
||||||
|
|
@ -995,7 +996,7 @@ func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, v
|
||||||
api.lastNewPayloadLock.Unlock()
|
api.lastNewPayloadLock.Unlock()
|
||||||
|
|
||||||
log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash)
|
log.Trace("Executing block statelessly", "number", block.Number(), "hash", params.BlockHash)
|
||||||
stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), block, witness)
|
stateRoot, receiptRoot, err := core.ExecuteStateless(api.eth.BlockChain().Config(), vm.Config{}, block, witness)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warn("ExecuteStatelessPayload: execution failed", "err", err)
|
log.Warn("ExecuteStatelessPayload: execution failed", "err", err)
|
||||||
errorMsg := err.Error()
|
errorMsg := err.Error()
|
||||||
|
|
@ -1030,7 +1031,7 @@ func (api *ConsensusAPI) delayPayloadImport(block *types.Block) engine.PayloadSt
|
||||||
// payload as non-integratable on top of the existing sync. We'll just
|
// payload as non-integratable on top of the existing sync. We'll just
|
||||||
// have to rely on the beacon client to forcefully update the head with
|
// have to rely on the beacon client to forcefully update the head with
|
||||||
// a forkchoice update request.
|
// a forkchoice update request.
|
||||||
if api.eth.SyncMode() == downloader.FullSync {
|
if api.eth.SyncMode() == ethconfig.FullSync {
|
||||||
// In full sync mode, failure to import a well-formed block can only mean
|
// In full sync mode, failure to import a well-formed block can only mean
|
||||||
// that the parent state is missing and the syncer rejected extending the
|
// that the parent state is missing and the syncer rejected extending the
|
||||||
// current cycle with the new payload.
|
// current cycle with the new payload.
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/internal/version"
|
"github.com/ethereum/go-ethereum/internal/version"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
|
|
@ -452,7 +451,7 @@ func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block)
|
||||||
}
|
}
|
||||||
|
|
||||||
mcfg := miner.DefaultConfig
|
mcfg := miner.DefaultConfig
|
||||||
ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: mcfg}
|
ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: ethconfig.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: mcfg}
|
||||||
ethservice, err := eth.New(n, ethcfg)
|
ethservice, err := eth.New(n, ethcfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("can't create eth service:", err)
|
t.Fatal("can't create eth service:", err)
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
|
|
@ -49,7 +48,7 @@ func startSimulatedBeaconEthService(t *testing.T, genesis *core.Genesis, period
|
||||||
t.Fatal("can't create node:", err)
|
t.Fatal("can't create node:", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: miner.DefaultConfig}
|
ethcfg := ðconfig.Config{Genesis: genesis, SyncMode: ethconfig.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256, Miner: miner.DefaultConfig}
|
||||||
ethservice, err := eth.New(n, ethcfg)
|
ethservice, err := eth.New(n, ethcfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("can't create eth service:", err)
|
t.Fatal("can't create eth service:", err)
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ import (
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/node"
|
"github.com/ethereum/go-ethereum/node"
|
||||||
)
|
)
|
||||||
|
|
@ -62,7 +62,7 @@ func (tester *FullSyncTester) Start() error {
|
||||||
|
|
||||||
// Trigger beacon sync with the provided block hash as trusted
|
// Trigger beacon sync with the provided block hash as trusted
|
||||||
// chain head.
|
// chain head.
|
||||||
err := tester.backend.Downloader().BeaconDevSync(downloader.FullSync, tester.target, tester.closed)
|
err := tester.backend.Downloader().BeaconDevSync(ethconfig.FullSync, tester.target, tester.closed)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Info("Failed to trigger beacon sync", "err", err)
|
log.Info("Failed to trigger beacon sync", "err", err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -198,9 +199,9 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
||||||
var chainHead *types.Header
|
var chainHead *types.Header
|
||||||
|
|
||||||
switch d.getMode() {
|
switch d.getMode() {
|
||||||
case FullSync:
|
case ethconfig.FullSync:
|
||||||
chainHead = d.blockchain.CurrentBlock()
|
chainHead = d.blockchain.CurrentBlock()
|
||||||
case SnapSync:
|
case ethconfig.SnapSync:
|
||||||
chainHead = d.blockchain.CurrentSnapBlock()
|
chainHead = d.blockchain.CurrentSnapBlock()
|
||||||
default:
|
default:
|
||||||
panic("unknown sync mode")
|
panic("unknown sync mode")
|
||||||
|
|
@ -218,9 +219,9 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
||||||
}
|
}
|
||||||
var linked bool
|
var linked bool
|
||||||
switch d.getMode() {
|
switch d.getMode() {
|
||||||
case FullSync:
|
case ethconfig.FullSync:
|
||||||
linked = d.blockchain.HasBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
linked = d.blockchain.HasBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
||||||
case SnapSync:
|
case ethconfig.SnapSync:
|
||||||
linked = d.blockchain.HasFastBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
linked = d.blockchain.HasFastBlock(beaconTail.ParentHash, beaconTail.Number.Uint64()-1)
|
||||||
default:
|
default:
|
||||||
panic("unknown sync mode")
|
panic("unknown sync mode")
|
||||||
|
|
@ -253,9 +254,9 @@ func (d *Downloader) findBeaconAncestor() (uint64, error) {
|
||||||
|
|
||||||
var known bool
|
var known bool
|
||||||
switch d.getMode() {
|
switch d.getMode() {
|
||||||
case FullSync:
|
case ethconfig.FullSync:
|
||||||
known = d.blockchain.HasBlock(h.Hash(), n)
|
known = d.blockchain.HasBlock(h.Hash(), n)
|
||||||
case SnapSync:
|
case ethconfig.SnapSync:
|
||||||
known = d.blockchain.HasFastBlock(h.Hash(), n)
|
known = d.blockchain.HasFastBlock(h.Hash(), n)
|
||||||
default:
|
default:
|
||||||
panic("unknown sync mode")
|
panic("unknown sync mode")
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
"github.com/ethereum/go-ethereum/core/state/snapshot"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
|
|
@ -69,6 +70,17 @@ var (
|
||||||
errNoPivotHeader = errors.New("pivot header is not found")
|
errNoPivotHeader = errors.New("pivot header is not found")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// SyncMode defines the sync method of the downloader.
|
||||||
|
// Deprecated: use ethconfig.SyncMode instead
|
||||||
|
type SyncMode = ethconfig.SyncMode
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Deprecated: use ethconfig.FullSync
|
||||||
|
FullSync = ethconfig.FullSync
|
||||||
|
// Deprecated: use ethconfig.SnapSync
|
||||||
|
SnapSync = ethconfig.SnapSync
|
||||||
|
)
|
||||||
|
|
||||||
// peerDropFn is a callback type for dropping a peer detected as malicious.
|
// peerDropFn is a callback type for dropping a peer detected as malicious.
|
||||||
type peerDropFn func(id string)
|
type peerDropFn func(id string)
|
||||||
|
|
||||||
|
|
@ -230,9 +242,9 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
||||||
current := uint64(0)
|
current := uint64(0)
|
||||||
mode := d.getMode()
|
mode := d.getMode()
|
||||||
switch mode {
|
switch mode {
|
||||||
case FullSync:
|
case ethconfig.FullSync:
|
||||||
current = d.blockchain.CurrentBlock().Number.Uint64()
|
current = d.blockchain.CurrentBlock().Number.Uint64()
|
||||||
case SnapSync:
|
case ethconfig.SnapSync:
|
||||||
current = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
current = d.blockchain.CurrentSnapBlock().Number.Uint64()
|
||||||
default:
|
default:
|
||||||
log.Error("Unknown downloader mode", "mode", mode)
|
log.Error("Unknown downloader mode", "mode", mode)
|
||||||
|
|
@ -326,7 +338,7 @@ func (d *Downloader) synchronise(mode SyncMode, beaconPing chan struct{}) error
|
||||||
if d.notified.CompareAndSwap(false, true) {
|
if d.notified.CompareAndSwap(false, true) {
|
||||||
log.Info("Block synchronisation started")
|
log.Info("Block synchronisation started")
|
||||||
}
|
}
|
||||||
if mode == SnapSync {
|
if mode == ethconfig.SnapSync {
|
||||||
// Snap sync will directly modify the persistent state, making the entire
|
// Snap sync will directly modify the persistent state, making the entire
|
||||||
// trie database unusable until the state is fully synced. To prevent any
|
// trie database unusable until the state is fully synced. To prevent any
|
||||||
// subsequent state reads, explicitly disable the trie database and state
|
// subsequent state reads, explicitly disable the trie database and state
|
||||||
|
|
@ -434,7 +446,7 @@ func (d *Downloader) syncToHead() (err error) {
|
||||||
// threshold (i.e. new chain). In that case we won't really snap sync
|
// threshold (i.e. new chain). In that case we won't really snap sync
|
||||||
// anyway, but still need a valid pivot block to avoid some code hitting
|
// anyway, but still need a valid pivot block to avoid some code hitting
|
||||||
// nil panics on access.
|
// nil panics on access.
|
||||||
if mode == SnapSync && pivot == nil {
|
if mode == ethconfig.SnapSync && pivot == nil {
|
||||||
pivot = d.blockchain.CurrentBlock()
|
pivot = d.blockchain.CurrentBlock()
|
||||||
}
|
}
|
||||||
height := latest.Number.Uint64()
|
height := latest.Number.Uint64()
|
||||||
|
|
@ -452,7 +464,7 @@ func (d *Downloader) syncToHead() (err error) {
|
||||||
d.syncStatsLock.Unlock()
|
d.syncStatsLock.Unlock()
|
||||||
|
|
||||||
// Ensure our origin point is below any snap sync pivot point
|
// Ensure our origin point is below any snap sync pivot point
|
||||||
if mode == SnapSync {
|
if mode == ethconfig.SnapSync {
|
||||||
if height <= uint64(fsMinFullBlocks) {
|
if height <= uint64(fsMinFullBlocks) {
|
||||||
origin = 0
|
origin = 0
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -466,10 +478,10 @@ func (d *Downloader) syncToHead() (err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
d.committed.Store(true)
|
d.committed.Store(true)
|
||||||
if mode == SnapSync && pivot.Number.Uint64() != 0 {
|
if mode == ethconfig.SnapSync && pivot.Number.Uint64() != 0 {
|
||||||
d.committed.Store(false)
|
d.committed.Store(false)
|
||||||
}
|
}
|
||||||
if mode == SnapSync {
|
if mode == ethconfig.SnapSync {
|
||||||
// Set the ancient data limitation. If we are running snap sync, all block
|
// Set the ancient data limitation. If we are running snap sync, all block
|
||||||
// data older than ancientLimit will be written to the ancient store. More
|
// data older than ancientLimit will be written to the ancient store. More
|
||||||
// recent data will be written to the active database and will wait for the
|
// recent data will be written to the active database and will wait for the
|
||||||
|
|
@ -523,13 +535,13 @@ func (d *Downloader) syncToHead() (err error) {
|
||||||
func() error { return d.fetchReceipts(origin + 1) }, // Receipts are retrieved during snap sync
|
func() error { return d.fetchReceipts(origin + 1) }, // Receipts are retrieved during snap sync
|
||||||
func() error { return d.processHeaders(origin + 1) },
|
func() error { return d.processHeaders(origin + 1) },
|
||||||
}
|
}
|
||||||
if mode == SnapSync {
|
if mode == ethconfig.SnapSync {
|
||||||
d.pivotLock.Lock()
|
d.pivotLock.Lock()
|
||||||
d.pivotHeader = pivot
|
d.pivotHeader = pivot
|
||||||
d.pivotLock.Unlock()
|
d.pivotLock.Unlock()
|
||||||
|
|
||||||
fetchers = append(fetchers, func() error { return d.processSnapSyncContent() })
|
fetchers = append(fetchers, func() error { return d.processSnapSyncContent() })
|
||||||
} else if mode == FullSync {
|
} else if mode == ethconfig.FullSync {
|
||||||
fetchers = append(fetchers, func() error { return d.processFullSyncContent() })
|
fetchers = append(fetchers, func() error { return d.processFullSyncContent() })
|
||||||
}
|
}
|
||||||
return d.spawnSync(fetchers)
|
return d.spawnSync(fetchers)
|
||||||
|
|
@ -676,7 +688,7 @@ func (d *Downloader) processHeaders(origin uint64) error {
|
||||||
chunkHashes := hashes[:limit]
|
chunkHashes := hashes[:limit]
|
||||||
|
|
||||||
// In case of header only syncing, validate the chunk immediately
|
// In case of header only syncing, validate the chunk immediately
|
||||||
if mode == SnapSync {
|
if mode == ethconfig.SnapSync {
|
||||||
// Although the received headers might be all valid, a legacy
|
// Although the received headers might be all valid, a legacy
|
||||||
// PoW/PoA sync must not accept post-merge headers. Make sure
|
// PoW/PoA sync must not accept post-merge headers. Make sure
|
||||||
// that any transition is rejected at this point.
|
// that any transition is rejected at this point.
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/common/prque"
|
"github.com/ethereum/go-ethereum/common/prque"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -180,7 +181,7 @@ func (q *queue) Reset(blockCacheLimit int, thresholdInitialSize int) {
|
||||||
defer q.lock.Unlock()
|
defer q.lock.Unlock()
|
||||||
|
|
||||||
q.closed = false
|
q.closed = false
|
||||||
q.mode = FullSync
|
q.mode = ethconfig.FullSync
|
||||||
|
|
||||||
q.headerHead = common.Hash{}
|
q.headerHead = common.Hash{}
|
||||||
q.headerPendPool = make(map[string]*fetchRequest)
|
q.headerPendPool = make(map[string]*fetchRequest)
|
||||||
|
|
@ -328,7 +329,7 @@ func (q *queue) Schedule(headers []*types.Header, hashes []common.Hash, from uin
|
||||||
q.blockTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
q.blockTaskQueue.Push(header, -int64(header.Number.Uint64()))
|
||||||
}
|
}
|
||||||
// Queue for receipt retrieval
|
// Queue for receipt retrieval
|
||||||
if q.mode == SnapSync && !header.EmptyReceipts() {
|
if q.mode == ethconfig.SnapSync && !header.EmptyReceipts() {
|
||||||
if _, ok := q.receiptTaskPool[hash]; ok {
|
if _, ok := q.receiptTaskPool[hash]; ok {
|
||||||
log.Warn("Header already scheduled for receipt fetch", "number", header.Number, "hash", hash)
|
log.Warn("Header already scheduled for receipt fetch", "number", header.Number, "hash", hash)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -523,7 +524,7 @@ func (q *queue) reserveHeaders(p *peerConnection, count int, taskPool map[common
|
||||||
// we can ask the resultcache if this header is within the
|
// we can ask the resultcache if this header is within the
|
||||||
// "prioritized" segment of blocks. If it is not, we need to throttle
|
// "prioritized" segment of blocks. If it is not, we need to throttle
|
||||||
|
|
||||||
stale, throttle, item, err := q.resultCache.AddFetch(header, q.mode == SnapSync)
|
stale, throttle, item, err := q.resultCache.AddFetch(header, q.mode == ethconfig.SnapSync)
|
||||||
if stale {
|
if stale {
|
||||||
// Don't put back in the task queue, this item has already been
|
// Don't put back in the task queue, this item has already been
|
||||||
// delivered upstream
|
// delivered upstream
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
|
@ -49,7 +48,7 @@ var FullNodeGPO = gasprice.Config{
|
||||||
|
|
||||||
// Defaults contains default settings for use on the Ethereum main net.
|
// Defaults contains default settings for use on the Ethereum main net.
|
||||||
var Defaults = Config{
|
var Defaults = Config{
|
||||||
SyncMode: downloader.SnapSync,
|
SyncMode: SnapSync,
|
||||||
NetworkId: 0, // enable auto configuration of networkID == chainID
|
NetworkId: 0, // enable auto configuration of networkID == chainID
|
||||||
TxLookupLimit: 2350000,
|
TxLookupLimit: 2350000,
|
||||||
TransactionHistory: 2350000,
|
TransactionHistory: 2350000,
|
||||||
|
|
@ -80,7 +79,7 @@ type Config struct {
|
||||||
// Network ID separates blockchains on the peer-to-peer networking level. When left
|
// Network ID separates blockchains on the peer-to-peer networking level. When left
|
||||||
// zero, the chain ID is used as network ID.
|
// zero, the chain ID is used as network ID.
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
SyncMode downloader.SyncMode
|
SyncMode SyncMode
|
||||||
|
|
||||||
// This can be set to list of enrtree:// URLs which will be queried for
|
// This can be set to list of enrtree:// URLs which will be queried for
|
||||||
// nodes to connect to.
|
// nodes to connect to.
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/gasprice"
|
"github.com/ethereum/go-ethereum/eth/gasprice"
|
||||||
"github.com/ethereum/go-ethereum/miner"
|
"github.com/ethereum/go-ethereum/miner"
|
||||||
)
|
)
|
||||||
|
|
@ -19,7 +18,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId uint64
|
NetworkId uint64
|
||||||
SyncMode downloader.SyncMode
|
SyncMode SyncMode
|
||||||
EthDiscoveryURLs []string
|
EthDiscoveryURLs []string
|
||||||
SnapDiscoveryURLs []string
|
SnapDiscoveryURLs []string
|
||||||
NoPruning bool
|
NoPruning bool
|
||||||
|
|
@ -95,7 +94,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Genesis *core.Genesis `toml:",omitempty"`
|
Genesis *core.Genesis `toml:",omitempty"`
|
||||||
NetworkId *uint64
|
NetworkId *uint64
|
||||||
SyncMode *downloader.SyncMode
|
SyncMode *SyncMode
|
||||||
EthDiscoveryURLs []string
|
EthDiscoveryURLs []string
|
||||||
SnapDiscoveryURLs []string
|
SnapDiscoveryURLs []string
|
||||||
NoPruning *bool
|
NoPruning *bool
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
// You should have received a copy of the GNU Lesser General Public License
|
// You should have received a copy of the GNU Lesser General Public License
|
||||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
package downloader
|
package ethconfig
|
||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
|
|
@ -217,21 +217,19 @@ func execute(ctx context.Context, call *core.Message, opts *Options, gasLimit ui
|
||||||
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
|
func run(ctx context.Context, call *core.Message, opts *Options) (*core.ExecutionResult, error) {
|
||||||
// Assemble the call and the call context
|
// Assemble the call and the call context
|
||||||
var (
|
var (
|
||||||
msgContext = core.NewEVMTxContext(call)
|
|
||||||
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
|
evmContext = core.NewEVMBlockContext(opts.Header, opts.Chain, nil)
|
||||||
|
|
||||||
dirtyState = opts.State.Copy()
|
dirtyState = opts.State.Copy()
|
||||||
)
|
)
|
||||||
// Lower the basefee to 0 to avoid breaking EVM
|
// Lower the basefee to 0 to avoid breaking EVM
|
||||||
// invariants (basefee < feecap).
|
// invariants (basefee < feecap).
|
||||||
if msgContext.GasPrice.Sign() == 0 {
|
if call.GasPrice.Sign() == 0 {
|
||||||
evmContext.BaseFee = new(big.Int)
|
evmContext.BaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
if msgContext.BlobFeeCap != nil && msgContext.BlobFeeCap.BitLen() == 0 {
|
if call.BlobGasFeeCap != nil && call.BlobGasFeeCap.BitLen() == 0 {
|
||||||
evmContext.BlobBaseFee = new(big.Int)
|
evmContext.BlobBaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
|
evm := vm.NewEVM(evmContext, dirtyState, opts.Config, vm.Config{NoBaseFee: true})
|
||||||
evm.SetTxContext(msgContext)
|
|
||||||
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
|
// Monitor the outer context and interrupt the EVM upon cancellation. To avoid
|
||||||
// a dangling goroutine until the outer estimation finishes, create an internal
|
// a dangling goroutine until the outer estimation finishes, create an internal
|
||||||
// context for the lifetime of this method call.
|
// context for the lifetime of this method call.
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/fetcher"
|
"github.com/ethereum/go-ethereum/eth/fetcher"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
|
|
@ -87,7 +88,7 @@ type handlerConfig struct {
|
||||||
Chain *core.BlockChain // Blockchain to serve data from
|
Chain *core.BlockChain // Blockchain to serve data from
|
||||||
TxPool txPool // Transaction pool to propagate from
|
TxPool txPool // Transaction pool to propagate from
|
||||||
Network uint64 // Network identifier to advertise
|
Network uint64 // Network identifier to advertise
|
||||||
Sync downloader.SyncMode // Whether to snap or full sync
|
Sync ethconfig.SyncMode // Whether to snap or full sync
|
||||||
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
BloomCache uint64 // Megabytes to alloc for snap sync bloom
|
||||||
EventMux *event.TypeMux // Legacy event mux, deprecate for `feed`
|
EventMux *event.TypeMux // Legacy event mux, deprecate for `feed`
|
||||||
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
RequiredBlocks map[uint64]common.Hash // Hard coded map of required block hashes for sync challenges
|
||||||
|
|
@ -145,7 +146,7 @@ func newHandler(config *handlerConfig) (*handler, error) {
|
||||||
handlerDoneCh: make(chan struct{}),
|
handlerDoneCh: make(chan struct{}),
|
||||||
handlerStartCh: make(chan struct{}),
|
handlerStartCh: make(chan struct{}),
|
||||||
}
|
}
|
||||||
if config.Sync == downloader.FullSync {
|
if config.Sync == ethconfig.FullSync {
|
||||||
// The database seems empty as the current block is the genesis. Yet the snap
|
// The database seems empty as the current block is the genesis. Yet the snap
|
||||||
// block is ahead, so snap sync was enabled for this node at a certain point.
|
// block is ahead, so snap sync was enabled for this node at a certain point.
|
||||||
// The scenarios where this can happen is
|
// The scenarios where this can happen is
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
|
@ -109,7 +109,7 @@ func testForkIDSplit(t *testing.T, protocol uint) {
|
||||||
Chain: chainNoFork,
|
Chain: chainNoFork,
|
||||||
TxPool: newTestTxPool(),
|
TxPool: newTestTxPool(),
|
||||||
Network: 1,
|
Network: 1,
|
||||||
Sync: downloader.FullSync,
|
Sync: ethconfig.FullSync,
|
||||||
BloomCache: 1,
|
BloomCache: 1,
|
||||||
})
|
})
|
||||||
ethProFork, _ = newHandler(&handlerConfig{
|
ethProFork, _ = newHandler(&handlerConfig{
|
||||||
|
|
@ -117,7 +117,7 @@ func testForkIDSplit(t *testing.T, protocol uint) {
|
||||||
Chain: chainProFork,
|
Chain: chainProFork,
|
||||||
TxPool: newTestTxPool(),
|
TxPool: newTestTxPool(),
|
||||||
Network: 1,
|
Network: 1,
|
||||||
Sync: downloader.FullSync,
|
Sync: ethconfig.FullSync,
|
||||||
BloomCache: 1,
|
BloomCache: 1,
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
|
@ -164,7 +164,7 @@ func newTestHandlerWithBlocks(blocks int) *testHandler {
|
||||||
Chain: chain,
|
Chain: chain,
|
||||||
TxPool: txpool,
|
TxPool: txpool,
|
||||||
Network: 1,
|
Network: 1,
|
||||||
Sync: downloader.SnapSync,
|
Sync: ethconfig.SnapSync,
|
||||||
BloomCache: 1,
|
BloomCache: 1,
|
||||||
})
|
})
|
||||||
handler.Start(1000)
|
handler.Start(1000)
|
||||||
|
|
|
||||||
|
|
@ -454,7 +454,7 @@ func ServiceGetByteCodesQuery(chain *core.BlockChain, req *GetByteCodesPacket) [
|
||||||
// Peers should not request the empty code, but if they do, at
|
// Peers should not request the empty code, but if they do, at
|
||||||
// least sent them back a correct response without db lookups
|
// least sent them back a correct response without db lookups
|
||||||
codes = append(codes, []byte{})
|
codes = append(codes, []byte{})
|
||||||
} else if blob, err := chain.ContractCodeWithPrefix(hash); err == nil {
|
} else if blob := chain.ContractCodeWithPrefix(hash); len(blob) > 0 {
|
||||||
codes = append(codes, blob)
|
codes = append(codes, blob)
|
||||||
bytes += uint64(len(blob))
|
bytes += uint64(len(blob))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -255,8 +255,6 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
}
|
}
|
||||||
// Assemble the transaction call message and return if the requested offset
|
// Assemble the transaction call message and return if the requested offset
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
|
|
||||||
// Not yet the searched for transaction, execute on top of the current state
|
// Not yet the searched for transaction, execute on top of the current state
|
||||||
statedb.SetTxContext(tx.Hash(), idx)
|
statedb.SetTxContext(tx.Hash(), idx)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
"github.com/ethereum/go-ethereum/eth/protocols/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
"github.com/ethereum/go-ethereum/eth/protocols/snap"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
|
|
@ -85,7 +85,7 @@ func testSnapSyncDisabling(t *testing.T, ethVer uint, snapVer uint) {
|
||||||
time.Sleep(250 * time.Millisecond)
|
time.Sleep(250 * time.Millisecond)
|
||||||
|
|
||||||
// Check that snap sync was disabled
|
// Check that snap sync was disabled
|
||||||
if err := empty.handler.downloader.BeaconSync(downloader.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()
|
empty.handler.enableSyncedFeatures()
|
||||||
|
|
|
||||||
|
|
@ -546,11 +546,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
var (
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
|
||||||
txContext = core.NewEVMTxContext(msg)
|
|
||||||
)
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
log.Warn("Tracing intermediate roots did not complete", "txindex", i, "txhash", tx.Hash(), "err", err)
|
||||||
|
|
@ -708,7 +704,6 @@ txloop:
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit)); err != nil {
|
||||||
failed = err
|
failed = err
|
||||||
break txloop
|
break txloop
|
||||||
|
|
@ -792,12 +787,11 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the transaction for un-traced execution
|
// Prepare the transaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ = core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext = core.NewEVMTxContext(msg)
|
vmConf vm.Config
|
||||||
vmConf vm.Config
|
dump *os.File
|
||||||
dump *os.File
|
writer *bufio.Writer
|
||||||
writer *bufio.Writer
|
err error
|
||||||
err error
|
|
||||||
)
|
)
|
||||||
// If the transaction needs tracing, swap out the configs
|
// If the transaction needs tracing, swap out the configs
|
||||||
if tx.Hash() == txHash || txHash == (common.Hash{}) {
|
if tx.Hash() == txHash || txHash == (common.Hash{}) {
|
||||||
|
|
@ -820,7 +814,6 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Execute the transaction and flush any traces to disk
|
// Execute the transaction and flush any traces to disk
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
statedb.SetTxContext(tx.Hash(), i)
|
statedb.SetTxContext(tx.Hash(), i)
|
||||||
if vmConf.Tracer.OnTxStart != nil {
|
if vmConf.Tracer.OnTxStart != nil {
|
||||||
vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
vmConf.Tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
|
|
@ -1014,9 +1007,8 @@ func (api *API) traceTx(ctx context.Context, tx *types.Transaction, message *cor
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// The actual TxContext will be created as part of ApplyTransactionWithEVM.
|
tracingStateDB := state.NewHookedState(statedb, tracer.Hooks)
|
||||||
evm := vm.NewEVM(vmctx, statedb, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
evm := vm.NewEVM(vmctx, tracingStateDB, api.backend.ChainConfig(), vm.Config{Tracer: tracer.Hooks, NoBaseFee: true})
|
||||||
evm.SetTxContext(vm.TxContext{GasPrice: message.GasPrice, BlobFeeCap: message.BlobGasFeeCap})
|
|
||||||
|
|
||||||
// Define a meaningful timeout of a single transaction trace
|
// Define a meaningful timeout of a single transaction trace
|
||||||
if config.Timeout != nil {
|
if config.Timeout != nil {
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/state"
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
@ -177,8 +178,6 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
return tx, context, statedb, release, nil
|
return tx, context, statedb, release, nil
|
||||||
}
|
}
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
txContext := core.NewEVMTxContext(msg)
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
if _, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas())); err != nil {
|
||||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction %#x failed: %v", tx.Hash(), err)
|
||||||
}
|
}
|
||||||
|
|
@ -187,6 +186,94 @@ func (b *testBackend) StateAtTransaction(ctx context.Context, block *types.Block
|
||||||
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
return nil, vm.BlockContext{}, nil, nil, fmt.Errorf("transaction index %d out of range for block %#x", txIndex, block.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type stateTracer struct {
|
||||||
|
Balance map[common.Address]*hexutil.Big
|
||||||
|
Nonce map[common.Address]hexutil.Uint64
|
||||||
|
Storage map[common.Address]map[common.Hash]common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func newStateTracer(ctx *Context, cfg json.RawMessage, chainCfg *params.ChainConfig) (*Tracer, error) {
|
||||||
|
t := &stateTracer{
|
||||||
|
Balance: make(map[common.Address]*hexutil.Big),
|
||||||
|
Nonce: make(map[common.Address]hexutil.Uint64),
|
||||||
|
Storage: make(map[common.Address]map[common.Hash]common.Hash),
|
||||||
|
}
|
||||||
|
return &Tracer{
|
||||||
|
GetResult: func() (json.RawMessage, error) {
|
||||||
|
return json.Marshal(t)
|
||||||
|
},
|
||||||
|
Hooks: &tracing.Hooks{
|
||||||
|
OnBalanceChange: func(addr common.Address, prev, new *big.Int, reason tracing.BalanceChangeReason) {
|
||||||
|
t.Balance[addr] = (*hexutil.Big)(new)
|
||||||
|
},
|
||||||
|
OnNonceChange: func(addr common.Address, prev, new uint64) {
|
||||||
|
t.Nonce[addr] = hexutil.Uint64(new)
|
||||||
|
},
|
||||||
|
OnStorageChange: func(addr common.Address, slot common.Hash, prev, new common.Hash) {
|
||||||
|
if t.Storage[addr] == nil {
|
||||||
|
t.Storage[addr] = make(map[common.Hash]common.Hash)
|
||||||
|
}
|
||||||
|
t.Storage[addr][slot] = new
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStateHooks(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
// Initialize test accounts
|
||||||
|
var (
|
||||||
|
key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
|
from = crypto.PubkeyToAddress(key.PublicKey)
|
||||||
|
to = common.HexToAddress("0x00000000000000000000000000000000deadbeef")
|
||||||
|
genesis = &core.Genesis{
|
||||||
|
Config: params.TestChainConfig,
|
||||||
|
Alloc: types.GenesisAlloc{
|
||||||
|
from: {Balance: big.NewInt(params.Ether)},
|
||||||
|
to: {
|
||||||
|
Code: []byte{
|
||||||
|
byte(vm.PUSH1), 0x2a, // stack: [42]
|
||||||
|
byte(vm.PUSH1), 0x0, // stack: [0, 42]
|
||||||
|
byte(vm.SSTORE), // stack: []
|
||||||
|
byte(vm.STOP),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
genBlocks = 2
|
||||||
|
signer = types.HomesteadSigner{}
|
||||||
|
nonce = uint64(0)
|
||||||
|
backend = newTestBackend(t, genBlocks, genesis, func(i int, b *core.BlockGen) {
|
||||||
|
// Transfer from account[0] to account[1]
|
||||||
|
// value: 1000 wei
|
||||||
|
// fee: 0 wei
|
||||||
|
tx, _ := types.SignTx(types.NewTx(&types.LegacyTx{
|
||||||
|
Nonce: nonce,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(1000),
|
||||||
|
Gas: params.TxGas,
|
||||||
|
GasPrice: b.BaseFee(),
|
||||||
|
Data: nil}),
|
||||||
|
signer, key)
|
||||||
|
b.AddTx(tx)
|
||||||
|
nonce++
|
||||||
|
})
|
||||||
|
)
|
||||||
|
defer backend.teardown()
|
||||||
|
DefaultDirectory.Register("stateTracer", newStateTracer, false)
|
||||||
|
api := NewAPI(backend)
|
||||||
|
tracer := "stateTracer"
|
||||||
|
res, err := api.TraceCall(context.Background(), ethapi.TransactionArgs{From: &from, To: &to, Value: (*hexutil.Big)(big.NewInt(1000))}, rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber), &TraceCallConfig{TraceConfig: TraceConfig{Tracer: &tracer}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to trace call: %v", err)
|
||||||
|
}
|
||||||
|
expected := `{"Balance":{"0x00000000000000000000000000000000deadbeef":"0x3e8","0x71562b71999873db5b286df957af199ec94617f7":"0xde0975924ed6f90"},"Nonce":{"0x71562b71999873db5b286df957af199ec94617f7":"0x3"},"Storage":{"0x00000000000000000000000000000000deadbeef":{"0x0000000000000000000000000000000000000000000000000000000000000000":"0x000000000000000000000000000000000000000000000000000000000000002a"}}}`
|
||||||
|
if expected != fmt.Sprintf("%s", res) {
|
||||||
|
t.Fatalf("unexpected trace result: have %s want %s", res, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTraceCall(t *testing.T) {
|
func TestTraceCall(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|
@ -448,7 +535,7 @@ func TestTraceTransaction(t *testing.T) {
|
||||||
Gas: params.TxGas,
|
Gas: params.TxGas,
|
||||||
Failed: false,
|
Failed: false,
|
||||||
ReturnValue: "",
|
ReturnValue: "",
|
||||||
StructLogs: []logger.StructLogRes{},
|
StructLogs: []json.RawMessage{},
|
||||||
}) {
|
}) {
|
||||||
t.Error("Transaction tracing result is different")
|
t.Error("Transaction tracing result is different")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,6 @@ func testCallTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, logState, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -206,11 +205,6 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
||||||
b.Fatalf("failed to parse testcase input: %v", err)
|
b.Fatalf("failed to parse testcase input: %v", err)
|
||||||
}
|
}
|
||||||
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
signer := types.MakeSigner(test.Genesis.Config, new(big.Int).SetUint64(uint64(test.Context.Number)), uint64(test.Context.Time))
|
||||||
origin, _ := signer.Sender(tx)
|
|
||||||
txContext := vm.TxContext{
|
|
||||||
Origin: origin,
|
|
||||||
GasPrice: tx.GasPrice(),
|
|
||||||
}
|
|
||||||
context := test.Context.toBlockContext(test.Genesis)
|
context := test.Context.toBlockContext(test.Genesis)
|
||||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -222,19 +216,25 @@ func benchTracer(tracerName string, test *callTracerTest, b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
||||||
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
|
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{})
|
||||||
if err != nil {
|
|
||||||
b.Fatalf("failed to create call tracer: %v", err)
|
|
||||||
}
|
|
||||||
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
snap := state.StateDB.Snapshot()
|
snap := state.StateDB.Snapshot()
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
tracer, err := tracers.DefaultDirectory.New(tracerName, new(tracers.Context), nil, test.Genesis.Config)
|
||||||
if _, err = st.TransitionDb(); err != nil {
|
if err != nil {
|
||||||
|
b.Fatalf("failed to create call tracer: %v", err)
|
||||||
|
}
|
||||||
|
evm.Config.Tracer = tracer.Hooks
|
||||||
|
if tracer.OnTxStart != nil {
|
||||||
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
|
}
|
||||||
|
_, err = core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
|
if err != nil {
|
||||||
b.Fatalf("failed to execute transaction: %v", err)
|
b.Fatalf("failed to execute transaction: %v", err)
|
||||||
}
|
}
|
||||||
|
if tracer.OnTxEnd != nil {
|
||||||
|
tracer.OnTxEnd(&types.Receipt{GasUsed: tx.Gas()}, nil)
|
||||||
|
}
|
||||||
if _, err = tracer.GetResult(); err != nil {
|
if _, err = tracer.GetResult(); err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
@ -372,12 +372,7 @@ func TestInternals(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err)
|
t.Fatalf("test %v: failed to sign transaction: %v", tc.name, err)
|
||||||
}
|
}
|
||||||
txContext := vm.TxContext{
|
|
||||||
Origin: origin,
|
|
||||||
GasPrice: tx.GasPrice(),
|
|
||||||
}
|
|
||||||
evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks})
|
evm := vm.NewEVM(context, logState, config, vm.Config{Tracer: tc.tracer.Hooks})
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0))
|
msg, err := core.TransactionToMessage(tx, signer, big.NewInt(0))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("test %v: failed to create message: %v", tc.name, err)
|
t.Fatalf("test %v: failed to create message: %v", tc.name, err)
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,6 @@ func flatCallTracerTestRunner(tracerName string, filename string, dirPath string
|
||||||
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
return fmt.Errorf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,6 @@ func testPrestateDiffTracer(tracerName string, dirPath string, t *testing.T) {
|
||||||
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
t.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
evm := vm.NewEVM(context, state.StateDB, test.Genesis.Config, vm.Config{Tracer: tracer.Hooks})
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
vmRet, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,7 @@ func TestSupplyOmittedFields(t *testing.T) {
|
||||||
|
|
||||||
expected := supplyInfo{
|
expected := supplyInfo{
|
||||||
Number: 0,
|
Number: 0,
|
||||||
Hash: common.HexToHash("0xc02ee8ee5b54a40e43f0fa827d431e1bd4f217e941790dda10b2521d1925a20b"),
|
Hash: common.HexToHash("0x3055fc27d6b4a08eb07033a0d1ee755a4b2988086f28a6189eac1b507525eeb1"),
|
||||||
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
ParentHash: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000000"),
|
||||||
}
|
}
|
||||||
actual := out[expected.Number]
|
actual := out[expected.Number]
|
||||||
|
|
|
||||||
|
|
@ -260,7 +260,7 @@ func (t *jsTracer) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from
|
||||||
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
t.activePrecompiles = vm.ActivePrecompiles(rules)
|
||||||
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
|
t.ctx["block"] = t.vm.ToValue(t.env.BlockNumber.Uint64())
|
||||||
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
|
t.ctx["gas"] = t.vm.ToValue(tx.Gas())
|
||||||
gasPriceBig, err := t.toBig(t.vm, env.GasPrice.String())
|
gasPriceBig, err := t.toBig(t.vm, tx.EffectiveGasTipValue(env.BaseFee).String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.err = err
|
t.err = err
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ type vmContext struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testCtx() *vmContext {
|
func testCtx() *vmContext {
|
||||||
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
|
return &vmContext{blockCtx: vm.BlockContext{BlockNumber: big.NewInt(1), BaseFee: big.NewInt(0)}, txCtx: vm.TxContext{GasPrice: big.NewInt(100000)}}
|
||||||
}
|
}
|
||||||
|
|
||||||
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
|
func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainConfig, contractCode []byte) (json.RawMessage, error) {
|
||||||
|
|
@ -76,7 +76,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo
|
||||||
contract.Code = contractCode
|
contract.Code = contractCode
|
||||||
}
|
}
|
||||||
|
|
||||||
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit}), contract.Caller())
|
tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice}), contract.Caller())
|
||||||
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
|
tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig())
|
||||||
ret, err := evm.Interpreter().Run(contract, []byte{}, false)
|
ret, err := evm.Interpreter().Run(contract, []byte{}, false)
|
||||||
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
|
tracer.OnExit(0, ret, startGas-contract.Gas, err, true)
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"maps"
|
||||||
"math/big"
|
"math/big"
|
||||||
"strings"
|
"strings"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
@ -38,15 +39,6 @@ import (
|
||||||
// Storage represents a contract's storage.
|
// Storage represents a contract's storage.
|
||||||
type Storage map[common.Hash]common.Hash
|
type Storage map[common.Hash]common.Hash
|
||||||
|
|
||||||
// Copy duplicates the current storage.
|
|
||||||
func (s Storage) Copy() Storage {
|
|
||||||
cpy := make(Storage, len(s))
|
|
||||||
for key, value := range s {
|
|
||||||
cpy[key] = value
|
|
||||||
}
|
|
||||||
return cpy
|
|
||||||
}
|
|
||||||
|
|
||||||
// Config are the configuration options for structured logger the EVM
|
// Config are the configuration options for structured logger the EVM
|
||||||
type Config struct {
|
type Config struct {
|
||||||
EnableMemory bool // enable memory capture
|
EnableMemory bool // enable memory capture
|
||||||
|
|
@ -54,15 +46,16 @@ type Config struct {
|
||||||
DisableStorage bool // disable storage capture
|
DisableStorage bool // disable storage capture
|
||||||
EnableReturnData bool // enable return data capture
|
EnableReturnData bool // enable return data capture
|
||||||
Debug bool // print output during capture end
|
Debug bool // print output during capture end
|
||||||
Limit int // maximum length of output, but zero means unlimited
|
Limit int // maximum size of output, but zero means unlimited
|
||||||
|
|
||||||
// Chain overrides, can be used to execute a trace using future fork rules
|
// Chain overrides, can be used to execute a trace using future fork rules
|
||||||
Overrides *params.ChainConfig `json:"overrides,omitempty"`
|
Overrides *params.ChainConfig `json:"overrides,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
|
//go:generate go run github.com/fjl/gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go
|
||||||
|
|
||||||
// StructLog is emitted to the EVM each cycle and lists information about the current internal state
|
// StructLog is emitted to the EVM each cycle and lists information about the
|
||||||
// prior to the execution of the statement.
|
// current internal state prior to the execution of the statement.
|
||||||
type StructLog struct {
|
type StructLog struct {
|
||||||
Pc uint64 `json:"pc"`
|
Pc uint64 `json:"pc"`
|
||||||
Op vm.OpCode `json:"op"`
|
Op vm.OpCode `json:"op"`
|
||||||
|
|
@ -102,29 +95,144 @@ func (s *StructLog) ErrorString() string {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WriteTo writes the human-readable log data into the supplied writer.
|
||||||
|
func (s *StructLog) WriteTo(writer io.Writer) {
|
||||||
|
fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", s.Op, s.Pc, s.Gas, s.GasCost)
|
||||||
|
if s.Err != nil {
|
||||||
|
fmt.Fprintf(writer, " ERROR: %v", s.Err)
|
||||||
|
}
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
|
||||||
|
if len(s.Stack) > 0 {
|
||||||
|
fmt.Fprintln(writer, "Stack:")
|
||||||
|
for i := len(s.Stack) - 1; i >= 0; i-- {
|
||||||
|
fmt.Fprintf(writer, "%08d %s\n", len(s.Stack)-i-1, s.Stack[i].Hex())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s.Memory) > 0 {
|
||||||
|
fmt.Fprintln(writer, "Memory:")
|
||||||
|
fmt.Fprint(writer, hex.Dump(s.Memory))
|
||||||
|
}
|
||||||
|
if len(s.Storage) > 0 {
|
||||||
|
fmt.Fprintln(writer, "Storage:")
|
||||||
|
for h, item := range s.Storage {
|
||||||
|
fmt.Fprintf(writer, "%x: %x\n", h, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(s.ReturnData) > 0 {
|
||||||
|
fmt.Fprintln(writer, "ReturnData:")
|
||||||
|
fmt.Fprint(writer, hex.Dump(s.ReturnData))
|
||||||
|
}
|
||||||
|
fmt.Fprintln(writer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// structLogLegacy stores a structured log emitted by the EVM while replaying a
|
||||||
|
// transaction in debug mode. It's the legacy format used in tracer. The differences
|
||||||
|
// between the structLog json and the 'legacy' json are:
|
||||||
|
//
|
||||||
|
// op:
|
||||||
|
// Legacy uses string (e.g. "SSTORE"), non-legacy uses a byte.
|
||||||
|
// non-legacy has an 'opName' field containing the op name.
|
||||||
|
//
|
||||||
|
// gas, gasCost:
|
||||||
|
// Legacy uses integers, non-legacy hex-strings
|
||||||
|
//
|
||||||
|
// memory:
|
||||||
|
// Legacy uses a list of 64-char strings, each representing 32-byte chunks
|
||||||
|
// of evm memory. Non-legacy just uses a string of hexdata, no chunking.
|
||||||
|
//
|
||||||
|
// storage:
|
||||||
|
// Legacy has a storage field while non-legacy doesn't.
|
||||||
|
type structLogLegacy struct {
|
||||||
|
Pc uint64 `json:"pc"`
|
||||||
|
Op string `json:"op"`
|
||||||
|
Gas uint64 `json:"gas"`
|
||||||
|
GasCost uint64 `json:"gasCost"`
|
||||||
|
Depth int `json:"depth"`
|
||||||
|
Error string `json:"error,omitempty"`
|
||||||
|
Stack *[]string `json:"stack,omitempty"`
|
||||||
|
ReturnData string `json:"returnData,omitempty"`
|
||||||
|
Memory *[]string `json:"memory,omitempty"`
|
||||||
|
Storage *map[string]string `json:"storage,omitempty"`
|
||||||
|
RefundCounter uint64 `json:"refund,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// toLegacyJSON converts the structLog to legacy json-encoded legacy form.
|
||||||
|
func (s *StructLog) toLegacyJSON() json.RawMessage {
|
||||||
|
msg := structLogLegacy{
|
||||||
|
Pc: s.Pc,
|
||||||
|
Op: s.Op.String(),
|
||||||
|
Gas: s.Gas,
|
||||||
|
GasCost: s.GasCost,
|
||||||
|
Depth: s.Depth,
|
||||||
|
Error: s.ErrorString(),
|
||||||
|
RefundCounter: s.RefundCounter,
|
||||||
|
}
|
||||||
|
if s.Stack != nil {
|
||||||
|
stack := make([]string, len(s.Stack))
|
||||||
|
for i, stackValue := range s.Stack {
|
||||||
|
stack[i] = stackValue.Hex()
|
||||||
|
}
|
||||||
|
msg.Stack = &stack
|
||||||
|
}
|
||||||
|
if len(s.ReturnData) > 0 {
|
||||||
|
msg.ReturnData = hexutil.Bytes(s.ReturnData).String()
|
||||||
|
}
|
||||||
|
if s.Memory != nil {
|
||||||
|
memory := make([]string, 0, (len(s.Memory)+31)/32)
|
||||||
|
for i := 0; i+32 <= len(s.Memory); i += 32 {
|
||||||
|
memory = append(memory, fmt.Sprintf("%x", s.Memory[i:i+32]))
|
||||||
|
}
|
||||||
|
msg.Memory = &memory
|
||||||
|
}
|
||||||
|
if s.Storage != nil {
|
||||||
|
storage := make(map[string]string)
|
||||||
|
for i, storageValue := range s.Storage {
|
||||||
|
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
|
||||||
|
}
|
||||||
|
msg.Storage = &storage
|
||||||
|
}
|
||||||
|
element, _ := json.Marshal(msg)
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
// StructLogger is an EVM state logger and implements EVMLogger.
|
// StructLogger is an EVM state logger and implements EVMLogger.
|
||||||
//
|
//
|
||||||
// StructLogger can capture state based on the given Log configuration and also keeps
|
// StructLogger can capture state based on the given Log configuration and also keeps
|
||||||
// a track record of modified storage which is used in reporting snapshots of the
|
// a track record of modified storage which is used in reporting snapshots of the
|
||||||
// contract their storage.
|
// contract their storage.
|
||||||
|
//
|
||||||
|
// A StructLogger can either yield it's output immediately (streaming) or store for
|
||||||
|
// later output.
|
||||||
type StructLogger struct {
|
type StructLogger struct {
|
||||||
cfg Config
|
cfg Config
|
||||||
env *tracing.VMContext
|
env *tracing.VMContext
|
||||||
|
|
||||||
storage map[common.Address]Storage
|
storage map[common.Address]Storage
|
||||||
logs []StructLog
|
|
||||||
output []byte
|
output []byte
|
||||||
err error
|
err error
|
||||||
usedGas uint64
|
usedGas uint64
|
||||||
|
|
||||||
|
writer io.Writer // If set, the logger will stream instead of store logs
|
||||||
|
logs []json.RawMessage // buffer of json-encoded logs
|
||||||
|
resultSize int
|
||||||
|
|
||||||
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
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStructLogger returns a new logger
|
// NewStreamingStructLogger returns a new streaming logger.
|
||||||
|
func NewStreamingStructLogger(cfg *Config, writer io.Writer) *StructLogger {
|
||||||
|
l := NewStructLogger(cfg)
|
||||||
|
l.writer = writer
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewStructLogger construct a new (non-streaming) struct logger.
|
||||||
func NewStructLogger(cfg *Config) *StructLogger {
|
func NewStructLogger(cfg *Config) *StructLogger {
|
||||||
logger := &StructLogger{
|
logger := &StructLogger{
|
||||||
storage: make(map[common.Address]Storage),
|
storage: make(map[common.Address]Storage),
|
||||||
|
logs: make([]json.RawMessage, 0),
|
||||||
}
|
}
|
||||||
if cfg != nil {
|
if cfg != nil {
|
||||||
logger.cfg = *cfg
|
logger.cfg = *cfg
|
||||||
|
|
@ -141,44 +249,36 @@ func (l *StructLogger) Hooks() *tracing.Hooks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset clears the data held by the logger.
|
|
||||||
func (l *StructLogger) Reset() {
|
|
||||||
l.storage = make(map[common.Address]Storage)
|
|
||||||
l.output = make([]byte, 0)
|
|
||||||
l.logs = l.logs[:0]
|
|
||||||
l.err = nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OnOpcode logs a new structured log message and pushes it out to the environment
|
// OnOpcode logs a new structured log message and pushes it out to the environment
|
||||||
//
|
//
|
||||||
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
// OnOpcode also tracks SLOAD/SSTORE ops to track storage change.
|
||||||
func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope tracing.OpContext, rData []byte, depth int, err error) {
|
||||||
// If tracing was interrupted, set the error and stop
|
// If tracing was interrupted, exit
|
||||||
if l.interrupt.Load() {
|
if l.interrupt.Load() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// check if already accumulated the specified number of logs
|
// check if already accumulated the size of the response.
|
||||||
if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) {
|
if l.cfg.Limit != 0 && l.resultSize > l.cfg.Limit {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
op := vm.OpCode(opcode)
|
op = vm.OpCode(opcode)
|
||||||
memory := scope.MemoryData()
|
memory = scope.MemoryData()
|
||||||
stack := scope.StackData()
|
contractAddr = scope.Address()
|
||||||
// Copy a snapshot of the current memory state to a new buffer
|
stack = scope.StackData()
|
||||||
var mem []byte
|
stackLen = len(stack)
|
||||||
|
)
|
||||||
|
log := StructLog{pc, op, gas, cost, nil, len(memory), nil, nil, nil, depth, l.env.StateDB.GetRefund(), err}
|
||||||
if l.cfg.EnableMemory {
|
if l.cfg.EnableMemory {
|
||||||
mem = make([]byte, len(memory))
|
log.Memory = memory
|
||||||
copy(mem, memory)
|
|
||||||
}
|
}
|
||||||
// Copy a snapshot of the current stack state to a new buffer
|
|
||||||
var stck []uint256.Int
|
|
||||||
if !l.cfg.DisableStack {
|
if !l.cfg.DisableStack {
|
||||||
stck = make([]uint256.Int, len(stack))
|
log.Stack = scope.StackData()
|
||||||
copy(stck, stack)
|
|
||||||
}
|
}
|
||||||
contractAddr := scope.Address()
|
if l.cfg.EnableReturnData {
|
||||||
stackLen := len(stack)
|
log.ReturnData = rData
|
||||||
|
}
|
||||||
|
|
||||||
// Copy a snapshot of the current storage to a new container
|
// Copy a snapshot of the current storage to a new container
|
||||||
var storage Storage
|
var storage Storage
|
||||||
if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) {
|
if !l.cfg.DisableStorage && (op == vm.SLOAD || op == vm.SSTORE) {
|
||||||
|
|
@ -194,7 +294,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
|
||||||
value = l.env.StateDB.GetState(contractAddr, address)
|
value = l.env.StateDB.GetState(contractAddr, address)
|
||||||
)
|
)
|
||||||
l.storage[contractAddr][address] = value
|
l.storage[contractAddr][address] = value
|
||||||
storage = l.storage[contractAddr].Copy()
|
storage = maps.Clone(l.storage[contractAddr])
|
||||||
} else if op == vm.SSTORE && stackLen >= 2 {
|
} else if op == vm.SSTORE && stackLen >= 2 {
|
||||||
// capture SSTORE opcodes and record the written entry in the local storage.
|
// capture SSTORE opcodes and record the written entry in the local storage.
|
||||||
var (
|
var (
|
||||||
|
|
@ -202,17 +302,19 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
|
||||||
address = common.Hash(stack[stackLen-1].Bytes32())
|
address = common.Hash(stack[stackLen-1].Bytes32())
|
||||||
)
|
)
|
||||||
l.storage[contractAddr][address] = value
|
l.storage[contractAddr][address] = value
|
||||||
storage = l.storage[contractAddr].Copy()
|
storage = maps.Clone(l.storage[contractAddr])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var rdata []byte
|
log.Storage = storage
|
||||||
if l.cfg.EnableReturnData {
|
|
||||||
rdata = make([]byte, len(rData))
|
// create a log
|
||||||
copy(rdata, rData)
|
if l.writer == nil {
|
||||||
|
entry := log.toLegacyJSON()
|
||||||
|
l.resultSize += len(entry)
|
||||||
|
l.logs = append(l.logs, entry)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// create a new snapshot of the EVM.
|
log.WriteTo(l.writer)
|
||||||
log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
|
|
||||||
l.logs = append(l.logs, log)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnExit is called a call frame finishes processing.
|
// OnExit is called a call frame finishes processing.
|
||||||
|
|
@ -246,7 +348,7 @@ func (l *StructLogger) GetResult() (json.RawMessage, error) {
|
||||||
Gas: l.usedGas,
|
Gas: l.usedGas,
|
||||||
Failed: failed,
|
Failed: failed,
|
||||||
ReturnValue: returnVal,
|
ReturnValue: returnVal,
|
||||||
StructLogs: formatLogs(l.StructLogs()),
|
StructLogs: l.logs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -273,9 +375,6 @@ func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogs returns the captured log entries.
|
|
||||||
func (l *StructLogger) StructLogs() []StructLog { return l.logs }
|
|
||||||
|
|
||||||
// Error returns the VM error captured by the trace.
|
// Error returns the VM error captured by the trace.
|
||||||
func (l *StructLogger) Error() error { return l.err }
|
func (l *StructLogger) Error() error { return l.err }
|
||||||
|
|
||||||
|
|
@ -283,49 +382,10 @@ func (l *StructLogger) Error() error { return l.err }
|
||||||
func (l *StructLogger) Output() []byte { return l.output }
|
func (l *StructLogger) Output() []byte { return l.output }
|
||||||
|
|
||||||
// WriteTrace writes a formatted trace to the given writer
|
// WriteTrace writes a formatted trace to the given writer
|
||||||
|
// @deprecated
|
||||||
func WriteTrace(writer io.Writer, logs []StructLog) {
|
func WriteTrace(writer io.Writer, logs []StructLog) {
|
||||||
for _, log := range logs {
|
for _, log := range logs {
|
||||||
fmt.Fprintf(writer, "%-16spc=%08d gas=%v cost=%v", log.Op, log.Pc, log.Gas, log.GasCost)
|
log.WriteTo(writer)
|
||||||
if log.Err != nil {
|
|
||||||
fmt.Fprintf(writer, " ERROR: %v", log.Err)
|
|
||||||
}
|
|
||||||
fmt.Fprintln(writer)
|
|
||||||
|
|
||||||
if len(log.Stack) > 0 {
|
|
||||||
fmt.Fprintln(writer, "Stack:")
|
|
||||||
for i := len(log.Stack) - 1; i >= 0; i-- {
|
|
||||||
fmt.Fprintf(writer, "%08d %s\n", len(log.Stack)-i-1, log.Stack[i].Hex())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(log.Memory) > 0 {
|
|
||||||
fmt.Fprintln(writer, "Memory:")
|
|
||||||
fmt.Fprint(writer, hex.Dump(log.Memory))
|
|
||||||
}
|
|
||||||
if len(log.Storage) > 0 {
|
|
||||||
fmt.Fprintln(writer, "Storage:")
|
|
||||||
for h, item := range log.Storage {
|
|
||||||
fmt.Fprintf(writer, "%x: %x\n", h, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(log.ReturnData) > 0 {
|
|
||||||
fmt.Fprintln(writer, "ReturnData:")
|
|
||||||
fmt.Fprint(writer, hex.Dump(log.ReturnData))
|
|
||||||
}
|
|
||||||
fmt.Fprintln(writer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// WriteLogs writes vm logs in a readable format to the given writer
|
|
||||||
func WriteLogs(writer io.Writer, logs []*types.Log) {
|
|
||||||
for _, log := range logs {
|
|
||||||
fmt.Fprintf(writer, "LOG%d: %x bn=%d txi=%x\n", len(log.Topics), log.Address, log.BlockNumber, log.TxIndex)
|
|
||||||
|
|
||||||
for i, topic := range log.Topics {
|
|
||||||
fmt.Fprintf(writer, "%08d %x\n", i, topic)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Fprint(writer, hex.Dump(log.Data))
|
|
||||||
fmt.Fprintln(writer)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -425,65 +485,8 @@ func (t *mdLogger) OnFault(pc uint64, op byte, gas, cost uint64, scope tracing.O
|
||||||
// while replaying a transaction in debug mode as well as transaction
|
// while replaying a transaction in debug mode as well as transaction
|
||||||
// execution status, the amount of gas used and the return value
|
// execution status, the amount of gas used and the return value
|
||||||
type ExecutionResult struct {
|
type ExecutionResult struct {
|
||||||
Gas uint64 `json:"gas"`
|
Gas uint64 `json:"gas"`
|
||||||
Failed bool `json:"failed"`
|
Failed bool `json:"failed"`
|
||||||
ReturnValue string `json:"returnValue"`
|
ReturnValue string `json:"returnValue"`
|
||||||
StructLogs []StructLogRes `json:"structLogs"`
|
StructLogs []json.RawMessage `json:"structLogs"`
|
||||||
}
|
|
||||||
|
|
||||||
// StructLogRes stores a structured log emitted by the EVM while replaying a
|
|
||||||
// transaction in debug mode
|
|
||||||
type StructLogRes struct {
|
|
||||||
Pc uint64 `json:"pc"`
|
|
||||||
Op string `json:"op"`
|
|
||||||
Gas uint64 `json:"gas"`
|
|
||||||
GasCost uint64 `json:"gasCost"`
|
|
||||||
Depth int `json:"depth"`
|
|
||||||
Error string `json:"error,omitempty"`
|
|
||||||
Stack *[]string `json:"stack,omitempty"`
|
|
||||||
ReturnData string `json:"returnData,omitempty"`
|
|
||||||
Memory *[]string `json:"memory,omitempty"`
|
|
||||||
Storage *map[string]string `json:"storage,omitempty"`
|
|
||||||
RefundCounter uint64 `json:"refund,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// formatLogs formats EVM returned structured logs for json output
|
|
||||||
func formatLogs(logs []StructLog) []StructLogRes {
|
|
||||||
formatted := make([]StructLogRes, len(logs))
|
|
||||||
for index, trace := range logs {
|
|
||||||
formatted[index] = StructLogRes{
|
|
||||||
Pc: trace.Pc,
|
|
||||||
Op: trace.Op.String(),
|
|
||||||
Gas: trace.Gas,
|
|
||||||
GasCost: trace.GasCost,
|
|
||||||
Depth: trace.Depth,
|
|
||||||
Error: trace.ErrorString(),
|
|
||||||
RefundCounter: trace.RefundCounter,
|
|
||||||
}
|
|
||||||
if trace.Stack != nil {
|
|
||||||
stack := make([]string, len(trace.Stack))
|
|
||||||
for i, stackValue := range trace.Stack {
|
|
||||||
stack[i] = stackValue.Hex()
|
|
||||||
}
|
|
||||||
formatted[index].Stack = &stack
|
|
||||||
}
|
|
||||||
if len(trace.ReturnData) > 0 {
|
|
||||||
formatted[index].ReturnData = hexutil.Bytes(trace.ReturnData).String()
|
|
||||||
}
|
|
||||||
if trace.Memory != nil {
|
|
||||||
memory := make([]string, 0, (len(trace.Memory)+31)/32)
|
|
||||||
for i := 0; i+32 <= len(trace.Memory); i += 32 {
|
|
||||||
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
|
|
||||||
}
|
|
||||||
formatted[index].Memory = &memory
|
|
||||||
}
|
|
||||||
if trace.Storage != nil {
|
|
||||||
storage := make(map[string]string)
|
|
||||||
for i, storageValue := range trace.Storage {
|
|
||||||
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
|
|
||||||
}
|
|
||||||
formatted[index].Storage = &storage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return formatted
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/tests"
|
"github.com/ethereum/go-ethereum/tests"
|
||||||
)
|
)
|
||||||
|
|
||||||
func BenchmarkTransactionTrace(b *testing.B) {
|
func BenchmarkTransactionTraceV2(b *testing.B) {
|
||||||
key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
key, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
|
||||||
from := crypto.PubkeyToAddress(key.PublicKey)
|
from := crypto.PubkeyToAddress(key.PublicKey)
|
||||||
gas := uint64(1000000) // 1M gas
|
gas := uint64(1000000) // 1M gas
|
||||||
|
|
@ -47,10 +47,6 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
txContext := vm.TxContext{
|
|
||||||
Origin: from,
|
|
||||||
GasPrice: tx.GasPrice(),
|
|
||||||
}
|
|
||||||
context := vm.BlockContext{
|
context := vm.BlockContext{
|
||||||
CanTransfer: core.CanTransfer,
|
CanTransfer: core.CanTransfer,
|
||||||
Transfer: core.Transfer,
|
Transfer: core.Transfer,
|
||||||
|
|
@ -82,15 +78,8 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
||||||
state := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
|
state := tests.MakePreState(rawdb.NewMemoryDatabase(), alloc, false, rawdb.HashScheme)
|
||||||
defer state.Close()
|
defer state.Close()
|
||||||
|
|
||||||
// Create the tracer, the EVM environment and run it
|
evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{})
|
||||||
tracer := logger.NewStructLogger(&logger.Config{
|
|
||||||
Debug: false,
|
|
||||||
//DisableStorage: true,
|
|
||||||
//EnableMemory: false,
|
|
||||||
//EnableReturnData: false,
|
|
||||||
})
|
|
||||||
evm := vm.NewEVM(context, state.StateDB, params.AllEthashProtocolChanges, vm.Config{Tracer: tracer.Hooks()})
|
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
msg, err := core.TransactionToMessage(tx, signer, context.BaseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
b.Fatalf("failed to prepare transaction for tracing: %v", err)
|
||||||
|
|
@ -99,18 +88,15 @@ func BenchmarkTransactionTrace(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
snap := state.StateDB.Snapshot()
|
tracer := logger.NewStructLogger(&logger.Config{Debug: false}).Hooks()
|
||||||
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
|
||||||
st := core.NewStateTransition(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
evm.Config.Tracer = tracer
|
||||||
res, err := st.TransitionDb()
|
|
||||||
|
snap := state.StateDB.Snapshot()
|
||||||
|
_, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(tx.Gas()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
tracer.OnTxEnd(&types.Receipt{GasUsed: res.UsedGas}, nil)
|
|
||||||
state.StateDB.RevertToSnapshot(snap)
|
state.StateDB.RevertToSnapshot(snap)
|
||||||
if have, want := len(tracer.StructLogs()), 244752; have != want {
|
|
||||||
b.Fatalf("trace wrong, want %d steps, have %d", want, have)
|
|
||||||
}
|
|
||||||
tracer.Reset()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/eth"
|
"github.com/ethereum/go-ethereum/eth"
|
||||||
"github.com/ethereum/go-ethereum/eth/catalyst"
|
"github.com/ethereum/go-ethereum/eth/catalyst"
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
|
||||||
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
"github.com/ethereum/go-ethereum/eth/ethconfig"
|
||||||
"github.com/ethereum/go-ethereum/eth/filters"
|
"github.com/ethereum/go-ethereum/eth/filters"
|
||||||
"github.com/ethereum/go-ethereum/ethclient"
|
"github.com/ethereum/go-ethereum/ethclient"
|
||||||
|
|
@ -85,7 +84,7 @@ func NewBackend(alloc types.GenesisAlloc, options ...func(nodeConf *node.Config,
|
||||||
GasLimit: ethconfig.Defaults.Miner.GasCeil,
|
GasLimit: ethconfig.Defaults.Miner.GasCeil,
|
||||||
Alloc: alloc,
|
Alloc: alloc,
|
||||||
}
|
}
|
||||||
ethConf.SyncMode = downloader.FullSync
|
ethConf.SyncMode = ethconfig.FullSync
|
||||||
ethConf.TxPool.NoLocals = true
|
ethConf.TxPool.NoLocals = true
|
||||||
|
|
||||||
for _, option := range options {
|
for _, option := range options {
|
||||||
|
|
|
||||||
26
go.mod
26
go.mod
|
|
@ -15,16 +15,16 @@ require (
|
||||||
github.com/cespare/cp v0.1.0
|
github.com/cespare/cp v0.1.0
|
||||||
github.com/cloudflare/cloudflare-go v0.79.0
|
github.com/cloudflare/cloudflare-go v0.79.0
|
||||||
github.com/cockroachdb/pebble v1.1.2
|
github.com/cockroachdb/pebble v1.1.2
|
||||||
github.com/consensys/gnark-crypto v0.12.1
|
github.com/consensys/gnark-crypto v0.14.0
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.0.0
|
github.com/crate-crypto/go-kzg-4844 v1.1.0
|
||||||
github.com/davecgh/go-spew v1.1.1
|
github.com/davecgh/go-spew v1.1.1
|
||||||
github.com/deckarep/golang-set/v2 v2.6.0
|
github.com/deckarep/golang-set/v2 v2.6.0
|
||||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1
|
||||||
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
github.com/donovanhide/eventsource v0.0.0-20210830082556-c59027999da0
|
||||||
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
github.com/dop251/goja v0.0.0-20230605162241-28ee0ee714f3
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0
|
github.com/ethereum/c-kzg-4844 v1.0.0
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9
|
github.com/ethereum/go-verkle v0.2.2
|
||||||
github.com/fatih/color v1.16.0
|
github.com/fatih/color v1.16.0
|
||||||
github.com/ferranbt/fastssz v0.1.2
|
github.com/ferranbt/fastssz v0.1.2
|
||||||
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
github.com/fjl/gencodec v0.0.0-20230517082657-f9840df7b83e
|
||||||
|
|
@ -70,13 +70,13 @@ require (
|
||||||
github.com/urfave/cli/v2 v2.25.7
|
github.com/urfave/cli/v2 v2.25.7
|
||||||
go.uber.org/automaxprocs v1.5.2
|
go.uber.org/automaxprocs v1.5.2
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/crypto v0.22.0
|
golang.org/x/crypto v0.26.0
|
||||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||||
golang.org/x/sync v0.7.0
|
golang.org/x/sync v0.10.0
|
||||||
golang.org/x/sys v0.26.0
|
golang.org/x/sys v0.28.0
|
||||||
golang.org/x/text v0.14.0
|
golang.org/x/text v0.17.0
|
||||||
golang.org/x/time v0.5.0
|
golang.org/x/time v0.5.0
|
||||||
golang.org/x/tools v0.20.0
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d
|
||||||
google.golang.org/protobuf v1.34.2
|
google.golang.org/protobuf v1.34.2
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v2 v2.4.0
|
gopkg.in/yaml.v2 v2.4.0
|
||||||
|
|
@ -98,14 +98,14 @@ require (
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.23.2 // indirect
|
||||||
github.com/aws/smithy-go v1.15.0 // indirect
|
github.com/aws/smithy-go v1.15.0 // indirect
|
||||||
github.com/beorn7/perks v1.0.1 // indirect
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
github.com/bits-and-blooms/bitset v1.13.0 // indirect
|
github.com/bits-and-blooms/bitset v1.17.0 // indirect
|
||||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
github.com/cockroachdb/errors v1.11.3 // indirect
|
github.com/cockroachdb/errors v1.11.3 // indirect
|
||||||
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce // indirect
|
||||||
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b // indirect
|
||||||
github.com/cockroachdb/redact v1.1.5 // indirect
|
github.com/cockroachdb/redact v1.1.5 // indirect
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 // indirect
|
||||||
github.com/consensys/bavard v0.1.13 // indirect
|
github.com/consensys/bavard v0.1.22 // indirect
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||||
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
github.com/deepmap/oapi-codegen v1.6.0 // indirect
|
||||||
github.com/dlclark/regexp2 v1.7.0 // indirect
|
github.com/dlclark/regexp2 v1.7.0 // indirect
|
||||||
|
|
@ -145,7 +145,7 @@ require (
|
||||||
github.com/prometheus/common v0.32.1 // indirect
|
github.com/prometheus/common v0.32.1 // indirect
|
||||||
github.com/prometheus/procfs v0.7.3 // indirect
|
github.com/prometheus/procfs v0.7.3 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
github.com/rogpeppe/go-internal v1.12.0 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
github.com/tklauser/go-sysconf v0.3.12 // indirect
|
||||||
github.com/tklauser/numcpus v0.6.1 // indirect
|
github.com/tklauser/numcpus v0.6.1 // indirect
|
||||||
|
|
@ -153,7 +153,7 @@ require (
|
||||||
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/mod v0.17.0 // indirect
|
golang.org/x/mod v0.17.0 // indirect
|
||||||
golang.org/x/net v0.24.0 // indirect
|
golang.org/x/net v0.25.0 // indirect
|
||||||
rsc.io/tmplfunc v0.0.3 // indirect
|
rsc.io/tmplfunc v0.0.3 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
59
go.sum
59
go.sum
|
|
@ -90,8 +90,8 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bits-and-blooms/bitset v1.13.0 h1:bAQ9OPNFYbGHV6Nez0tmNI0RiEu7/hxlYJRUA0wFAVE=
|
github.com/bits-and-blooms/bitset v1.17.0 h1:1X2TS7aHz1ELcC0yU1y2stUs/0ig5oMU6STFZGrhvHI=
|
||||||
github.com/bits-and-blooms/bitset v1.13.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
github.com/bits-and-blooms/bitset v1.17.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
github.com/cespare/cp v0.1.0 h1:SE+dxFebS7Iik5LK0tsi1k9ZCxEaFX4AjQmoyA+1dJk=
|
||||||
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
github.com/cespare/cp v0.1.0/go.mod h1:SOGHArjBr4JWaSDEVpWpo/hNg6RoKrls6Oh40hiwW+s=
|
||||||
|
|
@ -124,16 +124,16 @@ github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwP
|
||||||
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg=
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo=
|
||||||
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ=
|
||||||
github.com/consensys/bavard v0.1.13 h1:oLhMLOFGTLdlda/kma4VOJazblc7IM5y5QPd2A/YjhQ=
|
github.com/consensys/bavard v0.1.22 h1:Uw2CGvbXSZWhqK59X0VG/zOjpTFuOMcPLStrp1ihI0A=
|
||||||
github.com/consensys/bavard v0.1.13/go.mod h1:9ItSMtA/dXMAiL7BG6bqW2m3NdSEObYWoH223nGHukI=
|
github.com/consensys/bavard v0.1.22/go.mod h1:k/zVjHHC4B+PQy1Pg7fgvG3ALicQw540Crag8qx+dZs=
|
||||||
github.com/consensys/gnark-crypto v0.12.1 h1:lHH39WuuFgVHONRl3J0LRBtuYdQTumFSDtJF7HpyG8M=
|
github.com/consensys/gnark-crypto v0.14.0 h1:DDBdl4HaBtdQsq/wfMwJvZNE80sHidrK3Nfrefatm0E=
|
||||||
github.com/consensys/gnark-crypto v0.12.1/go.mod h1:v2Gy7L/4ZRosZ7Ivs+9SfUDr0f5UlG+EM5t7MPHiLuY=
|
github.com/consensys/gnark-crypto v0.14.0/go.mod h1:CU4UijNPsHawiVGNxe9co07FkzCeWHHrb1li/n1XoU0=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c h1:uQYC5Z1mdLRPrZhHjHxufI8+2UG/i25QG92j0Er9p6I=
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg=
|
||||||
github.com/crate-crypto/go-ipa v0.0.0-20240223125850-b1e8a79f509c/go.mod h1:geZJZH3SzKCqnz5VT0q/DyIG/tvu/dZk+VIfXicupJs=
|
github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM=
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.0.0 h1:TsSgHwrkTKecKJ4kadtHi4b3xHW5dCFUDFnUp1TsawI=
|
github.com/crate-crypto/go-kzg-4844 v1.1.0 h1:EN/u9k2TF6OWSHrCCDBBU6GLNMq88OspHHlMnHfoyU4=
|
||||||
github.com/crate-crypto/go-kzg-4844 v1.0.0/go.mod h1:1kMhvPgI0Ky3yIa+9lFySEBUBXkYxeOi8ZF1sYioxhc=
|
github.com/crate-crypto/go-kzg-4844 v1.1.0/go.mod h1:JolLjpSff1tCCJKaJx4psrlEdlXuJEC996PL3tTAFks=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV+0YP4qX0UQ7r2MoYZ+AvYDp12OF5yg4q8rGnyNh4=
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
|
@ -166,8 +166,8 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
|
github.com/ethereum/c-kzg-4844 v1.0.0 h1:0X1LBXxaEtYD9xsyj9B9ctQEZIpnvVDeoBx8aHEwTNA=
|
||||||
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
github.com/ethereum/c-kzg-4844 v1.0.0/go.mod h1:VewdlzQmpT5QSrVhbBuGoCdFJkpaJlO1aQputP83wc0=
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9 h1:8NfxH2iXvJ60YRB8ChToFTUzl8awsc3cJ8CbLjGIl/A=
|
github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8=
|
||||||
github.com/ethereum/go-verkle v0.1.1-0.20240829091221-dffa7562dbe9/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk=
|
||||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
|
github.com/ferranbt/fastssz v0.1.2 h1:Dky6dXlngF6Qjc+EfDipAkE83N5I5DE68bY6O0VLNPk=
|
||||||
|
|
@ -261,8 +261,8 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
|
|
@ -363,8 +363,8 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||||
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
github.com/labstack/echo/v4 v4.2.1/go.mod h1:AA49e0DZ8kk5jTOOCKNuPR6oTnBS0dYiM4FW1e6jwpg=
|
||||||
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
|
||||||
github.com/leanovate/gopter v0.2.9 h1:fQjYxZaynp97ozCzfOyOuAGOU4aU/z37zf/tOujFk7c=
|
github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4=
|
||||||
github.com/leanovate/gopter v0.2.9/go.mod h1:U2L/78B+KVFIx2VmW6onHJQzXtFb+p5y3y2Sh+Jxxv8=
|
github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c=
|
||||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||||
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ=
|
||||||
|
|
@ -483,8 +483,9 @@ github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||||
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
|
||||||
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
|
|
@ -558,8 +559,8 @@ golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPh
|
||||||
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE=
|
||||||
golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
|
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
|
||||||
golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
|
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
|
@ -634,8 +635,8 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
|
||||||
golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
|
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
|
||||||
golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
|
@ -655,8 +656,8 @@ golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJ
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
|
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||||
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
|
@ -720,8 +721,8 @@ golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo=
|
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
||||||
golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
|
@ -738,8 +739,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc=
|
||||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
|
|
@ -791,8 +792,8 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
|
||||||
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@ var (
|
||||||
Category: flags.LoggingCategory,
|
Category: flags.LoggingCategory,
|
||||||
}
|
}
|
||||||
traceFlag = &cli.StringFlag{
|
traceFlag = &cli.StringFlag{
|
||||||
Name: "trace",
|
Name: "go-execution-trace",
|
||||||
Usage: "Write execution trace to the given file",
|
Usage: "Write Go execution trace to the given file",
|
||||||
Category: flags.LoggingCategory,
|
Category: flags.LoggingCategory,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -867,7 +867,6 @@ func applyMessage(ctx context.Context, b Backend, args TransactionArgs, state *s
|
||||||
if precompiles != nil {
|
if precompiles != nil {
|
||||||
evm.SetPrecompiles(precompiles)
|
evm.SetPrecompiles(precompiles)
|
||||||
}
|
}
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
|
res, err := applyMessageWithEVM(ctx, evm, msg, timeout, gp)
|
||||||
// If an internal state error occurred, let that have precedence. Otherwise,
|
// If an internal state error occurred, let that have precedence. Otherwise,
|
||||||
// a "trie root missing" type of error will masquerade as e.g. "insufficient gas"
|
// a "trie root missing" type of error will masquerade as e.g. "insufficient gas"
|
||||||
|
|
@ -1331,17 +1330,17 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH
|
||||||
// Apply the transaction with the access list tracer
|
// Apply the transaction with the access list tracer
|
||||||
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
|
tracer := logger.NewAccessListTracer(accessList, args.from(), to, precompiles)
|
||||||
config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true}
|
config := vm.Config{Tracer: tracer.Hooks(), NoBaseFee: true}
|
||||||
vmenv := b.GetEVM(ctx, statedb, header, &config, nil)
|
evm := b.GetEVM(ctx, statedb, header, &config, nil)
|
||||||
|
|
||||||
// Lower the basefee to 0 to avoid breaking EVM
|
// Lower the basefee to 0 to avoid breaking EVM
|
||||||
// invariants (basefee < feecap).
|
// invariants (basefee < feecap).
|
||||||
if msg.GasPrice.Sign() == 0 {
|
if msg.GasPrice.Sign() == 0 {
|
||||||
vmenv.Context.BaseFee = new(big.Int)
|
evm.Context.BaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
|
if msg.BlobGasFeeCap != nil && msg.BlobGasFeeCap.BitLen() == 0 {
|
||||||
vmenv.Context.BlobBaseFee = new(big.Int)
|
evm.Context.BlobBaseFee = new(big.Int)
|
||||||
}
|
}
|
||||||
vmenv.SetTxContext(core.NewEVMTxContext(msg))
|
res, err := core.ApplyMessage(evm, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
||||||
res, err := core.ApplyMessage(vmenv, msg, new(core.GasPool).AddGas(msg.GasLimit))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
|
return nil, 0, nil, fmt.Errorf("failed to apply transaction: %v err: %v", args.ToTransaction(types.LegacyTxType).Hash(), err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,6 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
|
||||||
tracer.reset(tx.Hash(), uint(i))
|
tracer.reset(tx.Hash(), uint(i))
|
||||||
// EoA check is always skipped, even in validation mode.
|
// EoA check is always skipped, even in validation mode.
|
||||||
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
|
msg := call.ToMessage(header.BaseFee, !sim.validate, true)
|
||||||
evm.SetTxContext(core.NewEVMTxContext(msg))
|
|
||||||
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
result, err := applyMessageWithEVM(ctx, evm, msg, timeout, sim.gp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
txErr := txValidationError(err)
|
txErr := txValidationError(err)
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1",
|
"blockHash": "0xb3e447c77374fd285964cba692e96b1673a88a959726826b5b6e2dca15472b0a",
|
||||||
"blockNumber": "0x2",
|
"blockNumber": "0x2",
|
||||||
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
||||||
"cumulativeGasUsed": "0xcf50",
|
"cumulativeGasUsed": "0xcf50",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d",
|
"blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3",
|
||||||
"blockNumber": "0x4",
|
"blockNumber": "0x4",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x538d",
|
"cumulativeGasUsed": "0x538d",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
"blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa",
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5e28",
|
"cumulativeGasUsed": "0x5e28",
|
||||||
|
|
@ -19,7 +19,7 @@
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
"blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa",
|
||||||
"logIndex": "0x0",
|
"logIndex": "0x0",
|
||||||
"removed": false
|
"removed": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9",
|
"blockHash": "0xe9bd1d8c303b1af5c704b9d78e62c54a34af47e0db04ac1389a5ef74a619b9da",
|
||||||
"blockNumber": "0x1",
|
"blockNumber": "0x1",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"blobGasPrice": "0x1",
|
"blobGasPrice": "0x1",
|
||||||
"blobGasUsed": "0x20000",
|
"blobGasUsed": "0x20000",
|
||||||
"blockHash": "0x11e6318d77a45c01f89f76b56d36c6936c5250f4e2bd238cb7b09df73cf0cb7d",
|
"blockHash": "0x17124e31fb075a301b1d7d4135683b0a09fe4e6d453c54e2e734d5ee00744a49",
|
||||||
"blockNumber": "0x6",
|
"blockNumber": "0x6",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0x5526cd89bc188f20fd5e9bb50d8054dc5a51a81a74ed07eacf36a4a8b10de4b1",
|
"blockHash": "0xb3e447c77374fd285964cba692e96b1673a88a959726826b5b6e2dca15472b0a",
|
||||||
"blockNumber": "0x2",
|
"blockNumber": "0x2",
|
||||||
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
"contractAddress": "0xae9bea628c4ce503dcfd7e305cab4e29e7476592",
|
||||||
"cumulativeGasUsed": "0xcf50",
|
"cumulativeGasUsed": "0xcf50",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0xa04ad6be58c45fe483991b89416572bc50426b0de44b769757e95c704250f874",
|
"blockHash": "0x53bffe54375c0a31fe7bc0db7455db7d48278234c2400efa4d40d1c57cbe868d",
|
||||||
"blockNumber": "0x5",
|
"blockNumber": "0x5",
|
||||||
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
|
"contractAddress": "0xfdaa97661a584d977b4d3abb5370766ff5b86a18",
|
||||||
"cumulativeGasUsed": "0xe01c",
|
"cumulativeGasUsed": "0xe01c",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0x3e946aa9e252873af511b257d9d89a1bcafa54ce7c6a6442f8407ecdf81e288d",
|
"blockHash": "0x102e50de30318ee99a03a09db74387e79cad3165bf6840cc84249806a2a302f3",
|
||||||
"blockNumber": "0x4",
|
"blockNumber": "0x4",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x538d",
|
"cumulativeGasUsed": "0x538d",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0xda50d57d8802553b00bb8e4d777bd5c4114086941119ca04edb15429f4818ed9",
|
"blockHash": "0xe9bd1d8c303b1af5c704b9d78e62c54a34af47e0db04ac1389a5ef74a619b9da",
|
||||||
"blockNumber": "0x1",
|
"blockNumber": "0x1",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5208",
|
"cumulativeGasUsed": "0x5208",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
"blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa",
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"contractAddress": null,
|
"contractAddress": null,
|
||||||
"cumulativeGasUsed": "0x5e28",
|
"cumulativeGasUsed": "0x5e28",
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
"blockNumber": "0x3",
|
"blockNumber": "0x3",
|
||||||
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
"transactionHash": "0xeaf3921cbf03ba45bad4e6ab807b196ce3b2a0b5bacc355b6272fa96b11b4287",
|
||||||
"transactionIndex": "0x0",
|
"transactionIndex": "0x0",
|
||||||
"blockHash": "0xc281d4299fc4e8ce5bba7ecb8deb50f5403d604c806b36aa887dfe2ff84c064f",
|
"blockHash": "0xcc6225bf39327429a3d869af71182d619a354155187d0b5a8ecd6a9309cffcaa",
|
||||||
"logIndex": "0x0",
|
"logIndex": "0x0",
|
||||||
"removed": false
|
"removed": false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -121,18 +121,15 @@ func (miner *Miner) generateWork(params *generateParams, witness bool) *newPaylo
|
||||||
// Collect consensus-layer requests if Prague is enabled.
|
// Collect consensus-layer requests if Prague is enabled.
|
||||||
var requests [][]byte
|
var requests [][]byte
|
||||||
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) {
|
||||||
|
requests = [][]byte{}
|
||||||
// EIP-6110 deposits
|
// EIP-6110 deposits
|
||||||
depositRequests, err := core.ParseDepositLogs(allLogs, miner.chainConfig)
|
if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig); err != nil {
|
||||||
if err != nil {
|
|
||||||
return &newPayloadResult{err: err}
|
return &newPayloadResult{err: err}
|
||||||
}
|
}
|
||||||
requests = append(requests, depositRequests)
|
// EIP-7002
|
||||||
// EIP-7002 withdrawals
|
core.ProcessWithdrawalQueue(&requests, work.evm)
|
||||||
withdrawalRequests := core.ProcessWithdrawalQueue(work.evm)
|
|
||||||
requests = append(requests, withdrawalRequests)
|
|
||||||
// EIP-7251 consolidations
|
// EIP-7251 consolidations
|
||||||
consolidationRequests := core.ProcessConsolidationQueue(work.evm)
|
core.ProcessConsolidationQueue(&requests, work.evm)
|
||||||
requests = append(requests, consolidationRequests)
|
|
||||||
}
|
}
|
||||||
if requests != nil {
|
if requests != nil {
|
||||||
reqHash := types.CalcRequestsHash(requests)
|
reqHash := types.CalcRequestsHash(requests)
|
||||||
|
|
|
||||||
|
|
@ -234,10 +234,6 @@ compile_fuzzer github.com/ethereum/go-ethereum/tests/fuzzers/secp256k1 \
|
||||||
|
|
||||||
compile_fuzzer github.com/ethereum/go-ethereum/eth/protocols/eth \
|
compile_fuzzer github.com/ethereum/go-ethereum/eth/protocols/eth \
|
||||||
FuzzEthProtocolHandlers fuzz_eth_protocol_handlers \
|
FuzzEthProtocolHandlers fuzz_eth_protocol_handlers \
|
||||||
$repo/eth/protocols/eth/handler_test.go
|
$repo/eth/protocols/eth/handler_test.go,$repo/eth/protocols/eth/peer_test.go
|
||||||
|
|
||||||
|
|
||||||
#compile_fuzzer tests/fuzzers/vflux FuzzClientPool fuzzClientPool
|
|
||||||
#compile_fuzzer tests/fuzzers/difficulty Fuzz fuzzDifficulty
|
|
||||||
#compile_fuzzer tests/fuzzers/les Fuzz fuzzLes
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -277,7 +277,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the EVM.
|
// Prepare the EVM.
|
||||||
txContext := core.NewEVMTxContext(msg)
|
|
||||||
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
|
context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
|
||||||
context.GetHash = vmTestBlockHash
|
context.GetHash = vmTestBlockHash
|
||||||
context.BaseFee = baseFee
|
context.BaseFee = baseFee
|
||||||
|
|
@ -294,7 +293,6 @@ func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapsh
|
||||||
context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas)
|
context.BlobBaseFee = eip4844.CalcBlobFee(*t.json.Env.ExcessBlobGas)
|
||||||
}
|
}
|
||||||
evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
|
evm := vm.NewEVM(context, st.StateDB, config, vmconfig)
|
||||||
evm.SetTxContext(txContext)
|
|
||||||
|
|
||||||
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
|
if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil {
|
||||||
tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
|
tracer.OnTxStart(evm.GetVMContext(), nil, msg.From)
|
||||||
|
|
|
||||||
|
|
@ -486,13 +486,11 @@ func VerifyRangeProof(rootHash common.Hash, firstKey []byte, keys [][]byte, valu
|
||||||
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
|
return false, fmt.Errorf("inconsistent proof data, keys: %d, values: %d", len(keys), len(values))
|
||||||
}
|
}
|
||||||
// Ensure the received batch is monotonic increasing and contains no deletions
|
// Ensure the received batch is monotonic increasing and contains no deletions
|
||||||
for i := 0; i < len(keys)-1; i++ {
|
for i := 0; i < len(keys); i++ {
|
||||||
if bytes.Compare(keys[i], keys[i+1]) >= 0 {
|
if i < len(keys)-1 && bytes.Compare(keys[i], keys[i+1]) >= 0 {
|
||||||
return false, errors.New("range is not monotonically increasing")
|
return false, errors.New("range is not monotonically increasing")
|
||||||
}
|
}
|
||||||
}
|
if len(values[i]) == 0 {
|
||||||
for _, value := range values {
|
|
||||||
if len(value) == 0 {
|
|
||||||
return false, errors.New("range contains deletion")
|
return false, errors.New("range contains deletion")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -41,10 +41,10 @@ var (
|
||||||
zero = uint256.NewInt(0)
|
zero = uint256.NewInt(0)
|
||||||
verkleNodeWidthLog2 = 8
|
verkleNodeWidthLog2 = 8
|
||||||
headerStorageOffset = uint256.NewInt(64)
|
headerStorageOffset = uint256.NewInt(64)
|
||||||
mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(256), 31-uint(verkleNodeWidthLog2))
|
|
||||||
codeOffset = uint256.NewInt(128)
|
codeOffset = uint256.NewInt(128)
|
||||||
verkleNodeWidth = uint256.NewInt(256)
|
verkleNodeWidth = uint256.NewInt(256)
|
||||||
codeStorageDelta = uint256.NewInt(0).Sub(codeOffset, headerStorageOffset)
|
codeStorageDelta = uint256.NewInt(0).Sub(codeOffset, headerStorageOffset)
|
||||||
|
mainStorageOffsetLshVerkleNodeWidth = new(uint256.Int).Lsh(uint256.NewInt(1), 248-uint(verkleNodeWidthLog2))
|
||||||
|
|
||||||
index0Point *verkle.Point // pre-computed commitment of polynomial [2+256*64]
|
index0Point *verkle.Point // pre-computed commitment of polynomial [2+256*64]
|
||||||
|
|
||||||
|
|
@ -273,17 +273,9 @@ func StorageSlotKeyWithEvaluatedAddress(evaluated *verkle.Point, storageKey []by
|
||||||
}
|
}
|
||||||
|
|
||||||
func pointToHash(evaluated *verkle.Point, suffix byte) []byte {
|
func pointToHash(evaluated *verkle.Point, suffix byte) []byte {
|
||||||
// The output of Byte() is big endian for banderwagon. This
|
retb := verkle.HashPointToBytes(evaluated)
|
||||||
// introduces an imbalance in the tree, because hashes are
|
retb[31] = suffix
|
||||||
// elements of a 253-bit field. This means more than half the
|
return retb[:]
|
||||||
// tree would be empty. To avoid this problem, use a little
|
|
||||||
// endian commitment and chop the MSB.
|
|
||||||
bytes := evaluated.Bytes()
|
|
||||||
for i := 0; i < 16; i++ {
|
|
||||||
bytes[31-i], bytes[i] = bytes[i], bytes[31-i]
|
|
||||||
}
|
|
||||||
bytes[31] = suffix
|
|
||||||
return bytes[:]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func evaluateAddressPoint(address []byte) *verkle.Point {
|
func evaluateAddressPoint(address []byte) *verkle.Point {
|
||||||
|
|
|
||||||
|
|
@ -136,8 +136,8 @@ func TestVerkleRollBack(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure there is some code in the 2nd group
|
// ensure there is some code in the 2nd group of the 1st account
|
||||||
keyOf2ndGroup := []byte{141, 124, 185, 236, 50, 22, 185, 39, 244, 47, 97, 209, 96, 235, 22, 13, 205, 38, 18, 201, 128, 223, 0, 59, 146, 199, 222, 119, 133, 13, 91, 0}
|
keyOf2ndGroup := utils.CodeChunkKeyWithEvaluatedAddress(tr.cache.Get(common.Address{1}.Bytes()), uint256.NewInt(128))
|
||||||
chunk, err := tr.root.Get(keyOf2ndGroup, nil)
|
chunk, err := tr.root.Get(keyOf2ndGroup, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Failed to get account, %v", err)
|
t.Fatalf("Failed to get account, %v", err)
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,10 @@ type backend interface {
|
||||||
// An error will be returned if the specified state is not available.
|
// An error will be returned if the specified state is not available.
|
||||||
NodeReader(root common.Hash) (database.NodeReader, error)
|
NodeReader(root common.Hash) (database.NodeReader, error)
|
||||||
|
|
||||||
|
// StateReader returns a reader for accessing flat states within the specified
|
||||||
|
// state. An error will be returned if the specified state is not available.
|
||||||
|
StateReader(root common.Hash) (database.StateReader, error)
|
||||||
|
|
||||||
// Initialized returns an indicator if the state data is already initialized
|
// Initialized returns an indicator if the state data is already initialized
|
||||||
// according to the state scheme.
|
// according to the state scheme.
|
||||||
Initialized(genesisRoot common.Hash) bool
|
Initialized(genesisRoot common.Hash) bool
|
||||||
|
|
@ -122,6 +126,13 @@ func (db *Database) NodeReader(blockRoot common.Hash) (database.NodeReader, erro
|
||||||
return db.backend.NodeReader(blockRoot)
|
return db.backend.NodeReader(blockRoot)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateReader returns a reader that allows access to the state data associated
|
||||||
|
// with the specified state. An error will be returned if the specified state is
|
||||||
|
// not available.
|
||||||
|
func (db *Database) StateReader(blockRoot common.Hash) (database.StateReader, error) {
|
||||||
|
return db.backend.StateReader(blockRoot)
|
||||||
|
}
|
||||||
|
|
||||||
// Update performs a state transition by committing dirty nodes contained in the
|
// Update performs a state transition by committing dirty nodes contained in the
|
||||||
// given set in order to update state from the specified parent to the specified
|
// given set in order to update state from the specified parent to the specified
|
||||||
// root. The held pre-images accumulated up to this point will be flushed in case
|
// root. The held pre-images accumulated up to this point will be flushed in case
|
||||||
|
|
|
||||||
|
|
@ -635,3 +635,9 @@ func (reader *reader) Node(owner common.Hash, path []byte, hash common.Hash) ([]
|
||||||
blob, _ := reader.db.node(hash)
|
blob, _ := reader.db.node(hash)
|
||||||
return blob, nil
|
return blob, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StateReader returns a reader that allows access to the state data associated
|
||||||
|
// with the specified state.
|
||||||
|
func (db *Database) StateReader(root common.Hash) (database.StateReader, error) {
|
||||||
|
return nil, errors.New("not implemented")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,40 +33,56 @@ import (
|
||||||
// must be checked before diving into disk (since it basically is not yet written
|
// must be checked before diving into disk (since it basically is not yet written
|
||||||
// data).
|
// data).
|
||||||
type buffer struct {
|
type buffer struct {
|
||||||
layers uint64 // The number of diff layers aggregated inside
|
layers uint64 // The number of diff layers aggregated inside
|
||||||
limit uint64 // The maximum memory allowance in bytes
|
limit uint64 // The maximum memory allowance in bytes
|
||||||
nodes *nodeSet // Aggregated trie node set
|
nodes *nodeSet // Aggregated trie node set
|
||||||
|
states *stateSet // Aggregated state set
|
||||||
}
|
}
|
||||||
|
|
||||||
// newBuffer initializes the buffer with the provided states and trie nodes.
|
// newBuffer initializes the buffer with the provided states and trie nodes.
|
||||||
func newBuffer(limit int, nodes *nodeSet, layers uint64) *buffer {
|
func newBuffer(limit int, nodes *nodeSet, states *stateSet, layers uint64) *buffer {
|
||||||
// Don't panic for lazy users if any provided set is nil
|
// Don't panic for lazy users if any provided set is nil
|
||||||
if nodes == nil {
|
if nodes == nil {
|
||||||
nodes = newNodeSet(nil)
|
nodes = newNodeSet(nil)
|
||||||
}
|
}
|
||||||
|
if states == nil {
|
||||||
|
states = newStates(nil, nil)
|
||||||
|
}
|
||||||
return &buffer{
|
return &buffer{
|
||||||
layers: layers,
|
layers: layers,
|
||||||
limit: uint64(limit),
|
limit: uint64(limit),
|
||||||
nodes: nodes,
|
nodes: nodes,
|
||||||
|
states: states,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// account retrieves the account blob with account address hash.
|
||||||
|
func (b *buffer) account(hash common.Hash) ([]byte, bool) {
|
||||||
|
return b.states.account(hash)
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage retrieves the storage slot with account address hash and slot key.
|
||||||
|
func (b *buffer) storage(addrHash common.Hash, storageHash common.Hash) ([]byte, bool) {
|
||||||
|
return b.states.storage(addrHash, storageHash)
|
||||||
|
}
|
||||||
|
|
||||||
// node retrieves the trie node with node path and its trie identifier.
|
// node retrieves the trie node with node path and its trie identifier.
|
||||||
func (b *buffer) node(owner common.Hash, path []byte) (*trienode.Node, bool) {
|
func (b *buffer) node(owner common.Hash, path []byte) (*trienode.Node, bool) {
|
||||||
return b.nodes.node(owner, path)
|
return b.nodes.node(owner, path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// commit merges the provided states and trie nodes into the buffer.
|
// commit merges the provided states and trie nodes into the buffer.
|
||||||
func (b *buffer) commit(nodes *nodeSet) *buffer {
|
func (b *buffer) commit(nodes *nodeSet, states *stateSet) *buffer {
|
||||||
b.layers++
|
b.layers++
|
||||||
b.nodes.merge(nodes)
|
b.nodes.merge(nodes)
|
||||||
|
b.states.merge(states)
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
// revert is the reverse operation of commit. It also merges the provided states
|
// revertTo is the reverse operation of commit. It also merges the provided states
|
||||||
// and trie nodes into the buffer. The key difference is that the provided state
|
// and trie nodes into the buffer. The key difference is that the provided state
|
||||||
// set should reverse the changes made by the most recent state transition.
|
// set should reverse the changes made by the most recent state transition.
|
||||||
func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node) error {
|
func (b *buffer) revertTo(db ethdb.KeyValueReader, nodes map[common.Hash]map[string]*trienode.Node, accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) error {
|
||||||
// Short circuit if no embedded state transition to revert
|
// Short circuit if no embedded state transition to revert
|
||||||
if b.layers == 0 {
|
if b.layers == 0 {
|
||||||
return errStateUnrecoverable
|
return errStateUnrecoverable
|
||||||
|
|
@ -78,7 +94,8 @@ func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[strin
|
||||||
b.reset()
|
b.reset()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
b.nodes.revert(db, nodes)
|
b.nodes.revertTo(db, nodes)
|
||||||
|
b.states.revertTo(accounts, storages)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,6 +103,7 @@ func (b *buffer) revert(db ethdb.KeyValueReader, nodes map[common.Hash]map[strin
|
||||||
func (b *buffer) reset() {
|
func (b *buffer) reset() {
|
||||||
b.layers = 0
|
b.layers = 0
|
||||||
b.nodes.reset()
|
b.nodes.reset()
|
||||||
|
b.states.reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
// empty returns an indicator if buffer is empty.
|
// empty returns an indicator if buffer is empty.
|
||||||
|
|
@ -101,7 +119,7 @@ func (b *buffer) full() bool {
|
||||||
|
|
||||||
// size returns the approximate memory size of the held content.
|
// size returns the approximate memory size of the held content.
|
||||||
func (b *buffer) size() uint64 {
|
func (b *buffer) size() uint64 {
|
||||||
return b.nodes.size
|
return b.states.size + b.nodes.size
|
||||||
}
|
}
|
||||||
|
|
||||||
// flush persists the in-memory dirty trie node into the disk if the configured
|
// flush persists the in-memory dirty trie node into the disk if the configured
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,24 @@ type layer interface {
|
||||||
// - no error will be returned if the requested node is not found in database.
|
// - no error will be returned if the requested node is not found in database.
|
||||||
node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error)
|
node(owner common.Hash, path []byte, depth int) ([]byte, common.Hash, *nodeLoc, error)
|
||||||
|
|
||||||
|
// account directly retrieves the account RLP associated with a particular
|
||||||
|
// hash in the slim data format. An error will be returned if the read
|
||||||
|
// operation exits abnormally. Specifically, if the layer is already stale.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// - the returned account is not a copy, please don't modify it.
|
||||||
|
// - no error will be returned if the requested account is not found in database.
|
||||||
|
account(hash common.Hash, depth int) ([]byte, error)
|
||||||
|
|
||||||
|
// storage directly retrieves the storage data associated with a particular hash,
|
||||||
|
// within a particular account. An error will be returned if the read operation
|
||||||
|
// exits abnormally. Specifically, if the layer is already stale.
|
||||||
|
//
|
||||||
|
// Note:
|
||||||
|
// - the returned storage data is not a copy, please don't modify it.
|
||||||
|
// - no error will be returned if the requested slot is not found in database.
|
||||||
|
storage(accountHash, storageHash common.Hash, depth int) ([]byte, error)
|
||||||
|
|
||||||
// rootHash returns the root hash for which this layer was made.
|
// rootHash returns the root hash for which this layer was made.
|
||||||
rootHash() common.Hash
|
rootHash() common.Hash
|
||||||
|
|
||||||
|
|
@ -130,17 +148,18 @@ var Defaults = &Config{
|
||||||
// ReadOnly is the config in order to open database in read only mode.
|
// ReadOnly is the config in order to open database in read only mode.
|
||||||
var ReadOnly = &Config{ReadOnly: true}
|
var ReadOnly = &Config{ReadOnly: true}
|
||||||
|
|
||||||
// Database is a multiple-layered structure for maintaining in-memory trie nodes.
|
// Database is a multiple-layered structure for maintaining in-memory states
|
||||||
// It consists of one persistent base layer backed by a key-value store, on top
|
// along with its dirty trie nodes. It consists of one persistent base layer
|
||||||
// of which arbitrarily many in-memory diff layers are stacked. The memory diffs
|
// backed by a key-value store, on top of which arbitrarily many in-memory diff
|
||||||
// can form a tree with branching, but the disk layer is singleton and common to
|
// layers are stacked. The memory diffs can form a tree with branching, but the
|
||||||
// all. If a reorg goes deeper than the disk layer, a batch of reverse diffs can
|
// disk layer is singleton and common to all. If a reorg goes deeper than the
|
||||||
// be applied to rollback. The deepest reorg that can be handled depends on the
|
// disk layer, a batch of reverse diffs can be applied to rollback. The deepest
|
||||||
// amount of state histories tracked in the disk.
|
// reorg that can be handled depends on the amount of state histories tracked
|
||||||
|
// in the disk.
|
||||||
//
|
//
|
||||||
// At most one readable and writable database can be opened at the same time in
|
// At most one readable and writable database can be opened at the same time in
|
||||||
// the whole system which ensures that only one database writer can operate disk
|
// the whole system which ensures that only one database writer can operate the
|
||||||
// state. Unexpected open operations can cause the system to panic.
|
// persistent state. Unexpected open operations can cause the system to panic.
|
||||||
type Database struct {
|
type Database struct {
|
||||||
// readOnly is the flag whether the mutation is allowed to be applied.
|
// readOnly is the flag whether the mutation is allowed to be applied.
|
||||||
// It will be set automatically when the database is journaled during
|
// It will be set automatically when the database is journaled during
|
||||||
|
|
@ -358,7 +377,7 @@ func (db *Database) Enable(root common.Hash) error {
|
||||||
}
|
}
|
||||||
// Re-construct a new disk layer backed by persistent state
|
// Re-construct a new disk layer backed by persistent state
|
||||||
// with **empty clean cache and node buffer**.
|
// with **empty clean cache and node buffer**.
|
||||||
db.tree.reset(newDiskLayer(root, 0, db, nil, newBuffer(db.config.WriteBufferSize, nil, 0)))
|
db.tree.reset(newDiskLayer(root, 0, db, nil, newBuffer(db.config.WriteBufferSize, nil, nil, 0)))
|
||||||
|
|
||||||
// Re-enable the database as the final step.
|
// Re-enable the database as the final step.
|
||||||
db.waitSync = false
|
db.waitSync = false
|
||||||
|
|
|
||||||
|
|
@ -309,7 +309,7 @@ func (t *tester) generate(parent common.Hash) (common.Hash, *trienode.MergedNode
|
||||||
delete(t.storages, addrHash)
|
delete(t.storages, addrHash)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return root, ctx.nodes, NewStateSetWithOrigin(ctx.accountOrigin, ctx.storageOrigin)
|
return root, ctx.nodes, NewStateSetWithOrigin(ctx.accounts, ctx.storages, ctx.accountOrigin, ctx.storageOrigin)
|
||||||
}
|
}
|
||||||
|
|
||||||
// lastHash returns the latest root hash, or empty if nothing is cached.
|
// lastHash returns the latest root hash, or empty if nothing is cached.
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ func newDiffLayer(parent layer, root common.Hash, id uint64, block uint64, nodes
|
||||||
states: states,
|
states: states,
|
||||||
}
|
}
|
||||||
dirtyNodeWriteMeter.Mark(int64(nodes.size))
|
dirtyNodeWriteMeter.Mark(int64(nodes.size))
|
||||||
|
dirtyStateWriteMeter.Mark(int64(states.size))
|
||||||
log.Debug("Created new diff layer", "id", id, "block", block, "nodesize", common.StorageSize(nodes.size), "statesize", common.StorageSize(states.size))
|
log.Debug("Created new diff layer", "id", id, "block", block, "nodesize", common.StorageSize(nodes.size), "statesize", common.StorageSize(states.size))
|
||||||
return dl
|
return dl
|
||||||
}
|
}
|
||||||
|
|
@ -96,6 +97,58 @@ func (dl *diffLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
|
||||||
return dl.parent.node(owner, path, depth+1)
|
return dl.parent.node(owner, path, depth+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// account directly retrieves the account RLP associated with a particular
|
||||||
|
// hash in the slim data format.
|
||||||
|
//
|
||||||
|
// Note the returned account is not a copy, please don't modify it.
|
||||||
|
func (dl *diffLayer) account(hash common.Hash, depth int) ([]byte, error) {
|
||||||
|
// Hold the lock, ensure the parent won't be changed during the
|
||||||
|
// state accessing.
|
||||||
|
dl.lock.RLock()
|
||||||
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
if blob, found := dl.states.account(hash); found {
|
||||||
|
dirtyStateHitMeter.Mark(1)
|
||||||
|
dirtyStateHitDepthHist.Update(int64(depth))
|
||||||
|
dirtyStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
|
||||||
|
if len(blob) == 0 {
|
||||||
|
stateAccountInexMeter.Mark(1)
|
||||||
|
} else {
|
||||||
|
stateAccountExistMeter.Mark(1)
|
||||||
|
}
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
// Account is unknown to this layer, resolve from parent
|
||||||
|
return dl.parent.account(hash, depth+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage directly retrieves the storage data associated with a particular hash,
|
||||||
|
// within a particular account.
|
||||||
|
//
|
||||||
|
// Note the returned storage slot is not a copy, please don't modify it.
|
||||||
|
func (dl *diffLayer) storage(accountHash, storageHash common.Hash, depth int) ([]byte, error) {
|
||||||
|
// Hold the lock, ensure the parent won't be changed during the
|
||||||
|
// state accessing.
|
||||||
|
dl.lock.RLock()
|
||||||
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
if blob, found := dl.states.storage(accountHash, storageHash); found {
|
||||||
|
dirtyStateHitMeter.Mark(1)
|
||||||
|
dirtyStateHitDepthHist.Update(int64(depth))
|
||||||
|
dirtyStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
|
||||||
|
if len(blob) == 0 {
|
||||||
|
stateStorageInexMeter.Mark(1)
|
||||||
|
} else {
|
||||||
|
stateStorageExistMeter.Mark(1)
|
||||||
|
}
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
// storage slot is unknown to this layer, resolve from parent
|
||||||
|
return dl.parent.storage(accountHash, storageHash, depth+1)
|
||||||
|
}
|
||||||
|
|
||||||
// update implements the layer interface, creating a new layer on top of the
|
// update implements the layer interface, creating a new layer on top of the
|
||||||
// existing layer tree with the specified data items.
|
// existing layer tree with the specified data items.
|
||||||
func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer {
|
func (dl *diffLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer {
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import (
|
||||||
func emptyLayer() *diskLayer {
|
func emptyLayer() *diskLayer {
|
||||||
return &diskLayer{
|
return &diskLayer{
|
||||||
db: New(rawdb.NewMemoryDatabase(), nil, false),
|
db: New(rawdb.NewMemoryDatabase(), nil, false),
|
||||||
buffer: newBuffer(defaultBufferSize, nil, 0),
|
buffer: newBuffer(defaultBufferSize, nil, nil, 0),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ func benchmarkSearch(b *testing.B, depth int, total int) {
|
||||||
nblob = common.CopyBytes(blob)
|
nblob = common.CopyBytes(blob)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil))
|
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil))
|
||||||
}
|
}
|
||||||
var layer layer
|
var layer layer
|
||||||
layer = emptyLayer()
|
layer = emptyLayer()
|
||||||
|
|
@ -118,7 +118,7 @@ func BenchmarkPersist(b *testing.B) {
|
||||||
)
|
)
|
||||||
nodes[common.Hash{}][string(path)] = node
|
nodes[common.Hash{}][string(path)] = node
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil))
|
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil))
|
||||||
}
|
}
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
b.StopTimer()
|
b.StopTimer()
|
||||||
|
|
@ -156,7 +156,7 @@ func BenchmarkJournal(b *testing.B) {
|
||||||
)
|
)
|
||||||
nodes[common.Hash{}][string(path)] = node
|
nodes[common.Hash{}][string(path)] = node
|
||||||
}
|
}
|
||||||
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), new(StateSetWithOrigin))
|
return newDiffLayer(parent, common.Hash{}, 0, 0, newNodeSet(nodes), NewStateSetWithOrigin(nil, nil, nil, nil))
|
||||||
}
|
}
|
||||||
var layer layer
|
var layer layer
|
||||||
layer = emptyLayer()
|
layer = emptyLayer()
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package pathdb
|
package pathdb
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ type diskLayer struct {
|
||||||
id uint64 // Immutable, corresponding state id
|
id uint64 // Immutable, corresponding state id
|
||||||
db *Database // Path-based trie database
|
db *Database // Path-based trie database
|
||||||
nodes *fastcache.Cache // GC friendly memory cache of clean nodes
|
nodes *fastcache.Cache // GC friendly memory cache of clean nodes
|
||||||
buffer *buffer // Dirty buffer to aggregate writes of nodes
|
buffer *buffer // Dirty buffer to aggregate writes of nodes and states
|
||||||
stale bool // Signals that the layer became stale (state progressed)
|
stale bool // Signals that the layer became stale (state progressed)
|
||||||
lock sync.RWMutex // Lock used to protect stale flag
|
lock sync.RWMutex // Lock used to protect stale flag
|
||||||
}
|
}
|
||||||
|
|
@ -140,6 +141,75 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co
|
||||||
return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil
|
return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// account directly retrieves the account RLP associated with a particular
|
||||||
|
// hash in the slim data format.
|
||||||
|
//
|
||||||
|
// Note the returned account is not a copy, please don't modify it.
|
||||||
|
func (dl *diskLayer) account(hash common.Hash, depth int) ([]byte, error) {
|
||||||
|
dl.lock.RLock()
|
||||||
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
if dl.stale {
|
||||||
|
return nil, errSnapshotStale
|
||||||
|
}
|
||||||
|
// Try to retrieve the account from the not-yet-written
|
||||||
|
// node buffer first. Note the buffer is lock free since
|
||||||
|
// it's impossible to mutate the buffer before tagging the
|
||||||
|
// layer as stale.
|
||||||
|
blob, found := dl.buffer.account(hash)
|
||||||
|
if found {
|
||||||
|
dirtyStateHitMeter.Mark(1)
|
||||||
|
dirtyStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
dirtyStateHitDepthHist.Update(int64(depth))
|
||||||
|
|
||||||
|
if len(blob) == 0 {
|
||||||
|
stateAccountInexMeter.Mark(1)
|
||||||
|
} else {
|
||||||
|
stateAccountExistMeter.Mark(1)
|
||||||
|
}
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
dirtyStateMissMeter.Mark(1)
|
||||||
|
|
||||||
|
// TODO(rjl493456442) support persistent state retrieval
|
||||||
|
return nil, errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
// storage directly retrieves the storage data associated with a particular hash,
|
||||||
|
// within a particular account.
|
||||||
|
//
|
||||||
|
// Note the returned account is not a copy, please don't modify it.
|
||||||
|
func (dl *diskLayer) storage(accountHash, storageHash common.Hash, depth int) ([]byte, error) {
|
||||||
|
// Hold the lock, ensure the parent won't be changed during the
|
||||||
|
// state accessing.
|
||||||
|
dl.lock.RLock()
|
||||||
|
defer dl.lock.RUnlock()
|
||||||
|
|
||||||
|
if dl.stale {
|
||||||
|
return nil, errSnapshotStale
|
||||||
|
}
|
||||||
|
// Try to retrieve the storage slot from the not-yet-written
|
||||||
|
// node buffer first. Note the buffer is lock free since
|
||||||
|
// it's impossible to mutate the buffer before tagging the
|
||||||
|
// layer as stale.
|
||||||
|
if blob, found := dl.buffer.storage(accountHash, storageHash); found {
|
||||||
|
dirtyStateHitMeter.Mark(1)
|
||||||
|
dirtyStateReadMeter.Mark(int64(len(blob)))
|
||||||
|
dirtyStateHitDepthHist.Update(int64(depth))
|
||||||
|
|
||||||
|
if len(blob) == 0 {
|
||||||
|
stateStorageInexMeter.Mark(1)
|
||||||
|
} else {
|
||||||
|
stateStorageExistMeter.Mark(1)
|
||||||
|
}
|
||||||
|
return blob, nil
|
||||||
|
}
|
||||||
|
dirtyStateMissMeter.Mark(1)
|
||||||
|
|
||||||
|
// TODO(rjl493456442) support persistent state retrieval
|
||||||
|
return nil, errors.New("not supported")
|
||||||
|
}
|
||||||
|
|
||||||
// update implements the layer interface, returning a new diff layer on top
|
// update implements the layer interface, returning a new diff layer on top
|
||||||
// with the given state set.
|
// with the given state set.
|
||||||
func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer {
|
func (dl *diskLayer) update(root common.Hash, id uint64, block uint64, nodes *nodeSet, states *StateSetWithOrigin) *diffLayer {
|
||||||
|
|
@ -190,14 +260,14 @@ func (dl *diskLayer) commit(bottom *diffLayer, force bool) (*diskLayer, error) {
|
||||||
|
|
||||||
// In a unique scenario where the ID of the oldest history object (after tail
|
// In a unique scenario where the ID of the oldest history object (after tail
|
||||||
// truncation) surpasses the persisted state ID, we take the necessary action
|
// truncation) surpasses the persisted state ID, we take the necessary action
|
||||||
// of forcibly committing the cached dirty nodes to ensure that the persisted
|
// of forcibly committing the cached dirty states to ensure that the persisted
|
||||||
// state ID remains higher.
|
// state ID remains higher.
|
||||||
if !force && rawdb.ReadPersistentStateID(dl.db.diskdb) < oldest {
|
if !force && rawdb.ReadPersistentStateID(dl.db.diskdb) < oldest {
|
||||||
force = true
|
force = true
|
||||||
}
|
}
|
||||||
// Merge the trie nodes of the bottom-most diff layer into the buffer as the
|
// Merge the trie nodes and flat states of the bottom-most diff layer into the
|
||||||
// combined layer.
|
// buffer as the combined layer.
|
||||||
combined := dl.buffer.commit(bottom.nodes)
|
combined := dl.buffer.commit(bottom.nodes, bottom.states.stateSet)
|
||||||
if combined.full() || force {
|
if combined.full() || force {
|
||||||
if err := combined.flush(dl.db.diskdb, dl.db.freezer, dl.nodes, bottom.stateID()); err != nil {
|
if err := combined.flush(dl.db.diskdb, dl.db.freezer, dl.nodes, bottom.stateID()); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -225,6 +295,24 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
|
||||||
if dl.id == 0 {
|
if dl.id == 0 {
|
||||||
return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable)
|
return nil, fmt.Errorf("%w: zero state id", errStateUnrecoverable)
|
||||||
}
|
}
|
||||||
|
var (
|
||||||
|
buff = crypto.NewKeccakState()
|
||||||
|
hashes = make(map[common.Address]common.Hash)
|
||||||
|
accounts = make(map[common.Hash][]byte)
|
||||||
|
storages = make(map[common.Hash]map[common.Hash][]byte)
|
||||||
|
)
|
||||||
|
for addr, blob := range h.accounts {
|
||||||
|
hash := crypto.HashData(buff, addr.Bytes())
|
||||||
|
hashes[addr] = hash
|
||||||
|
accounts[hash] = blob
|
||||||
|
}
|
||||||
|
for addr, storage := range h.storages {
|
||||||
|
hash, ok := hashes[addr]
|
||||||
|
if !ok {
|
||||||
|
panic(fmt.Errorf("storage history with no account %x", addr))
|
||||||
|
}
|
||||||
|
storages[hash] = storage
|
||||||
|
}
|
||||||
// Apply the reverse state changes upon the current state. This must
|
// Apply the reverse state changes upon the current state. This must
|
||||||
// be done before holding the lock in order to access state in "this"
|
// be done before holding the lock in order to access state in "this"
|
||||||
// layer.
|
// layer.
|
||||||
|
|
@ -244,7 +332,7 @@ func (dl *diskLayer) revert(h *history) (*diskLayer, error) {
|
||||||
// needs to be reverted is not yet flushed and cached in node
|
// needs to be reverted is not yet flushed and cached in node
|
||||||
// buffer, otherwise, manipulate persistent state directly.
|
// buffer, otherwise, manipulate persistent state directly.
|
||||||
if !dl.buffer.empty() {
|
if !dl.buffer.empty() {
|
||||||
err := dl.buffer.revert(dl.db.diskdb, nodes)
|
err := dl.buffer.revertTo(dl.db.diskdb, nodes, accounts, storages)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,8 @@ var (
|
||||||
//
|
//
|
||||||
// - Version 0: initial version
|
// - Version 0: initial version
|
||||||
// - Version 1: storage.Incomplete field is removed
|
// - Version 1: storage.Incomplete field is removed
|
||||||
const journalVersion uint64 = 1
|
// - Version 2: add post-modification state values
|
||||||
|
const journalVersion uint64 = 2
|
||||||
|
|
||||||
// loadJournal tries to parse the layer journal from the disk.
|
// loadJournal tries to parse the layer journal from the disk.
|
||||||
func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
|
func (db *Database) loadJournal(diskRoot common.Hash) (layer, error) {
|
||||||
|
|
@ -108,7 +109,7 @@ func (db *Database) loadLayers() layer {
|
||||||
log.Info("Failed to load journal, discard it", "err", err)
|
log.Info("Failed to load journal, discard it", "err", err)
|
||||||
}
|
}
|
||||||
// Return single layer with persistent state.
|
// Return single layer with persistent state.
|
||||||
return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, newBuffer(db.config.WriteBufferSize, nil, 0))
|
return newDiskLayer(root, rawdb.ReadPersistentStateID(db.diskdb), db, nil, newBuffer(db.config.WriteBufferSize, nil, nil, 0))
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadDiskLayer reads the binary blob from the layer journal, reconstructing
|
// loadDiskLayer reads the binary blob from the layer journal, reconstructing
|
||||||
|
|
@ -135,7 +136,12 @@ func (db *Database) loadDiskLayer(r *rlp.Stream) (layer, error) {
|
||||||
if err := nodes.decode(r); err != nil {
|
if err := nodes.decode(r); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return newDiskLayer(root, id, db, nil, newBuffer(db.config.WriteBufferSize, &nodes, id-stored)), nil
|
// Resolve flat state sets in aggregated buffer
|
||||||
|
var states stateSet
|
||||||
|
if err := states.decode(r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return newDiskLayer(root, id, db, nil, newBuffer(db.config.WriteBufferSize, &nodes, &states, id-stored)), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadDiffLayer reads the next sections of a layer journal, reconstructing a new
|
// loadDiffLayer reads the next sections of a layer journal, reconstructing a new
|
||||||
|
|
@ -189,6 +195,10 @@ func (dl *diskLayer) journal(w io.Writer) error {
|
||||||
if err := dl.buffer.nodes.encode(w); err != nil {
|
if err := dl.buffer.nodes.encode(w); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
// Step four, write the accumulated flat states into the journal
|
||||||
|
if err := dl.buffer.states.encode(w); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
log.Debug("Journaled pathdb disk layer", "root", dl.root)
|
log.Debug("Journaled pathdb disk layer", "root", dl.root)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue