From c8d4d3f9a3a355aba953f007b0ba34a4d44c3e7a Mon Sep 17 00:00:00 2001 From: yihuang Date: Fri, 26 Nov 2021 22:19:28 +0800 Subject: [PATCH] fix: improve error message in `SendTransaction` json-rpc api (#786) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix error message in `SendTransaction` json-rpc api Closes: #785 Solution: - Remove `stacktrace.Propagate`s, and recover error message in jsonrpc server changelog fix error messages * Update x/evm/keeper/msg_server.go Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com> --- CHANGELOG.md | 1 + app/ante/ante.go | 14 +-- app/ante/eth.go | 175 +++++++++------------------ 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 | 34 +++--- x/evm/keeper/utils.go | 29 ++--- x/evm/types/chain_config.go | 2 +- 14 files changed, 112 insertions(+), 190 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 48f44935..15213703 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ## Improvements * (ci) [tharsis#784](https://github.com/tharsis/ethermint/pull/784) Enable automatic backport of PRs. +* (rpc) [tharsis#786](https://github.com/tharsis/ethermint/pull/786) Improve error message of `SendTransaction`/`SendRawTransaction` JSON-RPC APIs. ### Bug Fixes diff --git a/app/ante/ante.go b/app/ante/ante.go index 55c96866..fbb59016 100644 --- a/app/ante/ante.go +++ b/app/ante/ante.go @@ -4,8 +4,6 @@ import ( "fmt" "runtime/debug" - "github.com/palantir/stacktrace" - tmlog "github.com/tendermint/tendermint/libs/log" sdk "github.com/cosmos/cosmos-sdk/types" @@ -69,9 +67,10 @@ func NewAnteHandler( ) default: - return ctx, stacktrace.Propagate( - sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, typeURL), - "rejecting tx with unsupported extension option", + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrUnknownExtensionOptions, + "rejecting tx with unsupported extension option: %s", + typeURL, ) } @@ -100,10 +99,7 @@ func NewAnteHandler( authante.NewIncrementSequenceDecorator(ak), // innermost AnteDecorator ) default: - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx), - "transaction is not an SDK tx", - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) } return anteHandler(ctx, tx, sim) diff --git a/app/ante/eth.go b/app/ante/eth.go index 1220eb10..226d644a 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -4,8 +4,6 @@ import ( "errors" "math/big" - "github.com/palantir/stacktrace" - sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" tx "github.com/cosmos/cosmos-sdk/types/tx" @@ -59,10 +57,7 @@ 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, stacktrace.Propagate( - sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"), - "", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx") } chainID := esvd.evmKeeper.ChainID() @@ -76,18 +71,16 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s msg := tx.GetMsgs()[0] msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction", - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } sender, err := signer.Sender(msgEthTx.AsTransaction()) if err != nil { - return ctx, stacktrace.Propagate( - sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()), - "couldn't retrieve sender address ('%s') from the ethereum transaction", + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrorInvalidSigner, + "couldn't retrieve sender address ('%s') from the ethereum transaction: %s", msgEthTx.From, + err.Error(), ) } @@ -130,32 +123,26 @@ 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, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack tx data any for tx %d", i) + return ctx, sdkerrors.Wrapf(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, 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", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty") } // check whether the sender address is EOA fromAddr := common.BytesToAddress(from) codeHash := avd.evmKeeper.GetCodeHash(fromAddr) if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) { - return ctx, stacktrace.Propagate(sdkerrors.Wrapf(sdkerrors.ErrInvalidType, - "the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash), "") + return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, + "the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash) } acc := avd.ak.GetAccount(ctx, from) @@ -165,7 +152,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, stacktrace.Propagate(err, "failed to check sender balance") + return ctx, sdkerrors.Wrap(err, "failed to check sender balance") } } @@ -195,36 +182,30 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, return next(ctx, tx, simulate) } - for i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } // 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, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From) + return ctx, sdkerrors.Wrapf(err, "sequence not found for address %s", msgEthTx.From) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack tx data") + return ctx, sdkerrors.Wrap(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, stacktrace.Propagate( - sdkerrors.Wrapf( - sdkerrors.ErrInvalidSequence, - "invalid nonce; got %d, expected %d", txData.GetNonce(), seq, - ), - "", + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrInvalidSequence, + "invalid nonce; got %d, expected %d", txData.GetNonce(), seq, ) } } @@ -277,18 +258,15 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula var events sdk.Events - for i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack tx data") + return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") } fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance( @@ -301,7 +279,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula london, ) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to deduct transaction costs from user balance") + return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance") } events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String()))) @@ -353,13 +331,10 @@ 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 i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } var baseFee *big.Int @@ -369,7 +344,7 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate coreMsg, err := msgEthTx.AsMessage(signer, baseFee) if err != nil { - return ctx, stacktrace.Propagate( + return ctx, sdkerrors.Wrapf( err, "failed to create an ethereum core.Message from signer %T", signer, ) @@ -387,24 +362,20 @@ 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, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInsufficientFunds, "address %s", coreMsg.From()), - "failed to transfer %s using the EVM block context transfer function", 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(), ) } if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee == nil { - return ctx, stacktrace.Propagate( - sdkerrors.Wrap(evmtypes.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil"), - "address %s", coreMsg.From(), - ) + return ctx, sdkerrors.Wrap(evmtypes.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil") } if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee != nil && coreMsg.GasFeeCap().Cmp(baseFee) < 0 { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(evmtypes.ErrInvalidBaseFee, "max fee per gas less than block base fee (%s < %s)", coreMsg.GasFeeCap(), baseFee), - "address %s", coreMsg.From(), - ) + return ctx, sdkerrors.Wrapf(evmtypes.ErrInvalidBaseFee, "max fee per gas less than block base fee (%s < %s)", coreMsg.GasFeeCap(), baseFee) } } @@ -450,20 +421,17 @@ 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 i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } sender := common.BytesToAddress(msgEthTx.GetFrom()) txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack tx data") + return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") } ald.evmKeeper.PrepareAccessList(sender, txData.GetTo(), vm.ActivePrecompiles(rules), txData.GetAccessList()) @@ -490,18 +458,15 @@ 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 i, msg := range tx.GetMsgs() { + for _, msg := range tx.GetMsgs() { msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction %d", i, - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack tx data") + return ctx, sdkerrors.Wrap(err, "failed to unpack tx data") } // NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution @@ -517,17 +482,14 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s acc := issd.ak.GetAccount(ctx, addr) if acc == nil { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf( - sdkerrors.ErrUnknownAddress, - "account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr, - ), - "signer account not found", + return ctx, sdkerrors.Wrapf( + sdkerrors.ErrUnknownAddress, + "account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr, ) } if err := acc.SetSequence(acc.GetSequence() + 1); err != nil { - return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1) + return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1) } issd.ak.SetAccount(ctx, acc) @@ -560,7 +522,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, stacktrace.Propagate(err, "tx basic validation failed") + return ctx, sdkerrors.Wrap(err, "tx basic validation failed") } // For eth type cosmos tx, some fields should be veified as zero values, @@ -569,78 +531,51 @@ 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, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, - "for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, + "for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty") } if len(body.ExtensionOptions) != 1 { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1") } if len(protoTx.GetMsgs()) != 1 { - return ctx, stacktrace.Propagate( - sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx"), - "", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx") } msg := protoTx.GetMsgs()[0] msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx) if !ok { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)), - "failed to cast transaction", - ) + return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil)) } ethGasLimit := msgEthTx.GetGas() txData, err := evmtypes.UnpackTxData(msgEthTx.Data) if err != nil { - return ctx, stacktrace.Propagate(err, "failed to unpack MsgEthereumTx Data") + return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data") } params := vbd.evmKeeper.GetParams(ctx) ethFeeAmount := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee()))} authInfo := protoTx.AuthInfo if len(authInfo.SignerInfos) > 0 { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty") } if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty") } if !authInfo.Fee.Amount.IsEqual(ethFeeAmount) { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount") } if authInfo.Fee.GasLimit != ethGasLimit { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit") } sigs := protoTx.Signatures if len(sigs) > 0 { - return ctx, stacktrace.Propagate( - sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty"), - "invalid data in tx", - ) + return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty") } } diff --git a/go.mod b/go.mod index 8f730799..be3c4612 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,6 @@ require ( github.com/klauspost/compress v1.11.9 // indirect github.com/miguelmota/go-ethereum-hdwallet v0.1.1 github.com/onsi/ginkgo v1.16.5 - 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/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect diff --git a/go.sum b/go.sum index a9d3e8db..532135f6 100644 --- a/go.sum +++ b/go.sum @@ -799,8 +799,6 @@ 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 32b2308e..908dd9b2 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/ethereum/backend/backend.go @@ -12,6 +12,7 @@ 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" @@ -810,10 +811,10 @@ func (e *EVMBackend) SendTransaction(args evmtypes.TransactionArgs) (common.Hash // 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 err != nil || rsp.Code != 0 { - if err == nil { - err = errors.New(rsp.RawLog) - } + if rsp != nil && rsp.Code != 0 { + err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) + } + if err != nil { 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 d46b4edc..d0a230e2 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/ethereum/namespaces/eth/api.go @@ -22,6 +22,7 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/crypto/keyring" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/ethereum/go-ethereum/accounts/keystore" @@ -479,10 +480,10 @@ func (e *PublicAPI) SendRawTransaction(data hexutil.Bytes) (common.Hash, error) syncCtx := e.clientCtx.WithBroadcastMode(flags.BroadcastSync) rsp, err := syncCtx.BroadcastTx(txBytes) - if err != nil || rsp.Code != 0 { - if err == nil { - err = errors.New(rsp.RawLog) - } + if rsp != nil && rsp.Code != 0 { + err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) + } + if err != nil { 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 0ae4e6e9..3b82473c 100644 --- a/rpc/ethereum/namespaces/miner/api.go +++ b/rpc/ethereum/namespaces/miner/api.go @@ -1,7 +1,6 @@ package miner import ( - "errors" "math/big" "github.com/cosmos/cosmos-sdk/client" @@ -11,6 +10,7 @@ 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 err != nil || rsp.Code != 0 { - if err == nil { - err = errors.New(rsp.RawLog) - } + if rsp != nil && rsp.Code != 0 { + err = sdkerrors.ABCIError(rsp.Codespace, rsp.Code, rsp.RawLog) + } + if err != nil { 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 31f26ff0..3c5cbd73 100644 --- a/x/evm/keeper/grpc_query.go +++ b/x/evm/keeper/grpc_query.go @@ -10,7 +10,6 @@ import ( "github.com/ethereum/go-ethereum/eth/tracers" - "github.com/palantir/stacktrace" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" @@ -313,7 +312,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type rsp, err = k.ApplyMessageWithConfig(msg, nil, false, cfg) if err != nil { - if errors.Is(stacktrace.RootCause(err), core.ErrIntrinsicGas) { + if errors.Is(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 b735310c..750554b7 100644 --- a/x/evm/keeper/keeper.go +++ b/x/evm/keeper/keeper.go @@ -7,12 +7,12 @@ 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" "github.com/ethereum/go-ethereum/core" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" - "github.com/palantir/stacktrace" "github.com/tendermint/tendermint/libs/log" "github.com/ethereum/go-ethereum/params" @@ -341,11 +341,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{}, stacktrace.Propagate(err, "failed to transfer to module account") + return sdk.Coin{}, sdkerrors.Wrap(err, "failed to transfer to module account") } if err := k.bankKeeper.BurnCoins(k.Ctx(), types.ModuleName, sdk.Coins{prevBalance}); err != nil { - return sdk.Coin{}, stacktrace.Propagate(err, "failed to burn coins from evm module account") + return sdk.Coin{}, sdkerrors.Wrap(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 056b660a..c12a877c 100644 --- a/x/evm/keeper/msg_server.go +++ b/x/evm/keeper/msg_server.go @@ -5,12 +5,11 @@ 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" ) @@ -30,7 +29,7 @@ func (k *Keeper) EthereumTx(goCtx context.Context, msg *types.MsgEthereumTx) (*t response, err := k.ApplyTransaction(tx) if err != nil { - return nil, stacktrace.Propagate(err, "failed to apply transaction") + return nil, sdkerrors.Wrap(err, "failed to apply transaction") } attrs := []sdk.Attribute{ @@ -57,7 +56,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, stacktrace.Propagate(err, "failed to encode log") + return nil, sdkerrors.Wrap(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 1b3b0d20..02c64224 100644 --- a/x/evm/keeper/state_transition.go +++ b/x/evm/keeper/state_transition.go @@ -3,7 +3,6 @@ package keeper import ( "math/big" - "github.com/palantir/stacktrace" tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -29,7 +28,7 @@ func (k *Keeper) EVMConfig(ctx sdk.Context) (*types.EVMConfig, error) { // get the coinbase address from the block proposer coinbase, err := k.GetCoinbaseAddress(ctx) if err != nil { - return nil, stacktrace.Propagate(err, "failed to obtain coinbase address") + return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address") } var baseFee *big.Int @@ -176,7 +175,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT cfg, err := k.EVMConfig(ctx) if err != nil { - return nil, stacktrace.Propagate(err, "failed to load evm config") + return nil, sdkerrors.Wrap(err, "failed to load evm config") } // get the latest signer according to the chain rules from the config @@ -189,7 +188,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT msg, err := tx.AsMessage(signer, baseFee) if err != nil { - return nil, stacktrace.Propagate(err, "failed to return ethereum transaction as core message") + return nil, sdkerrors.Wrap(err, "failed to return ethereum transaction as core message") } txHash := tx.Hash() @@ -215,7 +214,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT res, err := k.ApplyMessageWithConfig(msg, nil, true, cfg) if err != nil { - return nil, stacktrace.Propagate(err, "failed to apply ethereum core message") + return nil, sdkerrors.Wrap(err, "failed to apply ethereum core message") } res.Hash = txHash.Hex() @@ -240,7 +239,7 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT // refund gas according to Ethereum gas accounting rules. if err := k.RefundGas(msg, msg.Gas()-res.GasUsed, cfg.Params.EvmDenom); err != nil { - return nil, stacktrace.Propagate(err, "failed to refund gas leftover gas to sender %s", msg.From()) + return nil, sdkerrors.Wrapf(err, "failed to refund gas leftover gas to sender %s", msg.From()) } if len(logs) > 0 { @@ -314,9 +313,9 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm // return error if contract creation or call are disabled through governance if !cfg.Params.EnableCreate && msg.To() == nil { - return nil, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") + return nil, sdkerrors.Wrap(types.ErrCreateDisabled, "failed to create new contract") } else if !cfg.Params.EnableCall && msg.To() != nil { - return nil, stacktrace.Propagate(types.ErrCallDisabled, "failed to call contract") + return nil, sdkerrors.Wrap(types.ErrCallDisabled, "failed to call contract") } sender := vm.AccountRef(msg.From()) @@ -326,12 +325,12 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm intrinsicGas, err := k.GetEthIntrinsicGas(msg, cfg.ChainConfig, contractCreation) if err != nil { // should have already been checked on Ante Handler - return nil, stacktrace.Propagate(err, "intrinsic gas failed") + return nil, sdkerrors.Wrap(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, stacktrace.Propagate(core.ErrIntrinsicGas, "apply message") + return nil, sdkerrors.Wrap(core.ErrIntrinsicGas, "apply message") } leftoverGas := msg.Gas() - intrinsicGas @@ -356,12 +355,12 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm // calculate gas refund if msg.Gas() < leftoverGas { - return nil, stacktrace.Propagate(types.ErrGasOverflow, "apply message") + return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message") } gasUsed := msg.Gas() - leftoverGas refund := k.GasToRefund(gasUsed, refundQuotient) if refund > gasUsed { - return nil, stacktrace.Propagate(types.ErrGasOverflow, "apply message") + return nil, sdkerrors.Wrap(types.ErrGasOverflow, "apply message") } gasUsed -= refund @@ -390,7 +389,7 @@ func (k *Keeper) ApplyMessageWithConfig(msg core.Message, tracer vm.Tracer, comm func (k *Keeper) ApplyMessage(msg core.Message, tracer vm.Tracer, commit bool) (*types.MsgEthereumTxResponse, error) { cfg, err := k.EVMConfig(k.Ctx()) if err != nil { - return nil, stacktrace.Propagate(err, "failed to load evm config") + return nil, sdkerrors.Wrap(err, "failed to load evm config") } return k.ApplyMessageWithConfig(msg, tracer, commit, cfg) } @@ -438,7 +437,7 @@ func (k *Keeper) RefundGas(msg core.Message, leftoverGas uint64, denom string) e 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 stacktrace.Propagate(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) + return sdkerrors.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) } default: // no refund, consume gas and update the tx gas meter @@ -461,9 +460,10 @@ 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{}, stacktrace.Propagate( - sdkerrors.Wrap(stakingtypes.ErrNoValidatorFound, consAddr.String()), - "failed to retrieve validator from block proposer address", + return common.Address{}, sdkerrors.Wrapf( + stakingtypes.ErrNoValidatorFound, + "failed to retrieve validator from block proposer address %s", + consAddr.String(), ) } diff --git a/x/evm/keeper/utils.go b/x/evm/keeper/utils.go index 44c70466..6a8b4e88 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -6,7 +6,6 @@ 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" @@ -28,7 +27,7 @@ func (k Keeper) DeductTxCostsFromUserBalance( // fetch sender account from signature signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom()) if err != nil { - return nil, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From) + return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From) } gasLimit := txData.GetGas() @@ -40,9 +39,9 @@ func (k Keeper) DeductTxCostsFromUserBalance( intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul) if err != nil { - return nil, stacktrace.Propagate(sdkerrors.Wrap( + return nil, sdkerrors.Wrapf( err, - "failed to compute intrinsic gas cost"), "failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", + "failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", isContractCreation, homestead, istanbul, ) } @@ -77,7 +76,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, stacktrace.Propagate( + return nil, sdkerrors.Wrapf( err, "failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From, @@ -99,22 +98,16 @@ func CheckSenderBalance( cost := txData.Cost() if cost.Sign() < 0 { - return stacktrace.Propagate( - sdkerrors.Wrapf( - sdkerrors.ErrInvalidCoins, - "tx cost (%s%s) is negative and invalid", cost, denom, - ), - "tx cost amount should never be negative") + return sdkerrors.Wrapf( + sdkerrors.ErrInvalidCoins, + "tx cost (%s%s) is negative and invalid", cost, denom, + ) } if balance.IsNegative() || balance.Amount.BigInt().Cmp(cost) < 0 { - 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 sdkerrors.Wrapf( + sdkerrors.ErrInsufficientFunds, + "sender balance < tx cost (%s < %s%s)", balance, txData.Cost(), denom, ) } return nil diff --git a/x/evm/types/chain_config.go b/x/evm/types/chain_config.go index 5de285e0..2efa47b1 100644 --- a/x/evm/types/chain_config.go +++ b/x/evm/types/chain_config.go @@ -129,7 +129,7 @@ func (cc ChainConfig) Validate() error { func validateHash(hex string) error { if hex != "" && strings.TrimSpace(hex) == "" { - return sdkerrors.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") + return sdkerrors.Wrap(ErrInvalidChainConfig, "hash cannot be blank") } return nil