Skip to content
This repository was archived by the owner on Sep 10, 2025. It is now read-only.

Commit d343b15

Browse files
authored
Merge pull request #11 from taurusgroup/master
master
2 parents e501b3b + 312db2c commit d343b15

File tree

2 files changed

+130
-2
lines changed

2 files changed

+130
-2
lines changed

eth/tracers/logger/logger.go

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,12 +100,22 @@ func (s *StructLog) ErrorString() string {
100100
return ""
101101
}
102102

103+
type wrappedLog struct {
104+
parent *wrappedLog
105+
error error
106+
log StructLog
107+
children []*wrappedLog
108+
}
109+
103110
// StructLogger is an EVM state logger and implements EVMLogger.
104111
//
105112
// StructLogger can capture state based on the given Log configuration and also keeps
106113
// a track record of modified storage which is used in reporting snapshots of the
107114
// contract their storage.
108115
type StructLogger struct {
116+
current *wrappedLog
117+
depth int
118+
109119
cfg Config
110120
env *vm.EVM
111121

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

147159
// CaptureState logs a new structured log message and pushes it out to the environment
@@ -160,6 +172,35 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
160172
memory := scope.Memory
161173
stack := scope.Stack
162174
contract := scope.Contract
175+
for ; l.depth > depth-1; l.depth = l.depth - 1 {
176+
i := l.depth - (depth - 1)
177+
if l.current.error == nil {
178+
switch stack.Data()[len(stack.Data())-i].Bytes32()[31] {
179+
case 0x00:
180+
l.current.error = fmt.Errorf("call failed")
181+
}
182+
}
183+
l.current = l.current.parent
184+
}
185+
if err != nil {
186+
l.current.error = err
187+
}
188+
switch op {
189+
case vm.CALL, vm.DELEGATECALL, vm.STATICCALL, vm.CALLCODE:
190+
l.depth = l.depth + 1
191+
wl := &wrappedLog{
192+
parent: l.current,
193+
error: l.current.error,
194+
}
195+
l.current.children = append(l.current.children, wl)
196+
l.current = wl
197+
case vm.REVERT:
198+
l.current.error = vm.ErrExecutionReverted
199+
return
200+
default:
201+
return
202+
}
203+
163204
// Copy a snapshot of the current memory state to a new buffer
164205
var mem []byte
165206
if l.cfg.EnableMemory {
@@ -209,7 +250,7 @@ func (l *StructLogger) CaptureState(pc uint64, op vm.OpCode, gas, cost uint64, s
209250
}
210251
// create a new snapshot of the EVM.
211252
log := StructLog{pc, op, gas, cost, mem, memory.Len(), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
212-
l.logs = append(l.logs, log)
253+
l.current.log = log
213254
}
214255

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

220261
// CaptureEnd is called after the call finishes to finalize the tracing.
221262
func (l *StructLogger) CaptureEnd(output []byte, gasUsed uint64, err error) {
263+
for ; l.depth > 1; l.depth-- {
264+
l.current = l.current.parent
265+
}
266+
l.current.log = StructLog{
267+
Op: vm.CALL,
268+
GasCost: gasUsed,
269+
ReturnData: output,
270+
Depth: 0,
271+
Err: err,
272+
}
273+
222274
l.output = output
223275
l.err = err
224276
if l.cfg.Debug {
@@ -269,8 +321,19 @@ func (l *StructLogger) CaptureTxEnd(restGas uint64) {
269321
l.usedGas = l.gasLimit - restGas
270322
}
271323

324+
// Depth first append for all children (stack max depth is 1024)
325+
func (l *wrappedLog) getLogs() []StructLog {
326+
var logs []StructLog
327+
l.log.Err = l.error
328+
logs = append(logs, l.log)
329+
for _, child := range l.children {
330+
logs = append(logs, child.getLogs()...)
331+
}
332+
return logs
333+
}
334+
272335
// StructLogs returns the captured log entries.
273-
func (l *StructLogger) StructLogs() []StructLog { return l.logs }
336+
func (l *StructLogger) StructLogs() []StructLog { return l.current.getLogs() }
274337

275338
// Error returns the VM error captured by the trace.
276339
func (l *StructLogger) Error() error { return l.err }

internal/ethapi/api.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,71 @@ func (s *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs, b
12231223
return DoEstimateGas(ctx, s.b, args, bNrOrHash, s.b.RPCGasCap())
12241224
}
12251225

1226+
// ExecutionResult groups all structured logs emitted by the EVM
1227+
// while replaying a transaction in debug mode as well as transaction
1228+
// execution status, the amount of gas used and the return value
1229+
type ExecutionResult struct {
1230+
Gas uint64 `json:"gas"`
1231+
Failed bool `json:"failed"`
1232+
ReturnValue string `json:"returnValue"`
1233+
StructLogs []StructLogRes `json:"structLogs"`
1234+
}
1235+
1236+
// StructLogRes stores a structured log emitted by the EVM while replaying a
1237+
// transaction in debug mode
1238+
type StructLogRes struct {
1239+
Pc uint64 `json:"pc"`
1240+
Op string `json:"op"`
1241+
Gas uint64 `json:"gas"`
1242+
GasCost uint64 `json:"gasCost"`
1243+
Depth int `json:"depth"`
1244+
Error string `json:"error,omitempty"`
1245+
Stack *[]string `json:"stack,omitempty"`
1246+
Memory *[]string `json:"memory,omitempty"`
1247+
Storage *map[string]string `json:"storage,omitempty"`
1248+
}
1249+
1250+
// FormatLogs formats EVM returned structured logs for json output
1251+
func FormatLogs(logs []logger.StructLog) []StructLogRes {
1252+
formatted := make([]StructLogRes, len(logs))
1253+
for index, trace := range logs {
1254+
var errString string
1255+
if trace.Err != nil {
1256+
errString = trace.Err.Error()
1257+
}
1258+
formatted[index] = StructLogRes{
1259+
Pc: trace.Pc,
1260+
Op: trace.Op.String(),
1261+
Gas: trace.Gas,
1262+
GasCost: trace.GasCost,
1263+
Depth: trace.Depth,
1264+
Error: errString,
1265+
}
1266+
if trace.Stack != nil {
1267+
stack := make([]string, len(trace.Stack))
1268+
for i, stackValue := range trace.Stack {
1269+
stack[i] = stackValue.Hex()
1270+
}
1271+
formatted[index].Stack = &stack
1272+
}
1273+
if trace.Memory != nil {
1274+
memory := make([]string, 0, (len(trace.Memory)+31)/32)
1275+
for i := 0; i+32 <= len(trace.Memory); i += 32 {
1276+
memory = append(memory, fmt.Sprintf("%x", trace.Memory[i:i+32]))
1277+
}
1278+
formatted[index].Memory = &memory
1279+
}
1280+
if trace.Storage != nil {
1281+
storage := make(map[string]string)
1282+
for i, storageValue := range trace.Storage {
1283+
storage[fmt.Sprintf("%x", i)] = fmt.Sprintf("%x", storageValue)
1284+
}
1285+
formatted[index].Storage = &storage
1286+
}
1287+
}
1288+
return formatted
1289+
}
1290+
12261291
// RPCMarshalHeader converts the given header to the RPC output .
12271292
func RPCMarshalHeader(head *types.Header) map[string]interface{} {
12281293
result := map[string]interface{}{

0 commit comments

Comments
 (0)