From c9e06fa7ad1be7fa88a3172936baafaee5b2b7d9 Mon Sep 17 00:00:00 2001 From: mmsqe Date: Mon, 11 Nov 2024 10:17:32 +0800 Subject: [PATCH] Problem: incorrect balance when no tracer in predecessors (#558) * Problem: incorrect balance when no tracer in predecessors * lint --- CHANGELOG.md | 1 + rpc/types/utils.go | 8 +++--- types/dynamic_fee.go | 4 +-- x/evm/keeper/grpc_query.go | 59 ++++++++++++++++++++++++-------------- x/evm/types/codec.go | 8 +++--- 5 files changed, 48 insertions(+), 32 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28b6971aa3..e59663687d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (cli) [#543](https://github.com/crypto-org-chain/ethermint/pull/543) Fix graceful shutdown. * (rpc) [#545](https://github.com/crypto-org-chain/ethermint/pull/545) Fix state overwrite in debug trace APIs. * (rpc) [#554](https://github.com/crypto-org-chain/ethermint/pull/554) No trace detail on insufficient balance. +* (rpc) [#558](https://github.com/crypto-org-chain/ethermint/pull/558) New tracer in predecessors to trace balance correctly when `debug_traceTransaction`. ### Improvements diff --git a/rpc/types/utils.go b/rpc/types/utils.go index c0ae4b4e2e..a8e5f21f14 100644 --- a/rpc/types/utils.go +++ b/rpc/types/utils.go @@ -288,9 +288,9 @@ func BaseFeeFromEvents(events []abci.Event) *big.Int { // CheckTxFee is an internal function used to check whether the fee of // the given transaction is _reasonable_(under the cap). -func CheckTxFee(gasPrice *big.Int, gas uint64, cap float64) error { +func CheckTxFee(gasPrice *big.Int, gas uint64, feeCap float64) error { // Short circuit if there is no cap for transaction fee at all. - if cap == 0 { + if feeCap == 0 { return nil } totalfee := new(big.Float).SetInt(new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gas))) @@ -300,8 +300,8 @@ func CheckTxFee(gasPrice *big.Int, gas uint64, cap float64) error { feeEth := new(big.Float).Quo(totalfee, oneToken) // no need to check error from parsing feeFloat, _ := feeEth.Float64() - if feeFloat > cap { - return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, cap) + if feeFloat > feeCap { + return fmt.Errorf("tx fee (%.2f ether) exceeds the configured cap (%.2f ether)", feeFloat, feeCap) } return nil } diff --git a/types/dynamic_fee.go b/types/dynamic_fee.go index 04bc572e7e..c3e783ff26 100644 --- a/types/dynamic_fee.go +++ b/types/dynamic_fee.go @@ -20,7 +20,7 @@ import ( ) // HasDynamicFeeExtensionOption returns true if the tx implements the `ExtensionOptionDynamicFeeTx` extension option. -func HasDynamicFeeExtensionOption(any *codectypes.Any) bool { - _, ok := any.GetCachedValue().(*ExtensionOptionDynamicFeeTx) +func HasDynamicFeeExtensionOption(codecAny *codectypes.Any) bool { + _, ok := codecAny.GetCachedValue().(*ExtensionOptionDynamicFeeTx) return ok } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index 13626e35a9..a173cff820 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -41,6 +41,7 @@ import ( rpctypes "github.com/evmos/ethermint/rpc/types" ethermint "github.com/evmos/ethermint/types" + "github.com/evmos/ethermint/x/evm/statedb" "github.com/evmos/ethermint/x/evm/types" ) @@ -424,6 +425,7 @@ func execTrace[T traceRequest]( msgCb func( ctx sdk.Context, cfg *EVMConfig, + traceConfig *types.TraceConfig, ) (*core.Message, error), ) ([]byte, error) { var zero T @@ -457,7 +459,7 @@ func execTrace[T traceRequest]( return nil, status.Errorf(codes.Internal, "failed to load evm config: %s", err.Error()) } - msg, err := msgCb(ctx, cfg) + msg, err := msgCb(ctx, cfg, req.GetTraceConfig()) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -484,9 +486,14 @@ func (k Keeper) TraceTx(c context.Context, req *types.QueryTraceTxRequest) (*typ c, req, k, - func(ctx sdk.Context, cfg *EVMConfig) (*core.Message, error) { + func(ctx sdk.Context, cfg *EVMConfig, traceConfig *types.TraceConfig) (*core.Message, error) { signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) - cfg.Tracer = types.NewNoOpTracer() + tracer, err := newTacer(&logger.Config{}, cfg.TxConfig, traceConfig) + if err != nil { + return nil, status.Error(codes.Internal, err.Error()) + } + cfg.Tracer = tracer + cfg.DebugTrace = true for i, tx := range req.Predecessors { ethTx := tx.AsTransaction() msg, err := core.TransactionToMessage(ethTx, signer, cfg.BaseFee) @@ -601,7 +608,7 @@ func (k Keeper) TraceCall(c context.Context, req *types.QueryTraceCallRequest) ( c, req, k, - func(ctx sdk.Context, cfg *EVMConfig) (*core.Message, error) { + func(ctx sdk.Context, cfg *EVMConfig, _ *types.TraceConfig) (*core.Message, error) { var args types.TransactionArgs err := json.Unmarshal(req.Args, &args) if err != nil { @@ -628,6 +635,31 @@ func (k Keeper) TraceCall(c context.Context, req *types.QueryTraceCallRequest) ( }, nil } +func newTacer(logConfig *logger.Config, txConfig statedb.TxConfig, traceConfig *types.TraceConfig) (tracers.Tracer, error) { + tracer := logger.NewStructLogger(logConfig) + if traceConfig != nil && traceConfig.Tracer != "" { + txIndex, err := ethermint.SafeInt(txConfig.TxIndex) + if err != nil { + return nil, err + } + tCtx := &tracers.Context{ + BlockHash: txConfig.BlockHash, + TxIndex: txIndex, + TxHash: txConfig.TxHash, + } + var cfg json.RawMessage + if traceConfig.TracerJsonConfig != "" { + cfg = json.RawMessage(traceConfig.TracerJsonConfig) + } + tracer, err := tracers.DefaultDirectory.New(traceConfig.Tracer, tCtx, cfg) + if err != nil { + return nil, err + } + return tracer, nil + } + return tracer, nil +} + // prepareTrace prepare trace on one Ethereum message, it returns a tuple: (traceResult, nextLogIndex, error). func (k *Keeper) prepareTrace( ctx sdk.Context, @@ -663,28 +695,11 @@ func (k *Keeper) prepareTrace( Overrides: overrides, } - tracer = logger.NewStructLogger(&logConfig) - - txIndex, err := ethermint.SafeInt(txConfig.TxIndex) + tracer, err = newTacer(&logConfig, txConfig, traceConfig) if err != nil { return nil, 0, status.Error(codes.Internal, err.Error()) } - tCtx := &tracers.Context{ - BlockHash: txConfig.BlockHash, - TxIndex: txIndex, - TxHash: txConfig.TxHash, - } - if traceConfig.Tracer != "" { - var cfg json.RawMessage - if traceConfig.TracerJsonConfig != "" { - cfg = json.RawMessage(traceConfig.TracerJsonConfig) - } - if tracer, err = tracers.DefaultDirectory.New(traceConfig.Tracer, tCtx, cfg); err != nil { - return nil, 0, status.Error(codes.Internal, err.Error()) - } - } - // Define a meaningful timeout of a single transaction trace if traceConfig.Timeout != "" { if timeout, err = time.ParseDuration(traceConfig.Timeout); err != nil { diff --git a/x/evm/types/codec.go b/x/evm/types/codec.go index 9b681d4846..babecead77 100644 --- a/x/evm/types/codec.go +++ b/x/evm/types/codec.go @@ -92,14 +92,14 @@ func PackTxData(txData TxData) (*codectypes.Any, error) { // UnpackTxData unpacks an Any into a TxData. It returns an error if the // client state can't be unpacked into a TxData. -func UnpackTxData(any *codectypes.Any) (TxData, error) { - if any == nil { +func UnpackTxData(codecAny *codectypes.Any) (TxData, error) { + if codecAny == nil { return nil, errorsmod.Wrap(errortypes.ErrUnpackAny, "protobuf Any message cannot be nil") } - txData, ok := any.GetCachedValue().(TxData) + txData, ok := codecAny.GetCachedValue().(TxData) if !ok { - return nil, errorsmod.Wrapf(errortypes.ErrUnpackAny, "cannot unpack Any into TxData %T", any) + return nil, errorsmod.Wrapf(errortypes.ErrUnpackAny, "cannot unpack Any into TxData %T", codecAny) } return txData, nil