forked from cerc-io/laconicd-deprecated
fix: use EffectiveGasPrice in ante handler for dynamic fee tx (#817)
* Use effectiveGasPrice in ante handler for dynamic fee tx Closes: #814 Solution: - use effectiveGasPrice when check minimal-gas-prices, and deduct fee in ante handler - implement an EthMempoolFeeDecorator * add effectiveGasPrice to tx receipt * changelog * fix unit test * fix comments * add comments * Apply suggestions from code review Co-authored-by: Thomas Nguy <81727899+thomas-nguy@users.noreply.github.com> * review suggestions Co-authored-by: Thomas Nguy <81727899+thomas-nguy@users.noreply.github.com> Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
co-authored by
Thomas Nguy
Federico Kunze Küllmer
parent
50e463725e
commit
ccc6f5b53d
+2
-2
@@ -53,8 +53,8 @@ func NewAnteHandler(
|
||||
// handle as *evmtypes.MsgEthereumTx
|
||||
|
||||
anteHandler = sdk.ChainAnteDecorators(
|
||||
NewEthSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
authante.NewMempoolFeeDecorator(),
|
||||
NewEthSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
|
||||
NewEthMempoolFeeDecorator(evmKeeper, feeMarketKeeper), // Check eth effective gas price against minimal-gas-prices
|
||||
authante.NewTxTimeoutHeightDecorator(),
|
||||
authante.NewValidateMemoDecorator(ak),
|
||||
NewEthValidateBasicDecorator(evmKeeper),
|
||||
|
||||
@@ -193,7 +193,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
// bigger than MaxGasWanted
|
||||
txBuilder.SetGasLimit(uint64(1 << 63))
|
||||
return txBuilder.GetTx()
|
||||
}, false, true, false,
|
||||
}, true, false, false,
|
||||
},
|
||||
{
|
||||
"fail - CheckTx (memo too long)",
|
||||
@@ -286,7 +286,7 @@ func (suite AnteTestSuite) TestAnteHandler() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(tc.reCheckTx).WithIsReCheckTx(tc.reCheckTx)
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
|
||||
|
||||
// expConsumed := params.TxGasContractCreation + params.TxGas
|
||||
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
|
||||
@@ -314,8 +314,6 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
suite.Require().NoError(acc.SetSequence(1))
|
||||
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
|
||||
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
txFn func() sdk.Tx
|
||||
@@ -501,7 +499,7 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
// bigger than MaxGasWanted
|
||||
txBuilder.SetGasLimit(uint64(1 << 63))
|
||||
return txBuilder.GetTx()
|
||||
}, false, true, false,
|
||||
}, true, false, false,
|
||||
},
|
||||
{
|
||||
"fail - CheckTx (memo too long)",
|
||||
@@ -530,7 +528,8 @@ func (suite AnteTestSuite) TestAnteHandlerWithDynamicTxFee() {
|
||||
|
||||
for _, tc := range testCases {
|
||||
suite.Run(tc.name, func() {
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(tc.reCheckTx).WithIsReCheckTx(tc.reCheckTx)
|
||||
suite.ctx = suite.ctx.WithIsCheckTx(tc.checkTx).WithIsReCheckTx(tc.reCheckTx)
|
||||
suite.app.EvmKeeper.AddBalance(addr, big.NewInt((ethparams.InitialBaseFee+10)*100000))
|
||||
_, err := suite.anteHandler(suite.ctx, tc.txFn(), false)
|
||||
if tc.expPass {
|
||||
suite.Require().NoError(err)
|
||||
|
||||
@@ -543,3 +543,58 @@ func (esc EthSetupContextDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simul
|
||||
newCtx = ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
return next(newCtx, tx, simulate)
|
||||
}
|
||||
|
||||
// EthMempoolFeeDecorator will check if the transaction's effective fee is at least as large
|
||||
// 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.
|
||||
// Note this only applies when ctx.CheckTx = true
|
||||
// If fee is high enough or not CheckTx, then call next AnteHandler
|
||||
// CONTRACT: Tx must implement FeeTx to use MempoolFeeDecorator
|
||||
type EthMempoolFeeDecorator struct {
|
||||
feemarketKeeper evmtypes.FeeMarketKeeper
|
||||
evmKeeper EVMKeeper
|
||||
}
|
||||
|
||||
func NewEthMempoolFeeDecorator(ek EVMKeeper, fmk evmtypes.FeeMarketKeeper) EthMempoolFeeDecorator {
|
||||
return EthMempoolFeeDecorator{
|
||||
feemarketKeeper: fmk,
|
||||
evmKeeper: ek,
|
||||
}
|
||||
}
|
||||
|
||||
// AnteHandle ensures that the provided fees meet a minimum threshold for the validator,
|
||||
// if this is a CheckTx. This is only for local mempool purposes, and thus
|
||||
// is only ran on check tx.
|
||||
func (mfd EthMempoolFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
|
||||
if ctx.IsCheckTx() && !simulate {
|
||||
if len(tx.GetMsgs()) != 1 {
|
||||
return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "only 1 ethereum msg supported per tx")
|
||||
}
|
||||
msg, ok := tx.GetMsgs()[0].(*evmtypes.MsgEthereumTx)
|
||||
if !ok {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "invalid transaction type %T, expected %T", tx, (*evmtypes.MsgEthereumTx)(nil))
|
||||
}
|
||||
|
||||
var feeAmt *big.Int
|
||||
|
||||
feeMktParams := mfd.feemarketKeeper.GetParams(ctx)
|
||||
params := mfd.evmKeeper.GetParams(ctx)
|
||||
chainID := mfd.evmKeeper.ChainID()
|
||||
ethCfg := params.ChainConfig.EthereumConfig(chainID)
|
||||
evmDenom := params.EvmDenom
|
||||
if evmtypes.IsLondon(ethCfg, ctx.BlockHeight()) && !feeMktParams.NoBaseFee {
|
||||
baseFee := mfd.feemarketKeeper.GetBaseFee(ctx)
|
||||
feeAmt = msg.GetEffectiveFee(baseFee)
|
||||
} else {
|
||||
feeAmt = msg.GetFee()
|
||||
}
|
||||
|
||||
glDec := sdk.NewDec(int64(msg.GetGas()))
|
||||
requiredFee := ctx.MinGasPrices().AmountOf(evmDenom).Mul(glDec)
|
||||
if sdk.NewDecFromBigInt(feeAmt).LT(requiredFee) {
|
||||
return ctx, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "insufficient fees; got: %s required: %s", feeAmt, requiredFee)
|
||||
}
|
||||
}
|
||||
|
||||
return next(ctx, tx, simulate)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user