Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
- Ethereum Classic Spiral network upgrade [#6078](https://github.com/hyperledger/besu/pull/6078)
- Add a method to read from a `Memory` instance without altering its inner state [#6073](https://github.com/hyperledger/besu/pull/6073)
- Accept `input` and `data` field for the payload of transaction-related RPC methods [#6094](https://github.com/hyperledger/besu/pull/6094)
- Add APIs to set and get the min gas price a transaction must pay for being selected during block creation [#6097](https://github.com/hyperledger/besu/pull/6097)

### Bug fixes

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ public enum RpcMethod {
MINER_STOP("miner_stop"),
MINER_GET_MIN_PRIORITY_FEE("miner_getMinPriorityFee"),
MINER_SET_MIN_PRIORITY_FEE("miner_setMinPriorityFee"),
MINER_GET_MIN_GAS_PRICE("miner_getMinGasPrice"),
MINER_SET_MIN_GAS_PRICE("miner_setMinGasPrice"),
NET_ENODE("net_enode"),
NET_LISTENING("net_listening"),
NET_PEER_COUNT("net_peerCount"),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.miner;

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.methods.JsonRpcMethod;
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.core.MiningParameters;

public class MinerGetMinGasPrice implements JsonRpcMethod {
private final MiningParameters miningParameters;

public MinerGetMinGasPrice(final MiningParameters miningParameters) {
this.miningParameters = miningParameters;
}

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

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
return new JsonRpcSuccessResponse(
requestContext.getRequest().getId(),
Quantity.create(miningParameters.getMinTransactionGasPrice()));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.miner;

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.methods.JsonRpcMethod;
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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.core.MiningParameters;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MinerSetMinGasPrice implements JsonRpcMethod {
private static final Logger LOG = LoggerFactory.getLogger(MinerSetMinGasPrice.class);

private final MiningParameters miningParameters;

public MinerSetMinGasPrice(final MiningParameters miningParameters) {
this.miningParameters = miningParameters;
}

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

@Override
public JsonRpcResponse response(final JsonRpcRequestContext requestContext) {
try {
final Wei minGasPrice =
Wei.fromHexString(requestContext.getRequiredParameter(0, String.class));
miningParameters.setMinTransactionGasPrice(minGasPrice);
LOG.debug("min gas price changed to {}", minGasPrice.toHumanReadableString());
return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), true);
} catch (final IllegalArgumentException invalidJsonRpcParameters) {
return new JsonRpcErrorResponse(
requestContext.getRequest().getId(),
new JsonRpcError(RpcErrorType.INVALID_PARAMS, invalidJsonRpcParameters.getMessage()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerChangeTargetGasLimit;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerGetMinGasPrice;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerGetMinPriorityFee;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetCoinbase;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetEtherbase;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetMinGasPrice;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerSetMinPriorityFee;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStart;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.miner.MinerStop;
Expand Down Expand Up @@ -54,6 +56,8 @@ protected Map<String, JsonRpcMethod> create() {
new MinerSetEtherbase(minerSetCoinbase),
new MinerChangeTargetGasLimit(miningCoordinator),
new MinerGetMinPriorityFee(miningParameters),
new MinerSetMinPriorityFee(miningParameters));
new MinerSetMinPriorityFee(miningParameters),
new MinerGetMinGasPrice(miningParameters),
new MinerSetMinGasPrice(miningParameters));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.miner;

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.datatypes.Wei;
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.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.core.ImmutableMiningParameters;
import org.hyperledger.besu.ethereum.core.MiningParameters;

import org.junit.jupiter.api.Test;

public class MinerGetMinGasPriceTest {

@Test
public void shouldReturnDefaultMinGasPrice() {
final MiningParameters miningParameters = ImmutableMiningParameters.newDefault();
final MinerGetMinGasPrice method = new MinerGetMinGasPrice(miningParameters);
final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", method.getName(), new Object[] {}));

final JsonRpcResponse expected =
new JsonRpcSuccessResponse(
request.getRequest().getId(),
Quantity.create(MiningParameters.MutableInitValues.DEFAULT_MIN_TRANSACTION_GAS_PRICE));

final JsonRpcResponse actual = method.response(request);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}

@Test
public void shouldReturnSetAtRuntimeMinGasPrice() {
final MiningParameters miningParameters = ImmutableMiningParameters.newDefault();
final MinerGetMinGasPrice method = new MinerGetMinGasPrice(miningParameters);

final Wei minGasPriceAtRuntime = Wei.of(2000);

miningParameters.setMinTransactionGasPrice(minGasPriceAtRuntime);

final JsonRpcRequestContext request =
new JsonRpcRequestContext(new JsonRpcRequest("2.0", method.getName(), new Object[] {}));

final JsonRpcResponse expected =
new JsonRpcSuccessResponse(
request.getRequest().getId(), Quantity.create(minGasPriceAtRuntime));

final JsonRpcResponse actual = method.response(request);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright Hyperledger Besu Contributors.
*
* 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.miner;

import static org.assertj.core.api.Assertions.assertThat;

import org.hyperledger.besu.datatypes.Wei;
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.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.response.RpcErrorType;
import org.hyperledger.besu.ethereum.core.MiningParameters;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

public class MinerSetMinGasPriceTest {
MiningParameters miningParameters = MiningParameters.newDefault();
private MinerSetMinGasPrice method;

@BeforeEach
public void setUp() {
method = new MinerSetMinGasPrice(miningParameters);
}

@Test
public void shouldReturnFalseWhenParameterIsInvalid() {
final String newMinGasPrice = "-1";
final var request = request(newMinGasPrice);

method.response(request);
final JsonRpcResponse expected =
new JsonRpcErrorResponse(
request.getRequest().getId(),
new JsonRpcError(
RpcErrorType.INVALID_PARAMS,
"Illegal character '-' found at index 0 in hex binary representation"));

final JsonRpcResponse actual = method.response(request);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
}

@Test
public void shouldChangeMinPriorityFee() {
final String newMinGasPrice = "0x10";
final var request = request(newMinGasPrice);
method.response(request);
final JsonRpcResponse expected = new JsonRpcSuccessResponse(request.getRequest().getId(), true);

final JsonRpcResponse actual = method.response(request);
assertThat(actual).usingRecursiveComparison().isEqualTo(expected);
assertThat(miningParameters.getMinTransactionGasPrice())
.isEqualTo(Wei.fromHexString(newMinGasPrice));
}

private JsonRpcRequestContext request(final String newMinGasPrice) {
return new JsonRpcRequestContext(
new JsonRpcRequest("2.0", method.getName(), new Object[] {newMinGasPrice}));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,30 +71,27 @@ public TransactionSelectionResult evaluateTransactionPostProcessing(
*/
private boolean transactionCurrentPriceBelowMin(final PendingTransaction pendingTransaction) {
final Transaction transaction = pendingTransaction.getTransaction();
// Here we only care about EIP1159 since for Frontier and local transactions the checks
// that we do when accepting them in the pool are enough
if (transaction.getType().supports1559FeeMarket() && !pendingTransaction.hasPriority()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just double checking, did you mean to drop the first condition of this if?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, because now the minGasPrice could change at runtime, so the check done in the txpool is no more enough, and we need to redo it here for every tx


// For EIP1559 transactions, the price is dynamic and depends on network conditions, so we can
// only calculate at this time the current minimum price the transaction is willing to pay
// and if it is above the minimum accepted by the node.
// If below we do not delete the transaction, since when we added the transaction to the pool,
// we assured sure that the maxFeePerGas is >= of the minimum price accepted by the node
// and so the price of the transaction could satisfy this rule in the future
final Wei currentMinTransactionGasPriceInBlock =
// Priority txs are exempt from this check
if (!pendingTransaction.hasPriority()) {
// since the minGasPrice can change at runtime, we need to recheck it everytime
final Wei transactionGasPriceInBlock =
context
.feeMarket()
.getTransactionPriceCalculator()
.price(transaction, context.processableBlockHeader().getBaseFee());

if (context
.miningParameters()
.getMinTransactionGasPrice()
.compareTo(currentMinTransactionGasPriceInBlock)
.compareTo(transactionGasPriceInBlock)
> 0) {
LOG.trace(
"Current gas fee of {} is lower than configured minimum {}, skipping",
pendingTransaction,
context.miningParameters().getMinTransactionGasPrice());
LOG.atTrace()
.setMessage(
"Current gas price of {} is {} and lower than the configured minimum {}, skipping")
.addArgument(pendingTransaction::toTraceLog)
.addArgument(transactionGasPriceInBlock)
.addArgument(context.miningParameters()::getMinTransactionGasPrice)
.log();
return true;
}
}
Expand Down
Loading