Merge pull request #29 from taurusgroup/master

master
This commit is contained in:
intx4 2024-10-01 14:44:29 +02:00 committed by GitHub
commit 0c55428f52
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 132 additions and 2 deletions

View file

@ -102,12 +102,22 @@ func (s *StructLog) ErrorString() string {
return "" return ""
} }
type wrappedLog struct {
parent *wrappedLog
error error
log StructLog
children []*wrappedLog
}
// StructLogger is an EVM state logger and implements EVMLogger. // StructLogger is an EVM state logger and implements EVMLogger.
// //
// 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 Config cfg Config
env *tracing.VMContext env *tracing.VMContext
@ -165,6 +175,36 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
op := vm.OpCode(opcode) op := vm.OpCode(opcode)
memory := scope.MemoryData() memory := scope.MemoryData()
stack := scope.StackData() stack := scope.StackData()
for ; l.depth > depth-1; l.depth = l.depth - 1 {
i := l.depth - (depth - 1)
if l.current.error == nil {
switch stack[len(stack)-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 // Copy a snapshot of the current memory state to a new buffer
var mem []byte var mem []byte
if l.cfg.EnableMemory { if l.cfg.EnableMemory {
@ -212,7 +252,7 @@ func (l *StructLogger) OnOpcode(pc uint64, opcode byte, gas, cost uint64, scope
} }
// create a new snapshot of the EVM. // create a new snapshot of the EVM.
log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err} log := StructLog{pc, op, gas, cost, mem, len(memory), stck, rdata, storage, depth, l.env.StateDB.GetRefund(), err}
l.logs = append(l.logs, log) l.current.log = log
} }
// OnExit is called a call frame finishes processing. // OnExit is called a call frame finishes processing.
@ -220,6 +260,18 @@ func (l *StructLogger) OnExit(depth int, output []byte, gasUsed uint64, err erro
if depth != 0 { if depth != 0 {
return return
} }
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.output = output
l.err = err l.err = err
if l.cfg.Debug { if l.cfg.Debug {
@ -258,6 +310,8 @@ func (l *StructLogger) Stop(err error) {
func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) { func (l *StructLogger) OnTxStart(env *tracing.VMContext, tx *types.Transaction, from common.Address) {
l.env = env l.env = env
l.depth = 0
l.current = &wrappedLog{}
} }
func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) { func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) {
@ -273,8 +327,19 @@ func (l *StructLogger) OnTxEnd(receipt *types.Receipt, err error) {
} }
} }
// 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 }

View file

@ -1363,6 +1363,71 @@ func (api *BlockChainAPI) EstimateGas(ctx context.Context, args TransactionArgs,
return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.b.RPCGasCap()) return DoEstimateGas(ctx, api.b, args, bNrOrHash, overrides, api.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 . // RPCMarshalHeader converts the given header to the RPC output .
func RPCMarshalHeader(head *types.Header) map[string]interface{} { func RPCMarshalHeader(head *types.Header) map[string]interface{} {
result := map[string]interface{}{ result := map[string]interface{}{