From 82805507f7d2e83cad547736883dc22acfb52440 Mon Sep 17 00:00:00 2001 From: Thomas Nguy <81727899+thomas-nguy@users.noreply.github.com> Date: Mon, 29 Nov 2021 19:07:22 +0900 Subject: [PATCH] revert tharsis#786 (#19) --- CHANGELOG.md | 6 + app/ante/ante.go | 14 ++- app/ante/eth.go | 164 ++++++++++++++++++--------- go.mod | 1 + go.sum | 2 + rpc/ethereum/backend/backend.go | 9 +- rpc/ethereum/namespaces/eth/api.go | 9 +- rpc/ethereum/namespaces/miner/api.go | 10 +- x/evm/keeper/grpc_query.go | 3 +- x/evm/keeper/keeper.go | 6 +- x/evm/keeper/msg_server.go | 7 +- x/evm/keeper/state_transition.go | 38 +++---- x/evm/keeper/utils.go | 29 +++-- x/evm/types/chain_config.go | 2 +- 14 files changed, 189 insertions(+), 111 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e87fe273b5..8b7f0a0afa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,6 +37,12 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Unreleased +### Bug Fixes +- [crypto-org-chain/ethermint#19](https://github.com/crypto-org-chain/ethermint/pull/19) revert tharsis#786 because it contains consensus breaking changes + + +## [v0.7.2-cronos-3] - 2021-11-29 + ### Bug Fixes - [tharsis#781](https://github.com/tharsis/ethermint/pull/781) fix empty transactions in getBlock diff --git a/app/ante/ante.go b/app/ante/ante.go index c68ceaeb7e..9177c4639c 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -4,6 +4,8 @@ import ( "fmt" "runtime/debug" + "github.com/palantir/stacktrace" + tmlog "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" @@ -66,10 +68,9 @@ func NewAnteHandler( ) default: - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrUnknownExtensionOptions, - "rejecting tx with unsupported extension option: %s", - typeURL, + return ctx, stacktrace.Propagate( + sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, typeURL), + "rejecting tx with unsupported extension option", ) } @@ -98,7 +99,10 @@ func NewAnteHandler( authante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator ) default: - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx), + "transaction is not an SDK tx", + ) } return anteHandler(ctx, tx, sim) diff --git a/app/ante/eth.go b/app/ante/eth.go index 71567597b2..4056821ccb 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -8,6 +8,7 @@ import ( sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" tx "github.com/cosmos/cosmos-sdk/types/tx" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/palantir/stacktrace" ethermint "github.com/tharsis/ethermint/types" evmkeeper "github.com/tharsis/ethermint/x/evm/keeper" @@ -58,7 +59,10 @@ func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator { // won't see the error message. func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) { if tx == nil || len(tx.GetMsgs()) != 1 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx") + return ctx, stacktrace.Propagate( + sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"), + "", + ) } chainID := esvd.evmKeeper.ChainID() @@ -72,16 +76,18 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s msg := tx.GetMsgs()[0] msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction", + ) } sender, err := signer.Sender(msgEthTx.AsTransaction()) if err != nil { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrorInvalidSigner, - "couldn't retrieve sender address ('%s') from the ethereum transaction: %s", + return ctx, stacktrace.Propagate( + sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()), + "couldn't retrieve sender address ('%s') from the ethereum transaction", msgEthTx.From, - err.Error(), ) } @@ -124,26 +130,32 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i) + return ctx, stacktrace.Propagate(err, "failed to unpack tx data any for tx %d", i) } // sender address should be in the tx cache from the previous AnteHandle call from := msgEthTx.GetFrom() if from.Empty() { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "from address cannot be empty"), + "sender address should have been in the tx field from the previous AnteHandle call", + ) } // check whether the sender address is EOA fromAddr := common.BytesToAddress(from) codeHash := avd.evmKeeper.GetCodeHash(fromAddr) if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, - "the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash) + return ctx, stacktrace.Propagate(sdkerrors.Wrapf(sdkerrors.ErrInvalidType, + "the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash), "") } acc := avd.ak.GetAccount(ctx, from) @@ -153,7 +165,7 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx } if err := evmkeeper.CheckSenderBalance(ctx, avd.bankKeeper, from, txData, evmDenom); err != nil { - return ctx, sdkerrors.Wrap(err, "failed to check sender balance") + return ctx, stacktrace.Propagate(err, "failed to check sender balance") } } @@ -183,30 +195,36 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, return next(ctx, tx, simulate) } - for _, msg := range tx.GetMsgs() { + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } // sender address should be in the tx cache from the previous AnteHandle call seq, err := nvd.ak.GetSequence(ctx, msgEthTx.GetFrom()) if err != nil { - return ctx, sdkerrors.Wrapf(err, "sequence not found for address %s", msgEthTx.From) + return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") + return ctx, stacktrace.Propagate(err, "failed to unpack tx data") } // if multiple transactions are submitted in succession with increasing nonces, // all will be rejected except the first, since the first needs to be included in a block // before the sequence increments if txData.GetNonce() != seq { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrInvalidSequence, - "invalid nonce; got %d, expected %d", txData.GetNonce(), seq, + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf( + sdkerrors.ErrInvalidSequence, + "invalid nonce; got %d, expected %d", txData.GetNonce(), seq, + ), + "", ) } } @@ -256,15 +274,18 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula var events sdk.Events - for _, msg := range tx.GetMsgs() { + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") + return ctx, stacktrace.Propagate(err, "failed to unpack tx data") } fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance( @@ -276,7 +297,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula istanbul, ) if err != nil { - return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance") + return ctx, stacktrace.Propagate(err, "failed to deduct transaction costs from user balance") } events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String()))) @@ -325,15 +346,18 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID()) signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight())) - for _, msg := range tx.GetMsgs() { + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } coreMsg, err := msgEthTx.AsMessage(signer) if err != nil { - return ctx, sdkerrors.Wrapf( + return ctx, stacktrace.Propagate( err, "failed to create an ethereum core.Message from signer %T", signer, ) @@ -345,11 +369,9 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate // check that caller has enough balance to cover asset transfer for **topmost** call // NOTE: here the gas consumed is from the context with the infinite gas meter if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(ctd.evmKeeper, coreMsg.From(), coreMsg.Value()) { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, - "failed to transfer %s from address %s using the EVM block context transfer function", - coreMsg.Value(), - coreMsg.From(), + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "address %s", coreMsg.From()), + "failed to transfer %s using the EVM block context transfer function", coreMsg.Value(), ) } } @@ -396,17 +418,20 @@ func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b // setup the keeper context before setting the access list ald.evmKeeper.WithContext(ctx) - for _, msg := range tx.GetMsgs() { + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } sender := common.BytesToAddress(msgEthTx.GetFrom()) txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") + return ctx, stacktrace.Propagate(err, "failed to unpack tx data") } ald.evmKeeper.PrepareAccessList(sender, txData.GetTo(), vm.ActivePrecompiles(rules), txData.GetAccessList()) @@ -433,15 +458,18 @@ func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) EthIncrem // contract creation, the nonce will be incremented during the transaction execution and not within // this AnteHandler decorator. func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) { - for _, msg := range tx.GetMsgs() { + for i, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction %d", i, + ) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") + return ctx, stacktrace.Propagate(err, "failed to unpack tx data") } // NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution @@ -457,14 +485,17 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s acc := issd.ak.GetAccount(ctx, addr) if acc == nil { - return ctx, sdkerrors.Wrapf( - sdkerrors.ErrUnknownAddress, - "account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr, + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf( + sdkerrors.ErrUnknownAddress, + "account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr, + ), + "signer account not found", ) } if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { - return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1) + return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1) } issd.ak.SetAccount(ctx, acc) @@ -497,7 +528,7 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu err := tx.ValidateBasic() // ErrNoSignatures is fine with eth tx if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) { - return ctx, sdkerrors.Wrap(err, "tx basic validation failed") + return ctx, stacktrace.Propagate(err, "tx basic validation failed") } // For eth type cosmos tx, some fields should be veified as zero values, @@ -506,27 +537,39 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu protoTx := wrapperTx.GetProtoTx() body := protoTx.Body if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, - "for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, + "for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty"), + "invalid data in tx", + ) } if len(body.ExtensionOptions) != 1 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1"), + "invalid data in tx", + ) } if len(protoTx.GetMsgs()) != 1 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx") + return ctx, stacktrace.Propagate( + sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"), + "", + ) } msg := protoTx.GetMsgs()[0] msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), + "failed to cast transaction", + ) } ethGasLimit := msgEthTx.GetGas() txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data") + return ctx, stacktrace.Propagate(err, "failed to unpack MsgEthereumTx Data") } params := vbd.evmKeeper.GetParams(ctx) @@ -534,24 +577,39 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu authInfo := protoTx.AuthInfo if len(authInfo.SignerInfos) > 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty"), + "invalid data in tx", + ) } if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty"), + "invalid data in tx", + ) } if !authInfo.Fee.Amount.IsEqual(ethFeeAmount) { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount"), + "invalid data in tx", + ) } if authInfo.Fee.GasLimit != ethGasLimit { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit"), + "invalid data in tx", + ) } sigs := protoTx.Signatures if len(sigs) > 0 { - return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty") + return ctx, stacktrace.Propagate( + sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty"), + "invalid data in tx", + ) } } diff --git a/go.mod b/go.mod index af545e9599..4c03f486b5 100644 --- a/go.mod +++ b/go.mod @@ -16,6 +16,7 @@ require ( github.com/grpc-ecosystem/grpc-gateway v1.16.0 github.com/improbable-eng/grpc-web v0.14.1 github.com/miguelmota/go-ethereum-hdwallet v0.0.1 + github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177 github.com/pkg/errors v0.9.1 github.com/rakyll/statik v0.1.7 github.com/regen-network/cosmos-proto v0.3.1 diff --git a/go.sum b/go.sum index 21eb3af24a..649395ac7e 100644 --- a/go.sum +++ b/go.sum @@ -942,6 +942,8 @@ github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6 github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo= github.com/otiai10/mint v1.3.2/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc= github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM= +github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177 h1:nRlQD0u1871kaznCnn1EvYiMbum36v7hw1DLPEjds4o= +github.com/palantir/stacktrace v0.0.0-20161112013806-78658fd2d177/go.mod h1:ao5zGxj8Z4x60IOVYZUbDSmt3R8Ddo080vEgPosHpak= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0 h1:cBOtyMzM9HTpWjXfbbunk26uA6nG3a8n06Wieeh0MwY= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= diff --git a/rpc/ethereum/backend/backend.go b/rpc/ethereum/backend/backend.go index b0a8a94ff5..9c3b98ae8d 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/ethereum/backend/backend.go @@ -11,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/params" @@ -705,10 +704,10 @@ func (e *EVMBackend) SendTransaction(args types.SendTxArgs) (common.Hash, error) // NOTE: If error is encountered on the node, the broadcast will not return an error syncCtx := e.clientCtx.WithBroadcastMode(flags.BroadcastSync) rsp, err := syncCtx.BroadcastTx(txBytes) - if rsp != nil && rsp.Code != 0 { - err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) - } - if err != nil { + if err != nil || rsp.Code != 0 { + if err == nil { + err = errors.New(rsp.RawLog) + } e.logger.Error("failed to broadcast tx", "error", err.Error()) return txHash, err } diff --git a/rpc/ethereum/namespaces/eth/api.go b/rpc/ethereum/namespaces/eth/api.go index 0bc17f28ff..bd2f137e55 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/ethereum/namespaces/eth/api.go @@ -21,7 +21,6 @@ import ( codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -433,10 +432,10 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) syncCtx := e.clientCtx.WithBroadcastMode(flags.BroadcastSync) rsp, err := syncCtx.BroadcastTx(txBytes) - if rsp != nil && rsp.Code != 0 { - err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) - } - if err != nil { + if err != nil || rsp.Code != 0 { + if err == nil { + err = errors.New(rsp.RawLog) + } e.logger.Error("failed to broadcast tx", "error", err.Error()) return txHash, err } diff --git a/rpc/ethereum/namespaces/miner/api.go b/rpc/ethereum/namespaces/miner/api.go index 3b82473c3f..0ae4e6e977 100644 --- a/rpc/ethereum/namespaces/miner/api.go +++ b/rpc/ethereum/namespaces/miner/api.go @@ -1,6 +1,7 @@ package miner import ( + "errors" "math/big" "github.com/cosmos/cosmos-sdk/client" @@ -10,7 +11,6 @@ import ( "github.com/cosmos/cosmos-sdk/server" sdkconfig "github.com/cosmos/cosmos-sdk/server/config" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtx "github.com/cosmos/cosmos-sdk/x/auth/tx" distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types" @@ -143,10 +143,10 @@ func (api *API) SetEtherbase(etherbase common.Address) bool { // NOTE: If error is encountered on the node, the broadcast will not return an error syncCtx := api.clientCtx.WithBroadcastMode(flags.BroadcastSync) rsp, err := syncCtx.BroadcastTx(txBytes) - if rsp != nil && rsp.Code != 0 { - err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) - } - if err != nil { + if err != nil || rsp.Code != 0 { + if err == nil { + err = errors.New(rsp.RawLog) + } api.logger.Debug("failed to broadcast tx", "error", err.Error()) return false } diff --git a/x/evm/keeper/grpc_query.go b/x/evm/keeper/grpc_query.go index a336c66c6b..2174b78f74 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" + "github.com/palantir/stacktrace" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -315,7 +316,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type k.ctxStack.RevertAll() if err != nil { - if errors.Is(err, core.ErrIntrinsicGas) { + if errors.Is(stacktrace.RootCause(err), core.ErrIntrinsicGas) { return true, nil, nil // Special case, raise gas limit } return true, nil, err // Bail out diff --git a/x/evm/keeper/keeper.go b/x/evm/keeper/keeper.go index 47f6b261fb..fae3a69018 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -7,10 +7,10 @@ import ( "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" + "github.com/palantir/stacktrace" "github.com/tendermint/tendermint/libs/log" ethermint "github.com/tharsis/ethermint/types" @@ -334,11 +334,11 @@ func (k Keeper) ClearBalance(addr sdk.AccAddress) (prevBalance sdk.Coin, err err prevBalance = k.bankKeeper.GetBalance(k.Ctx(), addr, params.EvmDenom) if prevBalance.IsPositive() { if err := k.bankKeeper.SendCoinsFromAccountToModule(k.Ctx(), addr, types.ModuleName, sdk.Coins{prevBalance}); err != nil { - return sdk.Coin{}, sdkerrors.Wrap(err, "failed to transfer to module account") + return sdk.Coin{}, stacktrace.Propagate(err, "failed to transfer to module account") } if err := k.bankKeeper.BurnCoins(k.Ctx(), types.ModuleName, sdk.Coins{prevBalance}); err != nil { - return sdk.Coin{}, sdkerrors.Wrap(err, "failed to burn coins from evm module account") + return sdk.Coin{}, stacktrace.Propagate(err, "failed to burn coins from evm module account") } } diff --git a/x/evm/keeper/msg_server.go b/x/evm/keeper/msg_server.go index c12a877c84..056b660a95 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -5,11 +5,12 @@ import ( "encoding/json" "fmt" + "github.com/palantir/stacktrace" + tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/tharsis/ethermint/x/evm/types" ) @@ -29,7 +30,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t response, err := k.ApplyTransaction(tx) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to apply transaction") + return nil, stacktrace.Propagate(err, "failed to apply transaction") } attrs := []sdk.Attribute{ @@ -56,7 +57,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t for _, log := range response.Logs { value, err := json.Marshal(log) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to encode log") + return nil, stacktrace.Propagate(err, "failed to encode log") } txLogAttrs = append(txLogAttrs, sdk.NewAttribute(types.AttributeKeyTxLog, string(value))) } diff --git a/x/evm/keeper/state_transition.go b/x/evm/keeper/state_transition.go index 90d943697c..0c46d8d707 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -3,6 +3,7 @@ package keeper import ( "math/big" + "github.com/palantir/stacktrace" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -148,9 +149,9 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT // return error if contract creation or call are disabled through governance if !params.EnableCreate && tx.To() == nil { - return nil, sdkerrors.Wrap(types.ErrCreateDisabled, "failed to create new contract") + return nil, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") } else if !params.EnableCall && tx.To() != nil { - return nil, sdkerrors.Wrap(types.ErrCallDisabled, "failed to call contract") + return nil, stacktrace.Propagate(types.ErrCallDisabled, "failed to call contract") } ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) @@ -160,13 +161,13 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT msg, err := tx.AsMessage(signer) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to return ethereum transaction as core message") + return nil, stacktrace.Propagate(err, "failed to return ethereum transaction as core message") } // get the coinbase address from the block proposer coinbase, err := k.GetCoinbaseAddress(ctx) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address") + return nil, stacktrace.Propagate(err, "failed to obtain coinbase address") } // create an ethereum EVM instance and run the message @@ -193,7 +194,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT // pass false to execute in real mode, which do actual gas refunding res, err := k.ApplyMessage(evm, msg, ethCfg, false) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to apply ethereum core message") + return nil, stacktrace.Propagate(err, "failed to apply ethereum core message") } res.Hash = txHash.Hex() @@ -205,7 +206,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT // FIXME: some operations under deep context stack are extremely slow, // see `benchmark_test.go:BenchmarkDeepContextStack13`. if err = k.ctxStack.CommitToRevision(revision); err != nil { - return nil, sdkerrors.Wrap(err, "failed to commit ethereum core message") + return nil, stacktrace.Propagate(err, "failed to commit ethereum core message") } } else { // All cache layers are created by the EVM contract execution. So it is safe to commit them all @@ -286,12 +287,12 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo intrinsicGas, err := k.GetEthIntrinsicGas(msg, cfg, contractCreation) if err != nil { // should have already been checked on Ante Handler - return nil, sdkerrors.Wrap(err, "intrinsic gas failed") + return nil, stacktrace.Propagate(err, "intrinsic gas failed") } // Should check again even if it is checked on Ante Handler, because eth_call don't go through Ante Handler. if msg.Gas() < intrinsicGas { // eth_estimateGas will check for this exact error - return nil, sdkerrors.Wrap(core.ErrIntrinsicGas, "apply message") + return nil, stacktrace.Propagate(core.ErrIntrinsicGas, "apply message") } leftoverGas := msg.Gas() - intrinsicGas @@ -319,7 +320,7 @@ func (k *Keeper) ApplyMessage(evm *vm.EVM, msg core.Message, cfg *params.ChainCo // refund gas prior to handling the vm error in order to match the Ethereum gas consumption instead of the default SDK one. leftoverGas, err = k.RefundGas(msg, leftoverGas, refundQuotient) if err != nil { - return nil, sdkerrors.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From()) + return nil, stacktrace.Propagate(err, "failed to refund gas leftover gas to sender %s", msg.From()) } } @@ -346,9 +347,9 @@ func (k *Keeper) ApplyNativeMessage(msg core.Message) (*types.MsgEthereumTxRespo params := k.GetParams(ctx) // return error if contract creation or call are disabled through governance if !params.EnableCreate && msg.To() == nil { - return nil, sdkerrors.Wrap(types.ErrCreateDisabled, "failed to create new contract") + return nil, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") } else if !params.EnableCall && msg.To() != nil { - return nil, sdkerrors.Wrap(types.ErrCallDisabled, "failed to call contract") + return nil, stacktrace.Propagate(types.ErrCallDisabled, "failed to call contract") } ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) @@ -356,7 +357,7 @@ func (k *Keeper) ApplyNativeMessage(msg core.Message) (*types.MsgEthereumTxRespo // get the coinbase address from the block proposer coinbase, err := k.GetCoinbaseAddress(ctx) if err != nil { - return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address") + return nil, stacktrace.Propagate(err, "failed to obtain coinbase address") } evm := k.NewEVM(msg, ethCfg, params, coinbase, nil) @@ -397,7 +398,7 @@ func (k *Keeper) GasToRefund(gasConsumed, refundQuotient uint64) uint64 { func (k *Keeper) RefundGas(msg core.Message, leftoverGas, refundQuotient uint64) (uint64, error) { // safety check: leftover gas after execution should never exceed the gas limit defined on the message if leftoverGas > msg.Gas() { - return leftoverGas, sdkerrors.Wrapf( + return leftoverGas, stacktrace.Propagate( sdkerrors.Wrapf(types.ErrInconsistentGas, "leftover gas cannot be greater than gas limit (%d > %d)", leftoverGas, msg.Gas()), "failed to update gas consumed after refund of leftover gas", ) @@ -411,7 +412,7 @@ func (k *Keeper) RefundGas(msg core.Message, leftoverGas, refundQuotient uint64) // safety check: leftover gas after refund should never exceed the gas limit defined on the message if leftoverGas > msg.Gas() { - return leftoverGas, sdkerrors.Wrapf( + return leftoverGas, stacktrace.Propagate( sdkerrors.Wrapf(types.ErrInconsistentGas, "leftover gas cannot be greater than gas limit (%d > %d)", leftoverGas, msg.Gas()), "failed to update gas consumed after refund of %d gas", refund, ) @@ -434,7 +435,7 @@ func (k *Keeper) RefundGas(msg core.Message, leftoverGas, refundQuotient uint64) err := k.bankKeeper.SendCoinsFromModuleToAccount(k.Ctx(), authtypes.FeeCollectorName, msg.From().Bytes(), refundedCoins) if err != nil { err = sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "fee collector account failed to refund fees: %s", err.Error()) - return leftoverGas, sdkerrors.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) + return leftoverGas, stacktrace.Propagate(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) } default: // no refund, consume gas and update the tx gas meter @@ -457,10 +458,9 @@ func (k Keeper) GetCoinbaseAddress(ctx sdk.Context) (common.Address, error) { consAddr := sdk.ConsAddress(ctx.BlockHeader().ProposerAddress) validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) if !found { - return common.Address{}, sdkerrors.Wrapf( - stakingtypes.ErrNoValidatorFound, - "failed to retrieve validator from block proposer address %s", - consAddr.String(), + return common.Address{}, stacktrace.Propagate( + sdkerrors.Wrap(stakingtypes.ErrNoValidatorFound, consAddr.String()), + "failed to retrieve validator from block proposer address", ) } diff --git a/x/evm/keeper/utils.go b/x/evm/keeper/utils.go index f533cf2f3d..2c9ef9bd20 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -4,6 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authante "github.com/cosmos/cosmos-sdk/x/auth/ante" + "github.com/palantir/stacktrace" evmtypes "github.com/tharsis/ethermint/x/evm/types" @@ -25,7 +26,7 @@ func (k Keeper) DeductTxCostsFromUserBalance( // fetch sender account from signature signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom()) if err != nil { - return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From) + return nil, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From) } gasLimit := txData.GetGas() @@ -37,9 +38,9 @@ func (k Keeper) DeductTxCostsFromUserBalance( intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul) if err != nil { - return nil, sdkerrors.Wrapf( + return nil, stacktrace.Propagate(sdkerrors.Wrap( err, - "failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", + "failed to compute intrinsic gas cost"), "failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", isContractCreation, homestead, istanbul, ) } @@ -59,7 +60,7 @@ func (k Keeper) DeductTxCostsFromUserBalance( // deduct the full gas cost from the user balance if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil { - return nil, sdkerrors.Wrapf( + return nil, stacktrace.Propagate( err, "failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From, @@ -81,16 +82,22 @@ func CheckSenderBalance( cost := txData.Cost() if cost.Sign() < 0 { - return sdkerrors.Wrapf( - sdkerrors.ErrInvalidCoins, - "tx cost (%s%s) is negative and invalid", cost, denom, - ) + return stacktrace.Propagate( + sdkerrors.Wrapf( + sdkerrors.ErrInvalidCoins, + "tx cost (%s%s) is negative and invalid", cost, denom, + ), + "tx cost amount should never be negative") } if balance.IsNegative() || balance.Amount.BigInt().Cmp(cost) < 0 { - return sdkerrors.Wrapf( - sdkerrors.ErrInsufficientFunds, - "sender balance < tx cost (%s < %s%s)", balance, txData.Cost(), denom, + return stacktrace.Propagate( + sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, + "sender balance < tx cost (%s < %s%s)", balance, txData.Cost(), denom, + ), + "sender should have had enough funds to pay for tx cost = fee + amount (%s = %s + %s)", + cost, txData.Fee(), txData.GetValue(), ) } return nil diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 980f1e2d67..2cb2824097 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -131,7 +131,7 @@ func (cc ChainConfig) Validate() error { func validateHash(hex string) error { if hex != "" && strings.TrimSpace(hex) == "" { - return sdkerrors.Wrap(ErrInvalidChainConfig, "hash cannot be blank") + return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") } return nil