From 80f7c6c2996ad47f70a5070c400b1fd87a20c59c Mon Sep 17 00:00:00 2001 From: Martin Holst Swende Date: Wed, 7 Jun 2017 17:09:08 +0200 Subject: cmd/evm: add --prestate, --sender, --json flags for fuzzing (#14476) --- core/vm/gen_structlog.go | 95 +++++++++++++++++++++++++++++++++++++++++ core/vm/logger.go | 52 ++++++++++++++++------ core/vm/runtime/runtime.go | 12 +++--- core/vm/runtime/runtime_test.go | 2 +- 4 files changed, 142 insertions(+), 19 deletions(-) create mode 100644 core/vm/gen_structlog.go (limited to 'core') diff --git a/core/vm/gen_structlog.go b/core/vm/gen_structlog.go new file mode 100644 index 000000000..1c86b2256 --- /dev/null +++ b/core/vm/gen_structlog.go @@ -0,0 +1,95 @@ +// Code generated by github.com/fjl/gencodec. DO NOT EDIT. + +package vm + +import ( + "encoding/json" + "math/big" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/common/math" +) + +func (s StructLog) MarshalJSON() ([]byte, error) { + type StructLog struct { + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas math.HexOrDecimal64 `json:"gas"` + GasCost math.HexOrDecimal64 `json:"gasCost"` + Memory hexutil.Bytes `json:"memory"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + Err error `json:"error"` + OpName string `json:"opName"` + MemorySize int `json:"memSize"` + } + var enc StructLog + enc.Pc = s.Pc + enc.Op = s.Op + enc.Gas = math.HexOrDecimal64(s.Gas) + enc.GasCost = math.HexOrDecimal64(s.GasCost) + enc.Memory = s.Memory + if s.Stack != nil { + enc.Stack = make([]*math.HexOrDecimal256, len(s.Stack)) + for k, v := range s.Stack { + enc.Stack[k] = (*math.HexOrDecimal256)(v) + } + } + enc.Storage = s.Storage + enc.Depth = s.Depth + enc.Err = s.Err + enc.OpName = s.OpName() + enc.MemorySize = s.MemorySize() + return json.Marshal(&enc) +} + +func (s *StructLog) UnmarshalJSON(input []byte) error { + type StructLog struct { + Pc *uint64 `json:"pc"` + Op *OpCode `json:"op"` + Gas *math.HexOrDecimal64 `json:"gas"` + GasCost *math.HexOrDecimal64 `json:"gasCost"` + Memory hexutil.Bytes `json:"memory"` + Stack []*math.HexOrDecimal256 `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth *int `json:"depth"` + Err *error `json:"error"` + } + var dec StructLog + if err := json.Unmarshal(input, &dec); err != nil { + return err + } + if dec.Pc != nil { + s.Pc = *dec.Pc + } + if dec.Op != nil { + s.Op = *dec.Op + } + if dec.Gas != nil { + s.Gas = uint64(*dec.Gas) + } + if dec.GasCost != nil { + s.GasCost = uint64(*dec.GasCost) + } + if dec.Memory != nil { + s.Memory = dec.Memory + } + if dec.Stack != nil { + s.Stack = make([]*big.Int, len(dec.Stack)) + for k, v := range dec.Stack { + s.Stack[k] = (*big.Int)(v) + } + } + if dec.Storage != nil { + s.Storage = dec.Storage + } + if dec.Depth != nil { + s.Depth = *dec.Depth + } + if dec.Err != nil { + s.Err = *dec.Err + } + return nil +} diff --git a/core/vm/logger.go b/core/vm/logger.go index 825025b05..405ab169c 100644 --- a/core/vm/logger.go +++ b/core/vm/logger.go @@ -21,8 +21,10 @@ import ( "fmt" "io" "math/big" + "time" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" ) @@ -47,18 +49,38 @@ type LogConfig struct { Limit int // maximum length of output, but zero means unlimited } +//go:generate gencodec -type StructLog -field-override structLogMarshaling -out gen_structlog.go + // StructLog is emitted to the EVM each cycle and lists information about the current internal state // prior to the execution of the statement. type StructLog struct { - Pc uint64 - Op OpCode - Gas uint64 - GasCost uint64 - Memory []byte - Stack []*big.Int - Storage map[common.Hash]common.Hash - Depth int - Err error + Pc uint64 `json:"pc"` + Op OpCode `json:"op"` + Gas uint64 `json:"gas"` + GasCost uint64 `json:"gasCost"` + Memory []byte `json:"memory"` + Stack []*big.Int `json:"stack"` + Storage map[common.Hash]common.Hash `json:"-"` + Depth int `json:"depth"` + Err error `json:"error"` +} + +// overrides for gencodec +type structLogMarshaling struct { + Stack []*math.HexOrDecimal256 + Gas math.HexOrDecimal64 + GasCost math.HexOrDecimal64 + Memory hexutil.Bytes + OpName string `json:"opName"` + MemorySize int `json:"memSize"` +} + +func (s *StructLog) OpName() 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 @@ -68,6 +90,7 @@ type StructLog struct { // if you need to retain them beyond the current call. type Tracer interface { CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error + CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error } // StructLogger is an EVM state logger and implements Tracer. @@ -82,7 +105,7 @@ type StructLogger struct { changedValues map[common.Address]Storage } -// NewLogger returns a new logger +// NewStructLogger returns a new logger func NewStructLogger(cfg *LogConfig) *StructLogger { logger := &StructLogger{ changedValues: make(map[common.Address]Storage), @@ -93,9 +116,9 @@ func NewStructLogger(cfg *LogConfig) *StructLogger { return logger } -// captureState logs a new structured log message and pushes it out to the environment +// CaptureState logs a new structured log message and pushes it out to the environment // -// captureState also tracks SSTORE ops to track dirty values. +// CaptureState also tracks SSTORE ops to track dirty values. func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { // check if already accumulated the specified number of logs if l.cfg.Limit != 0 && l.cfg.Limit <= len(l.logs) { @@ -164,6 +187,11 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui return nil } +func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error { + fmt.Printf("0x%x", output) + return nil +} + // StructLogs returns a list of captured log entries func (l *StructLogger) StructLogs() []StructLog { return l.logs diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index 94265626f..aa386a995 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -125,7 +125,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { } // Create executes the code using the EVM create method -func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { +func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { if cfg == nil { cfg = new(Config) } @@ -141,13 +141,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { ) // Call the code with the given configuration. - code, address, _, err := vmenv.Create( + code, address, leftOverGas, err := vmenv.Create( sender, input, cfg.GasLimit, cfg.Value, ) - return code, address, err + return code, address, leftOverGas, err } // Call executes the code given by the contract's address. It will return the @@ -155,14 +155,14 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, error) { // // Call, unlike Execute, requires a config and also requires the State field to // be set. -func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) { +func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, error) { setDefaults(cfg) vmenv := NewEnv(cfg, cfg.State) sender := cfg.State.GetOrNewStateObject(cfg.Origin) // Call the code with the given configuration. - ret, _, err := vmenv.Call( + ret, leftOverGas, err := vmenv.Call( sender, address, input, @@ -170,5 +170,5 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, error) { cfg.Value, ) - return ret, err + return ret, leftOverGas, err } diff --git a/core/vm/runtime/runtime_test.go b/core/vm/runtime/runtime_test.go index fe39e97a0..7f40770d2 100644 --- a/core/vm/runtime/runtime_test.go +++ b/core/vm/runtime/runtime_test.go @@ -106,7 +106,7 @@ func TestCall(t *testing.T) { byte(vm.RETURN), }) - ret, err := Call(address, nil, &Config{State: state}) + ret, _, err := Call(address, nil, &Config{State: state}) if err != nil { t.Fatal("didn't expect error", err) } -- cgit v1.2.3