Skip to content

Commit

Permalink
Merge branch 'master' into release_v1.11.2
Browse files Browse the repository at this point in the history
  • Loading branch information
simonecid committed Mar 1, 2023
2 parents 73b01f4 + 42b793f commit ebcd50e
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 2 deletions.
67 changes: 65 additions & 2 deletions eth/tracers/logger/logger.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,22 @@ func (s *StructLog) ErrorString() string {
return ""
}

type wrappedLog struct {
parent *wrappedLog
error error
log StructLog
children []*wrappedLog
}

// StructLogger is an EVM state logger and implements EVMLogger.
//
// 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
// contract their storage.
type StructLogger struct {
current *wrappedLog
depth int

cfg Config
env *vm.EVM

Expand Down Expand Up @@ -142,6 +152,8 @@ func (l *StructLogger) Reset() {
// CaptureStart implements the EVMLogger interface to initialize the tracing operation.
func (l *StructLogger) CaptureStart(env *vm.EVM, from common.Address, to common.Address, create bool, input []byte, gas uint64, value *big.Int) {
l.env = env
l.depth = 0
l.current = &wrappedLog{}
}

// CaptureState logs a new structured log message and pushes it out to the environment
Expand All @@ -160,6 +172,35 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
memory := scope.Memory
stack := scope.Stack
contract := scope.Contract
for ; l.depth > depth-1; l.depth = l.depth - 1 {
i := l.depth - (depth - 1)
if l.current.error == nil {
switch stack.Data()[len(stack.Data())-i].Bytes32()[31] {
case 0x00:
l.current.error = fmt.Errorf("call failed")
}
}
l.current = l.current.parent
}
if err != nil {
l.current.error = err
}
switch op {
case vm.CALL, vm.DELEGATECALL, vm.STATICCALL, vm.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 vm.REVERT:
l.current.error = vm.ErrExecutionReverted
return
default:
return
}

// Copy a snapshot of the current memory state to a new buffer
var mem []byte
if l.cfg.EnableMemory {
Expand Down Expand Up @@ -209,7 +250,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
}
// create a new snapshot of the EVM.
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
l.logs = append(l.logs, log)
l.current.log = log
}

// CaptureFault implements the EVMLogger interface to trace an execution fault
Expand All @@ -219,6 +260,17 @@ func (l *StructLogger) CaptureFault(pc uint64, op vm.OpCode, gas, cost uint64, s

// CaptureEnd is called after the call finishes to finalize the tracing.
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
for ; l.depth > 1; l.depth-- {
l.current = l.current.parent
}
l.current.log = StructLog{
Op: vm.CALL,
GasCost: gasUsed,
ReturnData: output,
Depth: 0,
Err: err,
}

l.output = output
l.err = err
if l.cfg.Debug {
Expand Down Expand Up @@ -269,8 +321,19 @@ func (l *StructLogger) CaptureTxEnd(restGas uint64) {
l.usedGas = l.gasLimit - restGas
}

// 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.
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.
func (l *StructLogger) Error() error { return l.err }
Expand Down
65 changes: 65 additions & 0 deletions internal/ethapi/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,71 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b
return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())
}

// ExecutionResult groups all structured logs emitted by the EVM
// while replaying a transaction in debug mode as well as transaction
// execution status, the amount of gas used and the return value
type ExecutionResult struct {
Gas uint64 `json:"gas"`
Failed bool `json:"failed"`
ReturnValue string `json:"returnValue"`
StructLogs []StructLogRes `json:"structLogs"`
}

// StructLogRes stores a structured log emitted by the EVM while replaying a
// transaction in debug mode
type StructLogRes struct {
Pc uint64 `json:"pc"`
Op string `json:"op"`
Gas uint64 `json:"gas"`
GasCost uint64 `json:"gasCost"`
Depth int `json:"depth"`
Error string `json:"error,omitempty"`
Stack *[]string `json:"stack,omitempty"`
Memory *[]string `json:"memory,omitempty"`
Storage *map[string]string `json:"storage,omitempty"`
}

// FormatLogs formats EVM returned structured logs for json output
func FormatLogs(logs []logger.StructLog) []StructLogRes {
formatted := make([]StructLogRes, len(logs))
for index, trace := range logs {
var errString string
if trace.Err != nil {
errString = trace.Err.Error()
}
formatted[index] = StructLogRes{
Pc: trace.Pc,
Op: trace.Op.String(),
Gas: trace.Gas,
GasCost: trace.GasCost,
Depth: trace.Depth,
Error: errString,
}
if trace.Stack != nil {
stack := make([]string, len(trace.Stack))
for i, stackValue := range trace.Stack {
stack[i] = stackValue.Hex()
}
formatted[index].Stack = &stack
}
if trace.Memory != nil {
memory := make([]string, 0, (len(trace.Memory)+31)/32)
for i := 0; i+32 <= len(trace.Memory); i += 32 {
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
}
formatted[index].Memory = &memory
}
if trace.Storage != nil {
storage := make(map[string]string)
for i, storageValue := range trace.Storage {
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
}
formatted[index].Storage = &storage
}
}
return formatted
}

// RPCMarshalHeader converts the given header to the RPC output .
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
result := map[string]interface{}{
Expand Down

0 comments on commit ebcd50e

Please sign in to comment.