Skip to content
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

Support for eth_maxPriorityFeePerGasPrice #7194

Merged
merged 10 commits into from
Jun 11, 2024
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@
- Promote experimental --Xbonsai-trie-logs-pruning-window-size to production-ready, --bonsai-trie-logs-pruning-window-size [#7192](https://github.com/hyperledger/besu/pull/7192)
- `admin_nodeInfo` JSON/RPC call returns the currently active EVM version [#7127](https://github.com/hyperledger/besu/pull/7127)
- Improve the selection of the most profitable built block [#7174](https://github.com/hyperledger/besu/pull/7174)

- Support for eth_maxPriorityFeePerGas [#5658](https://github.com/hyperledger/besu/issues/5658)
### Bug fixes
- Make `eth_gasPrice` aware of the base fee market [#7102](https://github.com/hyperledger/besu/pull/7102)

- Validation errors ignored in accounts-allowlist and empty list [#7138](https://github.com/hyperledger/besu/issues/7138)
## 24.5.2

### Upcoming Breaking Changes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ public enum RpcMethod {
ETH_GET_FILTER_CHANGES("eth_getFilterChanges"),
ETH_GET_FILTER_LOGS("eth_getFilterLogs"),
ETH_GET_LOGS("eth_getLogs"),
ETH_GET_MAX_PRIORITY_FEE_PER_GAS("eth_maxPriorityFeePerGas"),
ETH_GET_MINER_DATA_BY_BLOCK_HASH("eth_getMinerDataByBlockHash"),
ETH_GET_MINER_DATA_BY_BLOCK_NUMBER("eth_getMinerDataByBlockNumber"),
ETH_GET_PROOF("eth_getProof"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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 org.hyperledger.besu.datatypes.Wei;
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.response.JsonRpcResponse;
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) {
this.blockchainQueries = blockchainQueries;
this.miningCoordinator = miningCoordinator;
}

@Override
public String getName() {
return RpcMethod.ETH_GET_MAX_PRIORITY_FEE_PER_GAS.getMethodName();
}

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(), Quantity.create(fetchAndLimitPriorityFeePerGas()));
}

private Wei fetchAndLimitPriorityFeePerGas() {
final Optional<Wei> gasPrice = blockchainQueries.gasPriorityFee();
return gasPrice.orElseGet(miningCoordinator::getMinPriorityFeePerGas);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetUncleCountByBlockNumber;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthGetWork;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthHashrate;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthMaxPriorityFeePerGas;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthMining;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewBlockFilter;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthNewFilter;
Expand Down Expand Up @@ -183,6 +184,7 @@ protected Map<String, JsonRpcMethod> create() {
new EthChainId(protocolSchedule.getChainId()),
new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule),
new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule),
new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule));
new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule),
new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/*
* Copyright contributors to Hyperledger Besu.
*
* 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 org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.hyperledger.besu.datatypes.Wei;
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 java.util.Optional;
import java.util.stream.Stream;

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)
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;

@Mock private BlockchainQueries blockchainQueries;
@Mock private MiningCoordinator miningCoordinator;

@BeforeEach
public void setUp() {
method = createEthMaxPriorityFeePerGasMethod();
}

@Test
public void shouldReturnCorrectMethodName() {
assertThat(method.getName()).isEqualTo(ETH_METHOD);
}

@Test
public void whenNoTransactionsExistReturnMinPriorityFeePerGasPrice() {
final JsonRpcRequestContext request = requestWithParams();
final String expectedWei = Wei.ONE.toShortHexString();
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei);
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE);

mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty());
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() {
final JsonRpcRequestContext request = requestWithParams();
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), null);
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(null);

mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.empty());
final JsonRpcResponse actualResponse = method.response(request);
assertThat(actualResponse).usingRecursiveComparison().isEqualTo(expectedResponse);
verify(miningCoordinator, VerificationModeFactory.times(1)).getMinPriorityFeePerGas();
}

@Test
public void whenTransactionsExistReturnMaxPriorityFeePerGasPrice() {
final JsonRpcRequestContext request = requestWithParams();
final String expectedWei = Wei.of(2000000000).toShortHexString();
final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(request.getRequest().getId(), expectedWei);
mockBlockchainQueriesMaxPriorityFeePerGasPrice(Optional.of(Wei.of(2000000000)));
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));
}

private void mockBlockchainQueriesMaxPriorityFeePerGasPrice(final Optional<Wei> result) {
when(blockchainQueries.gasPriorityFee()).thenReturn(result);
}

private JsonRpcRequestContext requestWithParams(final Object... params) {
return new JsonRpcRequestContext(new JsonRpcRequest(JSON_RPC_VERSION, ETH_METHOD, params));
}

private EthMaxPriorityFeePerGas createEthMaxPriorityFeePerGasMethod() {
return new EthMaxPriorityFeePerGas(blockchainQueries, miningCoordinator);
}
}
Loading