mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
Enables fast tracing for CALL family
This commit is contained in:
parent
fe2f153b55
commit
46d8bc473e
2 changed files with 73 additions and 3 deletions
|
|
@ -110,12 +110,22 @@ type Tracer interface {
|
||||||
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
|
CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type wrappedLog struct {
|
||||||
|
parent *wrappedLog
|
||||||
|
error error
|
||||||
|
log StructLog
|
||||||
|
children []*wrappedLog
|
||||||
|
}
|
||||||
|
|
||||||
// StructLogger is an EVM state logger and implements Tracer.
|
// StructLogger is an EVM state logger and implements Tracer.
|
||||||
//
|
//
|
||||||
// StructLogger can capture state based on the given Log configuration and also keeps
|
// StructLogger can capture state based on the given Log configuration and also keeps
|
||||||
// a track record of modified storage which is used in reporting snapshots of the
|
// a track record of modified storage which is used in reporting snapshots of the
|
||||||
// contract their storage.
|
// contract their storage.
|
||||||
type StructLogger struct {
|
type StructLogger struct {
|
||||||
|
current *wrappedLog
|
||||||
|
depth int
|
||||||
|
|
||||||
cfg LogConfig
|
cfg LogConfig
|
||||||
|
|
||||||
storage map[common.Address]Storage
|
storage map[common.Address]Storage
|
||||||
|
|
@ -145,12 +155,45 @@ func (l *StructLogger) Reset() {
|
||||||
|
|
||||||
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
// CaptureStart implements the Tracer interface to initialize the tracing operation.
|
||||||
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
func (l *StructLogger) CaptureStart(env *EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
|
||||||
|
l.depth = 0
|
||||||
|
l.current = &wrappedLog{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func errToStr(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return err.Error()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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 SLOAD/SSTORE ops to track storage change.
|
// CaptureState also tracks SLOAD/SSTORE ops to track storage change.
|
||||||
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost uint64, scope *ScopeContext, rData []byte, depth int, err error) {
|
||||||
|
for ; l.depth > depth-1; l.depth-- {
|
||||||
|
l.current = l.current.parent
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
if l.current.error != nil {
|
||||||
|
l.current.error=fmt.Errorf("%s:%s", l.current.error.Error(), err.Error())
|
||||||
|
}
|
||||||
|
l.current.error = err
|
||||||
|
}
|
||||||
|
switch op {
|
||||||
|
case CALL,DELEGATECALL,STATICCALL,CALLCODE:
|
||||||
|
l.depth = l.depth+1
|
||||||
|
wl := &wrappedLog{
|
||||||
|
parent: l.current,
|
||||||
|
error: l.current.error,
|
||||||
|
}
|
||||||
|
l.current.children = append(l.current.children, wl)
|
||||||
|
l.current = wl
|
||||||
|
case REVERT:
|
||||||
|
l.current.error = ErrExecutionReverted
|
||||||
|
return
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
memory := scope.Memory
|
memory := scope.Memory
|
||||||
stack := scope.Stack
|
stack := scope.Stack
|
||||||
contract := scope.Contract
|
contract := scope.Contract
|
||||||
|
|
@ -205,7 +248,7 @@ func (l *StructLogger) CaptureState(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||||
}
|
}
|
||||||
// create a new snapshot of the EVM.
|
// create a new snapshot of the EVM.
|
||||||
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, env.StateDB.GetRefund(), err}
|
||||||
l.logs = append(l.logs, log)
|
l.current.log = log
|
||||||
}
|
}
|
||||||
|
|
||||||
// CaptureFault implements the Tracer interface to trace an execution fault
|
// CaptureFault implements the Tracer interface to trace an execution fault
|
||||||
|
|
@ -215,6 +258,16 @@ func (l *StructLogger) CaptureFault(env *EVM, pc uint64, op OpCode, gas, cost ui
|
||||||
|
|
||||||
// CaptureEnd is called after the call finishes to finalize the tracing.
|
// CaptureEnd is called after the call finishes to finalize the tracing.
|
||||||
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration, err error) {
|
||||||
|
for ; l.depth > 1; l.depth-- {
|
||||||
|
l.current = l.current.parent
|
||||||
|
}
|
||||||
|
l.current.log = StructLog{
|
||||||
|
Op: CALL,
|
||||||
|
GasCost: gasUsed,
|
||||||
|
ReturnData: output,
|
||||||
|
Depth: 0,
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
l.output = output
|
l.output = output
|
||||||
l.err = err
|
l.err = err
|
||||||
if l.cfg.Debug {
|
if l.cfg.Debug {
|
||||||
|
|
@ -225,8 +278,21 @@ func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, t time.Duration
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Depth first append for all children (stack max depth is 1024)
|
||||||
|
func (l *wrappedLog) getLogs() []StructLog {
|
||||||
|
var logs []StructLog
|
||||||
|
l.log.Err = l.error
|
||||||
|
logs = append(logs, l.log)
|
||||||
|
for _, child := range l.children {
|
||||||
|
logs = append(logs, child.getLogs()...)
|
||||||
|
}
|
||||||
|
return logs
|
||||||
|
}
|
||||||
|
|
||||||
// StructLogs returns the captured log entries.
|
// StructLogs returns the captured log entries.
|
||||||
func (l *StructLogger) StructLogs() []StructLog { return l.logs }
|
func (l *StructLogger) StructLogs() []StructLog {
|
||||||
|
return l.current.getLogs()
|
||||||
|
}
|
||||||
|
|
||||||
// Error returns the VM error captured by the trace.
|
// Error returns the VM error captured by the trace.
|
||||||
func (l *StructLogger) Error() error { return l.err }
|
func (l *StructLogger) Error() error { return l.err }
|
||||||
|
|
|
||||||
|
|
@ -1142,13 +1142,17 @@ type StructLogRes struct {
|
||||||
func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
func FormatLogs(logs []vm.StructLog) []StructLogRes {
|
||||||
formatted := make([]StructLogRes, len(logs))
|
formatted := make([]StructLogRes, len(logs))
|
||||||
for index, trace := range logs {
|
for index, trace := range logs {
|
||||||
|
var errString string
|
||||||
|
if trace.Err != nil {
|
||||||
|
errString = trace.Err.Error()
|
||||||
|
}
|
||||||
formatted[index] = StructLogRes{
|
formatted[index] = StructLogRes{
|
||||||
Pc: trace.Pc,
|
Pc: trace.Pc,
|
||||||
Op: trace.Op.String(),
|
Op: trace.Op.String(),
|
||||||
Gas: trace.Gas,
|
Gas: trace.Gas,
|
||||||
GasCost: trace.GasCost,
|
GasCost: trace.GasCost,
|
||||||
Depth: trace.Depth,
|
Depth: trace.Depth,
|
||||||
Error: trace.ErrorString(),
|
Error: errString,
|
||||||
}
|
}
|
||||||
if trace.Stack != nil {
|
if trace.Stack != nil {
|
||||||
stack := make([]string, len(trace.Stack))
|
stack := make([]string, len(trace.Stack))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue