cmd/evm, core/vm: add --nomemory, --nostack to evm (#14617)

This commit is contained in:
Martin Holst Swende 2017-06-21 14:52:31 +02:00 committed by Felix Lange
parent 9012863ad7
commit 9a44e1035e
5 changed files with 68 additions and 47 deletions

View File

@ -28,25 +28,32 @@ import (
type JSONLogger struct { type JSONLogger struct {
encoder *json.Encoder encoder *json.Encoder
cfg *vm.LogConfig
} }
func NewJSONLogger(writer io.Writer) *JSONLogger { func NewJSONLogger(cfg *vm.LogConfig, writer io.Writer) *JSONLogger {
return &JSONLogger{json.NewEncoder(writer)} return &JSONLogger{json.NewEncoder(writer), cfg}
} }
// CaptureState outputs state information on the logger. // CaptureState outputs state information on the logger.
func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error { func (l *JSONLogger) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode, gas, cost uint64, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
return l.encoder.Encode(vm.StructLog{ log := vm.StructLog{
Pc: pc, Pc: pc,
Op: op, Op: op,
Gas: gas + cost, Gas: gas + cost,
GasCost: cost, GasCost: cost,
Memory: memory.Data(), MemorySize: memory.Len(),
Stack: stack.Data(), Storage: nil,
Storage: nil, Depth: depth,
Depth: depth, Err: err,
Err: err, }
}) if !l.cfg.DisableMemory {
log.Memory = memory.Data()
}
if !l.cfg.DisableStack {
log.Stack = stack.Data()
}
return l.encoder.Encode(log)
} }
// CaptureEnd is triggered at end of execution. // CaptureEnd is triggered at end of execution.

View File

@ -102,6 +102,14 @@ var (
Name: "sender", Name: "sender",
Usage: "The transaction origin", Usage: "The transaction origin",
} }
DisableMemoryFlag = cli.BoolFlag{
Name: "nomemory",
Usage: "disable memory output",
}
DisableStackFlag = cli.BoolFlag{
Name: "nostack",
Usage: "disable stack output",
}
) )
func init() { func init() {
@ -123,6 +131,8 @@ func init() {
GenesisFlag, GenesisFlag,
MachineFlag, MachineFlag,
SenderFlag, SenderFlag,
DisableMemoryFlag,
DisableStackFlag,
} }
app.Commands = []cli.Command{ app.Commands = []cli.Command{
compileCommand, compileCommand,

View File

@ -73,6 +73,10 @@ func runCmd(ctx *cli.Context) error {
glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false))) glogger := log.NewGlogHandler(log.StreamHandler(os.Stderr, log.TerminalFormat(false)))
glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name))) glogger.Verbosity(log.Lvl(ctx.GlobalInt(VerbosityFlag.Name)))
log.Root().SetHandler(glogger) log.Root().SetHandler(glogger)
logconfig := &vm.LogConfig{
DisableMemory: ctx.GlobalBool(DisableMemoryFlag.Name),
DisableStack: ctx.GlobalBool(DisableStackFlag.Name),
}
var ( var (
tracer vm.Tracer tracer vm.Tracer
@ -82,12 +86,12 @@ func runCmd(ctx *cli.Context) error {
sender = common.StringToAddress("sender") sender = common.StringToAddress("sender")
) )
if ctx.GlobalBool(MachineFlag.Name) { if ctx.GlobalBool(MachineFlag.Name) {
tracer = NewJSONLogger(os.Stdout) tracer = NewJSONLogger(logconfig, os.Stdout)
} else if ctx.GlobalBool(DebugFlag.Name) { } else if ctx.GlobalBool(DebugFlag.Name) {
debugLogger = vm.NewStructLogger(nil) debugLogger = vm.NewStructLogger(logconfig)
tracer = debugLogger tracer = debugLogger
} else { } else {
debugLogger = vm.NewStructLogger(nil) debugLogger = vm.NewStructLogger(logconfig)
} }
if ctx.GlobalString(GenesisFlag.Name) != "" { if ctx.GlobalString(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))

View File

@ -18,12 +18,12 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
Gas math.HexOrDecimal64 `json:"gas"` Gas math.HexOrDecimal64 `json:"gas"`
GasCost math.HexOrDecimal64 `json:"gasCost"` GasCost math.HexOrDecimal64 `json:"gasCost"`
Memory hexutil.Bytes `json:"memory"` Memory hexutil.Bytes `json:"memory"`
MemorySize int `json:"memSize"`
Stack []*math.HexOrDecimal256 `json:"stack"` Stack []*math.HexOrDecimal256 `json:"stack"`
Storage map[common.Hash]common.Hash `json:"-"` Storage map[common.Hash]common.Hash `json:"-"`
Depth int `json:"depth"` Depth int `json:"depth"`
Err error `json:"error"` Err error `json:"error"`
OpName string `json:"opName"` OpName string `json:"opName"`
MemorySize int `json:"memSize"`
} }
var enc StructLog var enc StructLog
enc.Pc = s.Pc enc.Pc = s.Pc
@ -31,6 +31,7 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.Gas = math.HexOrDecimal64(s.Gas) enc.Gas = math.HexOrDecimal64(s.Gas)
enc.GasCost = math.HexOrDecimal64(s.GasCost) enc.GasCost = math.HexOrDecimal64(s.GasCost)
enc.Memory = s.Memory enc.Memory = s.Memory
enc.MemorySize = s.MemorySize
if s.Stack != nil { if s.Stack != nil {
enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack)) enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack))
for k, v := range s.Stack { for k, v := range s.Stack {
@ -41,21 +42,21 @@ func (s StructLog) MarshalJSON() ([]byte, error) {
enc.Depth = s.Depth enc.Depth = s.Depth
enc.Err = s.Err enc.Err = s.Err
enc.OpName = s.OpName() enc.OpName = s.OpName()
enc.MemorySize = s.MemorySize()
return json.Marshal(&enc) return json.Marshal(&enc)
} }
func (s *StructLog) UnmarshalJSON(input []byte) error { func (s *StructLog) UnmarshalJSON(input []byte) error {
type StructLog struct { type StructLog struct {
Pc *uint64 `json:"pc"` Pc *uint64 `json:"pc"`
Op *OpCode `json:"op"` Op *OpCode `json:"op"`
Gas *math.HexOrDecimal64 `json:"gas"` Gas *math.HexOrDecimal64 `json:"gas"`
GasCost *math.HexOrDecimal64 `json:"gasCost"` GasCost *math.HexOrDecimal64 `json:"gasCost"`
Memory hexutil.Bytes `json:"memory"` Memory hexutil.Bytes `json:"memory"`
Stack []*math.HexOrDecimal256 `json:"stack"` MemorySize *int `json:"memSize"`
Storage map[common.Hash]common.Hash `json:"-"` Stack []*math.HexOrDecimal256 `json:"stack"`
Depth *int `json:"depth"` Storage map[common.Hash]common.Hash `json:"-"`
Err *error `json:"error"` Depth *int `json:"depth"`
Err *error `json:"error"`
} }
var dec StructLog var dec StructLog
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
@ -76,6 +77,9 @@ func (s *StructLog) UnmarshalJSON(input []byte) error {
if dec.Memory != nil { if dec.Memory != nil {
s.Memory = dec.Memory s.Memory = dec.Memory
} }
if dec.MemorySize != nil {
s.MemorySize = *dec.MemorySize
}
if dec.Stack != nil { if dec.Stack != nil {
s.Stack = make([]*big.Int, len(dec.Stack)) s.Stack = make([]*big.Int, len(dec.Stack))
for k, v := range dec.Stack { for k, v := range dec.Stack {

View File

@ -54,35 +54,31 @@ type LogConfig struct {
// StructLog is emitted to the EVM each cycle and lists information about the current internal state // StructLog is emitted to the EVM each cycle and lists information about the current internal state
// prior to the execution of the statement. // prior to the execution of the statement.
type StructLog struct { type StructLog struct {
Pc uint64 `json:"pc"` Pc uint64 `json:"pc"`
Op OpCode `json:"op"` Op OpCode `json:"op"`
Gas uint64 `json:"gas"` Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"` GasCost uint64 `json:"gasCost"`
Memory []byte `json:"memory"` Memory []byte `json:"memory"`
Stack []*big.Int `json:"stack"` MemorySize int `json:"memSize"`
Storage map[common.Hash]common.Hash `json:"-"` Stack []*big.Int `json:"stack"`
Depth int `json:"depth"` Storage map[common.Hash]common.Hash `json:"-"`
Err error `json:"error"` Depth int `json:"depth"`
Err error `json:"error"`
} }
// overrides for gencodec // overrides for gencodec
type structLogMarshaling struct { type structLogMarshaling struct {
Stack []*math.HexOrDecimal256 Stack []*math.HexOrDecimal256
Gas math.HexOrDecimal64 Gas math.HexOrDecimal64
GasCost math.HexOrDecimal64 GasCost math.HexOrDecimal64
Memory hexutil.Bytes Memory hexutil.Bytes
OpName string `json:"opName"` OpName string `json:"opName"`
MemorySize int `json:"memSize"`
} }
func (s *StructLog) OpName() string { func (s *StructLog) OpName() string {
return s.Op.String() return s.Op.String()
} }
func (s *StructLog) MemorySize() int {
return len(s.Memory)
}
// Tracer is used to collect execution traces from an EVM transaction // Tracer is used to collect execution traces from an EVM transaction
// execution. CaptureState is called for each step of the VM with the // execution. CaptureState is called for each step of the VM with the
// current VM state. // current VM state.
@ -181,7 +177,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
} }
} }
// create a new snaptshot of the EVM. // create a new snaptshot of the EVM.
log := StructLog{pc, op, gas, cost, mem, stck, storage, env.depth, err} log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, storage, depth, err}
l.logs = append(l.logs, log) l.logs = append(l.logs, log)
return nil return nil