2020-04-17 22:32:01 +00:00
|
|
|
|
package ante
|
|
|
|
|
|
|
|
|
|
import (
|
2021-09-05 11:03:06 +00:00
|
|
|
|
"errors"
|
2020-04-17 22:32:01 +00:00
|
|
|
|
"math/big"
|
|
|
|
|
|
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
|
|
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
2021-11-08 13:00:35 +00:00
|
|
|
|
tx "github.com/cosmos/cosmos-sdk/types/tx"
|
2020-04-17 22:32:01 +00:00
|
|
|
|
authante "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
|
|
|
|
|
2021-06-22 10:49:18 +00:00
|
|
|
|
ethermint "github.com/tharsis/ethermint/types"
|
2021-09-03 15:55:37 +00:00
|
|
|
|
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
|
2021-06-22 10:49:18 +00:00
|
|
|
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2020-06-22 16:07:35 +00:00
|
|
|
|
"github.com/ethereum/go-ethereum/common"
|
2021-05-10 16:34:00 +00:00
|
|
|
|
"github.com/ethereum/go-ethereum/core"
|
|
|
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
2021-06-02 08:52:53 +00:00
|
|
|
|
"github.com/ethereum/go-ethereum/core/vm"
|
2020-04-17 22:32:01 +00:00
|
|
|
|
)
|
|
|
|
|
|
2020-09-02 19:41:05 +00:00
|
|
|
|
// EVMKeeper defines the expected keeper interface used on the Eth AnteHandler
|
|
|
|
|
type EVMKeeper interface {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
vm.StateDB
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
ChainID() *big.Int
|
2020-09-02 19:41:05 +00:00
|
|
|
|
GetParams(ctx sdk.Context) evmtypes.Params
|
2021-05-25 12:56:36 +00:00
|
|
|
|
WithContext(ctx sdk.Context)
|
|
|
|
|
ResetRefundTransient(ctx sdk.Context)
|
2021-10-22 17:21:03 +00:00
|
|
|
|
NewEVM(msg core.Message, cfg *evmtypes.EVMConfig, tracer vm.Tracer) *vm.EVM
|
2021-06-15 17:39:41 +00:00
|
|
|
|
GetCodeHash(addr common.Address) common.Hash
|
2021-09-22 10:26:29 +00:00
|
|
|
|
DeductTxCostsFromUserBalance(
|
2021-10-04 14:58:06 +00:00
|
|
|
|
ctx sdk.Context, msgEthTx evmtypes.MsgEthereumTx, txData evmtypes.TxData, denom string, homestead, istanbul, london bool,
|
2021-09-22 10:26:29 +00:00
|
|
|
|
) (sdk.Coins, error)
|
2020-09-02 19:41:05 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-08 13:00:35 +00:00
|
|
|
|
type protoTxProvider interface {
|
|
|
|
|
GetProtoTx() *tx.Tx
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// EthSigVerificationDecorator validates an ethereum signatures
|
2021-04-18 16:39:15 +00:00
|
|
|
|
type EthSigVerificationDecorator struct {
|
2021-05-10 16:34:00 +00:00
|
|
|
|
evmKeeper EVMKeeper
|
2021-04-18 16:39:15 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
|
|
|
|
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
|
2021-05-10 16:34:00 +00:00
|
|
|
|
func NewEthSigVerificationDecorator(ek EVMKeeper) EthSigVerificationDecorator {
|
|
|
|
|
return EthSigVerificationDecorator{
|
|
|
|
|
evmKeeper: ek,
|
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// AnteHandle validates checks that the registered chain id is the same as the one on the message, and
|
|
|
|
|
// that the signer address matches the one defined on the message.
|
2021-06-25 13:28:28 +00:00
|
|
|
|
// It's not skipped for RecheckTx, because it set `From` address which is critical from other ante handler to work.
|
|
|
|
|
// Failure in RecheckTx will prevent tx to be included into block, especially when CheckTx succeed, in which case user
|
|
|
|
|
// won't see the error message.
|
2020-04-17 22:32:01 +00:00
|
|
|
|
func (esvd EthSigVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
2021-06-29 17:02:21 +00:00
|
|
|
|
if tx == nil || len(tx.GetMsgs()) != 1 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx")
|
2021-06-11 13:38:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
chainID := esvd.evmKeeper.ChainID()
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
params := esvd.evmKeeper.GetParams(ctx)
|
2021-05-10 16:34:00 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
2021-05-10 16:34:00 +00:00
|
|
|
|
blockNum := big.NewInt(ctx.BlockHeight())
|
|
|
|
|
signer := ethtypes.MakeSigner(ethCfg, blockNum)
|
|
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
|
msg := tx.GetMsgs()[0]
|
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-06-11 13:38:51 +00:00
|
|
|
|
}
|
2021-05-10 16:34:00 +00:00
|
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
|
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(
|
|
|
|
|
sdkerrors.ErrorInvalidSigner,
|
|
|
|
|
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
|
2021-06-15 07:19:31 +00:00
|
|
|
|
msgEthTx.From,
|
2021-11-26 14:19:28 +00:00
|
|
|
|
err.Error(),
|
2021-06-15 07:19:31 +00:00
|
|
|
|
)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-11 13:38:51 +00:00
|
|
|
|
// set up the sender to the transaction field if not already
|
|
|
|
|
msgEthTx.From = sender.Hex()
|
|
|
|
|
|
|
|
|
|
return next(ctx, msgEthTx, simulate)
|
2021-04-18 16:39:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EthAccountVerificationDecorator validates an account balance checks
|
|
|
|
|
type EthAccountVerificationDecorator struct {
|
2021-09-03 15:55:37 +00:00
|
|
|
|
ak evmtypes.AccountKeeper
|
|
|
|
|
bankKeeper evmtypes.BankKeeper
|
2021-04-17 10:00:07 +00:00
|
|
|
|
evmKeeper EVMKeeper
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 16:39:15 +00:00
|
|
|
|
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
2021-09-03 15:55:37 +00:00
|
|
|
|
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) EthAccountVerificationDecorator {
|
2021-04-18 16:39:15 +00:00
|
|
|
|
return EthAccountVerificationDecorator{
|
2021-04-17 10:00:07 +00:00
|
|
|
|
ak: ak,
|
|
|
|
|
bankKeeper: bankKeeper,
|
|
|
|
|
evmKeeper: ek,
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// AnteHandle validates checks that the sender balance is greater than the total transaction cost.
|
|
|
|
|
// The account will be set to store if it doesn't exis, i.e cannot be found on store.
|
|
|
|
|
// This AnteHandler decorator will fail if:
|
|
|
|
|
// - any of the msgs is not a MsgEthereumTx
|
|
|
|
|
// - from address is empty
|
|
|
|
|
// - account balance is lower than the transaction cost
|
2021-04-18 16:39:15 +00:00
|
|
|
|
func (avd EthAccountVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
2020-04-17 22:32:01 +00:00
|
|
|
|
if !ctx.IsCheckTx() {
|
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 09:31:30 +00:00
|
|
|
|
avd.evmKeeper.WithContext(ctx)
|
|
|
|
|
evmDenom := avd.evmKeeper.GetParams(ctx).EvmDenom
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-06-15 07:19:31 +00:00
|
|
|
|
for i, msg := range tx.GetMsgs() {
|
2021-05-31 09:05:32 +00:00
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(err, "failed to unpack tx data any for tx %d", i)
|
2021-07-05 16:39:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// sender address should be in the tx cache from the previous AnteHandle call
|
|
|
|
|
from := msgEthTx.GetFrom()
|
|
|
|
|
if from.Empty() {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "from address cannot be empty")
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-06-15 17:39:41 +00:00
|
|
|
|
// check whether the sender address is EOA
|
|
|
|
|
fromAddr := common.BytesToAddress(from)
|
|
|
|
|
codeHash := avd.evmKeeper.GetCodeHash(fromAddr)
|
|
|
|
|
if codeHash != common.BytesToHash(evmtypes.EmptyCodeHash) {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInvalidType,
|
|
|
|
|
"the sender is not EOA: address <%v>, codeHash <%s>", fromAddr, codeHash)
|
2021-06-15 17:39:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-30 09:31:30 +00:00
|
|
|
|
acc := avd.ak.GetAccount(ctx, from)
|
2021-05-31 09:05:32 +00:00
|
|
|
|
if acc == nil {
|
2021-06-30 09:31:30 +00:00
|
|
|
|
acc = avd.ak.NewAccountWithAddress(ctx, from)
|
|
|
|
|
avd.ak.SetAccount(ctx, acc)
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-09-02 19:41:05 +00:00
|
|
|
|
|
2021-09-03 15:55:37 +00:00
|
|
|
|
if err := evmkeeper.CheckSenderBalance(ctx, avd.bankKeeper, from, txData, evmDenom); err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "failed to check sender balance")
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-06-15 17:39:41 +00:00
|
|
|
|
}
|
|
|
|
|
// recover the original gas meter
|
|
|
|
|
avd.evmKeeper.WithContext(ctx)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 16:39:15 +00:00
|
|
|
|
// EthNonceVerificationDecorator checks that the account nonce from the transaction matches
|
2020-05-04 22:41:17 +00:00
|
|
|
|
// the sender account sequence.
|
2021-04-18 16:39:15 +00:00
|
|
|
|
type EthNonceVerificationDecorator struct {
|
2021-09-03 15:55:37 +00:00
|
|
|
|
ak evmtypes.AccountKeeper
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 16:39:15 +00:00
|
|
|
|
// NewEthNonceVerificationDecorator creates a new EthNonceVerificationDecorator
|
2021-09-03 15:55:37 +00:00
|
|
|
|
func NewEthNonceVerificationDecorator(ak evmtypes.AccountKeeper) EthNonceVerificationDecorator {
|
2021-04-18 16:39:15 +00:00
|
|
|
|
return EthNonceVerificationDecorator{
|
2020-04-17 22:32:01 +00:00
|
|
|
|
ak: ak,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// AnteHandle validates that the transaction nonces are valid and equivalent to the sender account’s
|
|
|
|
|
// current nonce.
|
2021-04-18 16:39:15 +00:00
|
|
|
|
func (nvd EthNonceVerificationDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// no need to check the nonce on ReCheckTx
|
|
|
|
|
if ctx.IsReCheckTx() {
|
|
|
|
|
return next(ctx, tx, simulate)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-26 14:19:28 +00:00
|
|
|
|
for _, msg := range tx.GetMsgs() {
|
2021-05-31 09:05:32 +00:00
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// sender address should be in the tx cache from the previous AnteHandle call
|
2021-06-30 09:31:30 +00:00
|
|
|
|
seq, err := nvd.ak.GetSequence(ctx, msgEthTx.GetFrom())
|
2021-05-31 09:05:32 +00:00
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(err, "sequence not found for address %s", msgEthTx.From)
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
|
2021-07-05 16:39:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// 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
|
2021-07-05 16:39:08 +00:00
|
|
|
|
if txData.GetNonce() != seq {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(
|
|
|
|
|
sdkerrors.ErrInvalidSequence,
|
|
|
|
|
"invalid nonce; got %d, expected %d", txData.GetNonce(), seq,
|
2021-05-31 09:05:32 +00:00
|
|
|
|
)
|
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
|
|
|
|
|
// gas consumption.
|
|
|
|
|
type EthGasConsumeDecorator struct {
|
2021-09-22 10:26:29 +00:00
|
|
|
|
evmKeeper EVMKeeper
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
|
2021-10-04 14:58:06 +00:00
|
|
|
|
func NewEthGasConsumeDecorator(
|
|
|
|
|
evmKeeper EVMKeeper,
|
|
|
|
|
) EthGasConsumeDecorator {
|
2020-04-17 22:32:01 +00:00
|
|
|
|
return EthGasConsumeDecorator{
|
2021-09-22 10:26:29 +00:00
|
|
|
|
evmKeeper: evmKeeper,
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AnteHandle validates that the Ethereum tx message has enough to cover intrinsic gas
|
|
|
|
|
// (during CheckTx only) and that the sender has enough balance to pay for the gas cost.
|
|
|
|
|
//
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// Intrinsic gas for a transaction is the amount of gas that the transaction uses before the
|
|
|
|
|
// transaction is executed. The gas is a constant value plus any cost inccured by additional bytes
|
|
|
|
|
// of data supplied with the transaction.
|
|
|
|
|
//
|
|
|
|
|
// This AnteHandler decorator will fail if:
|
|
|
|
|
// - the transaction contains more than one message
|
|
|
|
|
// - the message is not a MsgEthereumTx
|
|
|
|
|
// - sender account cannot be found
|
|
|
|
|
// - transaction's gas limit is lower than the intrinsic gas
|
|
|
|
|
// - user doesn't have enough balance to deduct the transaction fees (gas_limit * gas_price)
|
|
|
|
|
// - transaction or block gas meter runs out of gas
|
2020-04-17 22:32:01 +00:00
|
|
|
|
func (egcd EthGasConsumeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// reset the refund gas value in the keeper for the current transaction
|
2021-06-30 09:31:30 +00:00
|
|
|
|
egcd.evmKeeper.ResetRefundTransient(ctx)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
params := egcd.evmKeeper.GetParams(ctx)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
ethCfg := params.ChainConfig.EthereumConfig(egcd.evmKeeper.ChainID())
|
2021-05-10 16:34:00 +00:00
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
blockHeight := big.NewInt(ctx.BlockHeight())
|
|
|
|
|
homestead := ethCfg.IsHomestead(blockHeight)
|
|
|
|
|
istanbul := ethCfg.IsIstanbul(blockHeight)
|
2021-10-05 15:38:20 +00:00
|
|
|
|
london := ethCfg.IsLondon(blockHeight)
|
2021-09-03 15:55:37 +00:00
|
|
|
|
evmDenom := params.EvmDenom
|
2021-05-10 16:34:00 +00:00
|
|
|
|
|
2021-09-02 12:26:16 +00:00
|
|
|
|
var events sdk.Events
|
|
|
|
|
|
2021-11-26 14:19:28 +00:00
|
|
|
|
for _, msg := range tx.GetMsgs() {
|
2021-05-31 09:05:32 +00:00
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
|
2021-07-05 16:39:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-22 10:26:29 +00:00
|
|
|
|
fees, err := egcd.evmKeeper.DeductTxCostsFromUserBalance(
|
2021-09-03 15:55:37 +00:00
|
|
|
|
ctx,
|
|
|
|
|
*msgEthTx,
|
|
|
|
|
txData,
|
|
|
|
|
evmDenom,
|
|
|
|
|
homestead,
|
|
|
|
|
istanbul,
|
2021-10-04 14:58:06 +00:00
|
|
|
|
london,
|
2021-09-03 15:55:37 +00:00
|
|
|
|
)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
2021-09-02 12:26:16 +00:00
|
|
|
|
|
|
|
|
|
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-09-02 12:26:16 +00:00
|
|
|
|
// TODO: change to typed events
|
|
|
|
|
ctx.EventManager().EmitEvents(events)
|
|
|
|
|
|
2021-06-14 14:24:08 +00:00
|
|
|
|
// TODO: deprecate after https://github.com/cosmos/cosmos-sdk/issues/9514 is fixed on SDK
|
|
|
|
|
blockGasLimit := ethermint.BlockGasLimit(ctx)
|
|
|
|
|
|
|
|
|
|
// NOTE: safety check
|
|
|
|
|
if blockGasLimit > 0 {
|
|
|
|
|
// generate a copy of the gas pool (i.e block gas meter) to see if we've run out of gas for this block
|
|
|
|
|
// if current gas consumed is greater than the limit, this funcion panics and the error is recovered on the Baseapp
|
|
|
|
|
gasPool := sdk.NewGasMeter(blockGasLimit)
|
|
|
|
|
gasPool.ConsumeGas(ctx.GasMeter().GasConsumedToLimit(), "gas pool check")
|
|
|
|
|
}
|
2021-05-25 12:56:36 +00:00
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// we know that we have enough gas on the pool to cover the intrinsic gas
|
|
|
|
|
// set up the updated context to the evm Keeper
|
|
|
|
|
egcd.evmKeeper.WithContext(ctx)
|
|
|
|
|
return next(ctx, tx, simulate)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
|
|
|
|
|
// context rules.
|
|
|
|
|
type CanTransferDecorator struct {
|
2021-10-04 14:58:06 +00:00
|
|
|
|
evmKeeper EVMKeeper
|
|
|
|
|
feemarketKeeper evmtypes.FeeMarketKeeper
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewCanTransferDecorator creates a new CanTransferDecorator instance.
|
2021-10-04 14:58:06 +00:00
|
|
|
|
func NewCanTransferDecorator(evmKeeper EVMKeeper, fmk evmtypes.FeeMarketKeeper) CanTransferDecorator {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
return CanTransferDecorator{
|
2021-10-04 14:58:06 +00:00
|
|
|
|
evmKeeper: evmKeeper,
|
|
|
|
|
feemarketKeeper: fmk,
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AnteHandle creates an EVM from the message and calls the BlockContext CanTransfer function to
|
|
|
|
|
// see if the address can execute the transaction.
|
|
|
|
|
func (ctd CanTransferDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
2021-06-30 09:31:30 +00:00
|
|
|
|
ctd.evmKeeper.WithContext(ctx)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
params := ctd.evmKeeper.GetParams(ctx)
|
2021-10-04 14:58:06 +00:00
|
|
|
|
feeMktParams := ctd.feemarketKeeper.GetParams(ctx)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
|
2021-07-14 09:13:55 +00:00
|
|
|
|
ethCfg := params.ChainConfig.EthereumConfig(ctd.evmKeeper.ChainID())
|
2021-06-11 13:38:51 +00:00
|
|
|
|
signer := ethtypes.MakeSigner(ethCfg, big.NewInt(ctx.BlockHeight()))
|
2021-06-02 08:52:53 +00:00
|
|
|
|
|
2021-11-26 14:19:28 +00:00
|
|
|
|
for _, msg := range tx.GetMsgs() {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-04 14:58:06 +00:00
|
|
|
|
var baseFee *big.Int
|
2021-10-13 13:39:47 +00:00
|
|
|
|
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee {
|
2021-10-04 14:58:06 +00:00
|
|
|
|
baseFee = ctd.feemarketKeeper.GetBaseFee(ctx)
|
|
|
|
|
}
|
|
|
|
|
|
2021-10-05 15:38:20 +00:00
|
|
|
|
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(
|
2021-06-15 07:19:31 +00:00
|
|
|
|
err,
|
|
|
|
|
"failed to create an ethereum core.Message from signer %T", signer,
|
|
|
|
|
)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-19 08:18:20 +00:00
|
|
|
|
// NOTE: pass in an empty coinbase address and nil tracer as we don't need them for the check below
|
2021-10-22 17:21:03 +00:00
|
|
|
|
cfg := &evmtypes.EVMConfig{
|
|
|
|
|
ChainConfig: ethCfg,
|
|
|
|
|
Params: params,
|
|
|
|
|
CoinBase: common.Address{},
|
|
|
|
|
BaseFee: baseFee,
|
|
|
|
|
}
|
|
|
|
|
evm := ctd.evmKeeper.NewEVM(coreMsg, cfg, evmtypes.NewNoOpTracer())
|
2021-06-02 08:52:53 +00:00
|
|
|
|
|
|
|
|
|
// 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()) {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(
|
|
|
|
|
sdkerrors.ErrInsufficientFunds,
|
|
|
|
|
"failed to transfer %s from address %s using the EVM block context transfer function",
|
|
|
|
|
coreMsg.Value(),
|
|
|
|
|
coreMsg.From(),
|
2021-06-15 07:19:31 +00:00
|
|
|
|
)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
2021-10-04 14:58:06 +00:00
|
|
|
|
|
2021-10-13 13:39:47 +00:00
|
|
|
|
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee == nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(evmtypes.ErrInvalidBaseFee, "base fee is supported but evm block context value is nil")
|
2021-10-05 15:38:20 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-10-13 13:39:47 +00:00
|
|
|
|
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee && baseFee != nil && coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(evmtypes.ErrInvalidBaseFee, "max fee per gas less than block base fee (%s < %s)", coreMsg.GasFeeCap(), baseFee)
|
2021-10-05 15:38:20 +00:00
|
|
|
|
}
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ctd.evmKeeper.WithContext(ctx)
|
|
|
|
|
|
|
|
|
|
// set the original gas meter
|
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// EthIncrementSenderSequenceDecorator increments the sequence of the signers.
|
2021-04-18 16:39:15 +00:00
|
|
|
|
type EthIncrementSenderSequenceDecorator struct {
|
2021-09-03 15:55:37 +00:00
|
|
|
|
ak evmtypes.AccountKeeper
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-04-18 16:39:15 +00:00
|
|
|
|
// NewEthIncrementSenderSequenceDecorator creates a new EthIncrementSenderSequenceDecorator.
|
2021-09-03 15:55:37 +00:00
|
|
|
|
func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) EthIncrementSenderSequenceDecorator {
|
2021-04-18 16:39:15 +00:00
|
|
|
|
return EthIncrementSenderSequenceDecorator{
|
2020-04-17 22:32:01 +00:00
|
|
|
|
ak: ak,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// AnteHandle handles incrementing the sequence of the signer (i.e sender). If the transaction is a
|
|
|
|
|
// contract creation, the nonce will be incremented during the transaction execution and not within
|
|
|
|
|
// this AnteHandler decorator.
|
2021-04-18 16:39:15 +00:00
|
|
|
|
func (issd EthIncrementSenderSequenceDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
for _, msg := range tx.GetMsgs() {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-06-02 08:52:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-07-05 16:39:08 +00:00
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "failed to unpack tx data")
|
2021-07-05 16:39:08 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// NOTE: on contract creation, the nonce is incremented within the EVM Create function during tx execution
|
|
|
|
|
// and not previous to the state transition ¯\_(ツ)_/¯
|
2021-07-05 16:39:08 +00:00
|
|
|
|
if txData.GetTo() == nil {
|
2021-06-02 08:52:53 +00:00
|
|
|
|
// contract creation, don't increment sequence on AnteHandler but on tx execution
|
|
|
|
|
// continue to the next item
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
// increment sequence of all signers
|
|
|
|
|
for _, addr := range msg.GetSigners() {
|
2021-06-30 09:31:30 +00:00
|
|
|
|
acc := issd.ak.GetAccount(ctx, addr)
|
2021-06-02 08:52:53 +00:00
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
if acc == nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(
|
|
|
|
|
sdkerrors.ErrUnknownAddress,
|
|
|
|
|
"account %s (%s) is nil", common.BytesToAddress(addr.Bytes()), addr,
|
2021-05-31 09:05:32 +00:00
|
|
|
|
)
|
|
|
|
|
}
|
2020-05-04 22:41:17 +00:00
|
|
|
|
|
2021-05-31 09:05:32 +00:00
|
|
|
|
if err := acc.SetSequence(acc.GetSequence() + 1); err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
2021-05-31 09:05:32 +00:00
|
|
|
|
}
|
2020-04-17 22:32:01 +00:00
|
|
|
|
|
2021-06-30 09:31:30 +00:00
|
|
|
|
issd.ak.SetAccount(ctx, acc)
|
2020-04-17 22:32:01 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-04 22:41:17 +00:00
|
|
|
|
// set the original gas meter
|
2020-04-17 22:32:01 +00:00
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
2021-06-21 10:44:37 +00:00
|
|
|
|
|
|
|
|
|
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
|
2021-11-08 13:00:35 +00:00
|
|
|
|
type EthValidateBasicDecorator struct {
|
|
|
|
|
evmKeeper EVMKeeper
|
|
|
|
|
}
|
2021-06-21 10:44:37 +00:00
|
|
|
|
|
|
|
|
|
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
|
2021-11-08 13:00:35 +00:00
|
|
|
|
func NewEthValidateBasicDecorator(ek EVMKeeper) EthValidateBasicDecorator {
|
|
|
|
|
return EthValidateBasicDecorator{
|
|
|
|
|
evmKeeper: ek,
|
|
|
|
|
}
|
2021-06-21 10:44:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AnteHandle handles basic validation of tx
|
|
|
|
|
func (vbd EthValidateBasicDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (sdk.Context, error) {
|
|
|
|
|
// no need to validate basic on recheck tx, call next antehandler
|
|
|
|
|
if ctx.IsReCheckTx() {
|
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
err := tx.ValidateBasic()
|
|
|
|
|
// ErrNoSignatures is fine with eth tx
|
2021-09-05 11:03:06 +00:00
|
|
|
|
if err != nil && !errors.Is(err, sdkerrors.ErrNoSignatures) {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "tx basic validation failed")
|
2021-06-21 10:44:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-11-08 13:00:35 +00:00
|
|
|
|
// For eth type cosmos tx, some fields should be veified as zero values,
|
|
|
|
|
// since we will only verify the signature against the hash of the MsgEthereumTx.Data
|
|
|
|
|
if wrapperTx, ok := tx.(protoTxProvider); ok {
|
|
|
|
|
protoTx := wrapperTx.GetProtoTx()
|
|
|
|
|
body := protoTx.Body
|
|
|
|
|
if body.Memo != "" || body.TimeoutHeight != uint64(0) || len(body.NonCriticalExtensionOptions) > 0 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest,
|
|
|
|
|
"for eth tx body Memo TimeoutHeight NonCriticalExtensionOptions should be empty")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(body.ExtensionOptions) != 1 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx length of ExtensionOptions should be 1")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(protoTx.GetMsgs()) != 1 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
msg := protoTx.GetMsgs()[0]
|
|
|
|
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
|
|
|
|
if !ok {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
ethGasLimit := msgEthTx.GetGas()
|
|
|
|
|
|
|
|
|
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
|
|
|
|
if err != nil {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(err, "failed to unpack MsgEthereumTx Data")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
params := vbd.evmKeeper.GetParams(ctx)
|
|
|
|
|
ethFeeAmount := sdk.Coins{sdk.NewCoin(params.EvmDenom, sdk.NewIntFromBigInt(txData.Fee()))}
|
|
|
|
|
|
|
|
|
|
authInfo := protoTx.AuthInfo
|
|
|
|
|
if len(authInfo.SignerInfos) > 0 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo SignerInfos should be empty")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if authInfo.Fee.Payer != "" || authInfo.Fee.Granter != "" {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx AuthInfo Fee payer and granter should be empty")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !authInfo.Fee.Amount.IsEqual(ethFeeAmount) {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee Amount")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if authInfo.Fee.GasLimit != ethGasLimit {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "invalid eth tx AuthInfo Fee GasLimit")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sigs := protoTx.Signatures
|
|
|
|
|
if len(sigs) > 0 {
|
2021-11-26 14:19:28 +00:00
|
|
|
|
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "for eth tx Signatures should be empty")
|
2021-11-08 13:00:35 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-21 10:44:37 +00:00
|
|
|
|
return next(ctx, tx, simulate)
|
|
|
|
|
}
|
2021-06-30 09:31:30 +00:00
|
|
|
|
|
|
|
|
|
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
|
|
|
|
|
// by setting the gas meter to infinite
|
|
|
|
|
type EthSetupContextDecorator struct{}
|
|
|
|
|
|
|
|
|
|
func NewEthSetUpContextDecorator() EthSetupContextDecorator {
|
|
|
|
|
return EthSetupContextDecorator{}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
|
|
|
|
// all transactions must implement GasTx
|
|
|
|
|
_, ok := tx.(authante.GasTx)
|
|
|
|
|
if !ok {
|
|
|
|
|
return newCtx, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be GasTx")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
|
|
|
|
return next(newCtx, tx, simulate)
|
|
|
|
|
}
|