diff --git a/CHANGELOG.md b/CHANGELOG.md index 58670c60aa..e87fe273b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,10 @@ Ref: https://keepachangelog.com/en/1.0.0/ - [crypto-org-chain/ethermint#15](https://github.com/crypto-org-chain/ethermint/pull/15) web3 rpc api returns wrong block gas limit - [crypto-org-chain/ethermint#16](https://github.com/crypto-org-chain/ethermint/pull/16) fix unwrap context panic in BlockMaxGasFromConsensusParams +### Improvements + +- [tharsis#786](https://github.com/tharsis/ethermint/pull/786) Improve error message of `SendTransaction`/`SendRawTransaction` JSON-RPC APIs. + ## [v0.7.2-cronos-2] - 2021-11-17 ### Bug Fixes diff --git a/app/ante/ante.go b/app/ante/ante.go index 9177c4639c..c68ceaeb7e 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" @@ -68,9 +66,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, ) } @@ -99,10 +98,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 4056821ccb..71567597b2 100644 --- a/app/ante/eth.go +++ b/app/ante/eth.go @@ -8,7 +8,6 @@ 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" @@ -59,10 +58,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 +72,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 +124,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 +153,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 +183,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, ) } } @@ -274,18 +256,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( @@ -297,7 +276,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula istanbul, ) 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()))) @@ -346,18 +325,15 @@ 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)) } coreMsg, err := msgEthTx.AsMessage(signer) if err != nil { - return ctx, stacktrace.Propagate( + return ctx, sdkerrors.Wrapf( err, "failed to create an ethereum core.Message from signer %T", signer, ) @@ -369,9 +345,11 @@ 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(), ) } } @@ -418,20 +396,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()) @@ -458,18 +433,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 @@ -485,17 +457,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) @@ -528,7 +497,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, @@ -537,39 +506,27 @@ 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) @@ -577,39 +534,24 @@ func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simu 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 4c03f486b5..af545e9599 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ 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 649395ac7e..21eb3af24a 100644 --- a/go.sum +++ b/go.sum @@ -942,8 +942,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 9c3b98ae8d..b0a8a94ff5 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/ethereum/backend/backend.go @@ -11,6 +11,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" @@ -704,10 +705,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 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 bd2f137e55..0bc17f28ff 100644 --- a/rpc/ethereum/namespaces/eth/api.go +++ b/rpc/ethereum/namespaces/eth/api.go @@ -21,6 +21,7 @@ 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" @@ -432,10 +433,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 0ae4e6e977..3b82473c3f 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 2174b78f74..a336c66c6b 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" @@ -316,7 +315,7 @@ func (k Keeper) EstimateGas(c context.Context, req *types.EthCallRequest) (*type k.ctxStack.RevertAll() 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 fae3a69018..47f6b261fb 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{}, 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 056b660a95..c12a877c84 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 0c46d8d707..90d943697c 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" @@ -149,9 +148,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, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") + return nil, sdkerrors.Wrap(types.ErrCreateDisabled, "failed to create new contract") } else if !params.EnableCall && tx.To() != nil { - return nil, stacktrace.Propagate(types.ErrCallDisabled, "failed to call contract") + return nil, sdkerrors.Wrap(types.ErrCallDisabled, "failed to call contract") } ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) @@ -161,13 +160,13 @@ func (k *Keeper) ApplyTransaction(tx *ethtypes.Transaction) (*types.MsgEthereumT msg, err := tx.AsMessage(signer) 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") } // 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") } // create an ethereum EVM instance and run the message @@ -194,7 +193,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, stacktrace.Propagate(err, "failed to apply ethereum core message") + return nil, sdkerrors.Wrap(err, "failed to apply ethereum core message") } res.Hash = txHash.Hex() @@ -206,7 +205,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, stacktrace.Propagate(err, "failed to commit ethereum core message") + return nil, sdkerrors.Wrap(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 @@ -287,12 +286,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, 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 @@ -320,7 +319,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, 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()) } } @@ -347,9 +346,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, stacktrace.Propagate(types.ErrCreateDisabled, "failed to create new contract") + return nil, sdkerrors.Wrap(types.ErrCreateDisabled, "failed to create new contract") } else if !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") } ethCfg := params.ChainConfig.EthereumConfig(k.eip155ChainID) @@ -357,7 +356,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, stacktrace.Propagate(err, "failed to obtain coinbase address") + return nil, sdkerrors.Wrap(err, "failed to obtain coinbase address") } evm := k.NewEVM(msg, ethCfg, params, coinbase, nil) @@ -398,7 +397,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, stacktrace.Propagate( + return leftoverGas, sdkerrors.Wrapf( 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", ) @@ -412,7 +411,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, stacktrace.Propagate( + return leftoverGas, sdkerrors.Wrapf( 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, ) @@ -435,7 +434,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, stacktrace.Propagate(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) + return leftoverGas, sdkerrors.Wrapf(err, "failed to refund %d leftover gas (%s)", leftoverGas, refundedCoins.String()) } default: // no refund, consume gas and update the tx gas meter @@ -458,9 +457,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 2c9ef9bd20..f533cf2f3d 100644 --- a/x/evm/keeper/utils.go +++ b/x/evm/keeper/utils.go @@ -4,7 +4,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" @@ -26,7 +25,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() @@ -38,9 +37,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, ) } @@ -60,7 +59,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, @@ -82,22 +81,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 2cb2824097..980f1e2d67 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.Wrapf(ErrInvalidChainConfig, "hash cannot be blank") + return sdkerrors.Wrap(ErrInvalidChainConfig, "hash cannot be blank") } return nil