-
Notifications
You must be signed in to change notification settings - Fork 829
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add EVM support #221
base: main
Are you sure you want to change the base?
Add EVM support #221
Changes from 11 commits
e8de01d
4578247
9e80a8a
02e7108
c00ce61
eada60e
5b125b2
4f4c6f6
2aad2f0
76d057d
7a5475c
50844ca
4bc74af
480715f
2601e26
775a802
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package ante | ||
|
||
import ( | ||
"fmt" | ||
"runtime/debug" | ||
|
||
tmlog "github.com/tendermint/tendermint/libs/log" | ||
|
||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/types/tx/signing" | ||
authante "github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
|
||
"github.com/evmos/ethermint/crypto/ethsecp256k1" | ||
) | ||
|
||
const ( | ||
secp256k1VerifyCost uint64 = 21000 | ||
) | ||
|
||
// NewAnteHandler returns an ante handler responsible for attempting to route an | ||
// Ethereum or SDK transaction to an internal ante handler for performing | ||
// transaction-level processing (e.g. fee payment, signature verification) before | ||
// being passed onto it's respective handler. | ||
func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) { | ||
if err := options.validate(); err != nil { | ||
return nil, err | ||
} | ||
|
||
return func( | ||
ctx sdk.Context, tx sdk.Tx, sim bool, | ||
) (newCtx sdk.Context, err error) { | ||
var anteHandler sdk.AnteHandler | ||
|
||
defer Recover(ctx.Logger(), &err) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want to remove the panic-recover here? we properly want to avoid recover panic as that may hide more severe bugs (and we may not be able to monitor this each time) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is a good question. I think it doesn't make sense for a single txn to bring down the whole chain though. Ill think it makes sense to add monitoring though There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yea the thing i'm worried about is this may hide err and make the chain get into a corrupted state. I'm aligned with having this on testnet + monitor, and remove before mainnet |
||
|
||
txWithExtensions, ok := tx.(authante.HasExtensionOptionsTx) | ||
if ok { | ||
opts := txWithExtensions.GetExtensionOptions() | ||
if len(opts) > 0 { | ||
switch typeURL := opts[0].GetTypeUrl(); typeURL { | ||
case "/ethermint.evm.v1.ExtensionOptionsEthereumTx": | ||
// handle as *evmtypes.MsgEthereumTx | ||
anteHandler = newEthAnteHandler(options) | ||
case "/ethermint.types.v1.ExtensionOptionsWeb3Tx": | ||
// handle as normal Cosmos SDK tx, except signature is checked for EIP712 representation | ||
anteHandler = newCosmosAnteHandlerEip712(options) | ||
case "/ethermint.types.v1.ExtensionOptionDynamicFeeTx": | ||
// cosmos-sdk tx with dynamic fee extension | ||
anteHandler = newCosmosAnteHandler(options) | ||
default: | ||
return ctx, sdkerrors.Wrapf( | ||
sdkerrors.ErrUnknownExtensionOptions, | ||
"rejecting tx with unsupported extension option: %s", typeURL, | ||
) | ||
} | ||
|
||
return anteHandler(ctx, tx, sim) | ||
} | ||
} | ||
|
||
// handle as totally normal Cosmos SDK tx | ||
switch tx.(type) { | ||
case sdk.Tx: | ||
anteHandler = newCosmosAnteHandler(options) | ||
default: | ||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type: %T", tx) | ||
} | ||
|
||
return anteHandler(ctx, tx, sim) | ||
}, nil | ||
} | ||
|
||
func Recover(logger tmlog.Logger, err *error) { | ||
if r := recover(); r != nil { | ||
*err = sdkerrors.Wrapf(sdkerrors.ErrPanic, "%v", r) | ||
|
||
if e, ok := r.(error); ok { | ||
logger.Error( | ||
"ante handler panicked", | ||
"error", e, | ||
"stack trace", string(debug.Stack()), | ||
) | ||
} else { | ||
logger.Error( | ||
"ante handler panicked", | ||
"recover", fmt.Sprintf("%v", r), | ||
) | ||
} | ||
} | ||
} | ||
|
||
var _ authante.SignatureVerificationGasConsumer = DefaultSigVerificationGasConsumer | ||
|
||
// DefaultSigVerificationGasConsumer is the default implementation of SignatureVerificationGasConsumer. It consumes gas | ||
// for signature verification based upon the public key type. The cost is fetched from the given params and is matched | ||
// by the concrete type. | ||
func DefaultSigVerificationGasConsumer( | ||
meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params, | ||
) error { | ||
// support for ethereum ECDSA secp256k1 keys | ||
_, ok := sig.PubKey.(*ethsecp256k1.PubKey) | ||
if ok { | ||
meter.ConsumeGas(secp256k1VerifyCost, "ante verify: eth_secp256k1") | ||
return nil | ||
} | ||
|
||
return authante.DefaultSigVerificationGasConsumer(meter, sig, params) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package ante | ||
|
||
import ( | ||
wasmkeeper "github.com/CosmWasm/wasmd/x/wasm/keeper" | ||
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types" | ||
"github.com/cosmos/cosmos-sdk/codec" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" | ||
"github.com/cosmos/cosmos-sdk/types/tx/signing" | ||
"github.com/cosmos/cosmos-sdk/x/auth/ante" | ||
authsigning "github.com/cosmos/cosmos-sdk/x/auth/signing" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
ibcante "github.com/cosmos/ibc-go/v3/modules/core/ante" | ||
ibckeeper "github.com/cosmos/ibc-go/v3/modules/core/keeper" | ||
"github.com/sei-protocol/sei-chain/utils/tracing" | ||
dexkeeper "github.com/sei-protocol/sei-chain/x/dex/keeper" | ||
oraclekeeper "github.com/sei-protocol/sei-chain/x/oracle/keeper" | ||
|
||
ethante "github.com/evmos/ethermint/app/ante" | ||
evmtypes "github.com/evmos/ethermint/x/evm/types" | ||
) | ||
|
||
// HandlerOptions defines the list of module keepers required to run the Evmos | ||
// AnteHandler decorators. | ||
type HandlerOptions struct { | ||
AccountKeeper evmtypes.AccountKeeper | ||
BankKeeper evmtypes.BankKeeper | ||
FeeMarketKeeper evmtypes.FeeMarketKeeper | ||
SignModeHandler authsigning.SignModeHandler | ||
SigGasConsumer func(meter sdk.GasMeter, sig signing.SignatureV2, params authtypes.Params) error | ||
IBCKeeper *ibckeeper.Keeper | ||
WasmKeeper *wasmkeeper.Keeper | ||
OracleKeeper *oraclekeeper.Keeper | ||
DexKeeper *dexkeeper.Keeper | ||
TxCounterStoreKey sdk.StoreKey | ||
WasmConfig *wasmtypes.WasmConfig | ||
EvmKeeper ethante.EVMKeeper | ||
FeegrantKeeper ante.FeegrantKeeper | ||
|
||
Cdc codec.BinaryCodec | ||
MaxTxGasWanted uint64 | ||
TracingInfo *tracing.Info | ||
} | ||
|
||
// Validate checks if the keepers are defined | ||
func (options HandlerOptions) validate() error { | ||
if options.AccountKeeper == nil { | ||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "account keeper is required for AnteHandler") | ||
} | ||
if options.BankKeeper == nil { | ||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "bank keeper is required for AnteHandler") | ||
} | ||
if options.SignModeHandler == nil { | ||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "sign mode handler is required for ante builder") | ||
} | ||
if options.FeeMarketKeeper == nil { | ||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "fee market keeper is required for AnteHandler") | ||
} | ||
if options.EvmKeeper == nil { | ||
return sdkerrors.Wrap(sdkerrors.ErrLogic, "evm keeper is required for AnteHandler") | ||
} | ||
return nil | ||
} | ||
|
||
// newEthAnteHandler creates the default ante handler for Ethereum transactions | ||
func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler { | ||
return sdk.ChainAnteDecorators( | ||
ethante.NewEthSetUpContextDecorator(options.EvmKeeper), // outermost AnteDecorator. SetUpContext must be called first | ||
ethante.NewEthMempoolFeeDecorator(options.EvmKeeper), // Check eth effective gas price against the node's minimal-gas-prices config | ||
ethante.NewEthMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), // Check eth effective gas price against the global MinGasPrice | ||
ethante.NewEthValidateBasicDecorator(options.EvmKeeper), | ||
ethante.NewEthSigVerificationDecorator(options.EvmKeeper), | ||
ethante.NewEthAccountVerificationDecorator(options.AccountKeeper, options.EvmKeeper), | ||
ethante.NewCanTransferDecorator(options.EvmKeeper), | ||
ethante.NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted), | ||
ethante.NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), | ||
ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), | ||
ethante.NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler. | ||
) | ||
} | ||
|
||
// newCosmosAnteHandler creates the default ante handler for Cosmos transactions | ||
func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler { | ||
return sdk.ChainAnteDecorators( | ||
ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs | ||
ante.NewSetUpContextDecorator(), | ||
ante.NewRejectExtensionOptionsDecorator(), | ||
ante.NewValidateBasicDecorator(), | ||
ante.NewMempoolFeeDecorator(), | ||
ethante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), | ||
ante.NewTxTimeoutHeightDecorator(), | ||
ante.NewValidateMemoDecorator(options.AccountKeeper), | ||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), | ||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), | ||
// SetPubKeyDecorator must be called before all signature verification decorators | ||
ante.NewSetPubKeyDecorator(options.AccountKeeper), | ||
ante.NewValidateSigCountDecorator(options.AccountKeeper), | ||
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), | ||
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), | ||
ante.NewIncrementSequenceDecorator(options.AccountKeeper), | ||
ibcante.NewAnteDecorator(options.IBCKeeper), | ||
ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), | ||
) | ||
} | ||
|
||
// newCosmosAnteHandlerEip712 creates the ante handler for transactions signed with EIP712 | ||
func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler { | ||
return sdk.ChainAnteDecorators( | ||
ethante.RejectMessagesDecorator{}, // reject MsgEthereumTxs | ||
ante.NewSetUpContextDecorator(), | ||
ante.NewMempoolFeeDecorator(), | ||
ante.NewValidateBasicDecorator(), | ||
ethante.NewMinGasPriceDecorator(options.FeeMarketKeeper, options.EvmKeeper), | ||
ante.NewTxTimeoutHeightDecorator(), | ||
ante.NewValidateMemoDecorator(options.AccountKeeper), | ||
ante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper), | ||
ante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper), | ||
// SetPubKeyDecorator must be called before all signature verification decorators | ||
ante.NewSetPubKeyDecorator(options.AccountKeeper), | ||
ante.NewValidateSigCountDecorator(options.AccountKeeper), | ||
ante.NewSigGasConsumeDecorator(options.AccountKeeper, options.SigGasConsumer), | ||
// Note: signature verification uses EIP instead of the cosmos signature validator | ||
ethante.NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler), | ||
ante.NewIncrementSequenceDecorator(options.AccountKeeper), | ||
ibcante.NewAnteDecorator(options.IBCKeeper), | ||
ethante.NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper), | ||
) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is it possible to return built EthAnteHandler & CosmosAnteHandler map here? or register ethAnteHandler to the cosmos ante decorator? returning a func here seems to make each tx creates a new AnteHandler here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. Done!