diff options
author | Jeffrey Wilcke <jeffrey@ethereum.org> | 2017-03-01 08:11:24 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2017-03-01 08:11:24 +0800 |
commit | 230cf2ec9142b6a8f421cb8873deb5df1566e89c (patch) | |
tree | b437803c8d90384d8ecb68e8a180db384535c018 /cmd/evm | |
parent | 7ff75ac2f2f8a62d52367271194aa7889a5b5c88 (diff) | |
download | dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar.gz dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar.bz2 dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar.lz dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar.xz dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.tar.zst dexon-230cf2ec9142b6a8f421cb8873deb5df1566e89c.zip |
cmd/evm, core/asm: add EVM assembler (#3686)
The evm compile command implements a simple assembly language that compiles to
EVM bytecode.
Diffstat (limited to 'cmd/evm')
-rw-r--r-- | cmd/evm/compiler.go | 55 | ||||
-rw-r--r-- | cmd/evm/internal/compiler/compiler.go | 39 | ||||
-rw-r--r-- | cmd/evm/main.go | 118 | ||||
-rw-r--r-- | cmd/evm/runner.go | 145 |
4 files changed, 242 insertions, 115 deletions
diff --git a/cmd/evm/compiler.go b/cmd/evm/compiler.go new file mode 100644 index 000000000..c019a2fe7 --- /dev/null +++ b/cmd/evm/compiler.go @@ -0,0 +1,55 @@ +// Copyright 2017 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/>. + +package main + +import ( + "errors" + "fmt" + "io/ioutil" + + "github.com/ethereum/go-ethereum/cmd/evm/internal/compiler" + + cli "gopkg.in/urfave/cli.v1" +) + +var compileCommand = cli.Command{ + Action: compileCmd, + Name: "compile", + Usage: "compiles easm source to evm binary", + ArgsUsage: "<file>", +} + +func compileCmd(ctx *cli.Context) error { + debug := ctx.GlobalBool(DebugFlag.Name) + + if len(ctx.Args().First()) == 0 { + return errors.New("filename required") + } + + fn := ctx.Args().First() + src, err := ioutil.ReadFile(fn) + if err != nil { + return err + } + + bin, err := compiler.Compile(fn, src, debug) + if err != nil { + return err + } + fmt.Println(bin) + return nil +} diff --git a/cmd/evm/internal/compiler/compiler.go b/cmd/evm/internal/compiler/compiler.go new file mode 100644 index 000000000..753ca6226 --- /dev/null +++ b/cmd/evm/internal/compiler/compiler.go @@ -0,0 +1,39 @@ +// Copyright 2017 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/>. + +package compiler + +import ( + "errors" + "fmt" + + "github.com/ethereum/go-ethereum/core/asm" +) + +func Compile(fn string, src []byte, debug bool) (string, error) { + compiler := asm.NewCompiler(debug) + compiler.Feed(asm.Lex(fn, src, debug)) + + bin, compileErrors := compiler.Compile() + if len(compileErrors) > 0 { + // report errors + for _, err := range compileErrors { + fmt.Printf("%s:%v\n", fn, err) + } + return "", errors.New("compiling failed") + } + return bin, nil +} diff --git a/cmd/evm/main.go b/cmd/evm/main.go index 601e62f77..5ce45b9ca 100644 --- a/cmd/evm/main.go +++ b/cmd/evm/main.go @@ -19,19 +19,10 @@ package main import ( "fmt" - "io/ioutil" "math/big" "os" - goruntime "runtime" - "time" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/common" - "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" "gopkg.in/urfave/cli.v1" ) @@ -108,113 +99,10 @@ func init() { InputFlag, DisableGasMeteringFlag, } - app.Action = run -} - -func run(ctx *cli.Context) error { - glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) - glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) - log.Root().SetHandler(glogger) - - var ( - db, _ = ethdb.NewMemDatabase() - statedb, _ = state.New(common.Hash{}, db) - address = common.StringToAddress("sender") - sender = vm.AccountRef(address) - ) - statedb.CreateAccount(common.StringToAddress("sender")) - - logger := vm.NewStructLogger(nil) - - tstart := time.Now() - - var ( - code []byte - ret []byte - err error - ) - - if ctx.GlobalString(CodeFlag.Name) != "" { - code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) - } else { - var hexcode []byte - if ctx.GlobalString(CodeFileFlag.Name) != "" { - var err error - hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) - if err != nil { - fmt.Printf("Could not load code from file: %v\n", err) - os.Exit(1) - } - } else { - var err error - hexcode, err = ioutil.ReadAll(os.Stdin) - if err != nil { - fmt.Printf("Could not load code from stdin: %v\n", err) - os.Exit(1) - } - } - code = common.Hex2Bytes(string(hexcode[:])) - } - - if ctx.GlobalBool(CreateFlag.Name) { - input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) - ret, _, err = runtime.Create(input, &runtime.Config{ - Origin: sender.Address(), - State: statedb, - GasLimit: ctx.GlobalUint64(GasFlag.Name), - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), - EVMConfig: vm.Config{ - Tracer: logger, - Debug: ctx.GlobalBool(DebugFlag.Name), - DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), - }, - }) - } else { - receiverAddress := common.StringToAddress("receiver") - statedb.CreateAccount(receiverAddress) - statedb.SetCode(receiverAddress, code) - - ret, err = runtime.Call(receiverAddress, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ - Origin: sender.Address(), - State: statedb, - GasLimit: ctx.GlobalUint64(GasFlag.Name), - GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), - Value: utils.GlobalBig(ctx, ValueFlag.Name), - EVMConfig: vm.Config{ - Tracer: logger, - Debug: ctx.GlobalBool(DebugFlag.Name), - DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), - }, - }) - } - vmdone := time.Since(tstart) - - if ctx.GlobalBool(DumpFlag.Name) { - statedb.Commit(true) - fmt.Println(string(statedb.Dump())) - } - vm.StdErrFormat(logger.StructLogs()) - - if ctx.GlobalBool(SysStatFlag.Name) { - var mem goruntime.MemStats - goruntime.ReadMemStats(&mem) - fmt.Printf("vm took %v\n", vmdone) - fmt.Printf(`alloc: %d -tot alloc: %d -no. malloc: %d -heap alloc: %d -heap objs: %d -num gc: %d -`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) - } - - fmt.Printf("OUT: 0x%x", ret) - if err != nil { - fmt.Printf(" error: %v", err) + app.Commands = []cli.Command{ + compileCommand, + runCommand, } - fmt.Println() - return nil } func main() { diff --git a/cmd/evm/runner.go b/cmd/evm/runner.go new file mode 100644 index 000000000..0bed46894 --- /dev/null +++ b/cmd/evm/runner.go @@ -0,0 +1,145 @@ +// Copyright 2017 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/>. + +package main + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "time" + + goruntime "runtime" + + "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" + "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" + cli "gopkg.in/urfave/cli.v1" +) + +var runCommand = cli.Command{ + Action: runCmd, + Name: "run", + Usage: "run arbitrary evm binary", + ArgsUsage: "<code>", + Description: `The run command runs arbitrary EVM code.`, +} + +func runCmd(ctx *cli.Context) error { + glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) + glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) + log.Root().SetHandler(glogger) + + var ( + db, _ = ethdb.NewMemDatabase() + statedb, _ = state.New(common.Hash{}, db) + sender = common.StringToAddress("sender") + logger = vm.NewStructLogger(nil) + tstart = time.Now() + ) + statedb.CreateAccount(sender) + + var ( + code []byte + ret []byte + err error + ) + if ctx.GlobalString(CodeFlag.Name) != "" { + code = common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name)) + } else { + var hexcode []byte + if ctx.GlobalString(CodeFileFlag.Name) != "" { + var err error + hexcode, err = ioutil.ReadFile(ctx.GlobalString(CodeFileFlag.Name)) + if err != nil { + fmt.Printf("Could not load code from file: %v\n", err) + os.Exit(1) + } + } else { + var err error + hexcode, err = ioutil.ReadAll(os.Stdin) + if err != nil { + fmt.Printf("Could not load code from stdin: %v\n", err) + os.Exit(1) + } + } + code = common.Hex2Bytes(string(bytes.TrimRight(hexcode, "\n"))) + } + + if ctx.GlobalBool(CreateFlag.Name) { + input := append(code, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name))...) + ret, _, err = runtime.Create(input, &runtime.Config{ + Origin: sender, + State: statedb, + GasLimit: ctx.GlobalUint64(GasFlag.Name), + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + EVMConfig: vm.Config{ + Tracer: logger, + Debug: ctx.GlobalBool(DebugFlag.Name), + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) + } else { + receiver := common.StringToAddress("receiver") + statedb.SetCode(receiver, code) + + ret, err = runtime.Call(receiver, common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), &runtime.Config{ + Origin: sender, + State: statedb, + GasLimit: ctx.GlobalUint64(GasFlag.Name), + GasPrice: utils.GlobalBig(ctx, PriceFlag.Name), + Value: utils.GlobalBig(ctx, ValueFlag.Name), + EVMConfig: vm.Config{ + Tracer: logger, + Debug: ctx.GlobalBool(DebugFlag.Name), + DisableGasMetering: ctx.GlobalBool(DisableGasMeteringFlag.Name), + }, + }) + } + vmdone := time.Since(tstart) + + if ctx.GlobalBool(DumpFlag.Name) { + statedb.Commit(true) + fmt.Println(string(statedb.Dump())) + } + vm.StdErrFormat(logger.StructLogs()) + + if ctx.GlobalBool(SysStatFlag.Name) { + var mem goruntime.MemStats + goruntime.ReadMemStats(&mem) + fmt.Printf("vm took %v\n", vmdone) + fmt.Printf(`alloc: %d +tot alloc: %d +no. malloc: %d +heap alloc: %d +heap objs: %d +num gc: %d +`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) + } + + fmt.Printf("OUT: 0x%x", ret) + if err != nil { + fmt.Printf(" error: %v", err) + } + fmt.Println() + return nil +} |