|
|
@ -14,7 +14,6 @@ |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; |
|
|
|
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; |
|
|
|
|
|
|
|
|
|
|
|
import static java.util.stream.Collectors.toUnmodifiableList; |
|
|
|
|
|
|
|
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; |
|
|
|
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; |
|
|
|
|
|
|
|
|
|
|
|
import org.hyperledger.besu.datatypes.Hash; |
|
|
|
import org.hyperledger.besu.datatypes.Hash; |
|
|
@ -32,6 +31,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.RpcErrorType; |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.FeeHistory; |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; |
|
|
|
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.ImmutableFeeHistory; |
|
|
|
|
|
|
|
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; |
|
|
|
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; |
|
|
|
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator; |
|
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain; |
|
|
|
import org.hyperledger.besu.ethereum.chain.Blockchain; |
|
|
|
import org.hyperledger.besu.ethereum.core.Block; |
|
|
|
import org.hyperledger.besu.ethereum.core.Block; |
|
|
@ -57,9 +57,11 @@ import com.github.benmanes.caffeine.cache.Cache; |
|
|
|
import com.github.benmanes.caffeine.cache.Caffeine; |
|
|
|
import com.github.benmanes.caffeine.cache.Caffeine; |
|
|
|
import com.google.common.annotations.VisibleForTesting; |
|
|
|
import com.google.common.annotations.VisibleForTesting; |
|
|
|
import com.google.common.collect.Streams; |
|
|
|
import com.google.common.collect.Streams; |
|
|
|
|
|
|
|
import org.apache.tuweni.units.bigints.UInt256s; |
|
|
|
|
|
|
|
|
|
|
|
public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
private final ProtocolSchedule protocolSchedule; |
|
|
|
private final ProtocolSchedule protocolSchedule; |
|
|
|
|
|
|
|
private final BlockchainQueries blockchainQueries; |
|
|
|
private final Blockchain blockchain; |
|
|
|
private final Blockchain blockchain; |
|
|
|
private final MiningCoordinator miningCoordinator; |
|
|
|
private final MiningCoordinator miningCoordinator; |
|
|
|
private final ApiConfiguration apiConfiguration; |
|
|
|
private final ApiConfiguration apiConfiguration; |
|
|
@ -70,13 +72,14 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
|
|
|
|
|
|
|
|
public EthFeeHistory( |
|
|
|
public EthFeeHistory( |
|
|
|
final ProtocolSchedule protocolSchedule, |
|
|
|
final ProtocolSchedule protocolSchedule, |
|
|
|
final Blockchain blockchain, |
|
|
|
final BlockchainQueries blockchainQueries, |
|
|
|
final MiningCoordinator miningCoordinator, |
|
|
|
final MiningCoordinator miningCoordinator, |
|
|
|
final ApiConfiguration apiConfiguration) { |
|
|
|
final ApiConfiguration apiConfiguration) { |
|
|
|
this.protocolSchedule = protocolSchedule; |
|
|
|
this.protocolSchedule = protocolSchedule; |
|
|
|
this.blockchain = blockchain; |
|
|
|
this.blockchainQueries = blockchainQueries; |
|
|
|
this.miningCoordinator = miningCoordinator; |
|
|
|
this.miningCoordinator = miningCoordinator; |
|
|
|
this.apiConfiguration = apiConfiguration; |
|
|
|
this.apiConfiguration = apiConfiguration; |
|
|
|
|
|
|
|
this.blockchain = blockchainQueries.getBlockchain(); |
|
|
|
this.cache = Caffeine.newBuilder().maximumSize(MAXIMUM_CACHE_SIZE).build(); |
|
|
|
this.cache = Caffeine.newBuilder().maximumSize(MAXIMUM_CACHE_SIZE).build(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -136,7 +139,8 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
final List<Double> gasUsedRatios = getGasUsedRatios(blockHeaderRange); |
|
|
|
final List<Double> gasUsedRatios = getGasUsedRatios(blockHeaderRange); |
|
|
|
final List<Double> blobGasUsedRatios = getBlobGasUsedRatios(blockHeaderRange); |
|
|
|
final List<Double> blobGasUsedRatios = getBlobGasUsedRatios(blockHeaderRange); |
|
|
|
final Optional<List<List<Wei>>> maybeRewards = |
|
|
|
final Optional<List<List<Wei>>> maybeRewards = |
|
|
|
maybeRewardPercentiles.map(rewards -> getRewards(rewards, blockHeaderRange)); |
|
|
|
maybeRewardPercentiles.map( |
|
|
|
|
|
|
|
percentiles -> getRewards(percentiles, blockHeaderRange, nextBaseFee)); |
|
|
|
return new JsonRpcSuccessResponse( |
|
|
|
return new JsonRpcSuccessResponse( |
|
|
|
requestId, |
|
|
|
requestId, |
|
|
|
createFeeHistoryResult( |
|
|
|
createFeeHistoryResult( |
|
|
@ -203,17 +207,19 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private List<List<Wei>> getRewards( |
|
|
|
private List<List<Wei>> getRewards( |
|
|
|
final List<Double> rewardPercentiles, final List<BlockHeader> blockHeaders) { |
|
|
|
final List<Double> rewardPercentiles, |
|
|
|
|
|
|
|
final List<BlockHeader> blockHeaders, |
|
|
|
|
|
|
|
final Wei nextBaseFee) { |
|
|
|
var sortedPercentiles = rewardPercentiles.stream().sorted().toList(); |
|
|
|
var sortedPercentiles = rewardPercentiles.stream().sorted().toList(); |
|
|
|
return blockHeaders.stream() |
|
|
|
return blockHeaders.stream() |
|
|
|
.parallel() |
|
|
|
.parallel() |
|
|
|
.map(blockHeader -> calculateBlockHeaderReward(sortedPercentiles, blockHeader)) |
|
|
|
.map(blockHeader -> calculateBlockHeaderReward(sortedPercentiles, blockHeader, nextBaseFee)) |
|
|
|
.flatMap(Optional::stream) |
|
|
|
.flatMap(Optional::stream) |
|
|
|
.toList(); |
|
|
|
.toList(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private Optional<List<Wei>> calculateBlockHeaderReward( |
|
|
|
private Optional<List<Wei>> calculateBlockHeaderReward( |
|
|
|
final List<Double> sortedPercentiles, final BlockHeader blockHeader) { |
|
|
|
final List<Double> sortedPercentiles, final BlockHeader blockHeader, final Wei nextBaseFee) { |
|
|
|
|
|
|
|
|
|
|
|
// Create a new key for the reward cache
|
|
|
|
// Create a new key for the reward cache
|
|
|
|
final RewardCacheKey key = new RewardCacheKey(blockHeader.getBlockHash(), sortedPercentiles); |
|
|
|
final RewardCacheKey key = new RewardCacheKey(blockHeader.getBlockHash(), sortedPercentiles); |
|
|
@ -226,7 +232,7 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
Optional<Block> block = blockchain.getBlockByHash(blockHeader.getBlockHash()); |
|
|
|
Optional<Block> block = blockchain.getBlockByHash(blockHeader.getBlockHash()); |
|
|
|
return block.map( |
|
|
|
return block.map( |
|
|
|
b -> { |
|
|
|
b -> { |
|
|
|
List<Wei> rewards = computeRewards(sortedPercentiles, b); |
|
|
|
List<Wei> rewards = computeRewards(sortedPercentiles, b, nextBaseFee); |
|
|
|
// Put the computed rewards in the cache for future use
|
|
|
|
// Put the computed rewards in the cache for future use
|
|
|
|
cache.put(key, rewards); |
|
|
|
cache.put(key, rewards); |
|
|
|
return rewards; |
|
|
|
return rewards; |
|
|
@ -237,7 +243,8 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
record TransactionInfo(Transaction transaction, Long gasUsed, Wei effectivePriorityFeePerGas) {} |
|
|
|
record TransactionInfo(Transaction transaction, Long gasUsed, Wei effectivePriorityFeePerGas) {} |
|
|
|
|
|
|
|
|
|
|
|
@VisibleForTesting |
|
|
|
@VisibleForTesting |
|
|
|
public List<Wei> computeRewards(final List<Double> rewardPercentiles, final Block block) { |
|
|
|
public List<Wei> computeRewards( |
|
|
|
|
|
|
|
final List<Double> rewardPercentiles, final Block block, final Wei nextBaseFee) { |
|
|
|
final List<Transaction> transactions = block.getBody().getTransactions(); |
|
|
|
final List<Transaction> transactions = block.getBody().getTransactions(); |
|
|
|
if (transactions.isEmpty()) { |
|
|
|
if (transactions.isEmpty()) { |
|
|
|
// all 0's for empty block
|
|
|
|
// all 0's for empty block
|
|
|
@ -253,7 +260,7 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
// If the priority fee boundary is set, return the bounded rewards. Otherwise, return the real
|
|
|
|
// If the priority fee boundary is set, return the bounded rewards. Otherwise, return the real
|
|
|
|
// rewards.
|
|
|
|
// rewards.
|
|
|
|
if (apiConfiguration.isGasAndPriorityFeeLimitingEnabled()) { |
|
|
|
if (apiConfiguration.isGasAndPriorityFeeLimitingEnabled()) { |
|
|
|
return boundRewards(realRewards); |
|
|
|
return boundRewards(realRewards, nextBaseFee); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
return realRewards; |
|
|
|
return realRewards; |
|
|
|
} |
|
|
|
} |
|
|
@ -292,16 +299,20 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
* This method returns a list of bounded rewards. |
|
|
|
* This method returns a list of bounded rewards. |
|
|
|
* |
|
|
|
* |
|
|
|
* @param rewards The list of rewards to be bounded. |
|
|
|
* @param rewards The list of rewards to be bounded. |
|
|
|
|
|
|
|
* @param nextBaseFee The base fee of the next block. |
|
|
|
* @return The list of bounded rewards. |
|
|
|
* @return The list of bounded rewards. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
private List<Wei> boundRewards(final List<Wei> rewards) { |
|
|
|
private List<Wei> boundRewards(final List<Wei> rewards, final Wei nextBaseFee) { |
|
|
|
Wei minPriorityFee = miningCoordinator.getMinPriorityFeePerGas(); |
|
|
|
final Wei lowerBoundGasPrice = blockchainQueries.gasPriceLowerBound(); |
|
|
|
Wei lowerBound = |
|
|
|
final Wei lowerBoundPriorityFee = lowerBoundGasPrice.subtract(nextBaseFee); |
|
|
|
minPriorityFee |
|
|
|
final Wei minPriorityFee = miningCoordinator.getMinPriorityFeePerGas(); |
|
|
|
|
|
|
|
final Wei forcedMinPriorityFee = UInt256s.max(minPriorityFee, lowerBoundPriorityFee); |
|
|
|
|
|
|
|
final Wei lowerBound = |
|
|
|
|
|
|
|
forcedMinPriorityFee |
|
|
|
.multiply(apiConfiguration.getLowerBoundGasAndPriorityFeeCoefficient()) |
|
|
|
.multiply(apiConfiguration.getLowerBoundGasAndPriorityFeeCoefficient()) |
|
|
|
.divide(100); |
|
|
|
.divide(100); |
|
|
|
Wei upperBound = |
|
|
|
final Wei upperBound = |
|
|
|
minPriorityFee |
|
|
|
forcedMinPriorityFee |
|
|
|
.multiply(apiConfiguration.getUpperBoundGasAndPriorityFeeCoefficient()) |
|
|
|
.multiply(apiConfiguration.getUpperBoundGasAndPriorityFeeCoefficient()) |
|
|
|
.divide(100); |
|
|
|
.divide(100); |
|
|
|
|
|
|
|
|
|
|
@ -438,7 +449,7 @@ public class EthFeeHistory implements JsonRpcMethod { |
|
|
|
.oldestBlock(oldestBlock) |
|
|
|
.oldestBlock(oldestBlock) |
|
|
|
.baseFeePerGas( |
|
|
|
.baseFeePerGas( |
|
|
|
Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee)) |
|
|
|
Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee)) |
|
|
|
.collect(toUnmodifiableList())) |
|
|
|
.toList()) |
|
|
|
.baseFeePerBlobGas(requestedBlobBaseFees) |
|
|
|
.baseFeePerBlobGas(requestedBlobBaseFees) |
|
|
|
.gasUsedRatio(gasUsedRatios) |
|
|
|
.gasUsedRatio(gasUsedRatios) |
|
|
|
.blobGasUsedRatio(blobGasUsedRatio) |
|
|
|
.blobGasUsedRatio(blobGasUsedRatio) |
|
|
|