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 }