github.com/ethereum/go-ethereum@v1.16.1/cmd/evm/main.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // evm executes EVM code snippets.
    18  package main
    19  
    20  import (
    21  	"fmt"
    22  	"io/fs"
    23  	"os"
    24  	"path/filepath"
    25  
    26  	"github.com/ethereum/go-ethereum/cmd/evm/internal/t8ntool"
    27  	"github.com/ethereum/go-ethereum/core/state"
    28  	"github.com/ethereum/go-ethereum/core/tracing"
    29  	"github.com/ethereum/go-ethereum/eth/tracers/logger"
    30  	"github.com/ethereum/go-ethereum/internal/debug"
    31  	"github.com/ethereum/go-ethereum/internal/flags"
    32  	"github.com/urfave/cli/v2"
    33  
    34  	// Force-load the tracer engines to trigger registration
    35  	_ "github.com/ethereum/go-ethereum/eth/tracers/js"
    36  	_ "github.com/ethereum/go-ethereum/eth/tracers/native"
    37  )
    38  
    39  // Some other nice-to-haves:
    40  // * accumulate traces into an object to bundle with test
    41  // * write tx identifier for trace before hand (blocktest only)
    42  // * combine blocktest and statetest runner logic using unified test interface
    43  
    44  const traceCategory = "TRACING"
    45  
    46  var (
    47  	// Test running flags.
    48  	RunFlag = &cli.StringFlag{
    49  		Name:  "run",
    50  		Value: ".*",
    51  		Usage: "Run only those tests matching the regular expression.",
    52  	}
    53  	BenchFlag = &cli.BoolFlag{
    54  		Name:     "bench",
    55  		Usage:    "benchmark the execution",
    56  		Category: flags.VMCategory,
    57  	}
    58  	WitnessCrossCheckFlag = &cli.BoolFlag{
    59  		Name:    "cross-check",
    60  		Aliases: []string{"xc"},
    61  		Usage:   "Cross-check stateful execution against stateless, verifying the witness generation.",
    62  	}
    63  
    64  	// Debugging flags.
    65  	DumpFlag = &cli.BoolFlag{
    66  		Name:  "dump",
    67  		Usage: "dumps the state after the run",
    68  	}
    69  	HumanReadableFlag = &cli.BoolFlag{
    70  		Name:  "human",
    71  		Usage: "\"Human-readable\" output",
    72  	}
    73  	StatDumpFlag = &cli.BoolFlag{
    74  		Name:  "statdump",
    75  		Usage: "displays stack and heap memory information",
    76  	}
    77  
    78  	// Tracing flags.
    79  	TraceFlag = &cli.BoolFlag{
    80  		Name:     "trace",
    81  		Usage:    "Enable tracing and output trace log.",
    82  		Category: traceCategory,
    83  	}
    84  	TraceFormatFlag = &cli.StringFlag{
    85  		Name:     "trace.format",
    86  		Usage:    "Trace output format to use (json|struct|md)",
    87  		Value:    "json",
    88  		Category: traceCategory,
    89  	}
    90  	TraceDisableMemoryFlag = &cli.BoolFlag{
    91  		Name:     "trace.nomemory",
    92  		Aliases:  []string{"nomemory"},
    93  		Value:    true,
    94  		Usage:    "disable memory output",
    95  		Category: traceCategory,
    96  	}
    97  	TraceDisableStackFlag = &cli.BoolFlag{
    98  		Name:     "trace.nostack",
    99  		Aliases:  []string{"nostack"},
   100  		Usage:    "disable stack output",
   101  		Category: traceCategory,
   102  	}
   103  	TraceDisableStorageFlag = &cli.BoolFlag{
   104  		Name:     "trace.nostorage",
   105  		Aliases:  []string{"nostorage"},
   106  		Usage:    "disable storage output",
   107  		Category: traceCategory,
   108  	}
   109  	TraceDisableReturnDataFlag = &cli.BoolFlag{
   110  		Name:     "trace.noreturndata",
   111  		Aliases:  []string{"noreturndata"},
   112  		Value:    true,
   113  		Usage:    "enable return data output",
   114  		Category: traceCategory,
   115  	}
   116  
   117  	// Deprecated flags.
   118  	DebugFlag = &cli.BoolFlag{
   119  		Name:     "debug",
   120  		Usage:    "output full trace logs (deprecated)",
   121  		Hidden:   true,
   122  		Category: traceCategory,
   123  	}
   124  	MachineFlag = &cli.BoolFlag{
   125  		Name:     "json",
   126  		Usage:    "output trace logs in machine readable format, json (deprecated)",
   127  		Hidden:   true,
   128  		Category: traceCategory,
   129  	}
   130  )
   131  
   132  // Command definitions.
   133  var (
   134  	stateTransitionCommand = &cli.Command{
   135  		Name:    "transition",
   136  		Aliases: []string{"t8n"},
   137  		Usage:   "Executes a full state transition",
   138  		Action:  t8ntool.Transition,
   139  		Flags: []cli.Flag{
   140  			t8ntool.TraceFlag,
   141  			t8ntool.TraceTracerFlag,
   142  			t8ntool.TraceTracerConfigFlag,
   143  			t8ntool.TraceEnableMemoryFlag,
   144  			t8ntool.TraceDisableStackFlag,
   145  			t8ntool.TraceEnableReturnDataFlag,
   146  			t8ntool.TraceEnableCallFramesFlag,
   147  			t8ntool.OutputBasedir,
   148  			t8ntool.OutputAllocFlag,
   149  			t8ntool.OutputResultFlag,
   150  			t8ntool.OutputBodyFlag,
   151  			t8ntool.InputAllocFlag,
   152  			t8ntool.InputEnvFlag,
   153  			t8ntool.InputTxsFlag,
   154  			t8ntool.ForknameFlag,
   155  			t8ntool.ChainIDFlag,
   156  			t8ntool.RewardFlag,
   157  		},
   158  	}
   159  	transactionCommand = &cli.Command{
   160  		Name:    "transaction",
   161  		Aliases: []string{"t9n"},
   162  		Usage:   "Performs transaction validation",
   163  		Action:  t8ntool.Transaction,
   164  		Flags: []cli.Flag{
   165  			t8ntool.InputTxsFlag,
   166  			t8ntool.ChainIDFlag,
   167  			t8ntool.ForknameFlag,
   168  		},
   169  	}
   170  
   171  	blockBuilderCommand = &cli.Command{
   172  		Name:    "block-builder",
   173  		Aliases: []string{"b11r"},
   174  		Usage:   "Builds a block",
   175  		Action:  t8ntool.BuildBlock,
   176  		Flags: []cli.Flag{
   177  			t8ntool.OutputBasedir,
   178  			t8ntool.OutputBlockFlag,
   179  			t8ntool.InputHeaderFlag,
   180  			t8ntool.InputOmmersFlag,
   181  			t8ntool.InputWithdrawalsFlag,
   182  			t8ntool.InputTxsRlpFlag,
   183  			t8ntool.SealCliqueFlag,
   184  		},
   185  	}
   186  )
   187  
   188  // traceFlags contains flags that configure tracing output.
   189  var traceFlags = []cli.Flag{
   190  	TraceFlag,
   191  	TraceFormatFlag,
   192  	TraceDisableStackFlag,
   193  	TraceDisableMemoryFlag,
   194  	TraceDisableStorageFlag,
   195  	TraceDisableReturnDataFlag,
   196  
   197  	// deprecated
   198  	DebugFlag,
   199  	MachineFlag,
   200  }
   201  
   202  var app = flags.NewApp("the evm command line interface")
   203  
   204  func init() {
   205  	app.Flags = debug.Flags
   206  	app.Commands = []*cli.Command{
   207  		runCommand,
   208  		blockTestCommand,
   209  		stateTestCommand,
   210  		stateTransitionCommand,
   211  		transactionCommand,
   212  		blockBuilderCommand,
   213  	}
   214  	app.Before = func(ctx *cli.Context) error {
   215  		flags.MigrateGlobalFlags(ctx)
   216  		return debug.Setup(ctx)
   217  	}
   218  	app.After = func(ctx *cli.Context) error {
   219  		debug.Exit()
   220  		return nil
   221  	}
   222  }
   223  
   224  func main() {
   225  	if err := app.Run(os.Args); err != nil {
   226  		fmt.Fprintln(os.Stderr, err)
   227  		os.Exit(1)
   228  	}
   229  }
   230  
   231  // tracerFromFlags parses the cli flags and returns the specified tracer.
   232  func tracerFromFlags(ctx *cli.Context) *tracing.Hooks {
   233  	config := &logger.Config{
   234  		EnableMemory:     !ctx.Bool(TraceDisableMemoryFlag.Name),
   235  		DisableStack:     ctx.Bool(TraceDisableStackFlag.Name),
   236  		DisableStorage:   ctx.Bool(TraceDisableStorageFlag.Name),
   237  		EnableReturnData: !ctx.Bool(TraceDisableReturnDataFlag.Name),
   238  	}
   239  	switch {
   240  	case ctx.Bool(TraceFlag.Name):
   241  		switch format := ctx.String(TraceFormatFlag.Name); format {
   242  		case "struct":
   243  			return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
   244  		case "json":
   245  			return logger.NewJSONLogger(config, os.Stderr)
   246  		case "md", "markdown":
   247  			return logger.NewMarkdownLogger(config, os.Stderr).Hooks()
   248  		default:
   249  			fmt.Fprintf(os.Stderr, "unknown trace format: %q\n", format)
   250  			os.Exit(1)
   251  			return nil
   252  		}
   253  	// Deprecated ways of configuring tracing.
   254  	case ctx.Bool(MachineFlag.Name):
   255  		return logger.NewJSONLogger(config, os.Stderr)
   256  	case ctx.Bool(DebugFlag.Name):
   257  		return logger.NewStreamingStructLogger(config, os.Stderr).Hooks()
   258  	default:
   259  		return nil
   260  	}
   261  }
   262  
   263  // collectFiles walks the given path. If the path is a directory, it will
   264  // return a list of all accumulates all files with json extension.
   265  // Otherwise (if path points to a file), it will return the path.
   266  func collectFiles(path string) []string {
   267  	var out []string
   268  	if info, err := os.Stat(path); err == nil && !info.IsDir() {
   269  		// User explicitly pointed out a file, ignore extension.
   270  		return []string{path}
   271  	}
   272  	err := filepath.Walk(path, func(path string, info fs.FileInfo, err error) error {
   273  		if err != nil {
   274  			return err
   275  		}
   276  		if !info.IsDir() && filepath.Ext(info.Name()) == ".json" {
   277  			out = append(out, path)
   278  		}
   279  		return nil
   280  	})
   281  	if err != nil {
   282  		fmt.Fprintln(os.Stderr, err)
   283  	}
   284  	return out
   285  }
   286  
   287  // dump returns a state dump for the most current trie.
   288  func dump(s *state.StateDB) *state.Dump {
   289  	root := s.IntermediateRoot(false)
   290  	cpy, _ := state.New(root, s.Database())
   291  	dump := cpy.RawDump(nil)
   292  	return &dump
   293  }