vm, ethapi: add `limit` option to traceTransaction
that specifies the maximum number of elements in the `structLogs` output. This option is useful for debugging a transaction that involves a large number of repetition. For example, ``` debug.traceTransaction(tx, {disableStorage: true, limit: 2}) ``` shows at most the first two steps in the `structLogs`.
This commit is contained in:
parent
b4cc8cbac4
commit
bb6115b737
|
@ -26,3 +26,4 @@ import (
|
||||||
var OutOfGasError = errors.New("Out of gas")
|
var OutOfGasError = errors.New("Out of gas")
|
||||||
var CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas")
|
var CodeStoreOutOfGasError = errors.New("Contract creation code storage out of gas")
|
||||||
var DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth)
|
var DepthError = fmt.Errorf("Max call depth exceeded (%d)", params.CallCreateDepth)
|
||||||
|
var TraceLimitReachedError = errors.New("The number of logs reached the specified limit")
|
||||||
|
|
|
@ -42,6 +42,7 @@ type LogConfig struct {
|
||||||
DisableStack bool // disable stack capture
|
DisableStack bool // disable stack capture
|
||||||
DisableStorage bool // disable storage capture
|
DisableStorage bool // disable storage capture
|
||||||
FullStorage bool // show full storage (slow)
|
FullStorage bool // show full storage (slow)
|
||||||
|
Limit int // maximum length of output, but zero means unlimited
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLog is emitted to the Environment each cycle and lists information about the current internal state
|
// StructLog is emitted to the Environment each cycle and lists information about the current internal state
|
||||||
|
@ -64,7 +65,7 @@ type StructLog struct {
|
||||||
// Note that reference types are actual VM data structures; make copies
|
// Note that reference types are actual VM data structures; make copies
|
||||||
// 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 Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error)
|
CaptureState(env Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogger is an EVM state logger and implements Tracer.
|
// StructLogger is an EVM state logger and implements Tracer.
|
||||||
|
@ -93,7 +94,12 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
|
||||||
// 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 Environment, pc uint64, op OpCode, gas, cost *big.Int, memory *Memory, stack *Stack, contract *Contract, depth int, err error) {
|
func (l *StructLogger) CaptureState(env Environment, pc uint64, op OpCode, gas, cost *big.Int, 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) {
|
||||||
|
return TraceLimitReachedError
|
||||||
|
}
|
||||||
|
|
||||||
// initialise new changed values storage container for this contract
|
// initialise new changed values storage container for this contract
|
||||||
// if not present.
|
// if not present.
|
||||||
if l.changedValues[contract.Address()] == nil {
|
if l.changedValues[contract.Address()] == nil {
|
||||||
|
@ -152,6 +158,7 @@ func (l *StructLogger) CaptureState(env Environment, pc uint64, op OpCode, gas,
|
||||||
log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.Depth(), err}
|
log := StructLog{pc, op, new(big.Int).Set(gas), cost, mem, stck, storage, env.Depth(), err}
|
||||||
|
|
||||||
l.logs = append(l.logs, log)
|
l.logs = append(l.logs, log)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructLogs returns a list of captured log entries
|
// StructLogs returns a list of captured log entries
|
||||||
|
|
|
@ -183,7 +183,10 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
|
||||||
mem.Resize(newMemSize.Uint64())
|
mem.Resize(newMemSize.Uint64())
|
||||||
// Add a log message
|
// Add a log message
|
||||||
if evm.cfg.Debug {
|
if evm.cfg.Debug {
|
||||||
evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil)
|
err = evm.cfg.Tracer.CaptureState(evm.env, pc, op, contract.Gas, cost, mem, stack, contract, evm.env.Depth(), nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opPtr := evm.jumpTable[op]; opPtr.valid {
|
if opPtr := evm.jumpTable[op]; opPtr.valid {
|
||||||
|
|
|
@ -278,7 +278,7 @@ func wrapError(context string, err error) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureState implements the Tracer interface to trace a single step of VM execution
|
// CaptureState implements the Tracer interface to trace a single step of VM execution
|
||||||
func (jst *JavascriptTracer) CaptureState(env vm.Environment, pc uint64, op vm.OpCode, gas, cost *big.Int, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) {
|
func (jst *JavascriptTracer) CaptureState(env vm.Environment, pc uint64, op vm.OpCode, gas, cost *big.Int, memory *vm.Memory, stack *vm.Stack, contract *vm.Contract, depth int, err error) error {
|
||||||
if jst.err == nil {
|
if jst.err == nil {
|
||||||
jst.memory.memory = memory
|
jst.memory.memory = memory
|
||||||
jst.stack.stack = stack
|
jst.stack.stack = stack
|
||||||
|
@ -301,6 +301,7 @@ func (jst *JavascriptTracer) CaptureState(env vm.Environment, pc uint64, op vm.O
|
||||||
jst.err = wrapError("step", err)
|
jst.err = wrapError("step", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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
|
||||||
|
|
Loading…
Reference in New Issue