diff --git a/cmd/evm/disasm.go b/cmd/evm/disasm.go index 4a442cf784..69f611e39b 100644 --- a/cmd/evm/disasm.go +++ b/cmd/evm/disasm.go @@ -44,7 +44,7 @@ func disasmCmd(ctx *cli.Context) error { return err } - code := strings.TrimSpace(string(in[:])) + code := strings.TrimSpace(string(in)) fmt.Printf("%v\n", code) return asm.PrintDisassembled(code) } diff --git a/cmd/evm/internal/compiler/compiler.go b/cmd/evm/internal/compiler/compiler.go index 753ca62264..54981b6697 100644 --- a/cmd/evm/internal/compiler/compiler.go +++ b/cmd/evm/internal/compiler/compiler.go @@ -25,7 +25,7 @@ import ( func Compile(fn string, src []byte, debug bool) (string, error) { compiler := asm.NewCompiler(debug) - compiler.Feed(asm.Lex(fn, src, debug)) + compiler.Feed(asm.Lex(src, debug)) bin, compileErrors := compiler.Compile() if len(compileErrors) > 0 { diff --git a/cmd/evm/main.go b/cmd/evm/main.go index a59cb1fb84..ebac2047aa 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -110,6 +110,11 @@ var ( Name: "nostack", Usage: "disable stack output", } + EVMInterpreterFlag = cli.StringFlag{ + Name: "vm.evm", + Usage: "External EVM configuration (default = built-in interpreter)", + Value: "", + } ) func init() { @@ -133,6 +138,7 @@ func init() { ReceiverFlag, DisableMemoryFlag, DisableStackFlag, + EVMInterpreterFlag, } app.Commands = []cli.Command{ compileCommand, diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go index 8a7399840c..bc5d00cfbe 100644 --- a/cmd/evm/runner.go +++ b/cmd/evm/runner.go @@ -21,20 +21,20 @@ import ( "encoding/json" "fmt" "io/ioutil" + "math/big" "os" + goruntime "runtime" "runtime/pprof" "time" - goruntime "runtime" - "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" + "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/runtime" - "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/params" cli "gopkg.in/urfave/cli.v1" @@ -76,18 +76,20 @@ func runCmd(ctx *cli.Context) error { logconfig := &vm.LogConfig{ DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name), DisableStack: ctx.GlobalBool(DisableStackFlag.Name), + Debug: ctx.GlobalBool(DebugFlag.Name), } var ( - tracer vm.Tracer - debugLogger *vm.StructLogger - statedb *state.StateDB - chainConfig *params.ChainConfig - sender = common.StringToAddress("sender") - receiver = common.StringToAddress("receiver") + tracer vm.Tracer + debugLogger *vm.StructLogger + statedb *state.StateDB + chainConfig *params.ChainConfig + sender = common.BytesToAddress([]byte("sender")) + receiver = common.BytesToAddress([]byte("receiver")) + genesisConfig *core.Genesis ) if ctx.GlobalBool(MachineFlag.Name) { - tracer = NewJSONLogger(logconfig, os.Stdout) + tracer = vm.NewJSONLogger(logconfig, os.Stdout) } else if ctx.GlobalBool(DebugFlag.Name) { debugLogger = vm.NewStructLogger(logconfig) tracer = debugLogger @@ -96,13 +98,14 @@ func runCmd(ctx *cli.Context) error { } if ctx.GlobalString(GenesisFlag.Name) != "" { gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) - db, _ := ethdb.NewMemDatabase() + genesisConfig = gen + db := rawdb.NewMemoryDatabase() genesis := gen.ToBlock(db) statedb, _ = state.New(genesis.Root(), state.NewDatabase(db)) chainConfig = gen.Config } else { - db, _ := ethdb.NewMemDatabase() - statedb, _ = state.New(common.Hash{}, state.NewDatabase(db)) + statedb, _ = state.New(common.Hash{}, state.NewDatabase(rawdb.NewMemoryDatabase())) + genesisConfig = new(core.Genesis) } if ctx.GlobalString(SenderFlag.Name) != "" { sender = common.HexToAddress(ctx.GlobalString(SenderFlag.Name)) @@ -154,15 +157,23 @@ func runCmd(ctx *cli.Context) error { } initialGas := ctx.GlobalUint64(GasFlag.Name) + if genesisConfig.GasLimit != 0 { + initialGas = genesisConfig.GasLimit + } runtimeConfig := runtime.Config{ - Origin: sender, - State: statedb, - GasLimit: initialGas, - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), + Origin: sender, + State: statedb, + GasLimit: initialGas, + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + Difficulty: genesisConfig.Difficulty, + Time: new(big.Int).SetUint64(genesisConfig.Timestamp), + Coinbase: genesisConfig.Coinbase, + BlockNumber: new(big.Int).SetUint64(genesisConfig.Number), EVMConfig: vm.Config{ - Tracer: tracer, - Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + Tracer: tracer, + Debug: ctx.GlobalBool(DebugFlag.Name) || ctx.GlobalBool(MachineFlag.Name), + EVMInterpreter: ctx.GlobalString(EVMInterpreterFlag.Name), }, } @@ -196,6 +207,7 @@ func runCmd(ctx *cli.Context) error { execTime := time.Since(tstart) if ctx.GlobalBool(DumpFlag.Name) { + statedb.Commit(true) statedb.IntermediateRoot(true) fmt.Println(string(statedb.Dump())) } @@ -234,9 +246,7 @@ Gas used: %d `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC, initialGas-leftOverGas) } - if tracer != nil { - tracer.CaptureEnd(ret, initialGas-leftOverGas, execTime, err) - } else { + if tracer == nil { fmt.Printf("0x%x\n", ret) if err != nil { fmt.Printf(" error: %v\n", err) diff --git a/cmd/evm/staterunner.go b/cmd/evm/staterunner.go index 071ea94ad0..b3c69d9b9d 100644 --- a/cmd/evm/staterunner.go +++ b/cmd/evm/staterunner.go @@ -38,6 +38,8 @@ var stateTestCommand = cli.Command{ ArgsUsage: "", } +// 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"` @@ -66,7 +68,7 @@ func stateTestCmd(ctx *cli.Context) error { ) switch { case ctx.GlobalBool(MachineFlag.Name): - tracer = NewJSONLogger(config, os.Stderr) + tracer = vm.NewJSONLogger(config, os.Stderr) case ctx.GlobalBool(DebugFlag.Name): debugger = vm.NewStructLogger(config) @@ -95,6 +97,10 @@ func stateTestCmd(ctx *cli.Context) error { // Run the test and aggregate the result result := &StatetestResult{Name: key, Fork: st.Fork, Pass: true} state, err := test.Run(st, cfg) + // print state root for evmlab tracing + if ctx.GlobalBool(MachineFlag.Name) && state != nil { + fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) + } if err != nil { // Test failed, mark as so and dump any state to aid debugging result.Pass, result.Error = false, err.Error() @@ -103,10 +109,6 @@ func stateTestCmd(ctx *cli.Context) error { result.State = &dump } } - // print state root for evmlab tracing (already committed above, so no need to delete objects again - if ctx.GlobalBool(MachineFlag.Name) && state != nil { - fmt.Fprintf(os.Stderr, "{\"stateRoot\": \"%x\"}\n", state.IntermediateRoot(false)) - } results = append(results, *result)