diff --git a/CHANGELOG.md b/CHANGELOG.md index f18f1a433d..dfcf2c1fcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Bug Fixes +* (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. * (rpc) [#1688](https://github.com/evmos/ethermint/pull/1688) Align filter rule for `debug_traceBlockByNumber` ### Improvements diff --git a/rpc/backend/chain_info.go b/rpc/backend/chain_info.go index 33954aa23a..abee63a461 100644 --- a/rpc/backend/chain_info.go +++ b/rpc/backend/chain_info.go @@ -146,41 +146,42 @@ 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 } 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) - } - blockStart := blockEnd - userBlockCountInt - if blockStart < 0 { - blockStart = 0 + if blocks > maxBlockCount { + return nil, fmt.Errorf("FeeHistory user block count %d higher than %d", blocks, maxBlockCount) } - blockCount := blockEnd - blockStart - + if blockEnd+1 < blocks { + blocks = blockEnd + 1 + } + // 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)) @@ -209,6 +210,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/utils.go b/rpc/backend/utils.go index 07c4a37614..a63f1dc285 100644 --- a/rpc/backend/utils.go +++ b/rpc/backend/utils.go @@ -15,6 +15,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" @@ -117,7 +118,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 9459cf8e73..df44e50d62 100644 --- a/rpc/types/types.go +++ b/rpc/types/types.go @@ -83,7 +83,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 0000000000..7dde9c187a --- /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 1039951a49..e376d2efd0 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)) }