rpc: debug_traceBlockByNumber endpoint (#555)

* Refactor traceTx

* add getTendermintBlock on backend

* keeper concurrency

* first version

* json rpc concurrency

* rever makefile change

* remove grpc traceblock

* create internal traceBlock function

* added types to evm module

* tendermintBlockByNumber rename

* added safe message check

* remove unnecesary line

* check error

* fix lint

* fix linter

* Update ethereum/rpc/namespaces/debug/api.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/rpc/namespaces/debug/api.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* Update ethereum/rpc/backend/backend.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>

* improve traceBlock performance

* fix linter

* add extra line on function parameters

* changed index to uint 64

* fix lint

* proto gen

* update endpoints documentation

* update changelog

* Apply suggestions from code review

* Update ethereum/rpc/namespaces/eth/filters/filters.go

Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
crypto-facs
2021-09-15 08:46:01 +00:00
committed by GitHub
co-authored by Federico Kunze Küllmer
parent ec7d8a37fd
commit 3f1eeb30b6
11 changed files with 346 additions and 151 deletions
+40 -35
View File
@@ -469,13 +469,6 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type
// executes the given message in the provided environment. The return value will
// be tracer dependent.
func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*types.QueryTraceTxResponse, error) {
// Assemble the structured logger or the JavaScript tracer
var (
tracer vm.Tracer
err error
resultData []byte
)
ctx := sdk.UnwrapSDKContext(c)
k.WithContext(ctx)
params := k.GetParams(ctx)
@@ -487,25 +480,48 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID)
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
coreMessage, err := req.Msg.AsMessage(signer)
result, err := k.traceTx(c, coinbase, signer, req.TxIndex, params, ctx, ethCfg, req.Msg, req.TraceConfig)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
resultData, err := json.Marshal(result)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
return &types.QueryTraceTxResponse{
Data: resultData,
}, nil
}
func (k *Keeper) traceTx(c context.Context, coinbase common.Address, signer ethtypes.Signer, txIndex uint64,
params types.Params, ctx sdk.Context, ethCfg *ethparams.ChainConfig, msg *types.MsgEthereumTx, traceConfig *types.TraceConfig) (*interface{}, error) {
// Assemble the structured logger or the JavaScript tracer
var (
tracer vm.Tracer
err error
)
coreMessage, err := msg.AsMessage(signer)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
switch {
case req.TraceConfig != nil && req.TraceConfig.Tracer != "":
case traceConfig != nil && traceConfig.Tracer != "":
timeout := defaultTraceTimeout
// TODO change timeout to time.duration
// Used string to comply with go ethereum
if req.TraceConfig.Timeout != "" {
if timeout, err = time.ParseDuration(req.TraceConfig.Timeout); err != nil {
if traceConfig.Timeout != "" {
if timeout, err = time.ParseDuration(traceConfig.Timeout); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "timeout value: %s", err.Error())
}
}
txContext := core.NewEVMTxContext(coreMessage)
// Constuct the JavaScript tracer to execute with
if tracer, err = tracers.New(req.TraceConfig.Tracer, txContext); err != nil {
// Construct the JavaScript tracer to execute with
if tracer, err = tracers.New(traceConfig.Tracer, txContext); err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
@@ -518,12 +534,12 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
}
}()
defer cancel()
case req.TraceConfig != nil && req.TraceConfig.LogConfig != nil:
case traceConfig != nil && traceConfig.LogConfig != nil:
logConfig := vm.LogConfig{
DisableMemory: req.TraceConfig.LogConfig.DisableMemory,
Debug: req.TraceConfig.LogConfig.Debug,
DisableStorage: req.TraceConfig.LogConfig.DisableStorage,
DisableStack: req.TraceConfig.LogConfig.DisableStack,
DisableMemory: traceConfig.LogConfig.DisableMemory,
Debug: traceConfig.LogConfig.Debug,
DisableStorage: traceConfig.LogConfig.DisableStorage,
DisableStack: traceConfig.LogConfig.DisableStack,
}
tracer = vm.NewStructLogger(&logConfig)
default:
@@ -532,45 +548,34 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ
evm := k.NewEVM(coreMessage, ethCfg, params, coinbase, tracer)
k.SetTxHashTransient(common.HexToHash(req.Msg.Hash))
k.SetTxIndexTransient(uint64(req.TxIndex))
k.SetTxHashTransient(common.HexToHash(msg.Hash))
k.SetTxIndexTransient(txIndex)
res, err := k.ApplyMessage(evm, coreMessage, ethCfg, true)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
var result interface{}
// Depending on the tracer type, format and return the trace result data.
switch tracer := tracer.(type) {
case *vm.StructLogger:
// TODO Return proper returnValue
result := types.ExecutionResult{
result = types.ExecutionResult{
Gas: res.GasUsed,
Failed: res.Failed(),
ReturnValue: "",
StructLogs: types.FormatLogs(tracer.StructLogs()),
}
resultData, err = json.Marshal(result)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
case *tracers.Tracer:
result, err := tracer.GetResult()
result, err = tracer.GetResult()
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
resultData, err = json.Marshal(result)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
default:
return nil, status.Error(codes.InvalidArgument, "invalid tracer type")
}
return &types.QueryTraceTxResponse{
Data: resultData,
}, nil
return &result, nil
}