forked from cerc-io/laconicd-deprecated
feat(ante, evm): set priority for eth transactions (#1214)
* Set priority for eth transactions Set the tx priority to the lowest priority in the messages. fix unit tests code cleanup and spec update spec fix go lint add priority integration test add python linter job add access list tx type fix gas limit remove ledger tag, so no need to replace hid dependency fix earlier check ibc-go v5.0.0-beta1 * fix pruned node integration test * Update x/feemarket/spec/09_antehandlers.md Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
This commit is contained in:
co-authored by
Federico Kunze Küllmer
parent
53f160cbb0
commit
e1560849dd
@@ -569,13 +569,14 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
|
||||
k.SetHooks(tc.hooks)
|
||||
|
||||
// add some fund to pay gas fee
|
||||
k.SetBalance(suite.ctx, suite.from, big.NewInt(10000000000))
|
||||
k.SetBalance(suite.ctx, suite.from, big.NewInt(1000000000000000))
|
||||
|
||||
contract := suite.deployERC20Contract()
|
||||
|
||||
data, err := types.ERC20Contract.ABI.Pack("transfer", suite.from, big.NewInt(10))
|
||||
suite.Require().NoError(err)
|
||||
|
||||
gasPrice := big.NewInt(1000000000) // must be bigger than or equal to baseFee
|
||||
nonce := k.GetNonce(suite.ctx, suite.from)
|
||||
tx := types.NewTx(
|
||||
suite.chainID,
|
||||
@@ -583,7 +584,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
|
||||
&contract,
|
||||
big.NewInt(0),
|
||||
tc.gasLimit,
|
||||
big.NewInt(1),
|
||||
gasPrice,
|
||||
nil,
|
||||
nil,
|
||||
data,
|
||||
@@ -595,7 +596,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
|
||||
|
||||
txData, err := types.UnpackTxData(tx.Data)
|
||||
suite.Require().NoError(err)
|
||||
_, err = k.DeductTxCostsFromUserBalance(suite.ctx, *tx, txData, "aphoton", true, true, true)
|
||||
_, _, err = k.DeductTxCostsFromUserBalance(suite.ctx, *tx, txData, "aphoton", true, true, true)
|
||||
suite.Require().NoError(err)
|
||||
|
||||
res, err := k.EthereumTx(sdk.WrapSDKContext(suite.ctx), tx)
|
||||
@@ -614,7 +615,7 @@ func (suite *EvmTestSuite) TestERC20TransferReverted() {
|
||||
}
|
||||
|
||||
// check gas refund works: only deducted fee for gas used, rather than gas limit.
|
||||
suite.Require().Equal(big.NewInt(int64(res.GasUsed)), new(big.Int).Sub(before, after))
|
||||
suite.Require().Equal(new(big.Int).Mul(gasPrice, big.NewInt(int64(res.GasUsed))), new(big.Int).Sub(before, after))
|
||||
|
||||
// nonce should not be increased.
|
||||
nonce2 := k.GetNonce(suite.ctx, suite.from)
|
||||
|
||||
@@ -29,9 +29,7 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("Feemarket", func() {
|
||||
var (
|
||||
privKey *ethsecp256k1.PrivKey
|
||||
)
|
||||
var privKey *ethsecp256k1.PrivKey
|
||||
|
||||
Describe("Performing EVM transactions", func() {
|
||||
type txParams struct {
|
||||
|
||||
@@ -293,7 +293,11 @@ func (k *Keeper) GetBalance(ctx sdk.Context, addr common.Address) *big.Int {
|
||||
// - `0`: london hardfork enabled but feemarket is not enabled.
|
||||
// - `n`: both london hardfork and feemarket are enabled.
|
||||
func (k Keeper) GetBaseFee(ctx sdk.Context, ethCfg *params.ChainConfig) *big.Int {
|
||||
if !types.IsLondon(ethCfg, ctx.BlockHeight()) {
|
||||
return k.getBaseFee(ctx, types.IsLondon(ethCfg, ctx.BlockHeight()))
|
||||
}
|
||||
|
||||
func (k Keeper) getBaseFee(ctx sdk.Context, london bool) *big.Int {
|
||||
if !london {
|
||||
return nil
|
||||
}
|
||||
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
|
||||
|
||||
+33
-17
@@ -1,6 +1,7 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
@@ -14,20 +15,26 @@ import (
|
||||
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
||||
)
|
||||
|
||||
// DefaultPriorityReduction is the default amount of price values required for 1 unit of priority.
|
||||
// Because priority is `int64` while price is `big.Int`, it's necessary to scale down the range to keep it more pratical.
|
||||
// The default value is the same as the `sdk.DefaultPowerReduction`.
|
||||
var DefaultPriorityReduction = sdk.DefaultPowerReduction
|
||||
|
||||
// DeductTxCostsFromUserBalance it calculates the tx costs and deducts the fees
|
||||
// returns (effectiveFee, priority, error)
|
||||
func (k Keeper) DeductTxCostsFromUserBalance(
|
||||
ctx sdk.Context,
|
||||
msgEthTx evmtypes.MsgEthereumTx,
|
||||
txData evmtypes.TxData,
|
||||
denom string,
|
||||
homestead, istanbul, london bool,
|
||||
) (sdk.Coins, error) {
|
||||
) (fees sdk.Coins, priority int64, err error) {
|
||||
isContractCreation := txData.GetTo() == nil
|
||||
|
||||
// fetch sender account from signature
|
||||
signerAcc, err := authante.GetSignerAcc(ctx, k.accountKeeper, msgEthTx.GetFrom())
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
|
||||
return nil, 0, sdkerrors.Wrapf(err, "account not found for sender %s", msgEthTx.From)
|
||||
}
|
||||
|
||||
gasLimit := txData.GetGas()
|
||||
@@ -39,7 +46,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
|
||||
|
||||
intrinsicGas, err := core.IntrinsicGas(txData.GetData(), accessList, isContractCreation, homestead, istanbul)
|
||||
if err != nil {
|
||||
return nil, sdkerrors.Wrapf(
|
||||
return nil, 0, sdkerrors.Wrapf(
|
||||
err,
|
||||
"failed to retrieve intrinsic gas, contract creation = %t; homestead = %t, istanbul = %t",
|
||||
isContractCreation, homestead, istanbul,
|
||||
@@ -48,7 +55,7 @@ func (k Keeper) DeductTxCostsFromUserBalance(
|
||||
|
||||
// intrinsic gas verification during CheckTx
|
||||
if ctx.IsCheckTx() && gasLimit < intrinsicGas {
|
||||
return nil, sdkerrors.Wrapf(
|
||||
return nil, 0, sdkerrors.Wrapf(
|
||||
sdkerrors.ErrOutOfGas,
|
||||
"gas limit too low: %d (gas limit) < %d (intrinsic gas)", gasLimit, intrinsicGas,
|
||||
)
|
||||
@@ -56,33 +63,42 @@ func (k Keeper) DeductTxCostsFromUserBalance(
|
||||
|
||||
var feeAmt *big.Int
|
||||
|
||||
feeMktParams := k.feeMarketKeeper.GetParams(ctx)
|
||||
if london && feeMktParams.IsBaseFeeEnabled(ctx.BlockHeight()) && txData.TxType() == ethtypes.DynamicFeeTxType {
|
||||
baseFee := k.feeMarketKeeper.GetBaseFee(ctx)
|
||||
if txData.GetGasFeeCap().Cmp(baseFee) < 0 {
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ", txData.GetGasFeeCap(), baseFee)
|
||||
}
|
||||
feeAmt = txData.EffectiveFee(baseFee)
|
||||
} else {
|
||||
feeAmt = txData.Fee()
|
||||
baseFee := k.getBaseFee(ctx, london)
|
||||
if baseFee != nil && txData.GetGasFeeCap().Cmp(baseFee) < 0 {
|
||||
return nil, 0, sdkerrors.Wrapf(sdkerrors.ErrInsufficientFee, "the tx gasfeecap is lower than the tx baseFee: %s (gasfeecap), %s (basefee) ", txData.GetGasFeeCap(), baseFee)
|
||||
}
|
||||
|
||||
feeAmt = txData.EffectiveFee(baseFee)
|
||||
if feeAmt.Sign() == 0 {
|
||||
// zero fee, no need to deduct
|
||||
return sdk.Coins{}, nil
|
||||
return sdk.Coins{}, 0, nil
|
||||
}
|
||||
|
||||
fees := sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(feeAmt))}
|
||||
fees = sdk.Coins{sdk.NewCoin(denom, sdkmath.NewIntFromBigInt(feeAmt))}
|
||||
|
||||
// deduct the full gas cost from the user balance
|
||||
if err := authante.DeductFees(k.bankKeeper, ctx, signerAcc, fees); err != nil {
|
||||
return nil, sdkerrors.Wrapf(
|
||||
return nil, 0, sdkerrors.Wrapf(
|
||||
err,
|
||||
"failed to deduct full gas cost %s from the user %s balance",
|
||||
fees, msgEthTx.From,
|
||||
)
|
||||
}
|
||||
return fees, nil
|
||||
|
||||
// calculate priority based on effective gas price
|
||||
tipPrice := txData.EffectiveGasPrice(baseFee)
|
||||
// if london hardfork is not enabled, tipPrice is the gasPrice
|
||||
if baseFee != nil {
|
||||
tipPrice = new(big.Int).Sub(tipPrice, baseFee)
|
||||
}
|
||||
priorityBig := new(big.Int).Quo(tipPrice, DefaultPriorityReduction.BigInt())
|
||||
if !priorityBig.IsInt64() {
|
||||
priority = math.MaxInt64
|
||||
} else {
|
||||
priority = priorityBig.Int64()
|
||||
}
|
||||
|
||||
return fees, priority, nil
|
||||
}
|
||||
|
||||
// CheckSenderBalance validates that the tx cost value is positive and that the
|
||||
|
||||
@@ -403,7 +403,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
|
||||
txData, _ := evmtypes.UnpackTxData(tx.Data)
|
||||
|
||||
fees, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
|
||||
fees, priority, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
|
||||
suite.ctx,
|
||||
*tx,
|
||||
txData,
|
||||
@@ -424,6 +424,7 @@ func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
||||
),
|
||||
"valid test %d failed, fee value is wrong ", i,
|
||||
)
|
||||
suite.Require().Equal(int64(0), priority)
|
||||
} else {
|
||||
suite.Require().Equal(
|
||||
fees,
|
||||
|
||||
@@ -232,6 +232,11 @@ func (tx AccessListTx) Cost() *big.Int {
|
||||
return cost(tx.Fee(), tx.GetValue())
|
||||
}
|
||||
|
||||
// EffectiveGasPrice is the same as GasPrice for AccessListTx
|
||||
func (tx AccessListTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
|
||||
return tx.GetGasPrice()
|
||||
}
|
||||
|
||||
// EffectiveFee is the same as Fee for AccessListTx
|
||||
func (tx AccessListTx) EffectiveFee(baseFee *big.Int) *big.Int {
|
||||
return tx.Fee()
|
||||
|
||||
@@ -265,14 +265,14 @@ func (tx DynamicFeeTx) Cost() *big.Int {
|
||||
return cost(tx.Fee(), tx.GetValue())
|
||||
}
|
||||
|
||||
// GetEffectiveGasPrice returns the effective gas price
|
||||
func (tx *DynamicFeeTx) GetEffectiveGasPrice(baseFee *big.Int) *big.Int {
|
||||
// EffectiveGasPrice returns the effective gas price
|
||||
func (tx *DynamicFeeTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
|
||||
return math.BigMin(new(big.Int).Add(tx.GasTipCap.BigInt(), baseFee), tx.GasFeeCap.BigInt())
|
||||
}
|
||||
|
||||
// EffectiveFee returns effective_gasprice * gaslimit.
|
||||
func (tx DynamicFeeTx) EffectiveFee(baseFee *big.Int) *big.Int {
|
||||
return fee(tx.GetEffectiveGasPrice(baseFee), tx.GasLimit)
|
||||
return fee(tx.EffectiveGasPrice(baseFee), tx.GasLimit)
|
||||
}
|
||||
|
||||
// EffectiveCost returns amount + effective_gasprice * gaslimit.
|
||||
|
||||
@@ -201,6 +201,11 @@ func (tx LegacyTx) Cost() *big.Int {
|
||||
return cost(tx.Fee(), tx.GetValue())
|
||||
}
|
||||
|
||||
// EffectiveGasPrice is the same as GasPrice for LegacyTx
|
||||
func (tx LegacyTx) EffectiveGasPrice(baseFee *big.Int) *big.Int {
|
||||
return tx.GetGasPrice()
|
||||
}
|
||||
|
||||
// EffectiveFee is the same as Fee for LegacyTx
|
||||
func (tx LegacyTx) EffectiveFee(baseFee *big.Int) *big.Int {
|
||||
return tx.Fee()
|
||||
|
||||
@@ -41,7 +41,8 @@ type TxData interface {
|
||||
Fee() *big.Int
|
||||
Cost() *big.Int
|
||||
|
||||
// effective fee according to current base fee
|
||||
// effective gasPrice/fee/cost according to current base fee
|
||||
EffectiveGasPrice(baseFee *big.Int) *big.Int
|
||||
EffectiveFee(baseFee *big.Int) *big.Int
|
||||
EffectiveCost(baseFee *big.Int) *big.Int
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user