-
Notifications
You must be signed in to change notification settings - Fork 1.1k
eth_feeHistory #2432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Closed
Closed
eth_feeHistory #2432
Changes from all commits
Commits
Show all changes
39 commits
Select commit
Hold shift + click to select a range
62dd31f
beginning
RatanRSur ec78644
fee history class and other stuff
RatanRSur 27a79f1
get first 3 fields working
RatanRSur e250c30
add a bunch of stuff to the failing test
RatanRSur 22dd003
add headers
RatanRSur dedf4dc
spotless
RatanRSur b5a6470
get all fields test working
RatanRSur 3f7ac5f
0 for base fee
RatanRSur 97a147c
add extra base fee
RatanRSur 1470c40
update names to latest spec
RatanRSur 7f61250
test block count higher than chain head
RatanRSur 70fdcca
add test for all zeros
RatanRSur 15ce6b5
error on block too high
RatanRSur 8b3a7e0
spotless
RatanRSur 4a4a354
get rpc spec test wired up and failing
RatanRSur ad89e50
fix tests
RatanRSur d0051dc
spotless
RatanRSur 60b5184
sorting and comments
RatanRSur c55e7a9
remove redundant assignment
RatanRSur 760338f
fix transaction selector
RatanRSur b169d79
make test presume 1559
RatanRSur cfb06bc
fix range errors
RatanRSur 253259f
switch to Immutable
RatanRSur 7ba5890
add fork block stuff
RatanRSur 783ac54
spotless
RatanRSur 4c89cdf
Merge branch 'master' of github.com:hyperledger/besu into fee-history
RatanRSur 8aa77a6
test upper bound for block count
RatanRSur 4aa9cc5
cleanup
RatanRSur 07f5f71
Merge branch 'master' of github.com:hyperledger/besu into fee-history
RatanRSur ae2c951
fix reorg tests
RatanRSur 3afe531
Merge branch 'master' of github.com:hyperledger/besu into fee-history
RatanRSur cc96aad
fix tests
RatanRSur b07979c
fix epfpg calc
RatanRSur 89cdd45
fix lambda names
RatanRSur a65895d
remove unnecessary check
RatanRSur 47de7f9
changelog
RatanRSur ce02ef3
Merge branch 'master' into fee-history
garyschulte 7e31430
Merge branch 'master' of github.com:hyperledger/besu into fee-history
RatanRSur a098f81
update ref tests
RatanRSur File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
188 changes: 188 additions & 0 deletions
188
...c/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,188 @@ | ||
| /* | ||
| * Copyright ConsenSys AG. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
| * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations under the License. | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; | ||
|
|
||
| import static java.util.stream.Collectors.toUnmodifiableList; | ||
|
|
||
| import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameter; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; | ||
| import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistoryResult; | ||
| import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; | ||
| import org.hyperledger.besu.ethereum.chain.Blockchain; | ||
| import org.hyperledger.besu.ethereum.core.BlockHeader; | ||
| import org.hyperledger.besu.ethereum.core.Transaction; | ||
| import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.Arrays; | ||
| import java.util.Comparator; | ||
| import java.util.List; | ||
| import java.util.Optional; | ||
| import java.util.stream.LongStream; | ||
| import java.util.stream.Stream; | ||
|
|
||
| public class EthFeeHistory implements JsonRpcMethod { | ||
| private final ProtocolSchedule protocolSchedule; | ||
| private final BlockchainQueries blockchainQueries; | ||
| private final Blockchain blockchain; | ||
|
|
||
| public EthFeeHistory( | ||
| final ProtocolSchedule protocolSchedule, final BlockchainQueries blockchainQueries) { | ||
| this.protocolSchedule = protocolSchedule; | ||
| this.blockchainQueries = blockchainQueries; | ||
| this.blockchain = blockchainQueries.getBlockchain(); | ||
| } | ||
|
|
||
| @Override | ||
| public String getName() { | ||
| return RpcMethod.ETH_FEE_HISTORY.getMethodName(); | ||
| } | ||
|
|
||
| @Override | ||
| public JsonRpcResponse response(final JsonRpcRequestContext request) { | ||
| final Object requestId = request.getRequest().getId(); | ||
|
|
||
| final long blockCount = request.getRequiredParameter(0, Long.class); | ||
| if (blockCount < 1 || blockCount > 1024) { | ||
| return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS); | ||
| } | ||
| final BlockParameter highestBlock = request.getRequiredParameter(1, BlockParameter.class); | ||
| final Optional<List<Double>> maybeRewardPercentiles = | ||
| request.getOptionalParameter(2, Double[].class).map(Arrays::asList); | ||
|
|
||
| final long chainHeadBlockNumber = blockchain.getChainHeadBlockNumber(); | ||
| final long resolvedHighestBlockNumber = | ||
| highestBlock | ||
| .getNumber() | ||
| .orElse( | ||
| chainHeadBlockNumber /* both latest and pending use the head block until we have pending block support */); | ||
|
|
||
| if (resolvedHighestBlockNumber > chainHeadBlockNumber) { | ||
| return new JsonRpcErrorResponse(requestId, JsonRpcError.INVALID_PARAMS); | ||
| } | ||
|
|
||
| final long oldestBlock = Math.max(0, resolvedHighestBlockNumber - (blockCount - 1)); | ||
|
|
||
| final List<BlockHeader> blockHeaders = | ||
| LongStream.range(oldestBlock, oldestBlock + blockCount) | ||
|
garyschulte marked this conversation as resolved.
|
||
| .mapToObj(blockchain::getBlockHeader) | ||
| .flatMap(Optional::stream) | ||
| .collect(toUnmodifiableList()); | ||
|
|
||
| // we return the base fees for the blocks requested and 1 more because we can always compute it | ||
| final List<Long> explicitlyRequestedBaseFees = | ||
| blockHeaders.stream() | ||
| .map(blockHeader -> blockHeader.getBaseFee().orElse(0L)) | ||
| .collect(toUnmodifiableList()); | ||
| final long nextBlockNumber = resolvedHighestBlockNumber + 1; | ||
| final Long nextBaseFee = | ||
| blockchain | ||
| .getBlockHeader(nextBlockNumber) | ||
| .map(blockHeader -> blockHeader.getBaseFee().orElse(0L)) | ||
| .orElseGet( | ||
| () -> | ||
| protocolSchedule | ||
| .getByBlockNumber(nextBlockNumber) | ||
| .getEip1559() | ||
| .map( | ||
| eip1559 -> { | ||
| final BlockHeader lastBlockHeader = | ||
| blockHeaders.get(blockHeaders.size() - 1); | ||
|
garyschulte marked this conversation as resolved.
|
||
| return eip1559.computeBaseFee( | ||
| nextBlockNumber, | ||
| explicitlyRequestedBaseFees.get( | ||
| explicitlyRequestedBaseFees.size() - 1), | ||
| lastBlockHeader.getGasUsed(), | ||
| eip1559.targetGasUsed(lastBlockHeader)); | ||
| }) | ||
| .orElse(0L)); | ||
|
|
||
| final List<Double> gasUsedRatios = | ||
| blockHeaders.stream() | ||
| .map(blockHeader -> blockHeader.getGasUsed() / (double) blockHeader.getGasLimit()) | ||
| .collect(toUnmodifiableList()); | ||
|
|
||
| final Optional<List<List<Long>>> maybeRewards = | ||
| maybeRewardPercentiles.map( | ||
| rewardPercentiles -> | ||
| LongStream.range(oldestBlock, oldestBlock + blockCount) | ||
| .mapToObj(blockchain::getBlockByNumber) | ||
| .flatMap(Optional::stream) | ||
|
garyschulte marked this conversation as resolved.
|
||
| .map( | ||
| block -> | ||
| computeRewards( | ||
| rewardPercentiles.stream().sorted().collect(toUnmodifiableList()), | ||
| block)) | ||
| .collect(toUnmodifiableList())); | ||
|
|
||
| final ImmutableFeeHistoryResult.Builder feeHistoryResultBuilder = | ||
| ImmutableFeeHistoryResult.builder() | ||
| .oldestBlock(oldestBlock) | ||
| .baseFeePerGas( | ||
| Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee)) | ||
| .collect(toUnmodifiableList())) | ||
| .gasUsedRatio(gasUsedRatios); | ||
| maybeRewards.ifPresent(feeHistoryResultBuilder::reward); | ||
| return new JsonRpcSuccessResponse(requestId, feeHistoryResultBuilder.build()); | ||
| } | ||
|
|
||
| private List<Long> computeRewards( | ||
| final List<Double> rewardPercentiles, final org.hyperledger.besu.ethereum.core.Block block) { | ||
| final List<Transaction> transactions = block.getBody().getTransactions(); | ||
| if (transactions.isEmpty()) { | ||
| // all 0's for empty block | ||
| return LongStream.generate(() -> 0) | ||
| .limit(rewardPercentiles.size()) | ||
| .boxed() | ||
| .collect(toUnmodifiableList()); | ||
| } | ||
|
|
||
| final Optional<Long> baseFee = block.getHeader().getBaseFee(); | ||
| final List<Transaction> transactionsAscendingEffectiveGasFee = | ||
| transactions.stream() | ||
| .sorted( | ||
| Comparator.comparing( | ||
| transaction -> transaction.getEffectivePriorityFeePerGas(baseFee))) | ||
| .collect(toUnmodifiableList()); | ||
|
|
||
| // We need to weight the percentile of rewards by the gas used in the transaction. | ||
| // That's why we're keeping track of the cumulative gas used and checking to see which | ||
| // percentile markers we've passed | ||
|
garyschulte marked this conversation as resolved.
|
||
| final ArrayList<Long> rewards = new ArrayList<>(); | ||
| int rewardPercentileIndex = 0; | ||
| long gasUsed = 0; | ||
| for (final Transaction transaction : transactionsAscendingEffectiveGasFee) { | ||
|
|
||
| gasUsed += | ||
| blockchainQueries | ||
| .transactionReceiptByTransactionHash(transaction.getHash()) | ||
| .get() | ||
| .getGasUsed(); | ||
|
|
||
| while (rewardPercentileIndex < rewardPercentiles.size() | ||
| && 100.0 * gasUsed / block.getHeader().getGasUsed() | ||
| >= rewardPercentiles.get(rewardPercentileIndex)) { | ||
| rewards.add(transaction.getEffectivePriorityFeePerGas(baseFee)); | ||
| rewardPercentileIndex++; | ||
| } | ||
| } | ||
| return rewards; | ||
| } | ||
| } | ||
40 changes: 40 additions & 0 deletions
40
...ain/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/FeeHistoryResult.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| /* | ||
| * Copyright ConsenSys AG. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with | ||
| * the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on | ||
| * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations under the License. | ||
| * | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
| package org.hyperledger.besu.ethereum.api.jsonrpc.internal.results; | ||
|
|
||
| import java.util.List; | ||
| import javax.annotation.Nullable; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonInclude; | ||
| import com.fasterxml.jackson.annotation.JsonProperty; | ||
| import org.immutables.value.Value; | ||
|
|
||
| @Value.Immutable | ||
| @JsonInclude(JsonInclude.Include.NON_NULL) | ||
| public interface FeeHistoryResult { | ||
|
|
||
| @JsonProperty("oldestBlock") | ||
| long getOldestBlock(); | ||
|
|
||
| @JsonProperty("baseFeePerGas") | ||
| List<Long> getBaseFeePerGas(); | ||
|
|
||
| @JsonProperty("gasUsedRatio") | ||
| List<Double> getGasUsedRatio(); | ||
|
|
||
| @Nullable | ||
| @JsonProperty("reward") | ||
| List<List<Long>> getReward(); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.