ante: add stacktrace (#123)
This commit is contained in:
parent
3a74d2402b
commit
7f72891c09
@ -3,6 +3,7 @@ package ante
|
||||
import (
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/palantir/stacktrace"
|
||||
log "github.com/xlab/suplog"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -73,8 +74,10 @@ func NewAnteHandler(
|
||||
)
|
||||
|
||||
default:
|
||||
log.WithField("type_url", typeURL).Errorln("rejecting tx with unsupported extension option")
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, typeURL)
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(sdkerrors.ErrUnknownExtensionOptions, typeURL),
|
||||
"rejecting tx with unsupported extension option",
|
||||
)
|
||||
}
|
||||
|
||||
return anteHandler(ctx, tx, sim)
|
||||
@ -102,7 +105,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)
|
||||
|
108
app/ante/eth.go
108
app/ante/eth.go
@ -6,6 +6,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"
|
||||
|
||||
ethermint "github.com/cosmos/ethermint/types"
|
||||
evmtypes "github.com/cosmos/ethermint/x/evm/types"
|
||||
@ -50,7 +51,10 @@ func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, s
|
||||
}
|
||||
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx, got %d", len(tx.GetMsgs()))
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx, got %d", len(tx.GetMsgs())),
|
||||
"",
|
||||
)
|
||||
}
|
||||
|
||||
// get and set account must be called with an infinite gas meter in order to prevent
|
||||
@ -71,12 +75,19 @@ 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{})
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction",
|
||||
)
|
||||
}
|
||||
|
||||
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error())
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(sdkerrors.ErrorInvalidSigner, err.Error()),
|
||||
"couldn't retrieve sender address ('%s') from the ethereum transaction",
|
||||
msgEthTx.From,
|
||||
)
|
||||
}
|
||||
|
||||
// set up the sender to the transaction field if not already
|
||||
@ -118,16 +129,22 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
|
||||
|
||||
evmDenom := avd.evmKeeper.GetParams(infCtx).EvmDenom
|
||||
|
||||
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{})
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
from := msgEthTx.GetFrom()
|
||||
if from.Empty() {
|
||||
return ctx, sdkerrors.Wrapf(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",
|
||||
)
|
||||
}
|
||||
|
||||
acc := avd.ak.GetAccount(infCtx, from)
|
||||
@ -136,12 +153,15 @@ func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx
|
||||
avd.ak.SetAccount(infCtx, acc)
|
||||
}
|
||||
|
||||
// validate sender has enough funds to pay for gas cost
|
||||
// validate sender has enough funds to pay for tx cost
|
||||
balance := avd.bankKeeper.GetBalance(infCtx, from, evmDenom)
|
||||
if balance.Amount.BigInt().Cmp(msgEthTx.Cost()) < 0 {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInsufficientFunds,
|
||||
"sender balance < tx gas cost (%s < %s%s)", balance.String(), msgEthTx.Cost().String(), evmDenom,
|
||||
"sender balance < tx cost (%s < %s%s)", balance, msgEthTx.Cost(), evmDenom,
|
||||
),
|
||||
"sender should have had enough funds to pay for tx cost = fee + amount (%s = %s + amount)", msgEthTx.Cost(), msgEthTx.Fee(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -174,25 +194,31 @@ func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx,
|
||||
// additional gas from being deducted.
|
||||
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
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{})
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
// sender address should be in the tx cache from the previous AnteHandle call
|
||||
seq, err := nvd.ak.GetSequence(infCtx, msgEthTx.GetFrom())
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return ctx, stacktrace.Propagate(err, "sequence not found for address %s", msgEthTx.From)
|
||||
}
|
||||
|
||||
// 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 msgEthTx.Data.Nonce != seq {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(
|
||||
sdkerrors.ErrInvalidSequence,
|
||||
"invalid nonce; got %d, expected %d", msgEthTx.Data.Nonce, seq,
|
||||
),
|
||||
"",
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -250,10 +276,13 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
homestead := ethCfg.IsHomestead(blockHeight)
|
||||
istanbul := ethCfg.IsIstanbul(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{})
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
isContractCreation := msgEthTx.To() == nil
|
||||
@ -261,7 +290,7 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
// fetch sender account from signature
|
||||
signerAcc, err := authante.GetSignerAcc(infCtx, egcd.ak, msgEthTx.GetFrom())
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return ctx, stacktrace.Propagate(err, "account not found for sender %s", msgEthTx.From)
|
||||
}
|
||||
|
||||
gasLimit := msgEthTx.GetGas()
|
||||
@ -273,7 +302,9 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
|
||||
intrinsicGas, err := core.IntrinsicGas(msgEthTx.Data.Input, accessList, isContractCreation, homestead, istanbul)
|
||||
if err != nil {
|
||||
return ctx, sdkerrors.Wrap(err, "failed to compute intrinsic gas cost")
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrap(err, "failed to compute intrinsic gas cost"),
|
||||
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t", isContractCreation, homestead, istanbul)
|
||||
}
|
||||
|
||||
// intrinsic gas verification during CheckTx
|
||||
@ -289,7 +320,10 @@ func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simula
|
||||
|
||||
// deduct the full gas cost from the user balance
|
||||
if err := authante.DeductFees(egcd.bankKeeper, infCtx, signerAcc, fees); err != nil {
|
||||
return ctx, err
|
||||
return ctx, stacktrace.Propagate(
|
||||
err,
|
||||
"failed to deduct full gas cost %s from the user %s balance", fees, msgEthTx.From,
|
||||
)
|
||||
}
|
||||
|
||||
// consume intrinsic gas for the current transaction. After runTx is executed on Baseapp, the
|
||||
@ -343,15 +377,21 @@ func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate
|
||||
ethCfg := config.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", msg)
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
coreMsg, err := msgEthTx.AsMessage(signer)
|
||||
if err != nil {
|
||||
return ctx, err
|
||||
return ctx, stacktrace.Propagate(
|
||||
err,
|
||||
"failed to create an ethereum core.Message from signer %T", signer,
|
||||
)
|
||||
}
|
||||
|
||||
evm := ctd.evmKeeper.NewEVM(coreMsg, ethCfg)
|
||||
@ -359,7 +399,10 @@ 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, "address %s", coreMsg.From().Hex())
|
||||
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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -414,10 +457,13 @@ func (ald AccessListDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate b
|
||||
// setup the keeper context before setting the access list
|
||||
ald.evmKeeper.WithContext(infCtx)
|
||||
|
||||
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", msg)
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
sender := common.BytesToAddress(msgEthTx.GetFrom())
|
||||
@ -450,10 +496,13 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
|
||||
// additional gas from being deducted.
|
||||
infCtx := ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
|
||||
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", msg)
|
||||
return ctx, stacktrace.Propagate(
|
||||
sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, &evmtypes.MsgEthereumTx{}),
|
||||
"failed to cast transaction %d", i,
|
||||
)
|
||||
}
|
||||
|
||||
// NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution
|
||||
@ -469,14 +518,17 @@ func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx s
|
||||
acc := issd.ak.GetAccount(infCtx, addr)
|
||||
|
||||
if acc == nil {
|
||||
return ctx, sdkerrors.Wrapf(
|
||||
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, err
|
||||
return ctx, stacktrace.Propagate(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
||||
}
|
||||
|
||||
issd.ak.SetAccount(infCtx, acc)
|
||||
|
Loading…
Reference in New Issue
Block a user