|
|
|
@ -18,70 +18,112 @@ |
|
|
|
|
package main |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"flag" |
|
|
|
|
"fmt" |
|
|
|
|
"log" |
|
|
|
|
"math/big" |
|
|
|
|
"os" |
|
|
|
|
"runtime" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/codegangsta/cli" |
|
|
|
|
"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/state" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/types" |
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm" |
|
|
|
|
"github.com/ethereum/go-ethereum/ethdb" |
|
|
|
|
"github.com/ethereum/go-ethereum/logger" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var ( |
|
|
|
|
code = flag.String("code", "", "evm code") |
|
|
|
|
loglevel = flag.Int("log", 4, "log level") |
|
|
|
|
gas = flag.String("gas", "1000000000", "gas amount") |
|
|
|
|
price = flag.String("price", "0", "gas price") |
|
|
|
|
value = flag.String("value", "0", "tx value") |
|
|
|
|
dump = flag.Bool("dump", false, "dump state after run") |
|
|
|
|
data = flag.String("data", "", "data") |
|
|
|
|
app *cli.App |
|
|
|
|
DebugFlag = cli.BoolFlag{ |
|
|
|
|
Name: "debug", |
|
|
|
|
Usage: "output full trace logs", |
|
|
|
|
} |
|
|
|
|
CodeFlag = cli.StringFlag{ |
|
|
|
|
Name: "code", |
|
|
|
|
Usage: "EVM code", |
|
|
|
|
} |
|
|
|
|
GasFlag = cli.StringFlag{ |
|
|
|
|
Name: "gas", |
|
|
|
|
Usage: "gas limit for the evm", |
|
|
|
|
Value: "10000000000", |
|
|
|
|
} |
|
|
|
|
PriceFlag = cli.StringFlag{ |
|
|
|
|
Name: "price", |
|
|
|
|
Usage: "price set for the evm", |
|
|
|
|
Value: "0", |
|
|
|
|
} |
|
|
|
|
ValueFlag = cli.StringFlag{ |
|
|
|
|
Name: "value", |
|
|
|
|
Usage: "value set for the evm", |
|
|
|
|
Value: "0", |
|
|
|
|
} |
|
|
|
|
DumpFlag = cli.BoolFlag{ |
|
|
|
|
Name: "dump", |
|
|
|
|
Usage: "dumps the state after the run", |
|
|
|
|
} |
|
|
|
|
InputFlag = cli.StringFlag{ |
|
|
|
|
Name: "input", |
|
|
|
|
Usage: "input for the EVM", |
|
|
|
|
} |
|
|
|
|
SysStatFlag = cli.BoolFlag{ |
|
|
|
|
Name: "sysstat", |
|
|
|
|
Usage: "display system stats", |
|
|
|
|
} |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
func perr(v ...interface{}) { |
|
|
|
|
fmt.Println(v...) |
|
|
|
|
//os.Exit(1)
|
|
|
|
|
func init() { |
|
|
|
|
app = utils.NewApp("0.2", "the evm command line interface") |
|
|
|
|
app.Flags = []cli.Flag{ |
|
|
|
|
DebugFlag, |
|
|
|
|
SysStatFlag, |
|
|
|
|
CodeFlag, |
|
|
|
|
GasFlag, |
|
|
|
|
PriceFlag, |
|
|
|
|
ValueFlag, |
|
|
|
|
DumpFlag, |
|
|
|
|
InputFlag, |
|
|
|
|
} |
|
|
|
|
app.Action = run |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
|
flag.Parse() |
|
|
|
|
|
|
|
|
|
logger.AddLogSystem(logger.NewStdLogSystem(os.Stdout, log.LstdFlags, logger.LogLevel(*loglevel))) |
|
|
|
|
func run(ctx *cli.Context) { |
|
|
|
|
vm.Debug = ctx.GlobalBool(DebugFlag.Name) |
|
|
|
|
|
|
|
|
|
vm.Debug = true |
|
|
|
|
db, _ := ethdb.NewMemDatabase() |
|
|
|
|
statedb := state.New(common.Hash{}, db) |
|
|
|
|
sender := statedb.CreateAccount(common.StringToAddress("sender")) |
|
|
|
|
receiver := statedb.CreateAccount(common.StringToAddress("receiver")) |
|
|
|
|
receiver.SetCode(common.Hex2Bytes(*code)) |
|
|
|
|
receiver.SetCode(common.Hex2Bytes(ctx.GlobalString(CodeFlag.Name))) |
|
|
|
|
|
|
|
|
|
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(*value)) |
|
|
|
|
vmenv := NewEnv(statedb, common.StringToAddress("evmuser"), common.Big(ctx.GlobalString(ValueFlag.Name))) |
|
|
|
|
|
|
|
|
|
tstart := time.Now() |
|
|
|
|
ret, e := vmenv.Call( |
|
|
|
|
sender, |
|
|
|
|
receiver.Address(), |
|
|
|
|
common.Hex2Bytes(ctx.GlobalString(InputFlag.Name)), |
|
|
|
|
common.Big(ctx.GlobalString(GasFlag.Name)), |
|
|
|
|
common.Big(ctx.GlobalString(PriceFlag.Name)), |
|
|
|
|
common.Big(ctx.GlobalString(ValueFlag.Name)), |
|
|
|
|
) |
|
|
|
|
vmdone := time.Since(tstart) |
|
|
|
|
|
|
|
|
|
ret, e := vmenv.Call(sender, receiver.Address(), common.Hex2Bytes(*data), common.Big(*gas), common.Big(*price), common.Big(*value)) |
|
|
|
|
|
|
|
|
|
logger.Flush() |
|
|
|
|
if e != nil { |
|
|
|
|
perr(e) |
|
|
|
|
fmt.Println(e) |
|
|
|
|
os.Exit(1) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if *dump { |
|
|
|
|
if ctx.GlobalBool(DumpFlag.Name) { |
|
|
|
|
fmt.Println(string(statedb.Dump())) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
vm.StdErrFormat(vmenv.StructLogs()) |
|
|
|
|
|
|
|
|
|
if ctx.GlobalBool(SysStatFlag.Name) { |
|
|
|
|
var mem runtime.MemStats |
|
|
|
|
runtime.ReadMemStats(&mem) |
|
|
|
|
fmt.Printf("vm took %v\n", time.Since(tstart)) |
|
|
|
|
fmt.Printf("vm took %v\n", vmdone) |
|
|
|
|
fmt.Printf(`alloc: %d |
|
|
|
|
tot alloc: %d |
|
|
|
|
no. malloc: %d |
|
|
|
@ -89,8 +131,16 @@ heap alloc: %d |
|
|
|
|
heap objs: %d |
|
|
|
|
num gc: %d |
|
|
|
|
`, mem.Alloc, mem.TotalAlloc, mem.Mallocs, mem.HeapAlloc, mem.HeapObjects, mem.NumGC) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fmt.Printf("%x\n", ret) |
|
|
|
|
fmt.Printf("OUT: 0x%x\n", ret) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func main() { |
|
|
|
|
if err := app.Run(os.Args); err != nil { |
|
|
|
|
fmt.Fprintln(os.Stderr, err) |
|
|
|
|
os.Exit(1) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type VMEnv struct { |
|
|
|
|