From 2e6e8637f88c4bd40f6371f8c36a2756c3fe78de Mon Sep 17 00:00:00 2001 From: yihuang Date: Sat, 25 Mar 2023 06:12:01 +0800 Subject: [PATCH] Problem: repeated tx sender recovery is wastful (#1717) * Problem: repeated tx sender recovery is wastful Solution: - only do once in ante handler, reuse the result * Update CHANGELOG.md Signed-off-by: yihuang * Update x/evm/types/msg.go Co-authored-by: mmsqe Signed-off-by: yihuang * return value * fix unit test --------- Signed-off-by: yihuang Co-authored-by: mmsqe * Update CHANGELOG.md * Update x/evm/types/msg.go * rename parameter * separate lines * run gofumpt --------- Signed-off-by: yihuang Co-authored-by: mmsqe Co-authored-by: Freddy Caceres --- CHANGELOG.md | 1 + x/evm/keeper/msg_server.go | 2 +- x/evm/keeper/state_transition.go | 9 +++-- .../keeper/state_transition_benchmark_test.go | 8 +++- x/evm/types/msg.go | 38 ++++++++++++++++++- 5 files changed, 50 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d249a64b28..75aada6eed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (evm) [#1582](https://github.com/evmos/ethermint/pull/1582) Cleanup `evm` files * (evm) [#1544](https://github.com/evmos/ethermint/pull/1544) Migrate deprecated event emitting to new `TypedEvent` * (deps) [#1532](https://github.com/evmos/ethermint/pull/1532) Upgrade Go-Ethereum version to [`v1.10.26`](https://github.com/ethereum/go-ethereum/releases/tag/v1.10.26). +* (ante) [#1717](https://github.com/evmos/ethermint/pull/1717) Reuse sender recovery result. ### Bug Fixes diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index 0e1b7eb6d5..0a96b48917 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -56,7 +56,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t labels = append(labels, telemetry.NewLabel("execution", "call")) } - response, err := k.ApplyTransaction(ctx, tx) + response, err := k.ApplyTransaction(ctx, msg) if err != nil { return nil, errorsmod.Wrap(err, "failed to apply transaction") } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index ad90dba5fd..5327052a37 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -146,7 +146,7 @@ func (k Keeper) GetHashFn(ctx sdk.Context) vm.GetHashFunc { // returning. // // For relevant discussion see: https://github.com/cosmos/cosmos-sdk/discussions/9072 -func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*types.MsgEthereumTxResponse, error) { +func (k *Keeper) ApplyTransaction(ctx sdk.Context, msgEth *types.MsgEthereumTx) (*types.MsgEthereumTxResponse, error) { var ( bloom *big.Int bloomReceipt ethtypes.Bloom @@ -156,11 +156,12 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t if err != nil { return nil, errorsmod.Wrap(err, "failed to load evm config") } - txConfig := k.TxConfig(ctx, tx.Hash()) + ethTx := msgEth.AsTransaction() + txConfig := k.TxConfig(ctx, ethTx.Hash()) // get the signer according to the chain rules from the config and block height signer := ethtypes.MakeSigner(cfg.ChainConfig, big.NewInt(ctx.BlockHeight())) - msg, err := tx.AsMessage(signer, cfg.BaseFee) + msg, err := msgEth.AsMessage(signer, cfg.BaseFee) if err != nil { return nil, errorsmod.Wrap(err, "failed to return ethereum transaction as core message") } @@ -206,7 +207,7 @@ func (k *Keeper) ApplyTransaction(ctx sdk.Context, tx *ethtypes.Transaction) (*t } receipt := ðtypes.Receipt{ - Type: tx.Type(), + Type: ethTx.Type(), PostState: nil, // TODO: intermediate state root CumulativeGasUsed: cumulativeGasUsed, Bloom: bloomReceipt, diff --git a/x/evm/keeper/state_transition_benchmark_test.go b/x/evm/keeper/state_transition_benchmark_test.go index 77df3af9ef..68e93d1ce5 100644 --- a/x/evm/keeper/state_transition_benchmark_test.go +++ b/x/evm/keeper/state_transition_benchmark_test.go @@ -46,7 +46,7 @@ func newSignedEthTx( addr sdk.Address, krSigner keyring.Signer, ethSigner ethtypes.Signer, -) (*ethtypes.Transaction, error) { +) (*evmtypes.MsgEthereumTx, error) { var ethTx *ethtypes.Transaction switch txData := txData.(type) { case *ethtypes.AccessListTx: @@ -72,7 +72,11 @@ func newSignedEthTx( return nil, err } - return ethTx, nil + var msg evmtypes.MsgEthereumTx + if err := msg.FromEthereumTx(ethTx); err != nil { + return nil, err + } + return &msg, nil } func newEthMsgTx( diff --git a/x/evm/types/msg.go b/x/evm/types/msg.go index f227e36a75..71164c593e 100644 --- a/x/evm/types/msg.go +++ b/x/evm/types/msg.go @@ -35,6 +35,7 @@ import ( "github.com/evmos/ethermint/types" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" ) @@ -325,7 +326,42 @@ func (msg MsgEthereumTx) AsTransaction() *ethtypes.Transaction { // AsMessage creates an Ethereum core.Message from the msg fields func (msg MsgEthereumTx) AsMessage(signer ethtypes.Signer, baseFee *big.Int) (core.Message, error) { - return msg.AsTransaction().AsMessage(signer, baseFee) + txData, err := UnpackTxData(msg.Data) + if err != nil { + return nil, err + } + + gasPrice, gasFeeCap, gasTipCap := txData.GetGasPrice(), txData.GetGasFeeCap(), txData.GetGasTipCap() + if baseFee != nil { + gasPrice = math.BigMin(gasPrice.Add(gasTipCap, baseFee), gasFeeCap) + } + var from common.Address + if len(msg.From) > 0 { + // user can't set arbitrary value in `From` field in transaction, + // the SigVerify ante handler will verify the signature and recover + // the sender address and populate the `From` field, so the other code can + // use it directly when available. + from = common.HexToAddress(msg.From) + } else { + // heavy path + from, err = signer.Sender(msg.AsTransaction()) + if err != nil { + return nil, err + } + } + ethMsg := ethtypes.NewMessage( + from, + txData.GetTo(), + txData.GetNonce(), + txData.GetValue(), + txData.GetGas(), + gasPrice, gasFeeCap, gasTipCap, + txData.GetData(), + txData.GetAccessList(), + false, + ) + + return ethMsg, nil } // GetSender extracts the sender address from the signature values using the latest signer for the given chainID.