fix: fix the rpc test cases
This commit is contained in:
parent
63b66c1ffc
commit
eb1af33649
@ -683,6 +683,7 @@ func NewEthermintApp(
|
|||||||
// app.ScopedTransferKeeper = scopedTransferKeeper
|
// app.ScopedTransferKeeper = scopedTransferKeeper
|
||||||
maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted))
|
maxGasWanted := cast.ToUint64(appOpts.Get(srvflags.EVMMaxTxGasWanted))
|
||||||
options := middleware.HandlerOptions{
|
options := middleware.HandlerOptions{
|
||||||
|
Codec: app.appCodec,
|
||||||
Debug: app.Trace(),
|
Debug: app.Trace(),
|
||||||
LegacyRouter: app.legacyRouter,
|
LegacyRouter: app.legacyRouter,
|
||||||
MsgServiceRouter: app.msgSvcRouter,
|
MsgServiceRouter: app.msgSvcRouter,
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
|
||||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx"
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
@ -18,6 +17,7 @@ import (
|
|||||||
"github.com/tharsis/ethermint/ethereum/eip712"
|
"github.com/tharsis/ethermint/ethereum/eip712"
|
||||||
ethermint "github.com/tharsis/ethermint/types"
|
ethermint "github.com/tharsis/ethermint/types"
|
||||||
|
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
@ -31,23 +31,25 @@ func init() {
|
|||||||
ethermintCodec = codec.NewProtoCodec(registry)
|
ethermintCodec = codec.NewProtoCodec(registry)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Eip712SigVerificationDecorator Verify all signatures for a tx and return an error if any are invalid. Note,
|
// Eip712SigVerificationMiddleware Verify all signatures for a tx and return an error if any are invalid. Note,
|
||||||
// the Eip712SigVerificationDecorator decorator will not get executed on ReCheck.
|
// the Eip712SigVerificationMiddleware middleware will not get executed on ReCheck.
|
||||||
//
|
//
|
||||||
// CONTRACT: Pubkeys are set in context for all signers before this decorator runs
|
// CONTRACT: Pubkeys are set in context for all signers before this middleware runs
|
||||||
// CONTRACT: Tx must implement SigVerifiableTx interface
|
// CONTRACT: Tx must implement SigVerifiableTx interface
|
||||||
type Eip712SigVerificationDecorator struct {
|
type Eip712SigVerificationMiddleware struct {
|
||||||
|
appCodec codec.Codec
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
ak evmtypes.AccountKeeper
|
ak evmtypes.AccountKeeper
|
||||||
signModeHandler authsigning.SignModeHandler
|
signModeHandler authsigning.SignModeHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = Eip712SigVerificationDecorator{}
|
var _ tx.Handler = Eip712SigVerificationMiddleware{}
|
||||||
|
|
||||||
// NewEip712SigVerificationDecorator creates a new Eip712SigVerificationDecorator
|
// NewEip712SigVerificationMiddleware creates a new Eip712SigVerificationMiddleware
|
||||||
func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) tx.Middleware {
|
func NewEip712SigVerificationMiddleware(appCodec codec.Codec, ak evmtypes.AccountKeeper, signModeHandler authsigning.SignModeHandler) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return Eip712SigVerificationDecorator{
|
return Eip712SigVerificationMiddleware{
|
||||||
|
appCodec: appCodec,
|
||||||
next: h,
|
next: h,
|
||||||
ak: ak,
|
ak: ak,
|
||||||
signModeHandler: signModeHandler,
|
signModeHandler: signModeHandler,
|
||||||
@ -55,43 +57,37 @@ func NewEip712SigVerificationDecorator(ak evmtypes.AccountKeeper, signModeHandle
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
func eipSigVerification(svd Eip712SigVerificationMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
func (svd Eip712SigVerificationDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
|
|
||||||
// no need to verify signatures on recheck tx
|
|
||||||
if ctx.IsReCheckTx() {
|
|
||||||
return svd.next.CheckTx(ctx, req, checkReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
sigTx, ok := reqTx.(authsigning.SigVerifiableTx)
|
sigTx, ok := reqTx.(authsigning.SigVerifiableTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", reqTx)
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement authsigning.SigVerifiableTx", reqTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
authSignTx, ok := reqTx.(authsigning.Tx)
|
authSignTx, ok := reqTx.(authsigning.Tx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", reqTx)
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "tx %T doesn't implement the authsigning.Tx interface", reqTx)
|
||||||
}
|
}
|
||||||
|
|
||||||
// stdSigs contains the sequence number, account number, and signatures.
|
// stdSigs contains the sequence number, account number, and signatures.
|
||||||
// When simulating, this would just be a 0-length slice.
|
// When simulating, this would just be a 0-length slice.
|
||||||
sigs, err := sigTx.GetSignaturesV2()
|
sigs, err := sigTx.GetSignaturesV2()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, err
|
return tx.Response{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
signerAddrs := sigTx.GetSigners()
|
signerAddrs := sigTx.GetSigners()
|
||||||
|
|
||||||
// EIP712 allows just one signature
|
// EIP712 allows just one signature
|
||||||
if len(sigs) != 1 {
|
if len(sigs) != 1 {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signers (%d); EIP712 signatures allows just one signature", len(sigs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// check that signer length and signature length are the same
|
// check that signer length and signature length are the same
|
||||||
if len(sigs) != len(signerAddrs) {
|
if len(sigs) != len(signerAddrs) {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnauthorized, "invalid number of signer; expected: %d, got %d", len(signerAddrs), len(sigs))
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP712 has just one signature, avoid looping here and only read index 0
|
// EIP712 has just one signature, avoid looping here and only read index 0
|
||||||
@ -100,18 +96,18 @@ func (svd Eip712SigVerificationDecorator) CheckTx(cx context.Context, req tx.Req
|
|||||||
|
|
||||||
acc, err := middleware.GetSignerAcc(ctx, svd.ak, signerAddrs[i])
|
acc, err := middleware.GetSignerAcc(ctx, svd.ak, signerAddrs[i])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, err
|
return tx.Response{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve pubkey
|
// retrieve pubkey
|
||||||
pubKey := acc.GetPubKey()
|
pubKey := acc.GetPubKey()
|
||||||
if pubKey == nil {
|
if pubKey == nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
|
return tx.Response{}, sdkerrors.Wrap(sdkerrors.ErrInvalidPubKey, "pubkey on account is not set")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check account sequence number.
|
// Check account sequence number.
|
||||||
if sig.Sequence != acc.GetSequence() {
|
if sig.Sequence != acc.GetSequence() {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrWrongSequence,
|
sdkerrors.ErrWrongSequence,
|
||||||
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
|
"account sequence mismatch, expected %d, got %d", acc.GetSequence(), sig.Sequence,
|
||||||
)
|
)
|
||||||
@ -132,27 +128,45 @@ func (svd Eip712SigVerificationDecorator) CheckTx(cx context.Context, req tx.Req
|
|||||||
Sequence: acc.GetSequence(),
|
Sequence: acc.GetSequence(),
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := VerifySignature(pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
|
if err := VerifySignature(svd.appCodec, pubKey, signerData, sig.Data, svd.signModeHandler, authSignTx); err != nil {
|
||||||
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
|
errMsg := fmt.Errorf("signature verification failed; please verify account number (%d) and chain-id (%s): %w", accNum, chainID, err)
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
|
return tx.Response{}, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, errMsg.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx implements tx.Handler
|
||||||
|
func (svd Eip712SigVerificationMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
if _, err := eipSigVerification(svd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return svd.next.CheckTx(ctx, req, checkReq)
|
return svd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (svd Eip712SigVerificationDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (svd Eip712SigVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := eipSigVerification(svd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return svd.next.DeliverTx(ctx, req)
|
return svd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (svd Eip712SigVerificationDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (svd Eip712SigVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := eipSigVerification(svd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return svd.next.SimulateTx(ctx, req)
|
return svd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// VerifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes
|
// VerifySignature verifies a transaction signature contained in SignatureData abstracting over different signing modes
|
||||||
// and single vs multi-signatures.
|
// and single vs multi-signatures.
|
||||||
func VerifySignature(
|
func VerifySignature(
|
||||||
|
appCodec codec.Codec,
|
||||||
pubKey cryptotypes.PubKey,
|
pubKey cryptotypes.PubKey,
|
||||||
signerData authsigning.SignerData,
|
signerData authsigning.SignerData,
|
||||||
sigData signing.SignatureData,
|
sigData signing.SignatureData,
|
||||||
@ -206,7 +220,7 @@ func VerifySignature(
|
|||||||
|
|
||||||
var optIface ethermint.ExtensionOptionsWeb3TxI
|
var optIface ethermint.ExtensionOptionsWeb3TxI
|
||||||
|
|
||||||
if err := ethermintCodec.UnpackAny(opts[0], &optIface); err != nil {
|
if err := appCodec.UnpackAny(opts[0], &optIface); err != nil {
|
||||||
return sdkerrors.Wrap(err, "failed to proto-unpack ExtensionOptionsWeb3Tx")
|
return sdkerrors.Wrap(err, "failed to proto-unpack ExtensionOptionsWeb3Tx")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,7 +245,7 @@ func VerifySignature(
|
|||||||
FeePayer: feePayer,
|
FeePayer: feePayer,
|
||||||
}
|
}
|
||||||
|
|
||||||
typedData, err := eip712.WrapTxToTypedData(ethermintCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
|
typedData, err := eip712.WrapTxToTypedData(appCodec, extOpt.TypedDataChainID, msgs[0], txBytes, feeDelegation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
|
return sdkerrors.Wrap(err, "failed to pack tx data in EIP712 object")
|
||||||
}
|
}
|
||||||
|
@ -17,26 +17,13 @@ import (
|
|||||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// EthSetupContextDecorator is adapted from SetUpContextDecorator from cosmos-sdk, it ignores gas consumption
|
// EthSetupContextMiddleware is adapted from SetUpContextMiddleware from cosmos-sdk, it ignores gas consumption
|
||||||
// by setting the gas meter to infinite
|
// by setting the gas meter to infinite
|
||||||
type EthSetupContextDecorator struct {
|
type EthSetupContextMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
|
||||||
func (esc EthSetupContextDecorator) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
|
||||||
if err != nil {
|
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset transient gas used to prepare the execution of current cosmos tx.
|
|
||||||
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
|
||||||
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
|
||||||
return esc.next.CheckTx(ctx, req, checkReq)
|
|
||||||
}
|
|
||||||
|
|
||||||
// gasContext returns a new context with a gas meter set from a given context.
|
// gasContext returns a new context with a gas meter set from a given context.
|
||||||
func gasContext(ctx sdk.Context, tx sdk.Tx, isSimulate bool) (sdk.Context, error) {
|
func gasContext(ctx sdk.Context, tx sdk.Tx, isSimulate bool) (sdk.Context, error) {
|
||||||
// all transactions must implement GasTx
|
// all transactions must implement GasTx
|
||||||
@ -62,16 +49,21 @@ func setGasMeter(ctx sdk.Context, gasLimit uint64, simulate bool) sdk.Context {
|
|||||||
return ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
|
return ctx.WithGasMeter(sdk.NewGasMeter(gasLimit))
|
||||||
}
|
}
|
||||||
|
|
||||||
// populateGas returns a new tx.Response with gas fields populated.
|
// CheckTx implements tx.Handler
|
||||||
func populateGas(res tx.Response, sdkCtx sdk.Context) tx.Response {
|
func (esc EthSetupContextMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
res.GasWanted = sdkCtx.GasMeter().Limit()
|
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
||||||
res.GasUsed = sdkCtx.GasMeter().GasConsumed()
|
if err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return res
|
// Reset transient gas used to prepare the execution of current cosmos tx.
|
||||||
|
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
||||||
|
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
||||||
|
return esc.next.CheckTx(sdkCtx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (esc EthSetupContextDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (esc EthSetupContextMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, err
|
return tx.Response{}, err
|
||||||
@ -80,11 +72,11 @@ func (esc EthSetupContextDecorator) DeliverTx(ctx context.Context, req tx.Reques
|
|||||||
// Reset transient gas used to prepare the execution of current cosmos tx.
|
// Reset transient gas used to prepare the execution of current cosmos tx.
|
||||||
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
||||||
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
||||||
return esc.next.DeliverTx(ctx, req)
|
return esc.next.DeliverTx(sdkCtx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (esc EthSetupContextDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (esc EthSetupContextMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
sdkCtx, err := gasContext(sdk.UnwrapSDKContext(ctx), req.Tx, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, err
|
return tx.Response{}, err
|
||||||
@ -93,33 +85,33 @@ func (esc EthSetupContextDecorator) SimulateTx(ctx context.Context, req tx.Reque
|
|||||||
// Reset transient gas used to prepare the execution of current cosmos tx.
|
// Reset transient gas used to prepare the execution of current cosmos tx.
|
||||||
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
// Transient gas-used is necessary to sum the gas-used of cosmos tx, when it contains multiple eth msgs.
|
||||||
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
esc.evmKeeper.ResetTransientGasUsed(sdkCtx)
|
||||||
return esc.next.SimulateTx(ctx, req)
|
return esc.next.SimulateTx(sdkCtx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthSetupContextDecorator{}
|
var _ tx.Handler = EthSetupContextMiddleware{}
|
||||||
|
|
||||||
func NewEthSetUpContextDecorator(evmKeeper EVMKeeper) tx.Middleware {
|
func NewEthSetUpContextMiddleware(evmKeeper EVMKeeper) tx.Middleware {
|
||||||
return func(txh tx.Handler) tx.Handler {
|
return func(txh tx.Handler) tx.Handler {
|
||||||
return EthSetupContextDecorator{
|
return EthSetupContextMiddleware{
|
||||||
next: txh,
|
next: txh,
|
||||||
evmKeeper: evmKeeper,
|
evmKeeper: evmKeeper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthMempoolFeeDecorator will check if the transaction's effective fee is at least as large
|
// EthMempoolFeeMiddleware will check if the transaction's effective fee is at least as large
|
||||||
// as the local validator's minimum gasFee (defined in validator config).
|
// as the local validator's minimum gasFee (defined in validator config).
|
||||||
// If fee is too low, decorator returns error and tx is rejected from mempool.
|
// If fee is too low, Middleware returns error and tx is rejected from mempool.
|
||||||
// Note this only applies when ctx.CheckTx = true
|
// Note this only applies when ctx.CheckTx = true
|
||||||
// If fee is high enough or not CheckTx, then call next AnteHandler
|
// If fee is high enough or not CheckTx, then call next AnteHandler
|
||||||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
|
// CONTRACT: Tx must implement FeeTx to use MempoolFeeMiddleware
|
||||||
type EthMempoolFeeDecorator struct {
|
type EthMempoolFeeMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
// CheckTx implements tx.Handler
|
||||||
func (mfd EthMempoolFeeDecorator) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
func (mfd EthMempoolFeeMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
|
||||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||||
params := mfd.evmKeeper.GetParams(sdkCtx)
|
params := mfd.evmKeeper.GetParams(sdkCtx)
|
||||||
@ -146,34 +138,34 @@ func (mfd EthMempoolFeeDecorator) CheckTx(ctx context.Context, req tx.Request, c
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (mfd EthMempoolFeeDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (mfd EthMempoolFeeMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return mfd.next.DeliverTx(ctx, req)
|
return mfd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (mfd EthMempoolFeeDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (mfd EthMempoolFeeMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return mfd.next.SimulateTx(ctx, req)
|
return mfd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthMempoolFeeDecorator{}
|
var _ tx.Handler = EthMempoolFeeMiddleware{}
|
||||||
|
|
||||||
func NewEthMempoolFeeDecorator(ek EVMKeeper) tx.Middleware {
|
func NewEthMempoolFeeMiddleware(ek EVMKeeper) tx.Middleware {
|
||||||
return func(txh tx.Handler) tx.Handler {
|
return func(txh tx.Handler) tx.Handler {
|
||||||
return EthMempoolFeeDecorator{
|
return EthMempoolFeeMiddleware{
|
||||||
next: txh,
|
next: txh,
|
||||||
evmKeeper: ek,
|
evmKeeper: ek,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthValidateBasicDecorator is adapted from ValidateBasicDecorator from cosmos-sdk, it ignores ErrNoSignatures
|
// EthValidateBasicMiddleware is adapted from ValidateBasicMiddleware from cosmos-sdk, it ignores ErrNoSignatures
|
||||||
type EthValidateBasicDecorator struct {
|
type EthValidateBasicMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
// CheckTx implements tx.Handler
|
||||||
func (vbd EthValidateBasicDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
func (vbd EthValidateBasicMiddleware) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
|
|
||||||
@ -255,21 +247,21 @@ func (vbd EthValidateBasicDecorator) CheckTx(cx context.Context, req tx.Request,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (vbd EthValidateBasicDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (vbd EthValidateBasicMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return vbd.next.DeliverTx(ctx, req)
|
return vbd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (vbd EthValidateBasicDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (vbd EthValidateBasicMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return vbd.next.SimulateTx(ctx, req)
|
return vbd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthValidateBasicDecorator{}
|
var _ tx.Handler = EthValidateBasicMiddleware{}
|
||||||
|
|
||||||
// NewEthValidateBasicDecorator creates a new EthValidateBasicDecorator
|
// NewEthValidateBasicMiddleware creates a new EthValidateBasicMiddleware
|
||||||
func NewEthValidateBasicDecorator(ek EVMKeeper) tx.Middleware {
|
func NewEthValidateBasicMiddleware(ek EVMKeeper) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return EthValidateBasicDecorator{
|
return EthValidateBasicMiddleware{
|
||||||
next: h,
|
next: h,
|
||||||
evmKeeper: ek,
|
evmKeeper: ek,
|
||||||
}
|
}
|
||||||
@ -277,14 +269,13 @@ func NewEthValidateBasicDecorator(ek EVMKeeper) tx.Middleware {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthSigVerificationDecorator validates an ethereum signatures
|
// EthSigVerificationMiddleware validates an ethereum signatures
|
||||||
type EthSigVerificationDecorator struct {
|
type EthSigVerificationMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
func ethSigVerificationMiddleware(esvd EthSigVerificationMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
func (esvd EthSigVerificationDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
chainID := esvd.evmKeeper.ChainID()
|
chainID := esvd.evmKeeper.ChainID()
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
@ -298,12 +289,12 @@ func (esvd EthSigVerificationDecorator) CheckTx(cx context.Context, req tx.Reque
|
|||||||
for _, msg := range reqTx.GetMsgs() {
|
for _, msg := range reqTx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
sender, err := signer.Sender(msgEthTx.AsTransaction())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrorInvalidSigner,
|
sdkerrors.ErrorInvalidSigner,
|
||||||
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
|
"couldn't retrieve sender address ('%s') from the ethereum transaction: %s",
|
||||||
msgEthTx.From,
|
msgEthTx.From,
|
||||||
@ -315,33 +306,50 @@ func (esvd EthSigVerificationDecorator) CheckTx(cx context.Context, req tx.Reque
|
|||||||
msgEthTx.From = sender.Hex()
|
msgEthTx.From = sender.Hex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tx.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx implements tx.Handler
|
||||||
|
func (esvd EthSigVerificationMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return esvd.next.CheckTx(ctx, req, checkReq)
|
return esvd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (esvd EthSigVerificationDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (esvd EthSigVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return esvd.next.DeliverTx(ctx, req)
|
return esvd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (esvd EthSigVerificationDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (esvd EthSigVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := ethSigVerificationMiddleware(esvd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return esvd.next.SimulateTx(ctx, req)
|
return esvd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthSigVerificationDecorator{}
|
var _ tx.Handler = EthSigVerificationMiddleware{}
|
||||||
|
|
||||||
// NewEthSigVerificationDecorator creates a new EthSigVerificationDecorator
|
// NewEthSigVerificationMiddleware creates a new EthSigVerificationMiddleware
|
||||||
func NewEthSigVerificationDecorator(ek EVMKeeper) tx.Middleware {
|
func NewEthSigVerificationMiddleware(ek EVMKeeper) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return EthSigVerificationDecorator{
|
return EthSigVerificationMiddleware{
|
||||||
next: h,
|
next: h,
|
||||||
evmKeeper: ek,
|
evmKeeper: ek,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthAccountVerificationDecorator validates an account balance checks
|
// EthAccountVerificationMiddleware validates an account balance checks
|
||||||
type EthAccountVerificationDecorator struct {
|
type EthAccountVerificationMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
ak evmtypes.AccountKeeper
|
ak evmtypes.AccountKeeper
|
||||||
bankKeeper evmtypes.BankKeeper
|
bankKeeper evmtypes.BankKeeper
|
||||||
@ -349,7 +357,7 @@ type EthAccountVerificationDecorator struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
// CheckTx implements tx.Handler
|
||||||
func (avd EthAccountVerificationDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
func (avd EthAccountVerificationMiddleware) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
if !ctx.IsCheckTx() {
|
if !ctx.IsCheckTx() {
|
||||||
@ -394,21 +402,21 @@ func (avd EthAccountVerificationDecorator) CheckTx(cx context.Context, req tx.Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (avd EthAccountVerificationDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (avd EthAccountVerificationMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return avd.next.DeliverTx(ctx, req)
|
return avd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (avd EthAccountVerificationDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (avd EthAccountVerificationMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return avd.next.SimulateTx(ctx, req)
|
return avd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthAccountVerificationDecorator{}
|
var _ tx.Handler = EthAccountVerificationMiddleware{}
|
||||||
|
|
||||||
// NewEthAccountVerificationDecorator creates a new EthAccountVerificationDecorator
|
// NewEthAccountVerificationMiddleware creates a new EthAccountVerificationMiddleware
|
||||||
func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) tx.Middleware {
|
func NewEthAccountVerificationMiddleware(ak evmtypes.AccountKeeper, bankKeeper evmtypes.BankKeeper, ek EVMKeeper) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return EthAccountVerificationDecorator{
|
return EthAccountVerificationMiddleware{
|
||||||
next: h,
|
next: h,
|
||||||
ak: ak,
|
ak: ak,
|
||||||
bankKeeper: bankKeeper,
|
bankKeeper: bankKeeper,
|
||||||
@ -417,16 +425,15 @@ func NewEthAccountVerificationDecorator(ak evmtypes.AccountKeeper, bankKeeper ev
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthGasConsumeDecorator validates enough intrinsic gas for the transaction and
|
// EthGasConsumeMiddleware validates enough intrinsic gas for the transaction and
|
||||||
// gas consumption.
|
// gas consumption.
|
||||||
type EthGasConsumeDecorator struct {
|
type EthGasConsumeMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
maxGasWanted uint64
|
maxGasWanted uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
func ethGasMiddleware(egcd EthGasConsumeMiddleware, cx context.Context, req tx.Request) (context.Context, tx.Response, error) {
|
||||||
func (egcd EthGasConsumeDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
|
|
||||||
@ -445,12 +452,12 @@ func (egcd EthGasConsumeDecorator) CheckTx(cx context.Context, req tx.Request, c
|
|||||||
for _, msg := range reqTx.GetMsgs() {
|
for _, msg := range reqTx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
return ctx, tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(err, "failed to unpack tx data")
|
return ctx, tx.Response{}, sdkerrors.Wrap(err, "failed to unpack tx data")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ctx.IsCheckTx() {
|
if ctx.IsCheckTx() {
|
||||||
@ -474,7 +481,7 @@ func (egcd EthGasConsumeDecorator) CheckTx(cx context.Context, req tx.Request, c
|
|||||||
london,
|
london,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
|
return ctx, tx.Response{}, sdkerrors.Wrapf(err, "failed to deduct transaction costs from user balance")
|
||||||
}
|
}
|
||||||
|
|
||||||
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
|
events = append(events, sdk.NewEvent(sdk.EventTypeTx, sdk.NewAttribute(sdk.AttributeKeyFee, fees.String())))
|
||||||
@ -498,28 +505,49 @@ func (egcd EthGasConsumeDecorator) CheckTx(cx context.Context, req tx.Request, c
|
|||||||
gasConsumed := ctx.GasMeter().GasConsumed()
|
gasConsumed := ctx.GasMeter().GasConsumed()
|
||||||
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
|
ctx = ctx.WithGasMeter(ethermint.NewInfiniteGasMeterWithLimit(gasWanted))
|
||||||
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
|
ctx.GasMeter().ConsumeGas(gasConsumed, "copy gas consumed")
|
||||||
return egcd.next.CheckTx(ctx, req, checkReq)
|
|
||||||
|
return ctx, tx.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx implements tx.Handler
|
||||||
|
func (egcd EthGasConsumeMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return egcd.next.CheckTx(newCtx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (egcd EthGasConsumeDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (egcd EthGasConsumeMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return egcd.next.DeliverTx(ctx, req)
|
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return egcd.next.DeliverTx(newCtx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (egcd EthGasConsumeDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (egcd EthGasConsumeMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return egcd.next.SimulateTx(ctx, req)
|
newCtx, _, err := ethGasMiddleware(egcd, ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return egcd.next.SimulateTx(newCtx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthGasConsumeDecorator{}
|
var _ tx.Handler = EthGasConsumeMiddleware{}
|
||||||
|
|
||||||
// NewEthGasConsumeDecorator creates a new EthGasConsumeDecorator
|
// NewEthGasConsumeMiddleware creates a new EthGasConsumeMiddleware
|
||||||
func NewEthGasConsumeDecorator(
|
func NewEthGasConsumeMiddleware(
|
||||||
evmKeeper EVMKeeper,
|
evmKeeper EVMKeeper,
|
||||||
maxGasWanted uint64,
|
maxGasWanted uint64,
|
||||||
) tx.Middleware {
|
) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return EthGasConsumeDecorator{
|
return EthGasConsumeMiddleware{
|
||||||
h,
|
h,
|
||||||
evmKeeper,
|
evmKeeper,
|
||||||
maxGasWanted,
|
maxGasWanted,
|
||||||
@ -527,15 +555,14 @@ func NewEthGasConsumeDecorator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CanTransferDecorator checks if the sender is allowed to transfer funds according to the EVM block
|
// CanTransferMiddleware checks if the sender is allowed to transfer funds according to the EVM block
|
||||||
// context rules.
|
// context rules.
|
||||||
type CanTransferDecorator struct {
|
type CanTransferMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
evmKeeper EVMKeeper
|
evmKeeper EVMKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
func canTransfer(ctd CanTransferMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
func (ctd CanTransferDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
params := ctd.evmKeeper.GetParams(ctx)
|
params := ctd.evmKeeper.GetParams(ctx)
|
||||||
@ -545,14 +572,14 @@ func (ctd CanTransferDecorator) CheckTx(cx context.Context, req tx.Request, chec
|
|||||||
for _, msg := range reqTx.GetMsgs() {
|
for _, msg := range reqTx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
baseFee := ctd.evmKeeper.BaseFee(ctx, ethCfg)
|
baseFee := ctd.evmKeeper.BaseFee(ctx, ethCfg)
|
||||||
|
|
||||||
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
coreMsg, err := msgEthTx.AsMessage(signer, baseFee)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
err,
|
err,
|
||||||
"failed to create an ethereum core.Message from signer %T", signer,
|
"failed to create an ethereum core.Message from signer %T", signer,
|
||||||
)
|
)
|
||||||
@ -571,7 +598,7 @@ func (ctd CanTransferDecorator) CheckTx(cx context.Context, req tx.Request, chec
|
|||||||
// check that caller has enough balance to cover asset transfer for **topmost** call
|
// 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
|
// NOTE: here the gas consumed is from the context with the infinite gas meter
|
||||||
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
if coreMsg.Value().Sign() > 0 && !evm.Context.CanTransfer(stateDB, coreMsg.From(), coreMsg.Value()) {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFunds,
|
sdkerrors.ErrInsufficientFunds,
|
||||||
"failed to transfer %s from address %s using the EVM block context transfer function",
|
"failed to transfer %s from address %s using the EVM block context transfer function",
|
||||||
coreMsg.Value(),
|
coreMsg.Value(),
|
||||||
@ -581,13 +608,13 @@ func (ctd CanTransferDecorator) CheckTx(cx context.Context, req tx.Request, chec
|
|||||||
|
|
||||||
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
|
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) {
|
||||||
if baseFee == nil {
|
if baseFee == nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(
|
return tx.Response{}, sdkerrors.Wrap(
|
||||||
evmtypes.ErrInvalidBaseFee,
|
evmtypes.ErrInvalidBaseFee,
|
||||||
"base fee is supported but evm block context value is nil",
|
"base fee is supported but evm block context value is nil",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
|
if coreMsg.GasFeeCap().Cmp(baseFee) < 0 {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrInsufficientFee,
|
sdkerrors.ErrInsufficientFee,
|
||||||
"max fee per gas less than block base fee (%s < %s)",
|
"max fee per gas less than block base fee (%s < %s)",
|
||||||
coreMsg.GasFeeCap(), baseFee,
|
coreMsg.GasFeeCap(), baseFee,
|
||||||
@ -596,57 +623,75 @@ func (ctd CanTransferDecorator) CheckTx(cx context.Context, req tx.Request, chec
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tx.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx implements tx.Handler
|
||||||
|
func (ctd CanTransferMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
if _, err := canTransfer(ctd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return ctd.next.CheckTx(ctx, req, checkReq)
|
return ctd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (ctd CanTransferDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (ctd CanTransferMiddleware) DeliverTx(cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
|
if _, err := canTransfer(ctd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return ctd.next.DeliverTx(ctx, req)
|
return ctd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (ctd CanTransferDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (ctd CanTransferMiddleware) SimulateTx(cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
|
if _, err := canTransfer(ctd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return ctd.next.SimulateTx(ctx, req)
|
return ctd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = CanTransferDecorator{}
|
var _ tx.Handler = CanTransferMiddleware{}
|
||||||
|
|
||||||
// NewCanTransferDecorator creates a new CanTransferDecorator instance.
|
// NewCanTransferMiddleware creates a new CanTransferMiddleware instance.
|
||||||
func NewCanTransferDecorator(evmKeeper EVMKeeper) tx.Middleware {
|
func NewCanTransferMiddleware(evmKeeper EVMKeeper) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return CanTransferDecorator{
|
return CanTransferMiddleware{
|
||||||
next: h,
|
next: h,
|
||||||
evmKeeper: evmKeeper,
|
evmKeeper: evmKeeper,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EthIncrementSenderSequenceDecorator increments the sequence of the signers.
|
// EthIncrementSenderSequenceMiddleware increments the sequence of the signers.
|
||||||
type EthIncrementSenderSequenceDecorator struct {
|
type EthIncrementSenderSequenceMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
ak evmtypes.AccountKeeper
|
ak evmtypes.AccountKeeper
|
||||||
}
|
}
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
func ethIncrementSenderSequence(issd EthIncrementSenderSequenceMiddleware, cx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
func (issd EthIncrementSenderSequenceDecorator) CheckTx(cx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
|
||||||
ctx := sdk.UnwrapSDKContext(cx)
|
ctx := sdk.UnwrapSDKContext(cx)
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
|
|
||||||
for _, msg := range reqTx.GetMsgs() {
|
for _, msg := range reqTx.GetMsgs() {
|
||||||
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
msgEthTx, ok := msg.(*evmtypes.MsgEthereumTx)
|
||||||
if !ok {
|
if !ok {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
return tx.Response{}, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid message type %T, expected %T", msg, (*evmtypes.MsgEthereumTx)(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
txData, err := evmtypes.UnpackTxData(msgEthTx.Data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrap(err, "failed to unpack tx data")
|
return tx.Response{}, sdkerrors.Wrap(err, "failed to unpack tx data")
|
||||||
}
|
}
|
||||||
|
|
||||||
// increase sequence of sender
|
// increase sequence of sender
|
||||||
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
|
acc := issd.ak.GetAccount(ctx, msgEthTx.GetFrom())
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrUnknownAddress,
|
sdkerrors.ErrUnknownAddress,
|
||||||
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
|
"account %s is nil", common.BytesToAddress(msgEthTx.GetFrom().Bytes()),
|
||||||
)
|
)
|
||||||
@ -656,42 +701,57 @@ func (issd EthIncrementSenderSequenceDecorator) CheckTx(cx context.Context, req
|
|||||||
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
|
// we merged the nonce verification to nonce increment, so when tx includes multiple messages
|
||||||
// with same sender, they'll be accepted.
|
// with same sender, they'll be accepted.
|
||||||
if txData.GetNonce() != nonce {
|
if txData.GetNonce() != nonce {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
return tx.Response{}, sdkerrors.Wrapf(
|
||||||
sdkerrors.ErrInvalidSequence,
|
sdkerrors.ErrInvalidSequence,
|
||||||
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
|
"invalid nonce; got %d, expected %d", txData.GetNonce(), nonce,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := acc.SetSequence(nonce + 1); err != nil {
|
if err := acc.SetSequence(nonce + 1); err != nil {
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
return tx.Response{}, sdkerrors.Wrapf(err, "failed to set sequence to %d", acc.GetSequence()+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
issd.ak.SetAccount(ctx, acc)
|
issd.ak.SetAccount(ctx, acc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tx.Response{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckTx implements tx.Handler
|
||||||
|
func (issd EthIncrementSenderSequenceMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
|
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return issd.next.CheckTx(ctx, req, checkReq)
|
return issd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (issd EthIncrementSenderSequenceDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (issd EthIncrementSenderSequenceMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
return issd.next.DeliverTx(ctx, req)
|
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return issd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (issd EthIncrementSenderSequenceDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (issd EthIncrementSenderSequenceMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := ethIncrementSenderSequence(issd, ctx, req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return issd.next.SimulateTx(ctx, req)
|
return issd.next.SimulateTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = EthIncrementSenderSequenceDecorator{}
|
var _ tx.Handler = EthIncrementSenderSequenceMiddleware{}
|
||||||
|
|
||||||
// NewEthIncrementSenderSequenceDecorator creates a new EthIncrementSenderSequenceDecorator.
|
// NewEthIncrementSenderSequenceMiddleware creates a new EthIncrementSenderSequenceMiddleware.
|
||||||
func NewEthIncrementSenderSequenceDecorator(ak evmtypes.AccountKeeper) tx.Middleware {
|
func NewEthIncrementSenderSequenceMiddleware(ak evmtypes.AccountKeeper) tx.Middleware {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return func(h tx.Handler) tx.Handler {
|
||||||
return EthIncrementSenderSequenceDecorator{
|
return EthIncrementSenderSequenceMiddleware{
|
||||||
next: h,
|
next: h,
|
||||||
ak: ak,
|
ak: ak,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx"
|
"github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
"github.com/cosmos/cosmos-sdk/types/tx/signing"
|
||||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
@ -17,6 +18,7 @@ import (
|
|||||||
type HandlerOptions struct {
|
type HandlerOptions struct {
|
||||||
Debug bool
|
Debug bool
|
||||||
|
|
||||||
|
Codec codec.Codec
|
||||||
// TxDecoder is used to decode the raw tx bytes into a sdk.Tx.
|
// TxDecoder is used to decode the raw tx bytes into a sdk.Tx.
|
||||||
TxDecoder sdk.TxDecoder
|
TxDecoder sdk.TxDecoder
|
||||||
|
|
||||||
@ -68,14 +70,14 @@ func (options HandlerOptions) Validate() error {
|
|||||||
func newEthAuthMiddleware(options HandlerOptions) (tx.Handler, error) {
|
func newEthAuthMiddleware(options HandlerOptions) (tx.Handler, error) {
|
||||||
return authmiddleware.ComposeMiddlewares(
|
return authmiddleware.ComposeMiddlewares(
|
||||||
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
||||||
NewEthSetUpContextDecorator(options.EvmKeeper),
|
NewEthSetUpContextMiddleware(options.EvmKeeper),
|
||||||
NewEthMempoolFeeDecorator(options.EvmKeeper),
|
NewEthMempoolFeeMiddleware(options.EvmKeeper),
|
||||||
NewEthValidateBasicDecorator(options.EvmKeeper),
|
NewEthValidateBasicMiddleware(options.EvmKeeper),
|
||||||
NewEthSigVerificationDecorator(options.EvmKeeper),
|
NewEthSigVerificationMiddleware(options.EvmKeeper),
|
||||||
NewEthAccountVerificationDecorator(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
|
NewEthAccountVerificationMiddleware(options.AccountKeeper, options.BankKeeper, options.EvmKeeper),
|
||||||
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
|
NewEthGasConsumeMiddleware(options.EvmKeeper, options.MaxTxGasWanted),
|
||||||
NewCanTransferDecorator(options.EvmKeeper),
|
NewCanTransferMiddleware(options.EvmKeeper),
|
||||||
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper),
|
NewEthIncrementSenderSequenceMiddleware(options.AccountKeeper),
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,6 +85,7 @@ func newCosmosAuthMiddleware(options HandlerOptions) (tx.Handler, error) {
|
|||||||
return authmiddleware.ComposeMiddlewares(
|
return authmiddleware.ComposeMiddlewares(
|
||||||
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
||||||
authmiddleware.NewTxDecoderMiddleware(options.TxDecoder),
|
authmiddleware.NewTxDecoderMiddleware(options.TxDecoder),
|
||||||
|
NewRejectMessagesMiddleware,
|
||||||
// Set a new GasMeter on sdk.Context.
|
// Set a new GasMeter on sdk.Context.
|
||||||
//
|
//
|
||||||
// Make sure the Gas middleware is outside of all other middlewares
|
// Make sure the Gas middleware is outside of all other middlewares
|
||||||
@ -127,6 +130,7 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) (tx.Handler, error) {
|
|||||||
|
|
||||||
return authmiddleware.ComposeMiddlewares(
|
return authmiddleware.ComposeMiddlewares(
|
||||||
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
authmiddleware.NewRunMsgsTxHandler(options.MsgServiceRouter, options.LegacyRouter),
|
||||||
|
NewRejectMessagesMiddleware,
|
||||||
authmiddleware.NewTxDecoderMiddleware(options.TxDecoder),
|
authmiddleware.NewTxDecoderMiddleware(options.TxDecoder),
|
||||||
// Set a new GasMeter on sdk.Context.
|
// Set a new GasMeter on sdk.Context.
|
||||||
//
|
//
|
||||||
@ -141,7 +145,7 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) (tx.Handler, error) {
|
|||||||
// emitted outside of this middleware.
|
// emitted outside of this middleware.
|
||||||
authmiddleware.NewIndexEventsTxMiddleware(options.IndexEvents),
|
authmiddleware.NewIndexEventsTxMiddleware(options.IndexEvents),
|
||||||
// Reject all extension options other than the ones needed by the feemarket.
|
// Reject all extension options other than the ones needed by the feemarket.
|
||||||
authmiddleware.NewExtensionOptionsMiddleware(options.ExtensionOptionChecker),
|
// authmiddleware.NewExtensionOptionsMiddleware(options.ExtensionOptionChecker),
|
||||||
authmiddleware.ValidateBasicMiddleware,
|
authmiddleware.ValidateBasicMiddleware,
|
||||||
authmiddleware.TxTimeoutHeightMiddleware,
|
authmiddleware.TxTimeoutHeightMiddleware,
|
||||||
authmiddleware.ValidateMemoMiddleware(options.AccountKeeper),
|
authmiddleware.ValidateMemoMiddleware(options.AccountKeeper),
|
||||||
@ -155,7 +159,7 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) (tx.Handler, error) {
|
|||||||
authmiddleware.ValidateSigCountMiddleware(options.AccountKeeper),
|
authmiddleware.ValidateSigCountMiddleware(options.AccountKeeper),
|
||||||
authmiddleware.SigGasConsumeMiddleware(options.AccountKeeper, options.SigGasConsumer),
|
authmiddleware.SigGasConsumeMiddleware(options.AccountKeeper, options.SigGasConsumer),
|
||||||
// Note: signature verification uses EIP instead of the cosmos signature validator
|
// Note: signature verification uses EIP instead of the cosmos signature validator
|
||||||
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
|
NewEip712SigVerificationMiddleware(options.Codec, options.AccountKeeper, options.SignModeHandler),
|
||||||
authmiddleware.IncrementSequenceMiddleware(options.AccountKeeper),
|
authmiddleware.IncrementSequenceMiddleware(options.AccountKeeper),
|
||||||
// Creates a new MultiStore branch, discards downstream writes if the downstream returns error.
|
// Creates a new MultiStore branch, discards downstream writes if the downstream returns error.
|
||||||
// These kinds of middlewares should be put under this:
|
// These kinds of middlewares should be put under this:
|
||||||
|
@ -8,16 +8,14 @@ import (
|
|||||||
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RejectMessagesDecorator prevents invalid msg types from being executed
|
// RejectMessagesMiddleware prevents invalid msg types from being executed
|
||||||
type RejectMessagesDecorator struct {
|
type RejectMessagesMiddleware struct {
|
||||||
next tx.Handler
|
next tx.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRejectMessagesDecorator() tx.Middleware {
|
func NewRejectMessagesMiddleware(txh tx.Handler) tx.Handler {
|
||||||
return func(h tx.Handler) tx.Handler {
|
return RejectMessagesMiddleware{
|
||||||
return RejectMessagesDecorator{
|
next: txh,
|
||||||
next: h,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -26,37 +24,33 @@ func NewRejectMessagesDecorator() tx.Middleware {
|
|||||||
// order to perform the refund.
|
// order to perform the refund.
|
||||||
|
|
||||||
// CheckTx implements tx.Handler
|
// CheckTx implements tx.Handler
|
||||||
func (rmd RejectMessagesDecorator) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
func (rmd RejectMessagesMiddleware) CheckTx(ctx context.Context, req tx.Request, checkReq tx.RequestCheckTx) (tx.Response, tx.ResponseCheckTx, error) {
|
||||||
reqTx := req.Tx
|
if _, err := reject(req); err != nil {
|
||||||
for _, msg := range reqTx.GetMsgs() {
|
return tx.Response{}, tx.ResponseCheckTx{}, err
|
||||||
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
|
||||||
return tx.Response{}, tx.ResponseCheckTx{}, sdkerrors.Wrapf(
|
|
||||||
sdkerrors.ErrInvalidType,
|
|
||||||
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rmd.next.CheckTx(ctx, req, checkReq)
|
return rmd.next.CheckTx(ctx, req, checkReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeliverTx implements tx.Handler
|
// DeliverTx implements tx.Handler
|
||||||
func (rmd RejectMessagesDecorator) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (rmd RejectMessagesMiddleware) DeliverTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
reqTx := req.Tx
|
if _, err := reject(req); err != nil {
|
||||||
for _, msg := range reqTx.GetMsgs() {
|
return tx.Response{}, err
|
||||||
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
|
||||||
return tx.Response{}, sdkerrors.Wrapf(
|
|
||||||
sdkerrors.ErrInvalidType,
|
|
||||||
"MsgEthereumTx needs to be contained within a tx with 'ExtensionOptionsEthereumTx' option",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rmd.next.DeliverTx(ctx, req)
|
return rmd.next.DeliverTx(ctx, req)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SimulateTx implements tx.Handler
|
// SimulateTx implements tx.Handler
|
||||||
func (rmd RejectMessagesDecorator) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
func (rmd RejectMessagesMiddleware) SimulateTx(ctx context.Context, req tx.Request) (tx.Response, error) {
|
||||||
|
if _, err := reject(req); err != nil {
|
||||||
|
return tx.Response{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return rmd.next.SimulateTx(ctx, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
func reject(req tx.Request) (tx.Response, error) {
|
||||||
reqTx := req.Tx
|
reqTx := req.Tx
|
||||||
for _, msg := range reqTx.GetMsgs() {
|
for _, msg := range reqTx.GetMsgs() {
|
||||||
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
if _, ok := msg.(*evmtypes.MsgEthereumTx); ok {
|
||||||
@ -67,7 +61,7 @@ func (rmd RejectMessagesDecorator) SimulateTx(ctx context.Context, req tx.Reques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rmd.next.SimulateTx(ctx, req)
|
return tx.Response{}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ tx.Handler = RejectMessagesDecorator{}
|
var _ tx.Handler = RejectMessagesMiddleware{}
|
||||||
|
@ -6,7 +6,6 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/std"
|
"github.com/cosmos/cosmos-sdk/std"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
|
|
||||||
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
|
cryptocodec "github.com/tharsis/ethermint/crypto/codec"
|
||||||
ethermint "github.com/tharsis/ethermint/types"
|
ethermint "github.com/tharsis/ethermint/types"
|
||||||
)
|
)
|
||||||
@ -21,7 +20,6 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
|||||||
// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.
|
// RegisterInterfaces registers Interfaces from types, crypto, and SDK std.
|
||||||
func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
|
func RegisterInterfaces(interfaceRegistry codectypes.InterfaceRegistry) {
|
||||||
std.RegisterInterfaces(interfaceRegistry)
|
std.RegisterInterfaces(interfaceRegistry)
|
||||||
txtypes.RegisterInterfaces(interfaceRegistry)
|
|
||||||
cryptocodec.RegisterInterfaces(interfaceRegistry)
|
cryptocodec.RegisterInterfaces(interfaceRegistry)
|
||||||
ethermint.RegisterInterfaces(interfaceRegistry)
|
ethermint.RegisterInterfaces(interfaceRegistry)
|
||||||
}
|
}
|
||||||
|
117
rpc/apis.go
117
rpc/apis.go
@ -3,6 +3,8 @@
|
|||||||
package rpc
|
package rpc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
|
|
||||||
@ -35,92 +37,96 @@ const (
|
|||||||
apiVersion = "1.0"
|
apiVersion = "1.0"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetRPCAPIs returns the list of all APIs
|
// APICreator creates the json-rpc api implementations.
|
||||||
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
|
type APICreator = func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API
|
||||||
nonceLock := new(types.AddrLocker)
|
|
||||||
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
|
||||||
|
|
||||||
var apis []rpc.API
|
// apiCreators defines the json-rpc api namespaces.
|
||||||
// remove duplicates
|
var apiCreators map[string]APICreator
|
||||||
selectedAPIs = unique(selectedAPIs)
|
|
||||||
|
|
||||||
for index := range selectedAPIs {
|
func init() {
|
||||||
switch selectedAPIs[index] {
|
apiCreators = map[string]APICreator{
|
||||||
case EthNamespace:
|
EthNamespace: func(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient) []rpc.API {
|
||||||
apis = append(apis,
|
nonceLock := new(types.AddrLocker)
|
||||||
rpc.API{
|
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: eth.NewPublicAPI(ctx.Logger, clientCtx, evmBackend, nonceLock),
|
Service: eth.NewPublicAPI(ctx.Logger, clientCtx, evmBackend, nonceLock),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
rpc.API{
|
{
|
||||||
Namespace: EthNamespace,
|
Namespace: EthNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: filters.NewPublicAPI(ctx.Logger, clientCtx, tmWSClient, evmBackend),
|
Service: filters.NewPublicAPI(ctx.Logger, clientCtx, tmWSClient, evmBackend),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case Web3Namespace:
|
},
|
||||||
apis = append(apis,
|
Web3Namespace: func(*server.Context, client.Context, *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: Web3Namespace,
|
Namespace: Web3Namespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: web3.NewPublicAPI(),
|
Service: web3.NewPublicAPI(),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case NetNamespace:
|
},
|
||||||
apis = append(apis,
|
NetNamespace: func(_ *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: NetNamespace,
|
Namespace: NetNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: net.NewPublicAPI(clientCtx),
|
Service: net.NewPublicAPI(clientCtx),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case PersonalNamespace:
|
},
|
||||||
apis = append(apis,
|
PersonalNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: PersonalNamespace,
|
Namespace: PersonalNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: personal.NewAPI(ctx.Logger, clientCtx, evmBackend),
|
Service: personal.NewAPI(ctx.Logger, clientCtx, evmBackend),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case TxPoolNamespace:
|
},
|
||||||
apis = append(apis,
|
TxPoolNamespace: func(ctx *server.Context, _ client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: TxPoolNamespace,
|
Namespace: TxPoolNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: txpool.NewPublicAPI(ctx.Logger),
|
Service: txpool.NewPublicAPI(ctx.Logger),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case DebugNamespace:
|
},
|
||||||
apis = append(apis,
|
DebugNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: DebugNamespace,
|
Namespace: DebugNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: debug.NewAPI(ctx, evmBackend, clientCtx),
|
Service: debug.NewAPI(ctx, evmBackend, clientCtx),
|
||||||
Public: true,
|
Public: true,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
case MinerNamespace:
|
},
|
||||||
apis = append(apis,
|
MinerNamespace: func(ctx *server.Context, clientCtx client.Context, _ *rpcclient.WSClient) []rpc.API {
|
||||||
rpc.API{
|
evmBackend := backend.NewEVMBackend(ctx, ctx.Logger, clientCtx)
|
||||||
|
return []rpc.API{
|
||||||
|
{
|
||||||
Namespace: MinerNamespace,
|
Namespace: MinerNamespace,
|
||||||
Version: apiVersion,
|
Version: apiVersion,
|
||||||
Service: miner.NewPrivateAPI(ctx, clientCtx, evmBackend),
|
Service: miner.NewPrivateAPI(ctx, clientCtx, evmBackend),
|
||||||
Public: false,
|
Public: false,
|
||||||
},
|
},
|
||||||
)
|
}
|
||||||
default:
|
},
|
||||||
ctx.Logger.Error("invalid namespace value", "namespace", selectedAPIs[index])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return apis
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func unique(intSlice []string) []string {
|
func unique(intSlice []string) []string {
|
||||||
@ -134,3 +140,28 @@ func unique(intSlice []string) []string {
|
|||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRPCAPIs returns the list of all APIs
|
||||||
|
func GetRPCAPIs(ctx *server.Context, clientCtx client.Context, tmWSClient *rpcclient.WSClient, selectedAPIs []string) []rpc.API {
|
||||||
|
var apis []rpc.API
|
||||||
|
|
||||||
|
for _, ns := range selectedAPIs {
|
||||||
|
if creator, ok := apiCreators[ns]; ok {
|
||||||
|
apis = append(apis, creator(ctx, clientCtx, tmWSClient)...)
|
||||||
|
} else {
|
||||||
|
ctx.Logger.Error("invalid namespace value", "namespace", ns)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return apis
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterAPINamespace registers a new API namespace with the API creator.
|
||||||
|
// This function fails if the namespace is already registered.
|
||||||
|
func RegisterAPINamespace(ns string, creator APICreator) error {
|
||||||
|
if _, ok := apiCreators[ns]; ok {
|
||||||
|
return fmt.Errorf("duplicated api namespace %s", ns)
|
||||||
|
}
|
||||||
|
apiCreators[ns] = creator
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
@ -144,7 +144,7 @@ if [[ -z $TEST || $TEST == "integration" ]] ; then
|
|||||||
|
|
||||||
for i in $(seq 1 "$TEST_QTD"); do
|
for i in $(seq 1 "$TEST_QTD"); do
|
||||||
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
|
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
|
||||||
echo "going to test ethermint node $HOST_RPC ..."
|
echo "going to test chibaclonk node $HOST_RPC ..."
|
||||||
MODE=$MODE HOST=$HOST_RPC go test ./tests/e2e/... -timeout=$time_out -v -short
|
MODE=$MODE HOST=$HOST_RPC go test ./tests/e2e/... -timeout=$time_out -v -short
|
||||||
TEST_FAIL=$?
|
TEST_FAIL=$?
|
||||||
done
|
done
|
||||||
@ -158,7 +158,7 @@ if [[ -z $TEST || $TEST == "rpc" || $TEST == "pending" ]]; then
|
|||||||
|
|
||||||
for i in $(seq 1 "$TEST_QTD"); do
|
for i in $(seq 1 "$TEST_QTD"); do
|
||||||
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
|
HOST_RPC=http://$IP_ADDR:$RPC_PORT"$i"
|
||||||
echo "going to test ethermint node $HOST_RPC ..."
|
echo "going to test chibaclonk node $HOST_RPC ..."
|
||||||
MODE=$MODE HOST=$HOST_RPC go test ./tests/rpc/... -timeout=$time_out -v -short
|
MODE=$MODE HOST=$HOST_RPC go test ./tests/rpc/... -timeout=$time_out -v -short
|
||||||
|
|
||||||
TEST_FAIL=$?
|
TEST_FAIL=$?
|
||||||
|
@ -170,11 +170,13 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONCodec) json.Raw
|
|||||||
|
|
||||||
// RandomizedParams creates randomized evm param changes for the simulator.
|
// RandomizedParams creates randomized evm param changes for the simulator.
|
||||||
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
|
func (AppModule) RandomizedParams(r *rand.Rand) []simtypes.ParamChange {
|
||||||
return nil
|
return simulation.ParamChanges(r)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RegisterStoreDecoder registers a decoder for evm module's types
|
// RegisterStoreDecoder registers a decoder for evm module's types
|
||||||
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {}
|
func (am AppModule) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
|
||||||
|
sdr[types.StoreKey] = simulation.NewDecodeStore()
|
||||||
|
}
|
||||||
|
|
||||||
// ProposalContents doesn't return any content functions for governance proposals.
|
// ProposalContents doesn't return any content functions for governance proposals.
|
||||||
func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
|
func (AppModule) ProposalContents(simState module.SimulationState) []simtypes.WeightedProposalContent {
|
||||||
@ -188,5 +190,7 @@ func (AppModule) GenerateGenesisState(simState *module.SimulationState) {
|
|||||||
|
|
||||||
// WeightedOperations returns the all the evm module operations with their respective weights.
|
// WeightedOperations returns the all the evm module operations with their respective weights.
|
||||||
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
|
func (am AppModule) WeightedOperations(simState module.SimulationState) []simtypes.WeightedOperation {
|
||||||
return nil
|
return simulation.WeightedOperations(
|
||||||
|
simState.AppParams, simState.Cdc, am.ak, am.keeper,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
31
x/evm/simulation/decoder.go
Normal file
31
x/evm/simulation/decoder.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package simulation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/kv"
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewDecodeStore returns a decoder function closure that unmarshals the KVPair's
|
||||||
|
// Value to the corresponding evm type.
|
||||||
|
func NewDecodeStore() func(kvA, kvB kv.Pair) string {
|
||||||
|
return func(kvA, kvB kv.Pair) string {
|
||||||
|
switch {
|
||||||
|
case bytes.Equal(kvA.Key[:1], types.KeyPrefixStorage):
|
||||||
|
storageHashA := common.BytesToHash(kvA.Value).Hex()
|
||||||
|
storageHashB := common.BytesToHash(kvB.Value).Hex()
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v\n%v", storageHashA, storageHashB)
|
||||||
|
case bytes.Equal(kvA.Key[:1], types.KeyPrefixCode):
|
||||||
|
codeHashA := common.BytesToHash(kvA.Value).Hex()
|
||||||
|
codeHashB := common.BytesToHash(kvB.Value).Hex()
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v\n%v", codeHashA, codeHashB)
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("invalid evm key prefix %X", kvA.Key[:1]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -3,12 +3,22 @@ package simulation
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/types/module"
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
|
|
||||||
"github.com/tharsis/ethermint/x/evm/types"
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// GenExtraEIPs randomly generates specific extra eips or not.
|
||||||
|
func genExtraEIPs(r *rand.Rand) []int64 {
|
||||||
|
var extraEIPs []int64
|
||||||
|
if r.Uint32()%2 == 0 {
|
||||||
|
extraEIPs = []int64{1344, 1884, 2200, 2929, 3198, 3529}
|
||||||
|
}
|
||||||
|
return extraEIPs
|
||||||
|
}
|
||||||
|
|
||||||
// RandomizedGenState generates a random GenesisState for nft
|
// RandomizedGenState generates a random GenesisState for nft
|
||||||
func RandomizedGenState(simState *module.SimulationState) {
|
func RandomizedGenState(simState *module.SimulationState) {
|
||||||
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig())
|
params := types.NewParams(types.DefaultEVMDenom, true, true, types.DefaultChainConfig())
|
||||||
|
302
x/evm/simulation/opereations.go
Normal file
302
x/evm/simulation/opereations.go
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
package simulation
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
sdktx "github.com/cosmos/cosmos-sdk/types/tx"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/types/module"
|
||||||
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||||
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
|
||||||
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
|
|
||||||
|
"github.com/tharsis/ethermint/encoding"
|
||||||
|
"github.com/tharsis/ethermint/server/config"
|
||||||
|
"github.com/tharsis/ethermint/tests"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/keeper"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
/* #nosec */
|
||||||
|
OpWeightMsgEthSimpleTransfer = "op_weight_msg_eth_simple_transfer"
|
||||||
|
/* #nosec */
|
||||||
|
OpWeightMsgEthCreateContract = "op_weight_msg_eth_create_contract"
|
||||||
|
/* #nosec */
|
||||||
|
OpWeightMsgEthCallContract = "op_weight_msg_eth_call_contract"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
WeightMsgEthSimpleTransfer = 50
|
||||||
|
WeightMsgEthCreateContract = 50
|
||||||
|
)
|
||||||
|
|
||||||
|
var ErrNoEnoughBalance = fmt.Errorf("no enough balance")
|
||||||
|
|
||||||
|
var maxWaitSeconds = 10
|
||||||
|
|
||||||
|
type simulateContext struct {
|
||||||
|
context sdk.Context
|
||||||
|
bapp *baseapp.BaseApp
|
||||||
|
rand *rand.Rand
|
||||||
|
keeper *keeper.Keeper
|
||||||
|
}
|
||||||
|
|
||||||
|
// WeightedOperations generate Two kinds of operations: SimulateEthSimpleTransfer, SimulateEthCreateContract.
|
||||||
|
// Contract call operations work as the future operations of SimulateEthCreateContract.
|
||||||
|
func WeightedOperations(
|
||||||
|
appParams simtypes.AppParams, cdc codec.JSONCodec, ak types.AccountKeeper, k *keeper.Keeper,
|
||||||
|
) simulation.WeightedOperations {
|
||||||
|
var (
|
||||||
|
weightMsgEthSimpleTransfer int
|
||||||
|
weightMsgEthCreateContract int
|
||||||
|
)
|
||||||
|
|
||||||
|
appParams.GetOrGenerate(cdc, OpWeightMsgEthSimpleTransfer, &weightMsgEthSimpleTransfer, nil,
|
||||||
|
func(_ *rand.Rand) {
|
||||||
|
weightMsgEthSimpleTransfer = WeightMsgEthSimpleTransfer
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
appParams.GetOrGenerate(cdc, OpWeightMsgEthCreateContract, &weightMsgEthCreateContract, nil,
|
||||||
|
func(_ *rand.Rand) {
|
||||||
|
weightMsgEthCreateContract = WeightMsgEthCreateContract
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
return simulation.WeightedOperations{
|
||||||
|
simulation.NewWeightedOperation(
|
||||||
|
weightMsgEthSimpleTransfer,
|
||||||
|
SimulateEthSimpleTransfer(ak, k),
|
||||||
|
),
|
||||||
|
simulation.NewWeightedOperation(
|
||||||
|
weightMsgEthCreateContract,
|
||||||
|
SimulateEthCreateContract(ak, k),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateEthSimpleTransfer simulate simple eth account transferring gas token.
|
||||||
|
// It randomly choose sender, recipient and transferable amount.
|
||||||
|
// Other tx details like nonce, gasprice, gaslimit are calculated to get valid value.
|
||||||
|
func SimulateEthSimpleTransfer(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
|
||||||
|
return func(
|
||||||
|
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
||||||
|
var recipient simtypes.Account
|
||||||
|
if r.Intn(2) == 1 {
|
||||||
|
recipient, _ = simtypes.RandomAcc(r, accs)
|
||||||
|
} else {
|
||||||
|
recipient = simtypes.RandomAccounts(r, 1)[0]
|
||||||
|
}
|
||||||
|
from := common.BytesToAddress(simAccount.Address)
|
||||||
|
to := common.BytesToAddress(recipient.Address)
|
||||||
|
|
||||||
|
simulateContext := &simulateContext{ctx, bapp, r, k}
|
||||||
|
|
||||||
|
return SimulateEthTx(simulateContext, &from, &to, nil, (*hexutil.Bytes)(&[]byte{}), simAccount.PrivKey, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateEthCreateContract simulate create an ERC20 contract.
|
||||||
|
// It makes operationSimulateEthCallContract the future operations of SimulateEthCreateContract to ensure valid contract call.
|
||||||
|
func SimulateEthCreateContract(ak types.AccountKeeper, k *keeper.Keeper) simtypes.Operation {
|
||||||
|
return func(
|
||||||
|
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
||||||
|
|
||||||
|
from := common.BytesToAddress(simAccount.Address)
|
||||||
|
nonce := k.GetNonce(ctx, from)
|
||||||
|
|
||||||
|
ctorArgs, err := types.ERC20Contract.ABI.Pack("", from, sdk.NewIntWithDecimal(1000, 18).BigInt())
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack owner and supply"), nil, err
|
||||||
|
}
|
||||||
|
data := types.ERC20Contract.Bin
|
||||||
|
data = append(data, ctorArgs...)
|
||||||
|
|
||||||
|
simulateContext := &simulateContext{ctx, bapp, r, k}
|
||||||
|
|
||||||
|
fops := make([]simtypes.FutureOperation, 1)
|
||||||
|
whenCall := ctx.BlockHeader().Time.Add(time.Duration(r.Intn(maxWaitSeconds)+1) * time.Second)
|
||||||
|
contractAddr := crypto.CreateAddress(from, nonce)
|
||||||
|
var tokenReceipient simtypes.Account
|
||||||
|
if r.Intn(2) == 1 {
|
||||||
|
tokenReceipient, _ = simtypes.RandomAcc(r, accs)
|
||||||
|
} else {
|
||||||
|
tokenReceipient = simtypes.RandomAccounts(r, 1)[0]
|
||||||
|
}
|
||||||
|
receipientAddr := common.BytesToAddress(tokenReceipient.Address)
|
||||||
|
fops[0] = simtypes.FutureOperation{
|
||||||
|
BlockTime: whenCall,
|
||||||
|
Op: operationSimulateEthCallContract(k, &contractAddr, &receipientAddr, nil),
|
||||||
|
}
|
||||||
|
return SimulateEthTx(simulateContext, &from, nil, nil, (*hexutil.Bytes)(&data), simAccount.PrivKey, fops)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// operationSimulateEthCallContract simulate calling an contract.
|
||||||
|
// It is always calling an ERC20 contract.
|
||||||
|
func operationSimulateEthCallContract(k *keeper.Keeper, contractAddr, to *common.Address, amount *big.Int) simtypes.Operation {
|
||||||
|
return func(
|
||||||
|
r *rand.Rand, bapp *baseapp.BaseApp, ctx sdk.Context, accs []simtypes.Account, chainID string,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
simAccount, _ := simtypes.RandomAcc(r, accs)
|
||||||
|
|
||||||
|
from := common.BytesToAddress(simAccount.Address)
|
||||||
|
|
||||||
|
ctorArgs, err := types.ERC20Contract.ABI.Pack("transfer", to, amount)
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not pack method and args"), nil, err
|
||||||
|
}
|
||||||
|
data := types.ERC20Contract.Bin
|
||||||
|
data = append(data, ctorArgs...)
|
||||||
|
|
||||||
|
simulateContext := &simulateContext{ctx, bapp, r, k}
|
||||||
|
|
||||||
|
return SimulateEthTx(simulateContext, &from, contractAddr, nil, (*hexutil.Bytes)(&data), simAccount.PrivKey, nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SimulateEthTx creates valid ethereum tx and pack it as cosmos tx, and deliver it.
|
||||||
|
func SimulateEthTx(
|
||||||
|
ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes, prv cryptotypes.PrivKey, fops []simtypes.FutureOperation,
|
||||||
|
) (simtypes.OperationMsg, []simtypes.FutureOperation, error) {
|
||||||
|
ethTx, err := CreateRandomValidEthTx(ctx, from, nil, nil, data)
|
||||||
|
if err == ErrNoEnoughBalance {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "no enough balance"), nil, nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not create valid eth tx"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
txConfig := encoding.MakeConfig(module.NewBasicManager()).TxConfig
|
||||||
|
txBuilder := txConfig.NewTxBuilder()
|
||||||
|
signedTx, err := GetSignedTx(ctx, txBuilder, ethTx, prv)
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "can not sign ethereum tx"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, _, err = ctx.bapp.SimDeliver(txConfig.TxEncoder(), signedTx)
|
||||||
|
if err != nil {
|
||||||
|
return simtypes.NoOpMsg(types.ModuleName, types.TypeMsgEthereumTx, "failed to deliver tx"), nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return simtypes.OperationMsg{}, fops, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateRandomValidEthTx create the ethereum tx with valid random values
|
||||||
|
func CreateRandomValidEthTx(ctx *simulateContext, from, to *common.Address, amount *big.Int, data *hexutil.Bytes) (ethTx *types.MsgEthereumTx, err error) {
|
||||||
|
estimateGas, err := EstimateGas(ctx, from, to, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
gasLimit := estimateGas + uint64(ctx.rand.Intn(int(sdktx.MaxGasWanted-estimateGas)))
|
||||||
|
ethChainID := ctx.keeper.ChainID()
|
||||||
|
chainConfig := ctx.keeper.GetParams(ctx.context).ChainConfig.EthereumConfig(ethChainID)
|
||||||
|
gasPrice := ctx.keeper.BaseFee(ctx.context, chainConfig)
|
||||||
|
gasFeeCap := new(big.Int).Add(gasPrice, big.NewInt(int64(ctx.rand.Int())))
|
||||||
|
gasTipCap := big.NewInt(int64(ctx.rand.Int()))
|
||||||
|
nonce := ctx.keeper.GetNonce(ctx.context, *from)
|
||||||
|
|
||||||
|
if amount == nil {
|
||||||
|
amount, err = RandomTransferableAmount(ctx, *from, gasLimit, gasFeeCap)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ethTx = types.NewTx(ethChainID, nonce, to, amount, gasLimit, gasPrice, gasFeeCap, gasTipCap, *data, nil)
|
||||||
|
ethTx.From = from.String()
|
||||||
|
return ethTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSignedTx sign the ethereum tx and packs it as a signing.Tx .
|
||||||
|
func GetSignedTx(ctx *simulateContext, txBuilder client.TxBuilder, msg *types.MsgEthereumTx, prv cryptotypes.PrivKey) (signedTx signing.Tx, err error) {
|
||||||
|
builder, ok := txBuilder.(tx.ExtensionOptionsTxBuilder)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("can not initiate ExtensionOptionsTxBuilder")
|
||||||
|
}
|
||||||
|
option, err := codectypes.NewAnyWithValue(&types.ExtensionOptionsEthereumTx{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
builder.SetExtensionOptions(option)
|
||||||
|
|
||||||
|
if err := msg.Sign(ethtypes.LatestSignerForChainID(ctx.keeper.ChainID()), tests.NewSigner(prv)); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = builder.SetMsgs(msg); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
txData, err := types.UnpackTxData(msg.Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
fees := sdk.NewCoins(sdk.NewCoin(ctx.keeper.GetParams(ctx.context).EvmDenom, sdk.NewIntFromBigInt(txData.Fee())))
|
||||||
|
builder.SetFeeAmount(fees)
|
||||||
|
builder.SetGasLimit(msg.GetGas())
|
||||||
|
|
||||||
|
signedTx = builder.GetTx()
|
||||||
|
return signedTx, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomTransferableAmount generates a random valid transferable amount.
|
||||||
|
// Transferable amount is between the range [0, spendable), spendable = balance - gasFeeCap * GasLimit.
|
||||||
|
func RandomTransferableAmount(ctx *simulateContext, address common.Address, gasLimit uint64, gasFeeCap *big.Int) (amount *big.Int, err error) {
|
||||||
|
balance := ctx.keeper.GetBalance(ctx.context, address)
|
||||||
|
feeLimit := new(big.Int).Mul(gasFeeCap, big.NewInt(int64(gasLimit)))
|
||||||
|
if (feeLimit.Cmp(balance)) > 0 {
|
||||||
|
return nil, ErrNoEnoughBalance
|
||||||
|
}
|
||||||
|
spendable := new(big.Int).Sub(balance, feeLimit)
|
||||||
|
if spendable.Cmp(big.NewInt(0)) == 0 {
|
||||||
|
amount = new(big.Int).Set(spendable)
|
||||||
|
return amount, nil
|
||||||
|
}
|
||||||
|
simAmount, err := simtypes.RandPositiveInt(ctx.rand, sdk.NewIntFromBigInt(spendable))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
amount = simAmount.BigInt()
|
||||||
|
return amount, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EstimateGas estimates the gas used by quering the keeper.
|
||||||
|
func EstimateGas(ctx *simulateContext, from, to *common.Address, data *hexutil.Bytes) (gas uint64, err error) {
|
||||||
|
args, err := json.Marshal(&types.TransactionArgs{To: to, From: from, Data: data})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := ctx.keeper.EstimateGas(sdk.WrapSDKContext(ctx.context), &types.EthCallRequest{
|
||||||
|
Args: args,
|
||||||
|
GasCap: config.DefaultGasCap,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return res.Gas, nil
|
||||||
|
}
|
28
x/evm/simulation/params.go
Normal file
28
x/evm/simulation/params.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package simulation
|
||||||
|
|
||||||
|
// DONTCOVER
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"math/rand"
|
||||||
|
|
||||||
|
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||||
|
"github.com/tharsis/ethermint/x/evm/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
keyExtraEIPs = "ExtraEIPs"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParamChanges defines the parameters that can be modified by param change proposals
|
||||||
|
// on the simulation.
|
||||||
|
func ParamChanges(r *rand.Rand) []simtypes.ParamChange {
|
||||||
|
return []simtypes.ParamChange{
|
||||||
|
simulation.NewSimParamChange(types.ModuleName, keyExtraEIPs,
|
||||||
|
func(r *rand.Rand) string {
|
||||||
|
return fmt.Sprintf("\"%d\"", genExtraEIPs(r))
|
||||||
|
},
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
@ -11,7 +11,7 @@ import (
|
|||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||||
|
|
||||||
// "github.com/cosmos/cosmos-sdk/x/auth/ante"
|
authmiddleware "github.com/cosmos/cosmos-sdk/x/auth/middleware"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
"github.com/cosmos/cosmos-sdk/x/auth/signing"
|
||||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
|
||||||
|
|
||||||
@ -23,9 +23,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ sdk.Msg = &MsgEthereumTx{}
|
_ sdk.Msg = &MsgEthereumTx{}
|
||||||
_ sdk.Tx = &MsgEthereumTx{}
|
_ sdk.Tx = &MsgEthereumTx{}
|
||||||
// _ ante.GasTx = &MsgEthereumTx{}
|
_ authmiddleware.GasTx = &MsgEthereumTx{}
|
||||||
|
|
||||||
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
|
_ codectypes.UnpackInterfacesMessage = MsgEthereumTx{}
|
||||||
)
|
)
|
||||||
|
Loading…
Reference in New Issue
Block a user