diff --git a/cmd/evm/README.md b/cmd/evm/README.md index 418417475d..8f0848bde8 100644 --- a/cmd/evm/README.md +++ b/cmd/evm/README.md @@ -29,6 +29,8 @@ Command line params that has to be supported are --trace Output full trace logs to files .jsonl --trace.nomemory Disable full memory dump in traces --trace.nostack Disable stack output in traces + --trace.noreturndata Disable return data output in traces + --output.basedir value Specifies where output files are placed. Will be created if it does not exist. (default: ".") --output.alloc alloc Determines where to put the alloc of the post-state. `stdout` - into the stdout output `stderr` - into the stderr output @@ -232,13 +234,13 @@ Example where blockhashes are provided: ./evm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace ``` ``` -cat trace-0.jsonl | grep BLOCKHASH -C2 +cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 ``` ``` -{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"depth":1,"refund":0,"opName":"PUSH1","error":""} -{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnStack":[],"depth":1,"refund":0,"opName":"BLOCKHASH","error":""} -{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnStack":[],"depth":1,"refund":0,"opName":"STOP","error":""} -{"output":"","gasUsed":"0x17","time":155861} +{"pc":0,"op":96,"gas":"0x5f58ef8","gasCost":"0x3","memory":"0x","memSize":0,"stack":[],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"PUSH1","error":""} +{"pc":2,"op":64,"gas":"0x5f58ef5","gasCost":"0x14","memory":"0x","memSize":0,"stack":["0x1"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"BLOCKHASH","error":""} +{"pc":3,"op":0,"gas":"0x5f58ee1","gasCost":"0x0","memory":"0x","memSize":0,"stack":["0xdac58aa524e50956d0c0bae7f3f8bb9d35381365d07804dd5b48a5a297c06af4"],"returnStack":[],"returnData":null,"depth":1,"refund":0,"opName":"STOP","error":""} +{"output":"","gasUsed":"0x17","time":112885} ``` In this example, the caller has not provided the required blockhash: @@ -254,9 +256,9 @@ Error code: 4 Another thing that can be done, is to chain invocations: ``` ./evm t8n --input.alloc=./testdata/1/alloc.json --input.txs=./testdata/1/txs.json --input.env=./testdata/1/env.json --output.alloc=stdout | ./evm t8n --input.alloc=stdin --input.env=./testdata/1/env.json --input.txs=./testdata/1/txs.json -INFO [06-29|11:52:04.934] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" -INFO [06-29|11:52:04.936] rejected tx index=0 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" -INFO [06-29|11:52:04.936] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" +INFO [08-03|15:25:15.168] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" +INFO [08-03|15:25:15.169] rejected tx index=0 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" +INFO [08-03|15:25:15.169] rejected tx index=1 hash="0557ba…18d673" from=0x8A8eAFb1cf62BfBeb1741769DAE1a9dd47996192 error="nonce too low" ``` What happened here, is that we first applied two identical transactions, so the second one was rejected. diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index a4fa971ebb..0fd6b869fc 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -81,7 +81,7 @@ type stEnvMarshaling struct { // Apply applies a set of transactions to a pre-state func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, txs types.Transactions, miningReward int64, - getTracerFn func(txIndex int) (tracer vm.Tracer, err error)) (*state.StateDB, *ExecutionResult, error) { + getTracerFn func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error)) (*state.StateDB, *ExecutionResult, error) { // Capture errors for BLOCKHASH operation, if we haven't been supplied the // required blockhashes @@ -135,7 +135,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, rejectedTxs = append(rejectedTxs, i) continue } - tracer, err := getTracerFn(txIndex) + tracer, err := getTracerFn(txIndex, tx.Hash()) if err != nil { return nil, nil, err } diff --git a/cmd/evm/internal/t8ntool/flags.go b/cmd/evm/internal/t8ntool/flags.go index d110af2c30..424156ba82 100644 --- a/cmd/evm/internal/t8ntool/flags.go +++ b/cmd/evm/internal/t8ntool/flags.go @@ -42,6 +42,11 @@ var ( Name: "trace.noreturndata", Usage: "Disable return data output in traces", } + OutputBasedir = cli.StringFlag{ + Name: "output.basedir", + Usage: "Specifies where output files are placed. Will be created if it does not exist.", + Value: "", + } OutputAllocFlag = cli.StringFlag{ Name: "output.alloc", Usage: "Determines where to put the `alloc` of the post-state.\n" + diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 079307b975..5119ed5fb7 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -22,6 +22,7 @@ import ( "io/ioutil" "math/big" "os" + "path" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -75,11 +76,22 @@ func Main(ctx *cli.Context) error { log.Root().SetHandler(glogger) var ( - err error - tracer vm.Tracer + err error + tracer vm.Tracer + baseDir = "" ) - var getTracer func(txIndex int) (vm.Tracer, error) + var getTracer func(txIndex int, txHash common.Hash) (vm.Tracer, error) + // If user specified a basedir, make sure it exists + if ctx.IsSet(OutputBasedir.Name) { + if base := ctx.String(OutputBasedir.Name); len(base) > 0 { + err := os.MkdirAll(base, 0755) // //rw-r--r-- + if err != nil { + return NewError(ErrorIO, fmt.Errorf("failed creating output basedir: %v", err)) + } + baseDir = base + } + } if ctx.Bool(TraceFlag.Name) { // Configure the EVM logger logConfig := &vm.LogConfig{ @@ -95,11 +107,11 @@ func Main(ctx *cli.Context) error { prevFile.Close() } }() - getTracer = func(txIndex int) (vm.Tracer, error) { + getTracer = func(txIndex int, txHash common.Hash) (vm.Tracer, error) { if prevFile != nil { prevFile.Close() } - traceFile, err := os.Create(fmt.Sprintf("trace-%d.jsonl", txIndex)) + traceFile, err := os.Create(path.Join(baseDir, fmt.Sprintf("trace-%d-%v.jsonl", txIndex, txHash.String()))) if err != nil { return nil, NewError(ErrorIO, fmt.Errorf("failed creating trace-file: %v", err)) } @@ -107,7 +119,7 @@ func Main(ctx *cli.Context) error { return vm.NewJSONLogger(logConfig, traceFile), nil } } else { - getTracer = func(txIndex int) (tracer vm.Tracer, err error) { + getTracer = func(txIndex int, txHash common.Hash) (tracer vm.Tracer, err error) { return nil, nil } } @@ -197,7 +209,7 @@ func Main(ctx *cli.Context) error { //postAlloc := state.DumpGenesisFormat(false, false, false) collector := make(Alloc) state.DumpToCollector(collector, false, false, false, nil, -1) - return dispatchOutput(ctx, result, collector) + return dispatchOutput(ctx, baseDir, result, collector) } @@ -224,12 +236,12 @@ func (g Alloc) OnAccount(addr common.Address, dumpAccount state.DumpAccount) { } // saveFile marshalls the object to the given file -func saveFile(filename string, data interface{}) error { +func saveFile(baseDir, filename string, data interface{}) error { b, err := json.MarshalIndent(data, "", " ") if err != nil { return NewError(ErrorJson, fmt.Errorf("failed marshalling output: %v", err)) } - if err = ioutil.WriteFile(filename, b, 0644); err != nil { + if err = ioutil.WriteFile(path.Join(baseDir, filename), b, 0644); err != nil { return NewError(ErrorIO, fmt.Errorf("failed writing output: %v", err)) } return nil @@ -237,26 +249,26 @@ func saveFile(filename string, data interface{}) error { // dispatchOutput writes the output data to either stderr or stdout, or to the specified // files -func dispatchOutput(ctx *cli.Context, result *ExecutionResult, alloc Alloc) error { +func dispatchOutput(ctx *cli.Context, baseDir string, result *ExecutionResult, alloc Alloc) error { stdOutObject := make(map[string]interface{}) stdErrObject := make(map[string]interface{}) - dispatch := func(fName, name string, obj interface{}) error { + dispatch := func(baseDir, fName, name string, obj interface{}) error { switch fName { case "stdout": stdOutObject[name] = obj case "stderr": stdErrObject[name] = obj default: // save to file - if err := saveFile(fName, obj); err != nil { + if err := saveFile(baseDir, fName, obj); err != nil { return err } } return nil } - if err := dispatch(ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { + if err := dispatch(baseDir, ctx.String(OutputAllocFlag.Name), "alloc", alloc); err != nil { return err } - if err := dispatch(ctx.String(OutputResultFlag.Name), "result", result); err != nil { + if err := dispatch(baseDir, ctx.String(OutputResultFlag.Name), "result", result); err != nil { return err } if len(stdOutObject) > 0 { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 7b472350d9..35c672142d 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -146,6 +146,7 @@ var stateTransitionCommand = cli.Command{ t8ntool.TraceDisableMemoryFlag, t8ntool.TraceDisableStackFlag, t8ntool.TraceDisableReturnDataFlag, + t8ntool.OutputBasedir, t8ntool.OutputAllocFlag, t8ntool.OutputResultFlag, t8ntool.InputAllocFlag, diff --git a/cmd/evm/transition-test.sh b/cmd/evm/transition-test.sh index d1400ca577..34c9249855 100644 --- a/cmd/evm/transition-test.sh +++ b/cmd/evm/transition-test.sh @@ -155,10 +155,10 @@ echo "Example where blockhashes are provided: " cmd="./evm t8n --input.alloc=./testdata/3/alloc.json --input.txs=./testdata/3/txs.json --input.env=./testdata/3/env.json --trace" tick && echo $cmd && tick $cmd 2>&1 >/dev/null -cmd="cat trace-0.jsonl | grep BLOCKHASH -C2" +cmd="cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2" tick && echo $cmd && tick echo "$ticks" -cat trace-0.jsonl | grep BLOCKHASH -C2 +cat trace-0-0x72fadbef39cd251a437eea619cfeda752271a5faaaa2147df012e112159ffb81.jsonl | grep BLOCKHASH -C2 echo "$ticks" echo ""