cmd/evm: better json output, add result to json

This commit is contained in:
Martin Holst Swende 2017-06-02 10:53:55 +02:00
parent c437b70c97
commit 567f69539e
3 changed files with 79 additions and 7 deletions

View file

@ -86,8 +86,9 @@ func runCmd(ctx *cli.Context) error {
} else if ctx.GlobalBool(DebugFlag.Name) { } else if ctx.GlobalBool(DebugFlag.Name) {
debugLogger = vm.NewStructLogger(nil) debugLogger = vm.NewStructLogger(nil)
tracer = debugLogger tracer = debugLogger
} else {
debugLogger = vm.NewStructLogger(nil)
} }
if ctx.GlobalString(GenesisFlag.Name) != "" { if ctx.GlobalString(GenesisFlag.Name) != "" {
gen := readGenesis(ctx.GlobalString(GenesisFlag.Name)) gen := readGenesis(ctx.GlobalString(GenesisFlag.Name))
_, statedb = gen.ToBlock() _, statedb = gen.ToBlock()
@ -216,11 +217,14 @@ GC calls: %d
`, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC) `, execTime, mem.HeapObjects, mem.Alloc, mem.TotalAlloc, mem.NumGC)
} }
if tracer != nil {
fmt.Printf("0x%x", ret) tracer.CaptureEnd(ret, 0, execTime)
if err != nil { } else {
fmt.Printf(" error: %v", err) fmt.Printf("0x%x\n", ret)
}
if err != nil {
fmt.Printf(" error: %v\n", err)
} }
fmt.Println()
return nil return nil
} }

View file

@ -22,6 +22,7 @@ import (
"fmt" "fmt"
"io" "io"
"math/big" "math/big"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/common/math"
@ -61,6 +62,50 @@ type StructLog struct {
Depth int Depth int
Err error Err error
} }
type StructLogJsonOut struct {
Pc uint64 `json:"pc"`
Op OpCode `json:"op"`
OpName string `json:"opName"`
Gas math.HexOrDecimal64 `json:"gas"`
GasCost math.HexOrDecimal64 `json:"gasCost"`
Memory string `json:"memory"`
Stack hexArray `json:"stack"`
//Storage map[common.Hash]common.Hash `json:"storage"`
Depth int `json:"depth"`
//Err error
}
type hexArray []*big.Int
// MarshalJSON encodes the memory as 32-byte hex strings instead of bigints
func (a hexArray) MarshalJSON() ([]byte, error) {
if items := ([]*big.Int)(a); len(items) > 0 {
hexitems := make([]*math.HexOrDecimal256, len(items))
for i, item := range items {
x := math.HexOrDecimal256(*item)
hexitems[i] = &x
}
return json.Marshal(hexitems)
}
return []byte("[]"), nil
}
// MarshalJSON encodes StructLog for json output
func (s StructLog) MarshalJSON() ([]byte, error) {
var enc StructLogJsonOut
enc.Pc = s.Pc
enc.Op = s.Op
enc.OpName = s.Op.String()
enc.Gas = math.HexOrDecimal64(s.Gas)
enc.GasCost = math.HexOrDecimal64(s.GasCost)
//enc.Memory = fmt.Sprintf("0x%v", len(common.Bytes2Hex(s.Memory))/2)
enc.Memory = fmt.Sprintf("%v bytes", len(s.Memory))
enc.Stack = s.Stack
//enc.Storage = s.Storage
enc.Depth = s.Depth
return json.Marshal(&enc)
}
// 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
@ -69,6 +114,7 @@ type StructLog struct {
// if you need to retain them beyond the current call. // if you need to retain them beyond the current call.
type Tracer interface { type Tracer interface {
CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error 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. // StructLogger is an EVM state logger and implements Tracer.
@ -110,9 +156,20 @@ func NewJSONLogger(writer io.Writer) *JSONLogger {
// CaptureState outputs state information on the logger // CaptureState outputs state information on the logger
func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error { func (l *JSONLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error {
log := StructLog{pc, op, gas, cost, memory.Data(), stack.Data(), nil, env.depth, err} log := StructLog{pc, op, gas + cost, cost, memory.Data(), stack.Data(), nil, env.depth, err}
return l.encoder.Encode(log) return l.encoder.Encode(log)
} }
func (l *JSONLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error {
type endLog struct {
Output string `json:"output"`
GasUsed math.HexOrDecimal64 `json:"gasUsed"`
Time time.Duration `json:"time"`
}
log := endLog{common.Bytes2Hex(output), math.HexOrDecimal64(gasUsed), t}
return l.encoder.Encode(log)
}
// 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
// //
@ -184,6 +241,10 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
l.logs = append(l.logs, log) l.logs = append(l.logs, log)
return nil 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 // StructLogs returns a list of captured log entries
func (l *StructLogger) StructLogs() []StructLog { func (l *StructLogger) StructLogs() []StructLog {

View file

@ -21,6 +21,7 @@ import (
"errors" "errors"
"fmt" "fmt"
"math/big" "math/big"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/common/hexutil"
@ -344,6 +345,12 @@ func (jst *JavascriptTracer) CaptureState(env *vm.EVM, pc uint64, op vm.OpCode,
return nil return nil
} }
// CaptureEnd is called after the call finishes
func (jst *JavascriptTracer) CaptureEnd(output []byte, gasUsed uint64, t time.Duration) error {
//TODO! @Arachnid please figure out of there's anything we can use this method for
return nil
}
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error // GetResult calls the Javascript 'result' function and returns its value, or any accumulated error
func (jst *JavascriptTracer) GetResult() (result interface{}, err error) { func (jst *JavascriptTracer) GetResult() (result interface{}, err error) {
if jst.err != nil { if jst.err != nil {