diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ff16a00..eadf3227 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,7 +36,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ # Changelog -## [v0.21.0-rc2] - 2022-1-20 +## [v0.21.0-rc2] - 2022-01-20 ### State Machine Breaking @@ -54,6 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes * (rpc) [#1600](https://github.com/evmos/ethermint/pull/1600) Revert changes from `TypedEvents` * (rpc) [#1613](https://github.com/evmos/ethermint/pull/1613) Change the default json-rpc listen address to localhost. +* (rpc) [#1611](https://github.com/evmos/ethermint/pull/1611) Add missing next fee in fee history, fix wrong oldestBlock and align earliest input as ethereum. * (proto) [#1586](https://github.com/evmos/ethermint/pull/1586) Avoid duplicate register proto type in `evm` & `feemarket` ## [v0.20.0] - 2022-12-28 diff --git a/gomod2nix.toml b/gomod2nix.toml index 21e2192e..d384d891 100644 --- a/gomod2nix.toml +++ b/gomod2nix.toml @@ -361,8 +361,8 @@ schema = 3 version = "v2.7.0" hash = "sha256-BKqQKCsPA73FaQwYpAY+QsWFHIncrG5jgRhC2IiNmCk=" [mod."github.com/onsi/gomega"] - version = "v1.24.2" - hash = "sha256-iascSzzBT1Uv/XybezSblIwwrq78BU4a9BVB5MvK6MM=" + version = "v1.25.0" + hash = "sha256-knaJppfBzKSMD4Gsqzx22SGrti7G5UyDBYrothAqsrs=" [mod."github.com/pelletier/go-toml"] version = "v1.9.5" hash = "sha256-RJ9K1BTId0Mled7S66iGgxHkZ5JKEIsrrNaEfM8aImc=" diff --git a/rpc/backend/chain_info.go b/rpc/backend/chain_info.go index 732724bb..bd78e1d1 100644 --- a/rpc/backend/chain_info.go +++ b/rpc/backend/chain_info.go @@ -161,7 +161,7 @@ func (b *Backend) FeeHistory( ) (*rpctypes.FeeHistoryResult, error) { blockEnd := int64(lastBlock) - if blockEnd <= 0 { + if blockEnd < 0 { blockNumber, err := b.BlockNumber() if err != nil { return nil, err @@ -169,36 +169,34 @@ func (b *Backend) FeeHistory( blockEnd = int64(blockNumber) } - userBlockCountInt := int64(userBlockCount) + blocks := int64(userBlockCount) maxBlockCount := int64(b.cfg.JSONRPC.FeeHistoryCap) - if userBlockCountInt > maxBlockCount { - return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", userBlockCountInt, maxBlockCount) + if blocks > maxBlockCount { + return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", blocks, maxBlockCount) } - blockStart := blockEnd - userBlockCountInt - if blockStart < 0 { - blockStart = 0 + if blockEnd+1 < blocks { + blocks = blockEnd + 1 } - - blockCount := blockEnd - blockStart - + // Ensure not trying to retrieve before genesis. + blockStart := blockEnd + 1 - blocks oldestBlock := (*hexutil.Big)(big.NewInt(blockStart)) // prepare space - reward := make([][]*hexutil.Big, blockCount) + reward := make([][]*hexutil.Big, blocks) rewardCount := len(rewardPercentiles) - for i := 0; i < int(blockCount); i++ { + for i := 0; i < int(blocks); i++ { reward[i] = make([]*hexutil.Big, rewardCount) } - thisBaseFee := make([]*hexutil.Big, blockCount) - thisGasUsedRatio := make([]float64, blockCount) + thisBaseFee := make([]*hexutil.Big, blocks+1) + thisGasUsedRatio := make([]float64, blocks) // rewards should only be calculated if reward percentiles were included calculateRewards := rewardCount != 0 // fetch block - for blockID := blockStart; blockID < blockEnd; blockID++ { + for blockID := blockStart; blockID <= blockEnd; blockID++ { index := int32(blockID - blockStart) // tendermint block tendermintblock, err := b.TendermintBlockByNumber(rpctypes.BlockNumber(blockID)) @@ -227,6 +225,7 @@ func (b *Backend) FeeHistory( // copy thisBaseFee[index] = (*hexutil.Big)(oneFeeHistory.BaseFee) + thisBaseFee[index+1] = (*hexutil.Big)(oneFeeHistory.NextBaseFee) thisGasUsedRatio[index] = oneFeeHistory.GasUsedRatio if calculateRewards { for j := 0; j < rewardCount; j++ { diff --git a/rpc/backend/chain_info_test.go b/rpc/backend/chain_info_test.go index 1ce536db..6d67bfe5 100644 --- a/rpc/backend/chain_info_test.go +++ b/rpc/backend/chain_info_test.go @@ -337,7 +337,7 @@ func (suite *BackendTestSuite) TestFeeHistory() { RegisterParamsError(queryClient, &header, ethrpc.BlockNumber(1).Int64()) }, 1, - 0, + -1, nil, nil, false, @@ -351,7 +351,7 @@ func (suite *BackendTestSuite) TestFeeHistory() { RegisterParams(queryClient, &header, ethrpc.BlockNumber(1).Int64()) }, 1, - 0, + -1, nil, nil, false, @@ -405,6 +405,7 @@ func (suite *BackendTestSuite) TestFeeHistory() { { "pass - Valid FeeHistoryResults object", func(validator sdk.AccAddress) { + var header metadata.MD baseFee := sdk.NewInt(1) queryClient := suite.backend.queryClient.QueryClient.(*mocks.EVMQueryClient) client := suite.backend.clientCtx.Client.(*mocks.Client) @@ -414,12 +415,14 @@ func (suite *BackendTestSuite) TestFeeHistory() { RegisterBaseFee(queryClient, baseFee) RegisterValidatorAccount(queryClient, validator) RegisterConsensusParams(client, 1) + RegisterParams(queryClient, &header, 1) + RegisterParamsWithoutHeader(queryClient, 1) }, 1, 1, &rpc.FeeHistoryResult{ - OldestBlock: (*hexutil.Big)(big.NewInt(0)), - BaseFee: []*hexutil.Big{(*hexutil.Big)(big.NewInt(1))}, + OldestBlock: (*hexutil.Big)(big.NewInt(1)), + BaseFee: []*hexutil.Big{(*hexutil.Big)(big.NewInt(1)), (*hexutil.Big)(big.NewInt(1))}, GasUsedRatio: []float64{0}, Reward: [][]*hexutil.Big{{(*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0)), (*hexutil.Big)(big.NewInt(0))}}, }, diff --git a/rpc/backend/utils.go b/rpc/backend/utils.go index db6445ea..629747c8 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/consensus/misc" ethtypes "github.com/ethereum/go-ethereum/core/types" abci "github.com/tendermint/tendermint/abci/types" @@ -132,7 +133,12 @@ func (b *Backend) processBlock( // set basefee targetOneFeeHistory.BaseFee = blockBaseFee - + cfg := b.ChainConfig() + if cfg.IsLondon(big.NewInt(blockHeight + 1)) { + targetOneFeeHistory.NextBaseFee = misc.CalcBaseFee(cfg, b.CurrentHeader()) + } else { + targetOneFeeHistory.NextBaseFee = new(big.Int) + } // set gas used ratio gasLimitUint64, ok := (*ethBlock)["gasLimit"].(hexutil.Uint64) if !ok { diff --git a/rpc/types/types.go b/rpc/types/types.go index 4992057e..dba665e0 100644 --- a/rpc/types/types.go +++ b/rpc/types/types.go @@ -98,7 +98,7 @@ type SignTransactionResult struct { } type OneFeeHistory struct { - BaseFee *big.Int // base fee for each block - Reward []*big.Int // each element of the array will have the tip provided to miners for the percentile given - GasUsedRatio float64 // the ratio of gas used to the gas limit for each block + BaseFee, NextBaseFee *big.Int // base fee for each block + Reward []*big.Int // each element of the array will have the tip provided to miners for the percentile given + GasUsedRatio float64 // the ratio of gas used to the gas limit for each block } diff --git a/tests/integration_tests/test_fee_history.py b/tests/integration_tests/test_fee_history.py new file mode 100644 index 00000000..7dde9c18 --- /dev/null +++ b/tests/integration_tests/test_fee_history.py @@ -0,0 +1,73 @@ +from concurrent.futures import ThreadPoolExecutor, as_completed + +import pytest +from web3 import Web3 + +from .network import setup_ethermint +from .utils import ADDRS, send_transaction + + +@pytest.fixture(scope="module") +def custom_ethermint(tmp_path_factory): + path = tmp_path_factory.mktemp("fee-history") + yield from setup_ethermint(path, 26500, long_timeout_commit=True) + + +@pytest.fixture(scope="module", params=["ethermint", "geth"]) +def cluster(request, custom_ethermint, geth): + """ + run on both ethermint and geth + """ + provider = request.param + if provider == "ethermint": + yield custom_ethermint + elif provider == "geth": + yield geth + else: + raise NotImplementedError + + +def test_basic(cluster): + w3: Web3 = cluster.w3 + call = w3.provider.make_request + tx = {"to": ADDRS["community"], "value": 10, "gasPrice": w3.eth.gas_price} + send_transaction(w3, tx) + size = 4 + # size of base fee + next fee + max = size + 1 + # only 1 base fee + next fee + min = 2 + method = "eth_feeHistory" + field = "baseFeePerGas" + percentiles = [100] + height = w3.eth.block_number + latest = dict( + blocks=["latest", hex(height)], + expect=max, + ) + earliest = dict( + blocks=["earliest", "0x0"], + expect=min, + ) + for tc in [latest, earliest]: + res = [] + with ThreadPoolExecutor(len(tc["blocks"])) as exec: + tasks = [ + exec.submit(call, method, [size, b, percentiles]) for b in tc["blocks"] + ] + res = [future.result()["result"][field] for future in as_completed(tasks)] + assert len(res) == len(tc["blocks"]) + assert res[0] == res[1] + assert len(res[0]) == tc["expect"] + + for x in range(max): + i = x + 1 + fee_history = call(method, [size, hex(i), percentiles]) + # start to reduce diff on i <= size - min + diff = size - min - i + reduce = size - diff + target = reduce if diff >= 0 else max + res = fee_history["result"] + assert len(res[field]) == target + oldest = i + min - max + assert res["oldestBlock"] == hex(oldest if oldest > 0 else 0) diff --git a/tests/rpc/rpc_test.go b/tests/rpc/rpc_test.go index 1039951a..e376d2ef 100644 --- a/tests/rpc/rpc_test.go +++ b/tests/rpc/rpc_test.go @@ -595,8 +595,8 @@ func TestEth_FeeHistory(t *testing.T) { baseFeePerGas := info["baseFeePerGas"].([]interface{}) gasUsedRatio := info["gasUsedRatio"].([]interface{}) - require.Equal(t, info["oldestBlock"].(string), "0x6") + require.Equal(t, info["oldestBlock"].(string), "0x7") require.Equal(t, 4, len(gasUsedRatio)) - require.Equal(t, 4, len(baseFeePerGas)) + require.Equal(t, 5, len(baseFeePerGas)) require.Equal(t, 4, len(reward)) }