mirror of
https://github.com/vacp2p/linea-besu.git
synced 2026-01-09 15:37:54 -05:00
Include current chain head block when computing eth_maxPriorityFeePerGas (#7485)
Signed-off-by: Fabio Di Fabio <fabio.difabio@consensys.net>
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
### Breaking Changes
|
||||
|
||||
### Additions and Improvements
|
||||
- Include current chain head block when computing `eth_maxPriorityFeePerGas` [#7485](https://github.com/hyperledger/besu/pull/7485)
|
||||
|
||||
### Bug fixes
|
||||
|
||||
|
||||
@@ -203,7 +203,7 @@ public class GraphQLDataFetchers {
|
||||
*
|
||||
* <p>The DataFetcher is a functional interface. It has a single method that takes a
|
||||
* DataFetchingEnvironment object as input and returns the maximum priority fee per gas as a Wei
|
||||
* object. If the maximum priority fee per gas is not available, it returns Wei.ZERO.
|
||||
* object.
|
||||
*
|
||||
* @return a DataFetcher that fetches the maximum priority fee per gas of the Ethereum node
|
||||
*/
|
||||
@@ -211,7 +211,7 @@ public class GraphQLDataFetchers {
|
||||
return dataFetchingEnvironment -> {
|
||||
final BlockchainQueries blockchainQuery =
|
||||
dataFetchingEnvironment.getGraphQlContext().get(GraphQLContextType.BLOCKCHAIN_QUERIES);
|
||||
return blockchainQuery.gasPriorityFee().orElse(Wei.ZERO);
|
||||
return blockchainQuery.gasPriorityFee();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -21,19 +21,13 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcRespon
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
|
||||
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class EthMaxPriorityFeePerGas implements JsonRpcMethod {
|
||||
|
||||
private final BlockchainQueries blockchainQueries;
|
||||
private final MiningCoordinator miningCoordinator;
|
||||
|
||||
public EthMaxPriorityFeePerGas(
|
||||
final BlockchainQueries blockchainQueries, final MiningCoordinator miningCoordinator) {
|
||||
public EthMaxPriorityFeePerGas(final BlockchainQueries blockchainQueries) {
|
||||
this.blockchainQueries = blockchainQueries;
|
||||
this.miningCoordinator = miningCoordinator;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -48,7 +42,6 @@ public class EthMaxPriorityFeePerGas implements JsonRpcMethod {
|
||||
}
|
||||
|
||||
private Wei fetchAndLimitPriorityFeePerGas() {
|
||||
final Optional<Wei> gasPrice = blockchainQueries.gasPriorityFee();
|
||||
return gasPrice.orElseGet(miningCoordinator::getMinPriorityFeePerGas);
|
||||
return blockchainQueries.gasPriorityFee();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,6 +185,6 @@ public class EthJsonRpcMethods extends ApiGroupJsonRpcMethods {
|
||||
new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule),
|
||||
new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule),
|
||||
new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule),
|
||||
new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator));
|
||||
new EthMaxPriorityFeePerGas(blockchainQueries));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ import org.hyperledger.besu.evm.log.LogsBloomFilter;
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
@@ -1006,7 +1005,7 @@ public class BlockchainQueries {
|
||||
.sorted()
|
||||
.toArray(Wei[]::new);
|
||||
|
||||
return (gasCollection == null || gasCollection.length == 0)
|
||||
return gasCollection.length == 0
|
||||
? gasPriceLowerBound(chainHeadHeader, nextBlockFeeMarket)
|
||||
: UInt256s.max(
|
||||
gasPriceLowerBound(chainHeadHeader, nextBlockFeeMarket),
|
||||
@@ -1045,31 +1044,39 @@ public class BlockchainQueries {
|
||||
return minGasPrice;
|
||||
}
|
||||
|
||||
public Optional<Wei> gasPriorityFee() {
|
||||
final long blockHeight = headBlockNumber();
|
||||
final BigInteger[] gasCollection =
|
||||
LongStream.range(Math.max(0, blockHeight - apiConfig.getGasPriceBlocks()), blockHeight)
|
||||
.mapToObj(
|
||||
l ->
|
||||
blockchain
|
||||
.getBlockByNumber(l)
|
||||
.map(Block::getBody)
|
||||
.map(BlockBody::getTransactions)
|
||||
.orElseThrow(
|
||||
() -> new IllegalStateException("Could not retrieve block #" + l)))
|
||||
public Wei gasPriorityFee() {
|
||||
final Block chainHeadBlock = blockchain.getChainHeadBlock();
|
||||
final long blockHeight = chainHeadBlock.getHeader().getNumber();
|
||||
|
||||
final Wei[] gasCollection =
|
||||
Stream.concat(
|
||||
LongStream.range(
|
||||
Math.max(0, blockHeight - apiConfig.getGasPriceBlocks() + 1), blockHeight)
|
||||
.mapToObj(
|
||||
l ->
|
||||
blockchain
|
||||
.getBlockByNumber(l)
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalStateException(
|
||||
"Could not retrieve block #" + l))),
|
||||
Stream.of(chainHeadBlock))
|
||||
.map(Block::getBody)
|
||||
.map(BlockBody::getTransactions)
|
||||
.flatMap(Collection::stream)
|
||||
.filter(t -> t.getMaxPriorityFeePerGas().isPresent())
|
||||
.map(t -> t.getMaxPriorityFeePerGas().get().toBigInteger())
|
||||
.sorted(BigInteger::compareTo)
|
||||
.toArray(BigInteger[]::new);
|
||||
return (gasCollection.length == 0)
|
||||
? Optional.empty()
|
||||
: Optional.of(
|
||||
Wei.of(
|
||||
gasCollection[
|
||||
Math.min(
|
||||
gasCollection.length - 1,
|
||||
(int) ((gasCollection.length) * apiConfig.getGasPriceFraction()))]));
|
||||
.map(t -> t.getMaxPriorityFeePerGas().get())
|
||||
.sorted()
|
||||
.toArray(Wei[]::new);
|
||||
|
||||
return gasCollection.length == 0
|
||||
? miningParameters.getMinPriorityFeePerGas()
|
||||
: UInt256s.max(
|
||||
miningParameters.getMinPriorityFeePerGas(),
|
||||
gasCollection[
|
||||
Math.min(
|
||||
gasCollection.length - 1,
|
||||
(int) ((gasCollection.length) * apiConfig.getGasPriceFraction()))]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.api.graphql;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
|
||||
import org.hyperledger.besu.ethereum.core.Synchronizer;
|
||||
@@ -38,7 +42,6 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class GraphQLHttpServiceCorsTest {
|
||||
@TempDir private Path folder;
|
||||
@@ -208,10 +211,11 @@ public class GraphQLHttpServiceCorsTest {
|
||||
config.setCorsAllowedDomains(Lists.newArrayList(corsAllowedDomains));
|
||||
}
|
||||
|
||||
final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class);
|
||||
final Synchronizer synchronizer = Mockito.mock(Synchronizer.class);
|
||||
final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
|
||||
when(blockchainQueries.gasPriorityFee()).thenReturn(Wei.ONE);
|
||||
final Synchronizer synchronizer = mock(Synchronizer.class);
|
||||
|
||||
final PoWMiningCoordinator miningCoordinatorMock = Mockito.mock(PoWMiningCoordinator.class);
|
||||
final PoWMiningCoordinator miningCoordinatorMock = mock(PoWMiningCoordinator.class);
|
||||
|
||||
// mock graphql context
|
||||
final Map<GraphQLContextType, Object> graphQLContextMap =
|
||||
@@ -219,7 +223,7 @@ public class GraphQLHttpServiceCorsTest {
|
||||
GraphQLContextType.BLOCKCHAIN_QUERIES,
|
||||
blockchainQueries,
|
||||
GraphQLContextType.TRANSACTION_POOL,
|
||||
Mockito.mock(TransactionPool.class),
|
||||
mock(TransactionPool.class),
|
||||
GraphQLContextType.MINING_COORDINATOR,
|
||||
miningCoordinatorMock,
|
||||
GraphQLContextType.SYNCHRONIZER,
|
||||
@@ -233,7 +237,7 @@ public class GraphQLHttpServiceCorsTest {
|
||||
|
||||
final GraphQLHttpService graphQLHttpService =
|
||||
new GraphQLHttpService(
|
||||
vertx, folder, config, graphQL, graphQLContextMap, Mockito.mock(EthScheduler.class));
|
||||
vertx, folder, config, graphQL, graphQLContextMap, mock(EthScheduler.class));
|
||||
graphQLHttpService.start().join();
|
||||
|
||||
return graphQLHttpService;
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
*/
|
||||
package org.hyperledger.besu.ethereum.api.graphql;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
|
||||
import org.hyperledger.besu.ethereum.core.Synchronizer;
|
||||
@@ -42,7 +46,6 @@ import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
public class GraphQLHttpServiceHostWhitelistTest {
|
||||
|
||||
@@ -69,17 +72,18 @@ public class GraphQLHttpServiceHostWhitelistTest {
|
||||
}
|
||||
|
||||
private GraphQLHttpService createGraphQLHttpService() throws Exception {
|
||||
final BlockchainQueries blockchainQueries = Mockito.mock(BlockchainQueries.class);
|
||||
final Synchronizer synchronizer = Mockito.mock(Synchronizer.class);
|
||||
final BlockchainQueries blockchainQueries = mock(BlockchainQueries.class);
|
||||
when(blockchainQueries.gasPriorityFee()).thenReturn(Wei.ONE);
|
||||
final Synchronizer synchronizer = mock(Synchronizer.class);
|
||||
|
||||
final PoWMiningCoordinator miningCoordinatorMock = Mockito.mock(PoWMiningCoordinator.class);
|
||||
final PoWMiningCoordinator miningCoordinatorMock = mock(PoWMiningCoordinator.class);
|
||||
|
||||
final Map<GraphQLContextType, Object> graphQLContextMap =
|
||||
Map.of(
|
||||
GraphQLContextType.BLOCKCHAIN_QUERIES,
|
||||
blockchainQueries,
|
||||
GraphQLContextType.TRANSACTION_POOL,
|
||||
Mockito.mock(TransactionPool.class),
|
||||
mock(TransactionPool.class),
|
||||
GraphQLContextType.MINING_COORDINATOR,
|
||||
miningCoordinatorMock,
|
||||
GraphQLContextType.SYNCHRONIZER,
|
||||
@@ -92,7 +96,7 @@ public class GraphQLHttpServiceHostWhitelistTest {
|
||||
final GraphQL graphQL = GraphQLProvider.buildGraphQL(dataFetchers);
|
||||
|
||||
return new GraphQLHttpService(
|
||||
vertx, folder, graphQLConfig, graphQL, graphQLContextMap, Mockito.mock(EthScheduler.class));
|
||||
vertx, folder, graphQLConfig, graphQL, graphQLContextMap, mock(EthScheduler.class));
|
||||
}
|
||||
|
||||
private static GraphQLConfiguration createGraphQLConfig() {
|
||||
|
||||
@@ -328,7 +328,7 @@ public class EthGasPriceTest {
|
||||
}
|
||||
|
||||
when(blockchain.getChainHeadBlock()).thenReturn(blocksByNumber.get(chainHeadBlockNumber));
|
||||
if (chainHeadBlockNumber > 1) {
|
||||
if (chainHeadBlockNumber > 0) {
|
||||
when(blockchain.getBlockByNumber(anyLong()))
|
||||
.thenAnswer(
|
||||
invocation -> Optional.of(blocksByNumber.get(invocation.getArgument(0, Long.class))));
|
||||
|
||||
@@ -15,29 +15,43 @@
|
||||
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.ArgumentMatchers.anyLong;
|
||||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import org.hyperledger.besu.datatypes.Address;
|
||||
import org.hyperledger.besu.datatypes.Hash;
|
||||
import org.hyperledger.besu.datatypes.TransactionType;
|
||||
import org.hyperledger.besu.datatypes.Wei;
|
||||
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
|
||||
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
|
||||
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.query.BlockchainQueries;
|
||||
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
|
||||
import org.hyperledger.besu.ethereum.chain.Blockchain;
|
||||
import org.hyperledger.besu.ethereum.core.Block;
|
||||
import org.hyperledger.besu.ethereum.core.BlockBody;
|
||||
import org.hyperledger.besu.ethereum.core.BlockHeader;
|
||||
import org.hyperledger.besu.ethereum.core.Difficulty;
|
||||
import org.hyperledger.besu.ethereum.core.MiningParameters;
|
||||
import org.hyperledger.besu.ethereum.core.Transaction;
|
||||
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
|
||||
import org.hyperledger.besu.ethereum.mainnet.feemarket.CancunFeeMarket;
|
||||
import org.hyperledger.besu.evm.log.LogsBloomFilter;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import org.apache.tuweni.bytes.Bytes;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.internal.verification.VerificationModeFactory;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
@@ -45,13 +59,20 @@ public class EthMaxPriorityFeePerGasTest {
|
||||
private static final String JSON_RPC_VERSION = "2.0";
|
||||
private static final String ETH_METHOD =
|
||||
RpcMethod.ETH_GET_MAX_PRIORITY_FEE_PER_GAS.getMethodName();
|
||||
private EthMaxPriorityFeePerGas method;
|
||||
private static final Wei DEFAULT_MIN_PRIORITY_FEE_PER_GAS = Wei.ZERO;
|
||||
private static final long DEFAULT_BLOCK_GAS_LIMIT = 100_000;
|
||||
private static final long DEFAULT_BLOCK_GAS_USED = 21_000;
|
||||
private static final Wei DEFAULT_BASE_FEE = Wei.of(100_000);
|
||||
|
||||
@Mock private BlockchainQueries blockchainQueries;
|
||||
@Mock private MiningCoordinator miningCoordinator;
|
||||
private EthMaxPriorityFeePerGas method;
|
||||
@Mock private ProtocolSchedule protocolSchedule;
|
||||
@Mock private Blockchain blockchain;
|
||||
private MiningParameters miningParameters;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
miningParameters =
|
||||
MiningParameters.newDefault().setMinPriorityFeePerGas(DEFAULT_MIN_PRIORITY_FEE_PER_GAS);
|
||||
method = createEthMaxPriorityFeePerGasMethod();
|
||||
}
|
||||
|
||||
@@ -63,71 +84,156 @@ public class EthMaxPriorityFeePerGasTest {
|
||||
@Test
|
||||
public void whenNoTransactionsExistReturnMinPriorityFeePerGasPrice() {
|
||||
final JsonRpcRequestContext request = requestWithParams();
|
||||
final String expectedWei = Wei.ONE.toShortHexString();
|
||||
final Wei expectedWei = Wei.ONE;
|
||||
miningParameters.setMinPriorityFeePerGas(expectedWei);
|
||||
final JsonRpcResponse expectedResponse =
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei);
|
||||
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE);
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString());
|
||||
|
||||
mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty());
|
||||
mockBlockchain(10, 0);
|
||||
final JsonRpcResponse actualResponse = method.response(request);
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||
verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@MethodSource("minPriorityFeePerGasValues")
|
||||
public void whenNoTransactionsExistReturnMinPriorityFeePerGasPriceExist(
|
||||
final Wei minPriorityFeePerGasValue) {
|
||||
final JsonRpcRequestContext request = requestWithParams();
|
||||
final String expectedWei = minPriorityFeePerGasValue.toShortHexString();
|
||||
final JsonRpcResponse expectedResponse =
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei);
|
||||
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(minPriorityFeePerGasValue);
|
||||
|
||||
mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty());
|
||||
final JsonRpcResponse actualResponse = method.response(request);
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||
verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenNoTransactionsExistReturnNullMinPriorityFeePerGasPriceExist() {
|
||||
public void whenTransactionsExistReturnMedianMaxPriorityFeePerGasPrice() {
|
||||
final JsonRpcRequestContext request = requestWithParams();
|
||||
final Wei expectedWei = Wei.of(51_000); // max priority fee per gas prices are 1000-100000 wei.
|
||||
final JsonRpcResponse expectedResponse =
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), null);
|
||||
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(null);
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString());
|
||||
|
||||
mockBlockchain(100, 1);
|
||||
|
||||
mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty());
|
||||
final JsonRpcResponse actualResponse = method.response(request);
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||
verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void whenTransactionsExistReturnMaxPriorityFeePerGasPrice() {
|
||||
public void returnMinPriorityFeePerGasWhenMedianValueIsLower() {
|
||||
final JsonRpcRequestContext request = requestWithParams();
|
||||
final String expectedWei = Wei.of(2000000000).toShortHexString();
|
||||
final Wei expectedWei = Wei.of(100_000);
|
||||
miningParameters.setMinPriorityFeePerGas(expectedWei);
|
||||
|
||||
mockBlockchain(100, 1);
|
||||
|
||||
// median value is 51000 wei, that is lower than the value this node is willing to accept,
|
||||
// so the configured min priority fee per gas is returned.
|
||||
final JsonRpcResponse expectedResponse =
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei);
|
||||
mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.of(Wei.of(2000000000)));
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString());
|
||||
|
||||
final JsonRpcResponse actualResponse = method.response(request);
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||
verify(miningCoordinator, VerificationModeFactory.times(0)).getMinPriorityFeePerGas();
|
||||
}
|
||||
|
||||
private static Stream<Arguments> minPriorityFeePerGasValues() {
|
||||
return Stream.of(Arguments.of(Wei.ONE), Arguments.of(Wei.ZERO));
|
||||
}
|
||||
@Test
|
||||
public void atGenesisReturnMinPriorityFeePerGas() {
|
||||
final JsonRpcRequestContext request = requestWithParams();
|
||||
final Wei expectedWei = Wei.ONE;
|
||||
miningParameters.setMinPriorityFeePerGas(expectedWei);
|
||||
final JsonRpcResponse expectedResponse =
|
||||
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei.toShortHexString());
|
||||
|
||||
private void mockBlockchainQueriesMaxPriorityFeePerGasPrice(final Optional<Wei> result) {
|
||||
when(blockchainQueries.gasPriorityFee()).thenReturn(result);
|
||||
mockBlockchain(0, 0);
|
||||
final JsonRpcResponse actualResponse = method.response(request);
|
||||
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
|
||||
}
|
||||
|
||||
private JsonRpcRequestContext requestWithParams(final Object... params) {
|
||||
return new JsonRpcRequestContext(new JsonRpcRequest(JSON_RPC_VERSION, ETH_METHOD, params));
|
||||
}
|
||||
|
||||
private void mockBlockchain(final long chainHeadBlockNumber, final int txsNum) {
|
||||
final var genesisBaseFee = DEFAULT_BASE_FEE;
|
||||
final var blocksByNumber = new HashMap<Long, Block>();
|
||||
|
||||
final var genesisBlock = createFakeBlock(0, 0, genesisBaseFee);
|
||||
blocksByNumber.put(0L, genesisBlock);
|
||||
|
||||
final var baseFeeMarket = new CancunFeeMarket(0, Optional.empty());
|
||||
|
||||
var baseFee = genesisBaseFee;
|
||||
for (long i = 1; i <= chainHeadBlockNumber; i++) {
|
||||
final var parentHeader = blocksByNumber.get(i - 1).getHeader();
|
||||
baseFee =
|
||||
baseFeeMarket.computeBaseFee(
|
||||
i,
|
||||
parentHeader.getBaseFee().get(),
|
||||
parentHeader.getGasUsed(),
|
||||
parentHeader.getGasLimit());
|
||||
blocksByNumber.put(i, createFakeBlock(i, txsNum, baseFee));
|
||||
}
|
||||
|
||||
when(blockchain.getChainHeadBlock()).thenReturn(blocksByNumber.get(chainHeadBlockNumber));
|
||||
if (chainHeadBlockNumber > 0) {
|
||||
when(blockchain.getBlockByNumber(anyLong()))
|
||||
.thenAnswer(
|
||||
invocation -> Optional.of(blocksByNumber.get(invocation.getArgument(0, Long.class))));
|
||||
}
|
||||
lenient()
|
||||
.when(blockchain.getChainHeadHeader())
|
||||
.thenReturn(blocksByNumber.get(chainHeadBlockNumber).getHeader());
|
||||
}
|
||||
|
||||
private Block createFakeBlock(final long height, final int txsNum, final Wei baseFee) {
|
||||
return createFakeBlock(
|
||||
height, txsNum, baseFee, DEFAULT_BLOCK_GAS_LIMIT, DEFAULT_BLOCK_GAS_USED * txsNum);
|
||||
}
|
||||
|
||||
private Block createFakeBlock(
|
||||
final long height,
|
||||
final int txsNum,
|
||||
final Wei baseFee,
|
||||
final long gasLimit,
|
||||
final long gasUsed) {
|
||||
return new Block(
|
||||
new BlockHeader(
|
||||
Hash.EMPTY,
|
||||
Hash.EMPTY_TRIE_HASH,
|
||||
Address.ZERO,
|
||||
Hash.EMPTY_TRIE_HASH,
|
||||
Hash.EMPTY_TRIE_HASH,
|
||||
Hash.EMPTY_TRIE_HASH,
|
||||
LogsBloomFilter.builder().build(),
|
||||
Difficulty.ONE,
|
||||
height,
|
||||
gasLimit,
|
||||
gasUsed,
|
||||
0,
|
||||
Bytes.EMPTY,
|
||||
baseFee,
|
||||
Hash.EMPTY,
|
||||
0,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null),
|
||||
new BlockBody(
|
||||
IntStream.range(0, txsNum)
|
||||
.mapToObj(
|
||||
i ->
|
||||
new Transaction.Builder()
|
||||
.chainId(BigInteger.ONE)
|
||||
.type(TransactionType.EIP1559)
|
||||
.nonce(i)
|
||||
.maxFeePerGas(Wei.of(height * 10_000L))
|
||||
.maxPriorityFeePerGas(Wei.of(height * 1_000L))
|
||||
.gasLimit(gasUsed)
|
||||
.value(Wei.ZERO)
|
||||
.build())
|
||||
.toList(),
|
||||
List.of()));
|
||||
}
|
||||
|
||||
private EthMaxPriorityFeePerGas createEthMaxPriorityFeePerGasMethod() {
|
||||
return new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator);
|
||||
return new EthMaxPriorityFeePerGas(
|
||||
new BlockchainQueries(
|
||||
protocolSchedule,
|
||||
blockchain,
|
||||
null,
|
||||
Optional.empty(),
|
||||
Optional.empty(),
|
||||
ImmutableApiConfiguration.builder().build(),
|
||||
miningParameters));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user