Skip to content

Commit

Permalink
imp(feemarket): update BaseFee based on GasWanted (#1105)
Browse files Browse the repository at this point in the history
* add gasWanted transient store keys

* add gasWanted transient store keeper functions

* add gasWanted transient store tracker

* add comment

* remove unncesary comment

* remove unnecesary function

* fix tests

* fix bad comment

* remove unnecesary comment

* update comment

* update changelog

* Update CHANGELOG.md

Co-authored-by: Federico Kunze Küllmer <[email protected]>

* add GasWantedDecorator

* remove unnecesary comments

* gasWanted decorator test

* fix tests

* fix tests and build

* fix lint

* updated end block event

* Update app/ante/fee_market.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

* fix undeclared variable

* Update app/ante/fee_market_test.go

* remove unnecesary line

* migrate MinGasMultiplier to FeeMarket module

* set limited gas wanted

* remove old newKeeper param

* update proto comment

* fix test

* update comments

* Update x/feemarket/keeper/abci.go

Co-authored-by: Federico Kunze Küllmer <[email protected]>

* address comments from review

* tidy

* tests

Co-authored-by: Federico Kunze Küllmer <[email protected]>
  • Loading branch information
mjtechworks and fedekunze committed Jun 5, 2022
1 parent e2c5875 commit f3bafbd
Show file tree
Hide file tree
Showing 46 changed files with 570 additions and 521 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Ref: https://keepachangelog.com/en/1.0.0/

## Unreleased

### State Machine Breaking

- (feemarket) [tharsis#1105](https://github.com/tharsis/ethermint/pull/1105) Update `BaseFee` calculation based on `GasWanted` instead of `GasUsed`.

### API Breaking

- (feemarket) [tharsis#1104](https://github.com/tharsis/ethermint/pull/1104) Enforce a minimum gas price for Cosmos and EVM transactions through the `MinGasPrice` parameter.
Expand Down
22 changes: 9 additions & 13 deletions app/ante/eth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,6 @@ import (
ethtypes "github.com/ethereum/go-ethereum/core/types"
)

func nextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}

func (suite AnteTestSuite) TestEthSigVerificationDecorator() {
dec := ante.NewEthSigVerificationDecorator(suite.app.EvmKeeper)
addr, privKey := tests.NewAddrKey()
Expand Down Expand Up @@ -46,7 +42,7 @@ func (suite AnteTestSuite) TestEthSigVerificationDecorator() {

for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down Expand Up @@ -134,7 +130,7 @@ func (suite AnteTestSuite) TestNewEthAccountVerificationDecorator() {
tc.malleate()
suite.Require().NoError(vmdb.Commit())

_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(tc.checkTx), tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down Expand Up @@ -190,7 +186,7 @@ func (suite AnteTestSuite) TestEthNonceVerificationDecorator() {
for _, tc := range testCases {
suite.Run(tc.name, func() {
tc.malleate()
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx.WithIsReCheckTx(tc.reCheckTx), tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down Expand Up @@ -287,12 +283,12 @@ func (suite AnteTestSuite) TestEthGasConsumeDecorator() {

if tc.expPanic {
suite.Require().Panics(func() {
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, nextFn)
_, _ = dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewGasMeter(1)), tc.tx, false, NextFn)
})
return
}

ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, nextFn)
ctx, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true).WithGasMeter(sdk.NewInfiniteGasMeter()), tc.tx, false, NextFn)
if tc.expPass {
suite.Require().NoError(err)
} else {
Expand Down Expand Up @@ -376,7 +372,7 @@ func (suite AnteTestSuite) TestCanTransferDecorator() {
tc.malleate()
suite.Require().NoError(vmdb.Commit())

_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx.WithIsCheckTx(true), tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down Expand Up @@ -455,12 +451,12 @@ func (suite AnteTestSuite) TestEthIncrementSenderSequenceDecorator() {

if tc.expPanic {
suite.Require().Panics(func() {
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, _ = dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)
})
return
}

_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down Expand Up @@ -497,7 +493,7 @@ func (suite AnteTestSuite) TestEthSetupContextDecorator() {

for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, nextFn)
_, err := dec.AnteHandle(suite.ctx, tc.tx, false, NextFn)

if tc.expPass {
suite.Require().NoError(err)
Expand Down
49 changes: 49 additions & 0 deletions app/ante/fee_market.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package ante

import (
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
)

// GasWantedDecorator keeps track of the gasWanted amount on the current block in transient store
// for BaseFee calculation.
// NOTE: This decorator does not perform any validation
type GasWantedDecorator struct {
evmKeeper EVMKeeper
feeMarketKeeper FeeMarketKeeper
}

// NewGasWantedDecorator creates a new NewGasWantedDecorator
func NewGasWantedDecorator(
evmKeeper EVMKeeper,
feeMarketKeeper FeeMarketKeeper,
) GasWantedDecorator {
return GasWantedDecorator{
evmKeeper,
feeMarketKeeper,
}
}

func (gwd GasWantedDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
params := gwd.evmKeeper.GetParams(ctx)
ethCfg := params.ChainConfig.EthereumConfig(gwd.evmKeeper.ChainID())

blockHeight := big.NewInt(ctx.BlockHeight())
london := ethCfg.IsLondon(blockHeight)

feeTx, ok := tx.(sdk.FeeTx)
if ok && london {
gasWanted := feeTx.GetGas()
feeMktParams := gwd.feeMarketKeeper.GetParams(ctx)
// Add total gasWanted to cumulative in block transientStore in FeeMarket module
if feeMktParams.IsBaseFeeEnabled(ctx.BlockHeight()) {
if _, err := gwd.feeMarketKeeper.AddTransientGasWanted(ctx, gasWanted); err != nil {
return ctx, sdkerrors.Wrapf(err, "failed to add gas wanted to transient store")
}
}
}

return next(ctx, tx, simulate)
}
94 changes: 94 additions & 0 deletions app/ante/fee_market_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package ante_test

import (
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/tharsis/ethermint/app/ante"
"github.com/tharsis/ethermint/tests"
evmtypes "github.com/tharsis/ethermint/x/evm/types"
)

func (suite AnteTestSuite) TestGasWantedDecorator() {
suite.enableFeemarket = true
suite.SetupTest()
dec := ante.NewGasWantedDecorator(suite.app.EvmKeeper, suite.app.FeeMarketKeeper)
from, fromPrivKey := tests.NewAddrKey()
to := tests.GenerateAddress()

testCases := []struct {
name string
expectedGasWanted uint64
malleate func() sdk.Tx
}{
{
"Cosmos Tx",
TestGasLimit,
func() sdk.Tx {
denom := evmtypes.DefaultEVMDenom
testMsg := banktypes.MsgSend{
FromAddress: "evmos1x8fhpj9nmhqk8z9kpgjt95ck2xwyue0ptzkucp",
ToAddress: "evmos1dx67l23hz9l0k9hcher8xz04uj7wf3yu26l2yn",
Amount: sdk.Coins{sdk.Coin{Amount: sdk.NewInt(10), Denom: denom}},
}
txBuilder := suite.CreateTestCosmosTxBuilder(sdk.NewInt(10), "stake", &testMsg)
return txBuilder.GetTx()
},
},
{
"Ethereum Legacy Tx",
TestGasLimit,
func() sdk.Tx {
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, nil)
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
},
},
{
"Ethereum Access List Tx",
TestGasLimit,
func() sdk.Tx {
emptyAccessList := ethtypes.AccessList{}
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), nil, nil, &emptyAccessList)
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
},
},
{
"Ethereum Dynamic Fee Tx (EIP1559)",
TestGasLimit,
func() sdk.Tx {
emptyAccessList := ethtypes.AccessList{}
msg := suite.BuildTestEthTx(from, to, nil, make([]byte, 0), big.NewInt(0), big.NewInt(100), big.NewInt(50), &emptyAccessList)
return suite.CreateTestTx(msg, fromPrivKey, 1, false)
},
},
{
"EIP712 message",
200000,
func() sdk.Tx {
amount := sdk.NewCoins(sdk.NewCoin(evmtypes.DefaultEVMDenom, sdk.NewInt(20)))
gas := uint64(200000)
acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, from.Bytes())
suite.Require().NoError(acc.SetSequence(1))
suite.app.AccountKeeper.SetAccount(suite.ctx, acc)
tx := suite.CreateTestEIP712TxBuilderMsgSend(acc.GetAddress(), fromPrivKey, suite.ctx.ChainID(), gas, amount)
return tx.GetTx()
},
},
}

// cumulative gas wanted from all test transactions in the same block
var expectedGasWanted uint64

for _, tc := range testCases {
suite.Run(tc.name, func() {
_, err := dec.AnteHandle(suite.ctx, tc.malleate(), false, NextFn)
suite.Require().NoError(err)

gasWanted := suite.app.FeeMarketKeeper.GetTransientGasWanted(suite.ctx)
expectedGasWanted += tc.expectedGasWanted
suite.Require().Equal(expectedGasWanted, gasWanted)
})
}
}
4 changes: 2 additions & 2 deletions app/ante/fees_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (s AnteTestSuite) TestMinGasPriceDecorator() {
// s.SetupTest(et.isCheckTx)
ctx := s.ctx.WithIsReCheckTx(et.isCheckTx)
dec := ante.NewMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
_, err := dec.AnteHandle(ctx, tc.malleate(), et.simulate, nextFn)
_, err := dec.AnteHandle(ctx, tc.malleate(), et.simulate, NextFn)

if tc.expPass {
s.Require().NoError(err, tc.name)
Expand Down Expand Up @@ -325,7 +325,7 @@ func (s AnteTestSuite) TestEthMinGasPriceDecorator() {
// s.SetupTest(et.isCheckTx)
s.SetupTest()
dec := ante.NewEthMinGasPriceDecorator(s.app.FeeMarketKeeper, s.app.EvmKeeper)
_, err := dec.AnteHandle(s.ctx, tc.malleate(), et.simulate, nextFn)
_, err := dec.AnteHandle(s.ctx, tc.malleate(), et.simulate, NextFn)

if tc.expPass {
s.Require().NoError(err, tc.name)
Expand Down
3 changes: 3 additions & 0 deletions app/ante/handler_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func newEthAnteHandler(options HandlerOptions) sdk.AnteHandler {
NewEthGasConsumeDecorator(options.EvmKeeper, options.MaxTxGasWanted),
NewEthIncrementSenderSequenceDecorator(options.AccountKeeper), // innermost AnteDecorator.
NewEthEmitEventDecorator(options.EvmKeeper), // emit eth tx hash and index at the very last ante handler.
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
)
}

Expand All @@ -81,6 +82,7 @@ func newCosmosAnteHandler(options HandlerOptions) sdk.AnteHandler {
ante.NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewAnteDecorator(options.IBCKeeper),
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
)
}

Expand All @@ -105,5 +107,6 @@ func newCosmosAnteHandlerEip712(options HandlerOptions) sdk.AnteHandler {
NewEip712SigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
ante.NewIncrementSequenceDecorator(options.AccountKeeper),
ibcante.NewAnteDecorator(options.IBCKeeper),
NewGasWantedDecorator(options.EvmKeeper, options.FeeMarketKeeper),
)
}
1 change: 1 addition & 0 deletions app/ante/interfaces.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ type protoTxProvider interface {
// FeeMarketKeeper defines the expected keeper interface used on the AnteHandler
type FeeMarketKeeper interface {
GetParams(ctx sdk.Context) (params feemarkettypes.Params)
AddTransientGasWanted(ctx sdk.Context, gasWanted uint64) (uint64, error)
}
15 changes: 10 additions & 5 deletions app/ante/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ type AnteTestSuite struct {
evmParamsOption func(*evmtypes.Params)
}

const TestGasLimit uint64 = 100000

func (suite *AnteTestSuite) StateDB() *statedb.StateDB {
return statedb.New(suite.ctx, suite.app.EvmKeeper, statedb.NewEmptyTxConfig(common.BytesToHash(suite.ctx.HeaderHash().Bytes())))
}
Expand Down Expand Up @@ -139,13 +141,13 @@ func (s *AnteTestSuite) BuildTestEthTx(
s.ctx,
common.BytesToAddress(from.Bytes()),
)
gasLimit := uint64(100000)

msgEthereumTx := evmtypes.NewTx(
chainID,
nonce,
&to,
amount,
gasLimit,
TestGasLimit,
gasPrice,
gasFeeCap,
gasTipCap,
Expand Down Expand Up @@ -237,11 +239,10 @@ func (suite *AnteTestSuite) CreateTestTxBuilder(
}

func (suite *AnteTestSuite) CreateTestCosmosTxBuilder(gasPrice sdk.Int, denom string, msgs ...sdk.Msg) client.TxBuilder {
gasLimit := uint64(1000000)
txBuilder := suite.clientCtx.TxConfig.NewTxBuilder()

txBuilder.SetGasLimit(gasLimit)
fees := &sdk.Coins{{Denom: denom, Amount: gasPrice.MulRaw(int64(gasLimit))}}
txBuilder.SetGasLimit(TestGasLimit)
fees := &sdk.Coins{{Denom: denom, Amount: gasPrice.MulRaw(int64(TestGasLimit))}}
txBuilder.SetFeeAmount(*fees)
err := txBuilder.SetMsgs(msgs...)
suite.Require().NoError(err)
Expand Down Expand Up @@ -330,6 +331,10 @@ func (suite *AnteTestSuite) CreateTestEIP712CosmosTxBuilder(
return builder
}

func NextFn(ctx sdk.Context, _ sdk.Tx, _ bool) (sdk.Context, error) {
return ctx, nil
}

var _ sdk.Tx = &invalidTx{}

type invalidTx struct{}
Expand Down
4 changes: 2 additions & 2 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ func NewEthermintApp(
)

// Add the EVM transient store key
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey)
tkeys := sdk.NewTransientStoreKeys(paramstypes.TStoreKey, evmtypes.TransientKey, feemarkettypes.TransientKey)
memKeys := sdk.NewMemoryStoreKeys(capabilitytypes.MemStoreKey)

app := &EthermintApp{
Expand Down Expand Up @@ -344,7 +344,7 @@ func NewEthermintApp(

// Create Ethermint keepers
app.FeeMarketKeeper = feemarketkeeper.NewKeeper(
appCodec, keys[feemarkettypes.StoreKey], app.GetSubspace(feemarkettypes.ModuleName),
appCodec, app.GetSubspace(feemarkettypes.ModuleName), keys[feemarkettypes.StoreKey], tkeys[feemarkettypes.TransientKey],
)

app.EvmKeeper = evmkeeper.NewKeeper(
Expand Down
4 changes: 2 additions & 2 deletions docs/api/proto-docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,6 @@ Params defines the EVM module parameters
| `enable_call` | [bool](#bool) | | enable call toggles state transitions that use the vm.Call function |
| `extra_eips` | [int64](#int64) | repeated | extra eips defines the additional EIPs for the vm.Config |
| `chain_config` | [ChainConfig](#ethermint.evm.v1.ChainConfig) | | chain config defines the EVM chain configuration parameters |
| `min_gas_multiplier` | [string](#string) | | min gas denominator bounds the minimum gasUsed to be charged to senders based on GasLimit |



Expand Down Expand Up @@ -955,6 +954,7 @@ Params defines the EVM module parameters
| `enable_height` | [int64](#int64) | | height at which the base fee calculation is enabled. |
| `base_fee` | [string](#string) | | base fee for EIP-1559 blocks. |
| `min_gas_price` | [string](#string) | | min_gas_price defines the minimum gas price value for cosmos and eth transactions |
| `min_gas_multiplier` | [string](#string) | | min gas denominator bounds the minimum gasUsed to be charged to senders based on GasLimit |



Expand Down Expand Up @@ -986,7 +986,7 @@ GenesisState defines the feemarket module's genesis state.
| Field | Type | Label | Description |
| ----- | ---- | ----- | ----------- |
| `params` | [Params](#ethermint.feemarket.v1.Params) | | params defines all the paramaters of the module. |
| `block_gas` | [uint64](#uint64) | | block gas is the amount of gas used on the last block before the upgrade. Zero by default. |
| `block_gas` | [uint64](#uint64) | | block gas is the amount of gas wanted on the last block before the upgrade. Zero by default. |



Expand Down
Loading

0 comments on commit f3bafbd

Please sign in to comment.