From cd3b0be5edf616db302b3f838fdfd3ae8c24d84e Mon Sep 17 00:00:00 2001 From: Thomas Nguy <81727899+thomas-nguy@users.noreply.github.com> Date: Fri, 15 Oct 2021 17:59:26 +0900 Subject: [PATCH] rpc, feemarket: store base fee in event (#673) * store base fee in event * update changelog --- CHANGELOG.md | 1 + rpc/ethereum/backend/backend.go | 20 +++++++++-------- rpc/ethereum/namespaces/eth/filters/api.go | 12 ++++------- rpc/ethereum/types/utils.go | 25 ++++++++++++++++++++++ x/feemarket/keeper/abci.go | 12 ++++++++++- x/feemarket/keeper/eip1559.go | 7 +++--- x/feemarket/keeper/keeper.go | 4 ++-- x/feemarket/types/events.go | 8 +++++++ x/feemarket/types/params.go | 4 ++++ 9 files changed, 70 insertions(+), 23 deletions(-) create mode 100644 x/feemarket/types/events.go diff --git a/CHANGELOG.md b/CHANGELOG.md index c6329375..a8832269 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* (rpc, evm) [tharsis#673](https://github.com/tharsis/ethermint/pull/673) Use tendermint events to store fee market basefee. * (rpc) [tharsis#624](https://github.com/tharsis/ethermint/pull/624) Implement new JSON-RPC endpoints from latest geth version * (evm) [tharsis#662](https://github.com/tharsis/ethermint/pull/662) Disable basefee for non london blocks diff --git a/rpc/ethereum/backend/backend.go b/rpc/ethereum/backend/backend.go index e7edc2d3..3dfbaa00 100644 --- a/rpc/ethereum/backend/backend.go +++ b/rpc/ethereum/backend/backend.go @@ -826,22 +826,24 @@ func (e *EVMBackend) BaseFee(height int64) (*big.Int, error) { return nil, nil } - res, err := e.queryClient.FeeMarket.BaseFee(types.ContextWithHeight(height), &feemarkettypes.QueryBaseFeeRequest{}) + blockRes, err := e.clientCtx.Client.BlockResults(e.ctx, &height) if err != nil { return nil, err } - if res.BaseFee != nil { + baseFee := types.BaseFeeFromEvents(blockRes.EndBlockEvents) + if baseFee != nil { + return baseFee, nil + } + + // If we cannot find in events, we tried to get it from the state. + // It will return feemarket.baseFee if london is activated but feemarket is not enable + res, err := e.queryClient.FeeMarket.BaseFee(types.ContextWithHeight(height), &feemarkettypes.QueryBaseFeeRequest{}) + if err == nil && res.BaseFee != nil { return res.BaseFee.BigInt(), nil } - resParams, err := e.queryClient.FeeMarket.Params(types.ContextWithHeight(height), &feemarkettypes.QueryParamsRequest{}) - if err != nil { - return nil, err - } - - baseFee := big.NewInt(resParams.Params.InitialBaseFee) - return baseFee, nil + return nil, nil } // GetFilteredBlocks returns the block height list match the given bloom filters. diff --git a/rpc/ethereum/namespaces/eth/filters/api.go b/rpc/ethereum/namespaces/eth/filters/api.go index 2922b603..19303321 100644 --- a/rpc/ethereum/namespaces/eth/filters/api.go +++ b/rpc/ethereum/namespaces/eth/filters/api.go @@ -3,7 +3,6 @@ package filters import ( "context" "fmt" - "math/big" "sync" "time" @@ -18,7 +17,6 @@ import ( "github.com/ethereum/go-ethereum/common" ethtypes "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/eth/filters" - "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rpc" evmtypes "github.com/tharsis/ethermint/x/evm/types" @@ -239,9 +237,6 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { return rpc.ID(fmt.Sprintf("error creating block filter: %s", err.Error())) } - // TODO: use events to get the base fee amount - baseFee := big.NewInt(params.InitialBaseFee) - api.filters[headerSub.ID()] = &filter{typ: filters.BlocksSubscription, deadline: time.NewTimer(deadline), hashes: []common.Hash{}, s: headerSub} go func(headersCh <-chan coretypes.ResultEvent, errCh <-chan error) { @@ -263,6 +258,8 @@ func (api *PublicFilterAPI) NewBlockFilter() rpc.ID { continue } + baseFee := types.BaseFeeFromEvents(data.ResultEndBlock.Events) + header := types.EthHeaderFromTendermint(data.Header, baseFee) api.filtersMu.Lock() if f, found := api.filters[headerSub.ID()]; found { @@ -296,9 +293,6 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er return &rpc.Subscription{}, err } - // TODO: use events to get the base fee amount - baseFee := big.NewInt(params.InitialBaseFee) - go func(headersCh <-chan coretypes.ResultEvent) { defer cancelSubs() @@ -316,6 +310,8 @@ func (api *PublicFilterAPI) NewHeads(ctx context.Context) (*rpc.Subscription, er continue } + baseFee := types.BaseFeeFromEvents(data.ResultEndBlock.Events) + header := types.EthHeaderFromTendermint(data.Header, baseFee) err = notifier.Notify(rpcSub.ID, header) if err != nil { diff --git a/rpc/ethereum/types/utils.go b/rpc/ethereum/types/utils.go index c2ebd41d..7cbaf2fc 100644 --- a/rpc/ethereum/types/utils.go +++ b/rpc/ethereum/types/utils.go @@ -1,11 +1,15 @@ package types import ( + "bytes" "context" "encoding/hex" "fmt" "math/big" + abci "github.com/tendermint/tendermint/abci/types" + feemarkettypes "github.com/tharsis/ethermint/x/feemarket/types" + tmbytes "github.com/tendermint/tendermint/libs/bytes" tmtypes "github.com/tendermint/tendermint/types" @@ -244,3 +248,24 @@ func NewRPCTransaction( } return result, nil } + +// BaseFeeFromEvents parses the feemarket basefee from cosmos events +func BaseFeeFromEvents(events []abci.Event) *big.Int { + for _, event := range events { + if event.Type != feemarkettypes.EventTypeFeeMarket { + continue + } + + for _, attr := range event.Attributes { + if bytes.Equal(attr.Key, []byte(feemarkettypes.AttributeKeyBaseFee)) { + result, success := new(big.Int).SetString(string(attr.Value), 10) + if success { + return result + } + + return nil + } + } + } + return nil +} diff --git a/x/feemarket/keeper/abci.go b/x/feemarket/keeper/abci.go index 8c709072..8c99b6f2 100644 --- a/x/feemarket/keeper/abci.go +++ b/x/feemarket/keeper/abci.go @@ -4,6 +4,7 @@ import ( "fmt" abci "github.com/tendermint/tendermint/abci/types" + "github.com/tharsis/ethermint/x/feemarket/types" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -13,13 +14,22 @@ import ( // an empty slice. func (k *Keeper) EndBlock(ctx sdk.Context, req abci.RequestEndBlock) { baseFee := k.CalculateBaseFee(ctx) + + // return immediately if base fee is nil if baseFee == nil { return } - // only set base fee if the NoBaseFee param is false k.SetBaseFee(ctx, baseFee) + // Store current base fee in event + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + types.EventTypeFeeMarket, + sdk.NewAttribute(types.AttributeKeyBaseFee, baseFee.String()), + ), + }) + if ctx.BlockGasMeter() == nil { k.Logger(ctx).Error("block gas meter is nil when setting block gas used") return diff --git a/x/feemarket/keeper/eip1559.go b/x/feemarket/keeper/eip1559.go index 0ce9faef..68261c9b 100644 --- a/x/feemarket/keeper/eip1559.go +++ b/x/feemarket/keeper/eip1559.go @@ -10,20 +10,21 @@ import ( ) // CalculateBaseFee calculates the base fee for the current block. This is only calculated once per -// block during EndBlock. If the NoBaseFee parameter is enabled, this function returns nil. +// block during EndBlock. If the NoBaseFee parameter is enabled or below activation height, this function returns nil. // NOTE: This code is inspired from the go-ethereum EIP1559 implementation and adapted to Cosmos SDK-based // chains. For the canonical code refer to: https://github.com/ethereum/go-ethereum/blob/master/consensus/misc/eip1559.go func (k Keeper) CalculateBaseFee(ctx sdk.Context) *big.Int { params := k.GetParams(ctx) - if params.NoBaseFee { + // Ignore the calculation if not enable + if !params.IsBaseFeeEnabled(ctx.BlockHeight()) { return nil } consParams := ctx.ConsensusParams() // If the current block is the first EIP-1559 block, return the InitialBaseFee. - if ctx.BlockHeight() <= params.EnableHeight { + if ctx.BlockHeight() == params.EnableHeight { return new(big.Int).SetInt64(params.InitialBaseFee) } diff --git a/x/feemarket/keeper/keeper.go b/x/feemarket/keeper/keeper.go index 43d130b8..a01867f4 100644 --- a/x/feemarket/keeper/keeper.go +++ b/x/feemarket/keeper/keeper.go @@ -71,7 +71,7 @@ func (k Keeper) SetBlockGasUsed(ctx sdk.Context, gas uint64) { // Required by EIP1559 base fee calculation. // ---------------------------------------------------------------------------- -// GetBlockGasUsed returns the last block gas used value from the store. +// GetLastBaseFee returns the last base fee value from the store. func (k Keeper) GetBaseFee(ctx sdk.Context) *big.Int { store := ctx.KVStore(k.storeKey) bz := store.Get(types.KeyPrefixBaseFee) @@ -82,7 +82,7 @@ func (k Keeper) GetBaseFee(ctx sdk.Context) *big.Int { return new(big.Int).SetBytes(bz) } -// SetBlockGasUsed gets the current block gas consumed to the store. +// SetBaseFee set the last base fee value to the store. // CONTRACT: this should be only called during EndBlock. func (k Keeper) SetBaseFee(ctx sdk.Context, baseFee *big.Int) { store := ctx.KVStore(k.storeKey) diff --git a/x/feemarket/types/events.go b/x/feemarket/types/events.go new file mode 100644 index 00000000..e673e988 --- /dev/null +++ b/x/feemarket/types/events.go @@ -0,0 +1,8 @@ +package types + +// feemarket module events +const ( + EventTypeFeeMarket = "fee_market" + + AttributeKeyBaseFee = "base_fee" +) diff --git a/x/feemarket/types/params.go b/x/feemarket/types/params.go index 7ef53311..a6ff3f00 100644 --- a/x/feemarket/types/params.go +++ b/x/feemarket/types/params.go @@ -80,6 +80,10 @@ func (p Params) Validate() error { return nil } +func (p *Params) IsBaseFeeEnabled(height int64) bool { + return !p.NoBaseFee && height >= p.EnableHeight +} + func validateBool(i interface{}) error { _, ok := i.(bool) if !ok {