trace/live: filter with address

Signed-off-by: jsvisa <delweng@gmail.com>
This commit is contained in:
jsvisa 2024-10-03 15:32:30 +08:00
parent 186d6d8d69
commit 3cbadcdf3d
3 changed files with 76 additions and 8 deletions

View file

@ -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) {

View file

@ -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

View file

@ -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"`