Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions eth/api_trace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package eth

import (
"context"
"encoding/json"

"github.com/ethereum/go-ethereum/eth/tracers"
"github.com/ethereum/go-ethereum/internal/ethapi"
"github.com/ethereum/go-ethereum/rpc"
)

type TraceAPI struct {
backend *EthAPIBackend
tracerAPI *tracers.API
}

func NewTraceAPI(b *EthAPIBackend) *TraceAPI {
return &TraceAPI{
backend: b,
tracerAPI: tracers.NewAPI(b),
}
}

// CallMany simulate a series of transactions in latest block
func (api *TraceAPI) CallMany(ctx context.Context, txs []ethapi.TransactionArgs) (map[string]interface{}, error) {
// get latest block number
latestBlockNumOrHash := rpc.BlockNumberOrHashWithNumber(rpc.LatestBlockNumber)
// prepare stateDiff tracer
tracerName := "stateDiffTracer"
config := tracers.TraceCallConfig{
TraceConfig: tracers.TraceConfig{
Tracer: &tracerName,
TracerConfig: json.RawMessage("{\"onlyTopCall\": false, \"withLog\": false}"),
},
}
// trace
traceResult, err := api.tracerAPI.TraceCallMany(ctx, txs, latestBlockNumOrHash, &config)
if err != nil {
return nil, err
}
result := map[string]interface{}{
"blockNumber": latestBlockNumOrHash.BlockNumber.String(),
"traceResult": traceResult,
}
return result, nil
}
3 changes: 3 additions & 0 deletions eth/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,9 @@ func (s *Ethereum) APIs() []rpc.API {
}, {
Namespace: "net",
Service: s.netRPCService,
}, {
Namespace: "trace",
Service: NewTraceAPI(s.APIBackend),
},
}...)
}
Expand Down
60 changes: 59 additions & 1 deletion eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,65 @@ func (api *API) TraceTransaction(ctx context.Context, hash common.Hash, config *
return api.traceTx(ctx, msg, txctx, vmctx, statedb, config)
}

func (api *API) TraceCallMany(ctx context.Context, args []ethapi.TransactionArgs, blockNrOrHash rpc.BlockNumberOrHash, config *TraceCallConfig) ([]interface{}, error) {
// Try to retrieve the specified block
var (
err error
block *types.Block
)
if hash, ok := blockNrOrHash.Hash(); ok {
block, err = api.blockByHash(ctx, hash)
} else if number, ok := blockNrOrHash.Number(); ok {
if number == rpc.PendingBlockNumber {
return nil, errors.New("tracing on top of pending is not supported")
}
block, err = api.blockByNumber(ctx, number)
} else {
return nil, errors.New("invalid arguments; neither block nor hash specified")
}
if err != nil {
return nil, err
}
// try to recompute the state
reexec := defaultTraceReexec
if config != nil && config.Reexec != nil {
reexec = *config.Reexec
}
statedb, release, err := api.backend.StateAtBlock(ctx, block, reexec, nil, true, false)
if err != nil {
return nil, err
}
defer release()
vmctx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
// Apply the customization rules if required.
if config != nil {
if err := config.StateOverrides.Apply(statedb); err != nil {
return nil, err
}
config.BlockOverrides.Apply(&vmctx)
}
var traceConfig *TraceConfig
if config != nil {
traceConfig = &config.TraceConfig
}

// loop over all the transactions and trace internal calls
result := []interface{}{}
for _, arg := range args {
msg, err := arg.ToMessage(api.backend.RPCGasCap(), block.BaseFee())
if err != nil {
return nil, err
}
res, err := api.traceTx(ctx, msg, new(Context), vmctx, statedb, traceConfig)
if err != nil {
return nil, err
}
// append all results
result = append(result, res)
}
return result, nil
}

// TraceCall lets you trace a given eth_call. It collects the structured logs
// created during the execution of EVM if the given transaction was added on
// top of the provided block and returns them as a JSON object.
Expand Down Expand Up @@ -912,7 +971,6 @@ func (api *API) TraceCall(ctx context.Context, args ethapi.TransactionArgs, bloc
if err != nil {
return nil, err
}

var traceConfig *TraceConfig
if config != nil {
traceConfig = &config.TraceConfig
Expand Down
Loading