go-ethereum/cmd/evm/main.go
Guillaume Ballet 2a2f106a01
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run
cmd/evm/internal/t8ntool, trie: support for verkle-at-genesis, use UBT, and move the transition tree to its own package (#32445)
This is broken off of #31730 to only focus on testing networks that
start with verkle at genesis.

The PR has seen a lot of work since its creation, and it now targets
creating and re-executing tests for a binary tree testnet without the
transition (so it starts at genesis). The transition tree has been moved
to its own package. It also replaces verkle with the binary tree for
this specific application.

---------

Co-authored-by: Gary Rong <garyrong0905@gmail.com>
2025-11-14 15:25:30 +01:00

341 lines
9.1 KiB
Go

// Copyright 2014 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/>.
// evm executes EVM code snippets.
package main
import (
"fmt"
"io/fs"
"os"
"path/filepath"
"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/flags"
"github.com/urfave/cli/v2"
// Force-load the tracer engines to trigger registration
_ "github.com/ethereum/go-ethereum/eth/tracers/js"
_ "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 (
// Test running flags.
RunFlag = &cli.StringFlag{
Name: "run",
Value: ".*",
Usage: "Run only those tests matching the regular expression.",
}
BenchFlag = &cli.BoolFlag{
Name: "bench",
Usage: "benchmark the execution",
Category: flags.VMCategory,
}
WitnessCrossCheckFlag = &cli.BoolFlag{
Name: "cross-check",
Aliases: []string{"xc"},
Usage: "Cross-check stateful execution against stateless, verifying the witness generation.",
}
// Debugging flags.
DumpFlag = &cli.BoolFlag{
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 (json|struct|md)",
Value: "json",
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{
Name: "json",
Usage: "output trace logs in machine readable format, json (deprecated)",
Hidden: true,
Category: traceCategory,
}
)
// Command definitions.
var (
stateTransitionCommand = &cli.Command{
Name: "transition",
Aliases: []string{"t8n"},
Usage: "Executes a full state transition",
Action: t8ntool.Transition,
Flags: []cli.Flag{
t8ntool.TraceFlag,
t8ntool.TraceTracerFlag,
t8ntool.TraceTracerConfigFlag,
t8ntool.TraceEnableMemoryFlag,
t8ntool.TraceDisableStackFlag,
t8ntool.TraceEnableReturnDataFlag,
t8ntool.TraceEnableCallFramesFlag,
t8ntool.OutputBasedir,
t8ntool.OutputAllocFlag,
t8ntool.OutputBTFlag,
t8ntool.OutputResultFlag,
t8ntool.OutputBodyFlag,
t8ntool.InputAllocFlag,
t8ntool.InputEnvFlag,
t8ntool.InputBTFlag,
t8ntool.InputTxsFlag,
t8ntool.ForknameFlag,
t8ntool.ChainIDFlag,
t8ntool.RewardFlag,
},
}
verkleCommand = &cli.Command{
Name: "verkle",
Aliases: []string{"vkt"},
Usage: "Binary Trie helpers",
Subcommands: []*cli.Command{
{
Name: "tree-keys",
Aliases: []string{"v"},
Usage: "compute a set of binary trie keys, given their source addresses and optional slot numbers",
Action: t8ntool.BinKeys,
Flags: []cli.Flag{
t8ntool.InputAllocFlag,
},
},
{
Name: "single-key",
Aliases: []string{"vk"},
Usage: "compute the binary trie key given an address and optional slot number",
Action: t8ntool.BinKey,
},
{
Name: "code-chunk-key",
Aliases: []string{"vck"},
Usage: "compute the binary trie key given an address and chunk number",
Action: t8ntool.BinaryCodeChunkKey,
},
{
Name: "chunkify-code",
Aliases: []string{"vcc"},
Usage: "chunkify a given bytecode for a binary trie",
Action: t8ntool.BinaryCodeChunkCode,
},
{
Name: "state-root",
Aliases: []string{"vsr"},
Usage: "compute the state-root of a binary trie for the given alloc",
Action: t8ntool.BinTrieRoot,
Flags: []cli.Flag{
t8ntool.InputAllocFlag,
},
},
},
}
transactionCommand = &cli.Command{
Name: "transaction",
Aliases: []string{"t9n"},
Usage: "Performs transaction validation",
Action: t8ntool.Transaction,
Flags: []cli.Flag{
t8ntool.InputTxsFlag,
t8ntool.ChainIDFlag,
t8ntool.ForknameFlag,
},
}
blockBuilderCommand = &cli.Command{
Name: "block-builder",
Aliases: []string{"b11r"},
Usage: "Builds a block",
Action: t8ntool.BuildBlock,
Flags: []cli.Flag{
t8ntool.OutputBasedir,
t8ntool.OutputBlockFlag,
t8ntool.InputHeaderFlag,
t8ntool.InputOmmersFlag,
t8ntool.InputWithdrawalsFlag,
t8ntool.InputTxsRlpFlag,
t8ntool.SealCliqueFlag,
},
}
)
// traceFlags contains flags that configure tracing output.
var traceFlags = []cli.Flag{
TraceFlag,
TraceFormatFlag,
TraceDisableStackFlag,
TraceDisableMemoryFlag,
TraceDisableStorageFlag,
TraceDisableReturnDataFlag,
// deprecated
DebugFlag,
MachineFlag,
}
var app = flags.NewApp("the evm command line interface")
func init() {
app.Flags = debug.Flags
app.Commands = []*cli.Command{
runCommand,
blockTestCommand,
stateTestCommand,
stateTransitionCommand,
transactionCommand,
blockBuilderCommand,
verkleCommand,
}
app.Before = func(ctx *cli.Context) error {
flags.MigrateGlobalFlags(ctx)
return debug.Setup(ctx)
}
app.After = func(ctx *cli.Context) error {
debug.Exit()
return nil
}
}
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
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):
switch format := ctx.String(TraceFormatFlag.Name); format {
case "struct":
return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
case "json":
return logger.NewJSONLogger(config, os.Stderr)
case "md", "markdown":
return logger.NewMarkdownLogger(config, os.Stderr).Hooks()
default:
fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format)
os.Exit(1)
return nil
}
// Deprecated ways of configuring tracing.
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
}
}
// collectFiles walks the given path. If the path is a directory, it will
// return a list of all accumulates all files with json extension.
// Otherwise (if path points to a file), it will return the path.
func collectFiles(path string) []string {
var out []string
if info, err := os.Stat(path); err == nil && !info.IsDir() {
// User explicitly pointed out a file, ignore extension.
return []string{path}
}
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
}