aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYoichi Hirai <i@yoichihirai.com>2016-09-30 18:22:42 +0800
committerYoichi Hirai <i@yoichihirai.com>2016-09-30 23:36:00 +0800
commitbb6115b737a05e3b8bf70ff2ad74c703589627cb (patch)
tree72dc4e8df47729e283735a7a3ecb59930c66b2c5
parentb4cc8cbac4c1756c179e497c53ee83515669fe13 (diff)
downloadgo-tangerine-bb6115b737a05e3b8bf70ff2ad74c703589627cb.tar.gz
go-tangerine-bb6115b737a05e3b8bf70ff2ad74c703589627cb.tar.zst
go-tangerine-bb6115b737a05e3b8bf70ff2ad74c703589627cb.zip
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`.
-rw-r--r--core/vm/errors.go1
-rw-r--r--core/vm/logger.go11
-rw-r--r--core/vm/vm.go5
-rw-r--r--internal/ethapi/tracer.go3
4 files changed, 16 insertions, 4 deletions
diff --git a/core/vm/errors.go b/core/vm/errors.go
index 116fbe456..1766bf9fb 100644
--- a/core/vm/errors.go
+++ b/core/vm/errors.go
@@ -26,3 +26,4 @@ import (
var OutOfGasError = errors.New("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 TraceLimitReachedError = errors.New("The number of logs reached the specified limit")
diff --git a/core/vm/logger.go b/core/vm/logger.go
index ae62b6b57..9e13d703b 100644
--- a/core/vm/logger.go
+++ b/core/vm/logger.go
@@ -42,6 +42,7 @@ type LogConfig struct {
DisableStack bool // disable stack capture
DisableStorage bool // disable storage capture
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
@@ -64,7 +65,7 @@ type StructLog struct {
// Note that reference types are actual VM data structures; make copies
// if you need to retain them beyond the current call.
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.
@@ -93,7 +94,12 @@ func NewStructLogger(cfg *LogConfig) *StructLogger {
// captureState logs a new structured log message and pushes it out to the environment
//
// 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
// if not present.
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}
l.logs = append(l.logs, log)
+ return nil
}
// StructLogs returns a list of captured log entries
diff --git a/core/vm/vm.go b/core/vm/vm.go
index 9d7b55058..6fee7178c 100644
--- a/core/vm/vm.go
+++ b/core/vm/vm.go
@@ -183,7 +183,10 @@ func (evm *EVM) Run(contract *Contract, input []byte) (ret []byte, err error) {
mem.Resize(newMemSize.Uint64())
// Add a log message
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 {
diff --git a/internal/ethapi/tracer.go b/internal/ethapi/tracer.go
index 16ec6ebf0..c6d4f814e 100644
--- a/internal/ethapi/tracer.go
+++ b/internal/ethapi/tracer.go
@@ -278,7 +278,7 @@ func wrapError(context string, err error) error {
}
// 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 {
jst.memory.memory = memory
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)
}
}
+ return nil
}
// GetResult calls the Javascript 'result' function and returns its value, or any accumulated error