From 3cbadcdf3d346eafb44985dca4574f0def40293f Mon Sep 17 00:00:00 2001 From: jsvisa Date: Thu, 3 Oct 2024 15:32:30 +0800 Subject: [PATCH] trace/live: filter with address Signed-off-by: jsvisa --- eth/tracers/live/live_api_trace.go | 32 +++++++++++++++----- eth/tracers/live/utils.go | 48 +++++++++++++++++++++++++++++- eth/tracers/native/call_flat.go | 4 +++ 3 files changed, 76 insertions(+), 8 deletions(-) diff --git a/eth/tracers/live/live_api_trace.go b/eth/tracers/live/live_api_trace.go index a795a3fa5c..3c2cdc6e38 100644 --- a/eth/tracers/live/live_api_trace.go +++ b/eth/tracers/live/live_api_trace.go @@ -41,10 +41,10 @@ func (api *traceAPI) Block(ctx context.Context, blockNr rpc.BlockNumber, cfg *tr blknum = api.live.latest.Load() } - return api.readBlockTraces(ctx, tracer, blknum, tracer == "parityTracer") + return api.readBlockTraces(ctx, tracer, blknum, tracer == "parityTracer", nil) } -func (api *traceAPI) readBlockTraces(ctx context.Context, tracer string, blknum uint64, isParity bool) ([]interface{}, error) { +func (api *traceAPI) readBlockTraces(ctx context.Context, tracer string, blknum uint64, isParity bool, parityTraceMatcher func(interface{}) bool) ([]interface{}, error) { traces, err := api.live.readBlockTraces(ctx, tracer, blknum) if err != nil { return nil, err @@ -52,10 +52,17 @@ func (api *traceAPI) readBlockTraces(ctx context.Context, tracer string, blknum results := make([]interface{}, 0, len(traces)) if isParity { - // Convert from []interface{} to []traceResult for i, trace := range traces { if parityTraces, ok := trace.Result.([]interface{}); ok { - results = append(results, parityTraces...) + if parityTraceMatcher == nil { + results = append(results, parityTraces...) + continue + } + for _, parityTrace := range parityTraces { + if parityTraceMatcher(parityTrace) { + results = append(results, parityTrace) + } + } } else { return nil, fmt.Errorf("invalid trace result type at index: %d", i) } @@ -146,8 +153,8 @@ func (api *traceAPI) Filter(ctx context.Context, req traceFilterConfig, cfg *tra toBlock = uint64(0) count = uint64(^uint(0)) after = uint64(0) - // fromAddrs = extractAddres(req.FromAddress) - // toAddrs = extractAddres(req.ToAddress) + fromAddrs = extractAddres(req.FromAddress) + toAddrs = extractAddres(req.ToAddress) ) if req.FromBlock != nil { @@ -170,7 +177,18 @@ func (api *traceAPI) Filter(ctx context.Context, req traceFilterConfig, cfg *tra after = *req.After } - return exportLimitedTraces(func(blknum uint64) ([]interface{}, error) { return api.readBlockTraces(ctx, tracer, blknum, isParity) }, fromBlock, toBlock, count, after) + var parityTraceMatcher func(interface{}) bool + if isParity && (len(fromAddrs) > 0 || len(toAddrs) > 0) { + parityTraceMatcher = func(trace interface{}) bool { + return filterParityTrace(trace, fromAddrs, toAddrs, req.Mode) + } + } + + traceGen := func(blknum uint64) ([]interface{}, error) { + return api.readBlockTraces(ctx, tracer, blknum, isParity, parityTraceMatcher) + } + + return exportLimitedTraces(traceGen, fromBlock, toBlock, count, after) } func (api *traceAPI) getTracerOrDefault(cfg *traceConfig) (string, error) { diff --git a/eth/tracers/live/utils.go b/eth/tracers/live/utils.go index 0e936892f1..baaa40432c 100644 --- a/eth/tracers/live/utils.go +++ b/eth/tracers/live/utils.go @@ -1,6 +1,11 @@ package live -import "github.com/ethereum/go-ethereum/common" +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/eth/tracers/native" + "github.com/ethereum/go-ethereum/log" + "github.com/mitchellh/mapstructure" +) func extractAddres(addrs []*common.Address) map[common.Address]struct{} { result := make(map[common.Address]struct{}, len(addrs)) @@ -12,6 +17,47 @@ func extractAddres(addrs []*common.Address) map[common.Address]struct{} { return result } +func containsAddress(addrs map[common.Address]struct{}, addr *common.Address) bool { + if addr == nil { + return false + } + _, ok := addrs[*addr] + return ok +} + +func filterParityTrace(trace interface{}, fromAddrs, toAddrs map[common.Address]struct{}, mode TraceFilterMode) bool { + var pt native.ParityTrace + if err := mapstructure.Decode(trace, &pt); err != nil { + log.Error("Failed to convert into ParityTrace", "err", err) + return false + } + var fromAddr, toAddr *common.Address + switch pt.Type { + case "call": + fromAddr = pt.Action.From + toAddr = pt.Action.To + case "create": + fromAddr = pt.Action.From + if pt.Result != nil { + toAddr = pt.Result.Address + } + case "suicide": + fromAddr = pt.Action.SelfDestructed + toAddr = pt.Action.RefundAddress + default: + // No matching for other types + return false + } + + fromMatch := len(fromAddrs) == 0 || containsAddress(fromAddrs, fromAddr) + toMatch := len(toAddrs) == 0 || containsAddress(toAddrs, toAddr) + + if mode == TraceFilterModeIntersection { + return fromMatch && toMatch + } + return fromMatch || toMatch +} + func exportLimitedTraces(gen func(blknum uint64) ([]interface{}, error), fromBlock, toBlock, count, after uint64) ([]interface{}, error) { var ( nExported uint64 // Number of traces exported diff --git a/eth/tracers/native/call_flat.go b/eth/tracers/native/call_flat.go index 658623455c..4f1e6e5e0a 100644 --- a/eth/tracers/native/call_flat.go +++ b/eth/tracers/native/call_flat.go @@ -59,6 +59,10 @@ var parityErrorMappingStartingWith = map[string]string{ "stack underflow": "Stack underflow", } +// ParityTrace represents a single trace item in Parity format. +// It is an alias for flatCallFrame, providing Parity-compatible naming. +type ParityTrace flatCallFrame + // flatCallFrame is a standalone callframe. type flatCallFrame struct { Action flatCallAction `json:"action"`