1076307e6b
* test DynamicFeeTx against state_transition_benchmark_test * add feemarketGenesis in the app setup param * add dynamicTxFee flag to KeeperTestSuite * add feemarketGenesis.BaseFee setup * update TestAddLog * fix gasFeeCap assignment in newMsgEthereumTx * modify keeperTestSuite helper functions to support dynamicTxFee * update test cases in grpc_query_test w/ dynamicTxFee * update the evm keeper utils tests * add dynamic tx fee in the ante tests * remove duplicate type define * fix error return type * update changelog Co-authored-by: Federico Kunze Küllmer <31522760+fedekunze@users.noreply.github.com>
444 lines
12 KiB
Go
444 lines
12 KiB
Go
package keeper_test
|
|
|
|
import (
|
|
"math/big"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
|
"github.com/ethereum/go-ethereum/common"
|
|
cmath "github.com/ethereum/go-ethereum/common/math"
|
|
ethtypes "github.com/ethereum/go-ethereum/core/types"
|
|
ethparams "github.com/ethereum/go-ethereum/params"
|
|
evmkeeper "github.com/tharsis/ethermint/x/evm/keeper"
|
|
evmtypes "github.com/tharsis/ethermint/x/evm/types"
|
|
)
|
|
|
|
func (suite *KeeperTestSuite) TestCheckSenderBalance() {
|
|
hundredInt := sdk.NewInt(100)
|
|
zeroInt := sdk.ZeroInt()
|
|
oneInt := sdk.OneInt()
|
|
fiveInt := sdk.NewInt(5)
|
|
fiftyInt := sdk.NewInt(50)
|
|
negInt := sdk.NewInt(-10)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
to string
|
|
gasLimit uint64
|
|
gasPrice *sdk.Int
|
|
gasFeeCap *big.Int
|
|
gasTipCap *big.Int
|
|
cost *sdk.Int
|
|
from string
|
|
accessList *ethtypes.AccessList
|
|
expectPass bool
|
|
dynamicTxFee bool
|
|
}{
|
|
{
|
|
name: "Enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Equal balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 99,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "negative cost",
|
|
to: suite.address.String(),
|
|
gasLimit: 1,
|
|
gasPrice: &oneInt,
|
|
cost: &negInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
{
|
|
name: "Higher gas limit, not enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 100,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
{
|
|
name: "Higher gas price, enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasPrice: &fiveInt,
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Higher gas price, not enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 20,
|
|
gasPrice: &fiveInt,
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
{
|
|
name: "Higher cost, enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasPrice: &fiveInt,
|
|
cost: &fiftyInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Higher cost, not enough balance",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasPrice: &fiveInt,
|
|
cost: &hundredInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
{
|
|
name: "Enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(1),
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Equal balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 99,
|
|
gasFeeCap: big.NewInt(1),
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "negative cost w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 1,
|
|
gasFeeCap: big.NewInt(1),
|
|
cost: &negInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Higher gas limit, not enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 100,
|
|
gasFeeCap: big.NewInt(1),
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Higher gas price, enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(5),
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Higher gas price, not enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 20,
|
|
gasFeeCap: big.NewInt(5),
|
|
cost: &oneInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Higher cost, enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(5),
|
|
cost: &fiftyInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "Higher cost, not enough balance w/ dynamicTxFee",
|
|
to: suite.address.String(),
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(5),
|
|
cost: &hundredInt,
|
|
from: suite.address.String(),
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
}
|
|
|
|
suite.app.EvmKeeper.AddBalance(suite.address, hundredInt.BigInt())
|
|
balance := suite.app.EvmKeeper.GetBalance(suite.address)
|
|
suite.Require().Equal(balance, hundredInt.BigInt())
|
|
|
|
for i, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
to := common.HexToAddress(tc.from)
|
|
|
|
var amount, gasPrice, gasFeeCap, gasTipCap *big.Int
|
|
if tc.cost != nil {
|
|
amount = tc.cost.BigInt()
|
|
}
|
|
|
|
if tc.dynamicTxFee {
|
|
gasFeeCap = tc.gasFeeCap
|
|
if tc.gasTipCap == nil {
|
|
gasTipCap = oneInt.BigInt()
|
|
} else {
|
|
gasTipCap = tc.gasTipCap
|
|
}
|
|
} else {
|
|
if tc.gasPrice != nil {
|
|
gasPrice = tc.gasPrice.BigInt()
|
|
}
|
|
}
|
|
|
|
tx := evmtypes.NewTx(zeroInt.BigInt(), 1, &to, amount, tc.gasLimit, gasPrice, gasFeeCap, gasTipCap, nil, tc.accessList)
|
|
tx.From = tc.from
|
|
|
|
txData, _ := evmtypes.UnpackTxData(tx.Data)
|
|
|
|
err := evmkeeper.CheckSenderBalance(
|
|
suite.app.EvmKeeper.Ctx(),
|
|
suite.app.BankKeeper,
|
|
suite.address[:],
|
|
txData,
|
|
evmtypes.DefaultEVMDenom,
|
|
)
|
|
|
|
if tc.expectPass {
|
|
suite.Require().NoError(err, "valid test %d failed", i)
|
|
} else {
|
|
suite.Require().Error(err, "invalid test %d passed", i)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func (suite *KeeperTestSuite) TestDeductTxCostsFromUserBalance() {
|
|
hundredInt := sdk.NewInt(100)
|
|
zeroInt := sdk.ZeroInt()
|
|
oneInt := sdk.NewInt(1)
|
|
fiveInt := sdk.NewInt(5)
|
|
fiftyInt := sdk.NewInt(50)
|
|
hundredBaseFeeInt := sdk.NewInt(ethparams.InitialBaseFee * 100)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
gasLimit uint64
|
|
gasPrice *sdk.Int
|
|
gasFeeCap *big.Int
|
|
gasTipCap *big.Int
|
|
cost *sdk.Int
|
|
accessList *ethtypes.AccessList
|
|
expectPass bool
|
|
dynamicTxFee bool
|
|
}{
|
|
{
|
|
name: "Enough balance",
|
|
gasLimit: 10,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Equal balance",
|
|
gasLimit: 100,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Higher gas limit, not enough balance",
|
|
gasLimit: 105,
|
|
gasPrice: &oneInt,
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
{
|
|
name: "Higher gas price, enough balance",
|
|
gasLimit: 20,
|
|
gasPrice: &fiveInt,
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
{
|
|
name: "Higher gas price, not enough balance",
|
|
gasLimit: 20,
|
|
gasPrice: &fiftyInt,
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
},
|
|
// This case is expected to be true because the fees can be deducted, but the tx
|
|
// execution is going to fail because there is no more balance to pay the cost
|
|
{
|
|
name: "Higher cost, enough balance",
|
|
gasLimit: 100,
|
|
gasPrice: &oneInt,
|
|
cost: &fiftyInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
},
|
|
// testcases with dynamicTxFee enabled.
|
|
{
|
|
name: "Invalid gasFeeCap w/ dynamicTxFee",
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(1),
|
|
gasTipCap: big.NewInt(1),
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
// TODO: is this case valid?
|
|
{
|
|
name: "empty fee failed to deduct",
|
|
gasLimit: 10,
|
|
gasFeeCap: big.NewInt(ethparams.InitialBaseFee),
|
|
gasTipCap: big.NewInt(1),
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: false,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "effectiveTip equal to gasTipCap",
|
|
gasLimit: 100,
|
|
gasFeeCap: big.NewInt(ethparams.InitialBaseFee + 2),
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
{
|
|
name: "effectiveTip equal to (gasFeeCap - baseFee)",
|
|
gasLimit: 105,
|
|
gasFeeCap: big.NewInt(ethparams.InitialBaseFee + 1),
|
|
gasTipCap: big.NewInt(2),
|
|
cost: &oneInt,
|
|
accessList: ðtypes.AccessList{},
|
|
expectPass: true,
|
|
dynamicTxFee: true,
|
|
},
|
|
}
|
|
|
|
for i, tc := range testCases {
|
|
suite.Run(tc.name, func() {
|
|
suite.dynamicTxFee = tc.dynamicTxFee
|
|
suite.SetupTest()
|
|
|
|
var amount, gasPrice, gasFeeCap, gasTipCap *big.Int
|
|
if tc.cost != nil {
|
|
amount = tc.cost.BigInt()
|
|
}
|
|
|
|
if suite.dynamicTxFee {
|
|
if tc.gasFeeCap != nil {
|
|
gasFeeCap = tc.gasFeeCap
|
|
}
|
|
if tc.gasTipCap == nil {
|
|
gasTipCap = oneInt.BigInt()
|
|
} else {
|
|
gasTipCap = tc.gasTipCap
|
|
}
|
|
suite.app.EvmKeeper.AddBalance(suite.address, hundredBaseFeeInt.BigInt())
|
|
balance := suite.app.EvmKeeper.GetBalance(suite.address)
|
|
suite.Require().Equal(balance, hundredBaseFeeInt.BigInt())
|
|
} else {
|
|
if tc.gasPrice != nil {
|
|
gasPrice = tc.gasPrice.BigInt()
|
|
}
|
|
|
|
suite.app.EvmKeeper.AddBalance(suite.address, hundredInt.BigInt())
|
|
balance := suite.app.EvmKeeper.GetBalance(suite.address)
|
|
suite.Require().Equal(balance, hundredInt.BigInt())
|
|
}
|
|
|
|
tx := evmtypes.NewTx(zeroInt.BigInt(), 1, &suite.address, amount, tc.gasLimit, gasPrice, gasFeeCap, gasTipCap, nil, tc.accessList)
|
|
tx.From = suite.address.String()
|
|
|
|
txData, _ := evmtypes.UnpackTxData(tx.Data)
|
|
|
|
fees, err := suite.app.EvmKeeper.DeductTxCostsFromUserBalance(
|
|
suite.app.EvmKeeper.Ctx(),
|
|
*tx,
|
|
txData,
|
|
evmtypes.DefaultEVMDenom,
|
|
false,
|
|
false,
|
|
suite.dynamicTxFee, // london
|
|
)
|
|
|
|
if tc.expectPass {
|
|
suite.Require().NoError(err, "valid test %d failed", i)
|
|
if tc.dynamicTxFee {
|
|
baseFee := suite.app.FeeMarketKeeper.GetBaseFee(suite.ctx)
|
|
gasFeeGap := new(big.Int).Sub(txData.GetGasFeeCap(), baseFee)
|
|
effectiveTip := cmath.BigMin(txData.GetGasTipCap(), gasFeeGap)
|
|
|
|
suite.Require().Equal(
|
|
fees,
|
|
sdk.NewCoins(
|
|
sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewIntFromBigInt(effectiveTip).Mul(sdk.NewIntFromUint64(tc.gasLimit))),
|
|
),
|
|
"valid test %d failed, fee value is wrong ", i,
|
|
)
|
|
} else {
|
|
suite.Require().Equal(
|
|
fees,
|
|
sdk.NewCoins(
|
|
sdk.NewCoin(evmtypes.DefaultEVMDenom, tc.gasPrice.Mul(sdk.NewIntFromUint64(tc.gasLimit))),
|
|
),
|
|
"valid test %d failed, fee value is wrong ", i,
|
|
)
|
|
}
|
|
} else {
|
|
suite.Require().Error(err, "invalid test %d passed", i)
|
|
suite.Require().Nil(fees, "invalid test %d passed. fees value must be nil", i)
|
|
}
|
|
})
|
|
}
|
|
suite.dynamicTxFee = false // reset flag
|
|
}
|