RC4 - eth_call and eth_feeHistory add blob fields (#6681)

* Add blobs to `eth_feeHistory` (#6679)

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>

* merge changelog

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

* merge

Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>

---------

Signed-off-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
Signed-off-by: Sally MacFarlane <macfarla.github@gmail.com>
Co-authored-by: Gabriel-Trintinalia <gabriel.trintinalia@consensys.net>
release-24.2.0 24.2.0-RC4
Sally MacFarlane 9 months ago committed by GitHub
parent ad4fdfa1d8
commit 698ec4204f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      CHANGELOG.md
  2. 26
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCallIntegrationTest.java
  3. 16
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthCreateAccessListIntegrationTest.java
  4. 14
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/frontier/EthEstimateGasIntegrationTest.java
  5. 18
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthCallIntegrationTest.java
  6. 12
      ethereum/api/src/integration-test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/fork/london/EthEstimateGasIntegrationTest.java
  7. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcErrorConverter.java
  8. 73
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistory.java
  9. 9
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/parameters/JsonCallParameter.java
  10. 2
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/response/RpcErrorType.java
  11. 12
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/results/FeeHistory.java
  12. 8
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcErrorTypeConverterTest.java
  13. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java
  14. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCreateAccessListTest.java
  15. 4
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java
  16. 102
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthFeeHistoryTest.java
  17. 6
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/privacy/methods/priv/PrivCallTest.java
  18. 23
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob.json
  19. 22
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_missing_maxFeePerBlobGas.json
  20. 23
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_too_many_blobs.json
  21. 23
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_call_blob_zero_fee.json
  22. 2
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_feeHistory_fieldNamesWithReward.json
  23. 4
      ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth/eth_feeHistory_fieldNamesWithoutReward.json
  24. 61
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/CallParameter.java
  25. 4
      ethereum/core/src/main/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulator.java
  26. 103
      ethereum/core/src/test/java/org/hyperledger/besu/ethereum/transaction/TransactionSimulatorTest.java

@ -15,6 +15,8 @@
- `--Xfilter-on-enr-fork-id` has been removed. To disable the feature use `--filter-on-enr-fork-id=false`. - `--Xfilter-on-enr-fork-id` has been removed. To disable the feature use `--filter-on-enr-fork-id=false`.
- `--engine-jwt-enabled` has been removed. Use `--engine-jwt-disabled` instead. [#6491](https://github.com/hyperledger/besu/pull/6491) - `--engine-jwt-enabled` has been removed. Use `--engine-jwt-disabled` instead. [#6491](https://github.com/hyperledger/besu/pull/6491)
- Release docker images now provided at ghcr.io instead of dockerhub - Release docker images now provided at ghcr.io instead of dockerhub
- Add blob transaction support to `eth_call` [#6661](https://github.com/hyperledger/besu/pull/6661)
- Add blobs to `eth_feeHistory` [#6679](https://github.com/hyperledger/besu/pull/6679)
### Deprecations ### Deprecations
- X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.4.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405) - X_SNAP and X_CHECKPOINT are marked for deprecation and will be removed in 24.4.0 in favor of SNAP and CHECKPOINT [#6405](https://github.com/hyperledger/besu/pull/6405)

@ -75,6 +75,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -100,6 +102,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "0x8"); final JsonRpcRequestContext request = requestWithParams(callParameter, "0x8");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -126,6 +130,8 @@ public class EthCallIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -152,6 +158,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -176,6 +184,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
true, true,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -200,6 +210,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
false, false,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -225,6 +237,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -249,6 +263,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -274,6 +290,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -298,6 +316,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -323,6 +343,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -348,6 +370,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x12a7b914"), Bytes.fromHexString("0x12a7b914"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -373,6 +397,8 @@ public class EthCallIntegrationTest {
null, null,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x");

@ -140,7 +140,8 @@ public class EthCreateAccessListIntegrationTest {
@Test @Test
public void shouldReturnExpectedValueForEmptyCallParameter() { public void shouldReturnExpectedValueForEmptyCallParameter() {
final JsonCallParameter callParameter = final JsonCallParameter callParameter =
new JsonCallParameter(null, null, null, null, null, null, null, null, null, null, null); new JsonCallParameter(
null, null, null, null, null, null, null, null, null, null, null, null, null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 0xcf08)); new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 0xcf08));
@ -164,6 +165,8 @@ public class EthCreateAccessListIntegrationTest {
null, null,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -189,6 +192,8 @@ public class EthCreateAccessListIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -214,6 +219,8 @@ public class EthCreateAccessListIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
false, false,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -227,7 +234,8 @@ public class EthCreateAccessListIntegrationTest {
@Test @Test
public void shouldReturnExpectedValueForInsufficientGas() { public void shouldReturnExpectedValueForInsufficientGas() {
final JsonCallParameter callParameter = final JsonCallParameter callParameter =
new JsonCallParameter(null, null, 1L, null, null, null, null, null, null, null, null); new JsonCallParameter(
null, null, 1L, null, null, null, null, null, null, null, null, null, null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 0xcf08)); new JsonRpcSuccessResponse(null, new CreateAccessListResult(new ArrayList<>(), 0xcf08));
@ -262,7 +270,9 @@ public class EthCreateAccessListIntegrationTest {
null, null,
null, null,
null, null,
accessList); accessList,
null,
null);
} }
private JsonRpcRequestContext requestWithParams(final Object... params) { private JsonRpcRequestContext requestWithParams(final Object... params) {

@ -65,7 +65,8 @@ public class EthEstimateGasIntegrationTest {
@Test @Test
public void shouldReturnExpectedValueForEmptyCallParameter() { public void shouldReturnExpectedValueForEmptyCallParameter() {
final JsonCallParameter callParameter = final JsonCallParameter callParameter =
new JsonCallParameter(null, null, null, null, null, null, null, null, null, null, null); new JsonCallParameter(
null, null, null, null, null, null, null, null, null, null, null, null, null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208");
@ -88,6 +89,8 @@ public class EthEstimateGasIntegrationTest {
null, null,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208");
@ -112,6 +115,8 @@ public class EthEstimateGasIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1b551"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1b551");
@ -136,6 +141,8 @@ public class EthEstimateGasIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
false, false,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1b551"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1b551");
@ -160,6 +167,8 @@ public class EthEstimateGasIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
true, true,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
@ -176,7 +185,8 @@ public class EthEstimateGasIntegrationTest {
@Test @Test
public void shouldReturnExpectedValueForInsufficientGas() { public void shouldReturnExpectedValueForInsufficientGas() {
final JsonCallParameter callParameter = final JsonCallParameter callParameter =
new JsonCallParameter(null, null, 1L, null, null, null, null, null, null, null, null); new JsonCallParameter(
null, null, 1L, null, null, null, null, null, null, null, null, null, null);
final JsonRpcRequestContext request = requestWithParams(callParameter); final JsonRpcRequestContext request = requestWithParams(callParameter);
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x5208");

@ -75,6 +75,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -100,6 +102,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -124,6 +128,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -149,6 +155,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -173,6 +181,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -198,6 +208,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -223,6 +235,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -247,6 +261,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -272,6 +288,8 @@ public class EthCallIntegrationTest {
Bytes.fromHexString("0x2e64cec1"), Bytes.fromHexString("0x2e64cec1"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = requestWithParams(callParameter, "latest"); final JsonRpcRequestContext request = requestWithParams(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =

@ -78,6 +78,8 @@ public class EthEstimateGasIntegrationTest {
null, null,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcResponse response = method.response(requestWithParams(callParameter)); final JsonRpcResponse response = method.response(requestWithParams(callParameter));
@ -100,7 +102,9 @@ public class EthEstimateGasIntegrationTest {
null, null,
null, null,
null, null,
createAccessList()); createAccessList(),
null,
null);
final JsonRpcResponse response = method.response(requestWithParams(callParameter)); final JsonRpcResponse response = method.response(requestWithParams(callParameter));
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x62d4"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x62d4");
@ -122,6 +126,8 @@ public class EthEstimateGasIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
null, null,
null,
null,
null); null);
final JsonRpcResponse response = method.response(requestWithParams(callParameter)); final JsonRpcResponse response = method.response(requestWithParams(callParameter));
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1f081"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x1f081");
@ -143,7 +149,9 @@ public class EthEstimateGasIntegrationTest {
"0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"), "0x608060405234801561001057600080fd5b50610157806100206000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bdab8bf146100515780639ae97baa14610068575b600080fd5b34801561005d57600080fd5b5061006661007f565b005b34801561007457600080fd5b5061007d6100b9565b005b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60016040518082815260200191505060405180910390a1565b7fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60026040518082815260200191505060405180910390a17fa53887c1eed04528e23301f55ad49a91634ef5021aa83a97d07fd16ed71c039a60036040518082815260200191505060405180910390a15600a165627a7a7230582010ddaa52e73a98c06dbcd22b234b97206c1d7ed64a7c048e10c2043a3d2309cb0029"),
null, null,
null, null,
createAccessList()); createAccessList(),
null,
null);
final JsonRpcResponse response = method.response(requestWithParams(callParameter)); final JsonRpcResponse response = method.response(requestWithParams(callParameter));
final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x2014d"); final JsonRpcResponse expectedResponse = new JsonRpcSuccessResponse(null, "0x2014d");

@ -79,6 +79,8 @@ public class JsonRpcErrorConverter {
return RpcErrorType.PLUGIN_TX_VALIDATOR; return RpcErrorType.PLUGIN_TX_VALIDATOR;
case INVALID_BLOBS: case INVALID_BLOBS:
return RpcErrorType.INVALID_BLOBS; return RpcErrorType.INVALID_BLOBS;
case BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE:
return RpcErrorType.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE;
case EXECUTION_HALTED: case EXECUTION_HALTED:
return RpcErrorType.EXECUTION_HALTED; return RpcErrorType.EXECUTION_HALTED;
default: default:

@ -15,6 +15,7 @@
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 java.util.stream.Collectors.toUnmodifiableList;
import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
@ -36,14 +37,17 @@ import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.BaseFeeMarket;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Optional; import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.LongStream; import java.util.stream.LongStream;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -104,15 +108,23 @@ public class EthFeeHistory implements JsonRpcMethod {
final List<BlockHeader> blockHeaderRange = getBlockHeaders(firstBlock, lastBlock); final List<BlockHeader> blockHeaderRange = getBlockHeaders(firstBlock, lastBlock);
final List<Wei> requestedBaseFees = getBaseFees(blockHeaderRange); final List<Wei> requestedBaseFees = getBaseFees(blockHeaderRange);
final List<Wei> requestedBlobBaseFees = getBlobBaseFees(blockHeaderRange);
final Wei nextBaseFee = final Wei nextBaseFee =
getNextBaseFee(highestBlockNumber, chainHeadHeader, requestedBaseFees, blockHeaderRange); getNextBaseFee(highestBlockNumber, chainHeadHeader, requestedBaseFees, blockHeaderRange);
final List<Double> gasUsedRatios = getGasUsedRatios(blockHeaderRange); final List<Double> gasUsedRatios = getGasUsedRatios(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(rewards -> getRewards(rewards, blockHeaderRange));
return new JsonRpcSuccessResponse( return new JsonRpcSuccessResponse(
requestId, requestId,
createFeeHistoryResult( createFeeHistoryResult(
firstBlock, requestedBaseFees, nextBaseFee, gasUsedRatios, maybeRewards)); firstBlock,
requestedBaseFees,
requestedBlobBaseFees,
nextBaseFee,
gasUsedRatios,
blobGasUsedRatios,
maybeRewards));
} }
private Wei getNextBaseFee( private Wei getNextBaseFee(
@ -326,23 +338,78 @@ public class EthFeeHistory implements JsonRpcMethod {
} }
private List<Wei> getBaseFees(final List<BlockHeader> blockHeaders) { private List<Wei> getBaseFees(final List<BlockHeader> blockHeaders) {
// we return the base fees for the blocks requested and 1 more because we can always compute it
return blockHeaders.stream() return blockHeaders.stream()
.map(blockHeader -> blockHeader.getBaseFee().orElse(Wei.ZERO)) .map(blockHeader -> blockHeader.getBaseFee().orElse(Wei.ZERO))
.toList(); .toList();
} }
private List<Wei> getBlobBaseFees(final List<BlockHeader> blockHeaders) {
if (blockHeaders.isEmpty()) {
return Collections.emptyList();
}
// Calculate the BlobFee for the requested range
List<Wei> baseFeesPerBlobGas =
blockHeaders.stream().map(this::getBlobGasFee).collect(Collectors.toList());
// Calculate the next blob base fee and add it to the list
Wei nextBlobBaseFee = getNextBlobFee(blockHeaders.get(blockHeaders.size() - 1));
baseFeesPerBlobGas.add(nextBlobBaseFee);
return baseFeesPerBlobGas;
}
private Wei getBlobGasFee(final BlockHeader header) {
return blockchain
.getBlockHeader(header.getParentHash())
.map(parent -> getBlobGasFee(protocolSchedule.getByBlockHeader(header), parent))
.orElse(Wei.ZERO);
}
private Wei getBlobGasFee(final ProtocolSpec spec, final BlockHeader parent) {
return spec.getFeeMarket().blobGasPricePerGas(calculateExcessBlobGasForParent(spec, parent));
}
private Wei getNextBlobFee(final BlockHeader header) {
// Attempt to retrieve the next header based on the current header's number.
long nextBlockNumber = header.getNumber() + 1;
return blockchain
.getBlockHeader(nextBlockNumber)
.map(nextHeader -> getBlobGasFee(protocolSchedule.getByBlockHeader(nextHeader), header))
// If the next header is not present, calculate the fee using the current time.
.orElseGet(
() ->
getBlobGasFee(
protocolSchedule.getForNextBlockHeader(header, System.currentTimeMillis()),
header));
}
private List<Double> getGasUsedRatios(final List<BlockHeader> blockHeaders) { private List<Double> getGasUsedRatios(final List<BlockHeader> blockHeaders) {
return blockHeaders.stream() return blockHeaders.stream()
.map(blockHeader -> blockHeader.getGasUsed() / (double) blockHeader.getGasLimit()) .map(blockHeader -> blockHeader.getGasUsed() / (double) blockHeader.getGasLimit())
.toList(); .toList();
} }
private List<Double> getBlobGasUsedRatios(final List<BlockHeader> blockHeaders) {
return blockHeaders.stream().map(this::calculateBlobGasUsedRatio).toList();
}
private double calculateBlobGasUsedRatio(final BlockHeader blockHeader) {
ProtocolSpec spec = protocolSchedule.getByBlockHeader(blockHeader);
long blobGasUsed = blockHeader.getBlobGasUsed().orElse(0L);
double currentBlobGasLimit = spec.getGasLimitCalculator().currentBlobGasLimit();
if (currentBlobGasLimit == 0) {
return 0;
}
return blobGasUsed / currentBlobGasLimit;
}
private FeeHistory.FeeHistoryResult createFeeHistoryResult( private FeeHistory.FeeHistoryResult createFeeHistoryResult(
final long oldestBlock, final long oldestBlock,
final List<Wei> explicitlyRequestedBaseFees, final List<Wei> explicitlyRequestedBaseFees,
final List<Wei> requestedBlobBaseFees,
final Wei nextBaseFee, final Wei nextBaseFee,
final List<Double> gasUsedRatios, final List<Double> gasUsedRatios,
final List<Double> blobGasUsedRatio,
final Optional<List<List<Wei>>> maybeRewards) { final Optional<List<List<Wei>>> maybeRewards) {
return FeeHistory.FeeHistoryResult.from( return FeeHistory.FeeHistoryResult.from(
ImmutableFeeHistory.builder() ImmutableFeeHistory.builder()
@ -350,7 +417,9 @@ public class EthFeeHistory implements JsonRpcMethod {
.baseFeePerGas( .baseFeePerGas(
Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee)) Stream.concat(explicitlyRequestedBaseFees.stream(), Stream.of(nextBaseFee))
.collect(toUnmodifiableList())) .collect(toUnmodifiableList()))
.baseFeePerBlobGas(requestedBlobBaseFees)
.gasUsedRatio(gasUsedRatios) .gasUsedRatio(gasUsedRatios)
.blobGasUsedRatio(blobGasUsedRatio)
.reward(maybeRewards) .reward(maybeRewards)
.build()); .build());
} }

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters;
import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.json.HexLongDeserializer; import org.hyperledger.besu.ethereum.core.json.HexLongDeserializer;
import org.hyperledger.besu.ethereum.core.json.HexStringDeserializer; import org.hyperledger.besu.ethereum.core.json.HexStringDeserializer;
@ -53,7 +54,9 @@ public class JsonCallParameter extends CallParameter {
@JsonDeserialize(using = HexStringDeserializer.class) @JsonProperty("input") @JsonDeserialize(using = HexStringDeserializer.class) @JsonProperty("input")
final Bytes input, final Bytes input,
@JsonProperty("strict") final Boolean strict, @JsonProperty("strict") final Boolean strict,
@JsonProperty("accessList") final List<AccessListEntry> accessList) { @JsonProperty("accessList") final List<AccessListEntry> accessList,
@JsonProperty("maxFeePerBlobGas") final Wei maxFeePerBlobGas,
@JsonProperty("blobVersionedHashes") final List<VersionedHash> blobVersionedHashes) {
super( super(
from, from,
@ -64,7 +67,9 @@ public class JsonCallParameter extends CallParameter {
Optional.ofNullable(maxFeePerGas), Optional.ofNullable(maxFeePerGas),
value, value,
Optional.ofNullable(input != null ? input : data).orElse(null), Optional.ofNullable(input != null ? input : data).orElse(null),
Optional.ofNullable(accessList)); Optional.ofNullable(accessList),
Optional.ofNullable(maxFeePerBlobGas),
Optional.ofNullable(blobVersionedHashes));
if (input != null && data != null) { if (input != null && data != null) {
throw new IllegalArgumentException("Only one of 'input' or 'data' should be provided"); throw new IllegalArgumentException("Only one of 'input' or 'data' should be provided");

@ -61,6 +61,8 @@ public enum RpcErrorType {
CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"), CHAIN_HEAD_WORLD_STATE_NOT_AVAILABLE(-32008, "Initial sync is still in progress"),
GAS_PRICE_TOO_LOW(-32009, "Gas price below configured minimum gas price"), GAS_PRICE_TOO_LOW(-32009, "Gas price below configured minimum gas price"),
GAS_PRICE_BELOW_CURRENT_BASE_FEE(-32009, "Gas price below current base fee"), GAS_PRICE_BELOW_CURRENT_BASE_FEE(-32009, "Gas price below current base fee"),
BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE(-32009, "blob gas price below current blob base fee"),
WRONG_CHAIN_ID(-32000, "Wrong chainId"), WRONG_CHAIN_ID(-32000, "Wrong chainId"),
REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED(-32000, "ChainId not supported"), REPLAY_PROTECTED_SIGNATURES_NOT_SUPPORTED(-32000, "ChainId not supported"),
REPLAY_PROTECTED_SIGNATURE_REQUIRED(-32000, "ChainId is required"), REPLAY_PROTECTED_SIGNATURE_REQUIRED(-32000, "ChainId is required"),

@ -33,8 +33,12 @@ public interface FeeHistory {
List<Wei> getBaseFeePerGas(); List<Wei> getBaseFeePerGas();
List<Wei> getBaseFeePerBlobGas();
List<Double> getGasUsedRatio(); List<Double> getGasUsedRatio();
List<Double> getBlobGasUsedRatio();
Optional<List<List<Wei>>> getReward(); Optional<List<List<Wei>>> getReward();
@Value.Immutable @Value.Immutable
@ -47,9 +51,15 @@ public interface FeeHistory {
@JsonProperty("baseFeePerGas") @JsonProperty("baseFeePerGas")
List<String> getBaseFeePerGas(); List<String> getBaseFeePerGas();
@JsonProperty("baseFeePerBlobGas")
List<String> getBaseFeePerBlobGas();
@JsonProperty("gasUsedRatio") @JsonProperty("gasUsedRatio")
List<Double> getGasUsedRatio(); List<Double> getGasUsedRatio();
@JsonProperty("blobGasUsedRatio")
List<Double> getBlobGasUsedRatio();
@Nullable @Nullable
@JsonProperty("reward") @JsonProperty("reward")
List<List<String>> getReward(); List<List<String>> getReward();
@ -60,7 +70,9 @@ public interface FeeHistory {
feeHistory.getBaseFeePerGas().stream() feeHistory.getBaseFeePerGas().stream()
.map(Quantity::create) .map(Quantity::create)
.collect(toUnmodifiableList()), .collect(toUnmodifiableList()),
feeHistory.getBaseFeePerBlobGas().stream().map(Quantity::create).toList(),
feeHistory.getGasUsedRatio(), feeHistory.getGasUsedRatio(),
feeHistory.getBlobGasUsedRatio(),
feeHistory feeHistory
.getReward() .getReward()
.map( .map(

@ -68,7 +68,13 @@ public class RpcErrorTypeConverterTest {
{ {
TransactionInvalidReason.TRANSACTION_REPLACEMENT_UNDERPRICED, TransactionInvalidReason.TRANSACTION_REPLACEMENT_UNDERPRICED,
RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED RpcErrorType.ETH_SEND_TX_REPLACEMENT_UNDERPRICED
} },
{
TransactionInvalidReason.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE,
RpcErrorType.BLOB_GAS_PRICE_BELOW_CURRENT_BLOB_BASE_FEE
},
{TransactionInvalidReason.TOTAL_BLOB_GAS_TOO_HIGH, RpcErrorType.TOTAL_BLOB_GAS_TOO_HIGH},
{TransactionInvalidReason.INVALID_BLOBS, RpcErrorType.INVALID_BLOBS}
}); });
} }

@ -116,7 +116,7 @@ public class EthCallTest {
public void shouldAcceptRequestWhenMissingOptionalFields() { public void shouldAcceptRequestWhenMissingOptionalFields() {
final JsonCallParameter callParameter = final JsonCallParameter callParameter =
new JsonCallParameter( new JsonCallParameter(
null, null, null, null, null, null, null, null, null, Boolean.FALSE, null); null, null, null, null, null, null, null, null, null, Boolean.FALSE, null, null, null);
final JsonRpcRequestContext request = ethCallRequest(callParameter, "latest"); final JsonRpcRequestContext request = ethCallRequest(callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
new JsonRpcSuccessResponse(null, Bytes.of().toString()); new JsonRpcSuccessResponse(null, Bytes.of().toString());
@ -455,6 +455,8 @@ public class EthCallTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
null, null,
null,
null,
null); null);
} }

@ -316,6 +316,8 @@ public class EthCreateAccessListTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
false, false,
null,
null,
null); null);
} }
@ -345,7 +347,9 @@ public class EthCreateAccessListTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
false, false,
accessListEntries); accessListEntries,
null,
null);
} }
private List<AccessListEntry> createAccessList() { private List<AccessListEntry> createAccessList() {

@ -473,6 +473,8 @@ public class EthEstimateGasTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
isStrict, isStrict,
null,
null,
null); null);
} }
@ -505,6 +507,8 @@ public class EthEstimateGasTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
false, false,
null,
null,
null); null);
} }

@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
import org.hyperledger.besu.consensus.merge.blockcreation.MergeCoordinator; import org.hyperledger.besu.consensus.merge.blockcreation.MergeCoordinator;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.GasLimitCalculator;
import org.hyperledger.besu.ethereum.api.ApiConfiguration; import org.hyperledger.besu.ethereum.api.ApiConfiguration;
import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration; import org.hyperledger.besu.ethereum.api.ImmutableApiConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequest;
@ -47,9 +48,12 @@ import org.hyperledger.besu.ethereum.core.BlockDataGenerator;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
import org.hyperledger.besu.ethereum.core.TransactionReceipt; import org.hyperledger.besu.ethereum.core.TransactionReceipt;
import org.hyperledger.besu.ethereum.mainnet.CancunTargetingGasLimitCalculator;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule;
import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec;
import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket; import org.hyperledger.besu.ethereum.mainnet.feemarket.FeeMarket;
import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator;
import org.hyperledger.besu.evm.gascalculator.LondonGasCalculator;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
@ -80,6 +84,8 @@ public class EthFeeHistoryTest {
miningCoordinator = mock(MergeCoordinator.class); miningCoordinator = mock(MergeCoordinator.class);
when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE); when(miningCoordinator.getMinPriorityFeePerGas()).thenReturn(Wei.ONE);
mockFork();
method = method =
new EthFeeHistory( new EthFeeHistory(
protocolSchedule, protocolSchedule,
@ -90,9 +96,6 @@ public class EthFeeHistoryTest {
@Test @Test
public void params() { public void params() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(londonSpec);
// should fail because no required params given // should fail because no required params given
assertThatThrownBy(this::feeHistoryRequest).isInstanceOf(InvalidJsonRpcParameters.class); assertThatThrownBy(this::feeHistoryRequest).isInstanceOf(InvalidJsonRpcParameters.class);
// should fail because newestBlock not given // should fail because newestBlock not given
@ -110,12 +113,7 @@ public class EthFeeHistoryTest {
@Test @Test
public void allFieldsPresentForLatestBlock() { public void allFieldsPresentForLatestBlock() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(protocolSchedule.getForNextBlockHeader(
eq(blockchain.getChainHeadHeader()),
eq(blockchain.getChainHeadHeader().getTimestamp())))
.thenReturn(londonSpec);
final Object latest = final Object latest =
((JsonRpcSuccessResponse) feeHistoryRequest("0x1", "latest", new double[] {100.0})) ((JsonRpcSuccessResponse) feeHistoryRequest("0x1", "latest", new double[] {100.0}))
.getResult(); .getResult();
@ -126,6 +124,8 @@ public class EthFeeHistoryTest {
.oldestBlock(10) .oldestBlock(10)
.baseFeePerGas(List.of(Wei.of(25496L), Wei.of(28683L))) .baseFeePerGas(List.of(Wei.of(25496L), Wei.of(28683L)))
.gasUsedRatio(List.of(0.9999999992132459)) .gasUsedRatio(List.of(0.9999999992132459))
.baseFeePerBlobGas(List.of(Wei.of(0), Wei.of(0)))
.blobGasUsedRatio(List.of(0.0))
.reward(List.of(List.of(Wei.of(1524763764L)))) .reward(List.of(List.of(Wei.of(1524763764L))))
.build())); .build()));
} }
@ -250,29 +250,19 @@ public class EthFeeHistoryTest {
@Test @Test
public void doesntGoPastChainHeadWithHighBlockCount() { public void doesntGoPastChainHeadWithHighBlockCount() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(protocolSchedule.getForNextBlockHeader(
eq(blockchain.getChainHeadHeader()),
eq(blockchain.getChainHeadHeader().getTimestamp())))
.thenReturn(londonSpec);
final FeeHistory.FeeHistoryResult result = final FeeHistory.FeeHistoryResult result =
(ImmutableFeeHistoryResult) (ImmutableFeeHistoryResult)
((JsonRpcSuccessResponse) feeHistoryRequest("0x14", "latest")).getResult(); ((JsonRpcSuccessResponse) feeHistoryRequest("0x14", "latest")).getResult();
assertThat(Long.decode(result.getOldestBlock())).isEqualTo(0); assertThat(Long.decode(result.getOldestBlock())).isEqualTo(0);
assertThat(result.getBaseFeePerGas()).hasSize(12); assertThat(result.getBaseFeePerGas()).hasSize(12);
assertThat(result.getGasUsedRatio()).hasSize(11); assertThat(result.getGasUsedRatio()).hasSize(11);
assertThat(result.getBaseFeePerBlobGas()).hasSize(12);
assertThat(result.getBlobGasUsedRatio()).hasSize(11);
assertThat(result.getReward()).isNull(); assertThat(result.getReward()).isNull();
} }
@Test @Test
public void feeValuesAreInTheBlockCountAndHighestBlock() { public void feeValuesAreInTheBlockCountAndHighestBlock() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(protocolSchedule.getForNextBlockHeader(
eq(blockchain.getChainHeadHeader()),
eq(blockchain.getChainHeadHeader().getTimestamp())))
.thenReturn(londonSpec);
double[] percentile = new double[] {100.0}; double[] percentile = new double[] {100.0};
final Object ninth = final Object ninth =
@ -286,12 +276,6 @@ public class EthFeeHistoryTest {
@Test @Test
public void feeValuesDontGoPastHighestBlock() { public void feeValuesDontGoPastHighestBlock() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(protocolSchedule.getForNextBlockHeader(
eq(blockchain.getChainHeadHeader()),
eq(blockchain.getChainHeadHeader().getTimestamp())))
.thenReturn(londonSpec);
double[] percentile = new double[] {100.0}; double[] percentile = new double[] {100.0};
final Object second = final Object second =
@ -345,6 +329,70 @@ public class EthFeeHistoryTest {
assertThat(((ImmutableFeeHistoryResult) feeObject).getReward().size()).isEqualTo(blockCount); assertThat(((ImmutableFeeHistoryResult) feeObject).getReward().size()).isEqualTo(blockCount);
assertThat(((ImmutableFeeHistoryResult) feeObject).getGasUsedRatio().size()) assertThat(((ImmutableFeeHistoryResult) feeObject).getGasUsedRatio().size())
.isEqualTo(blockCount); .isEqualTo(blockCount);
assertThat(((ImmutableFeeHistoryResult) feeObject).getBaseFeePerBlobGas().size())
.isEqualTo(blockCount + 1);
assertThat(((ImmutableFeeHistoryResult) feeObject).getBlobGasUsedRatio().size())
.isEqualTo(blockCount);
}
@Test
public void shouldCalculateBlobFeeCorrectly_preBlob() {
assertBlobBaseFee(List.of(Wei.ZERO, Wei.ZERO));
}
@Test
public void shouldCalculateBlobFeeCorrectly_postBlob() {
mockPostBlobFork();
assertBlobBaseFee(List.of(Wei.ONE, Wei.ONE));
}
@Test
public void shouldCalculateBlobFeeCorrectly_transitionFork() {
mockTransitionBlobFork();
assertBlobBaseFee(List.of(Wei.ZERO, Wei.ONE));
}
private void mockFork() {
final ProtocolSpec londonSpec = mock(ProtocolSpec.class);
when(londonSpec.getGasCalculator()).thenReturn(new LondonGasCalculator());
when(londonSpec.getFeeMarket()).thenReturn(FeeMarket.london(5));
when(londonSpec.getGasLimitCalculator()).thenReturn(mock(GasLimitCalculator.class));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(londonSpec);
when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(londonSpec);
}
private void mockPostBlobFork() {
final ProtocolSpec cancunSpec = mock(ProtocolSpec.class);
when(cancunSpec.getGasCalculator()).thenReturn(new CancunGasCalculator());
when(cancunSpec.getFeeMarket()).thenReturn(FeeMarket.cancun(5, Optional.empty()));
when(cancunSpec.getGasLimitCalculator())
.thenReturn(mock(CancunTargetingGasLimitCalculator.class));
when(protocolSchedule.getByBlockHeader(any())).thenReturn(cancunSpec);
when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(cancunSpec);
}
private void mockTransitionBlobFork() {
final ProtocolSpec cancunSpec = mock(ProtocolSpec.class);
when(cancunSpec.getGasCalculator()).thenReturn(new CancunGasCalculator());
when(cancunSpec.getFeeMarket()).thenReturn(FeeMarket.cancun(5, Optional.empty()));
when(cancunSpec.getGasLimitCalculator())
.thenReturn(mock(CancunTargetingGasLimitCalculator.class));
when(protocolSchedule.getForNextBlockHeader(any(), anyLong())).thenReturn(cancunSpec);
}
private void assertBlobBaseFee(final List<Wei> baseFeePerBlobGas) {
final Object latest = ((JsonRpcSuccessResponse) feeHistoryRequest("0x1", "latest")).getResult();
assertThat(latest)
.isEqualTo(
FeeHistory.FeeHistoryResult.from(
ImmutableFeeHistory.builder()
.oldestBlock(10)
.baseFeePerGas(List.of(Wei.of(25496L), Wei.of(28683L)))
.gasUsedRatio(List.of(0.9999999992132459))
.baseFeePerBlobGas(baseFeePerBlobGas)
.blobGasUsedRatio(List.of(0.0))
.build()));
} }
private JsonRpcResponse feeHistoryRequest(final Object... params) { private JsonRpcResponse feeHistoryRequest(final Object... params) {

@ -86,6 +86,8 @@ public class PrivCallTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = ethCallRequest(privacyGroupId, callParameter, "latest"); final JsonRpcRequestContext request = ethCallRequest(privacyGroupId, callParameter, "latest");
@ -122,6 +124,8 @@ public class PrivCallTest {
null, null,
null, null,
null, null,
null,
null,
null); null);
final JsonRpcRequestContext request = ethCallRequest(privacyGroupId, callParameter, "latest"); final JsonRpcRequestContext request = ethCallRequest(privacyGroupId, callParameter, "latest");
final JsonRpcResponse expectedResponse = final JsonRpcResponse expectedResponse =
@ -203,6 +207,8 @@ public class PrivCallTest {
Bytes.EMPTY, Bytes.EMPTY,
null, null,
null, null,
null,
null,
null); null);
} }

@ -0,0 +1,23 @@
{
"request": {
"id": 4,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914",
"blobVersionedHashes" : ["0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d"],
"maxFeePerBlobGas": "0x3b9aca00"
},
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 4,
"result": "0x0000000000000000000000000000000000000000000000000000000000000001"
},
"statusCode": 200
}

@ -0,0 +1,22 @@
{
"request": {
"id": 4,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914",
"blobVersionedHashes" : ["0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d"]
},
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 4,
"error":{"code":-32603,"message":"Internal error"}
},
"statusCode": 200
}

@ -0,0 +1,23 @@
{
"request": {
"id": 4,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914",
"blobVersionedHashes" : ["0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d","0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d"],
"maxFeePerBlobGas": "0x0"
},
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 4,
"error":{"code":-32000,"message":"Total blob gas too high"}
},
"statusCode": 200
}

@ -0,0 +1,23 @@
{
"request": {
"id": 4,
"jsonrpc": "2.0",
"method": "eth_call",
"params": [
{
"to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
"from": "a94f5374fce5edbc8e2a8697c15331677e6ebf0b",
"data": "0x12a7b914",
"blobVersionedHashes" : ["0x0100000051c8833cfbaf272e62da1285b183b0405357f62b052a4894ffcdaa2d"],
"maxFeePerBlobGas": "0x0"
},
"latest"
]
},
"response": {
"jsonrpc": "2.0",
"id": 4,
"error":{"code":-32009,"message":"blob gas price below current blob base fee"}
},
"statusCode": 200
}

@ -23,10 +23,12 @@
"0x3437004a", "0x3437004a",
"0x2dbc88c1" "0x2dbc88c1"
], ],
"baseFeePerBlobGas" : [ "0x0", "0x1", "0x1" ],
"gasUsedRatio": [ "gasUsedRatio": [
0.004079142040086682, 0.004079142040086682,
0.003713085594819442 0.003713085594819442
], ],
"blobGasUsedRatio" : [ 0.0, 0.3333333333333333 ],
"reward": [ "reward": [
[ [
"0x3b9aca00", "0x3b9aca00",

@ -18,10 +18,12 @@
"0x3437004a", "0x3437004a",
"0x2dbc88c1" "0x2dbc88c1"
], ],
"baseFeePerBlobGas" : [ "0x0", "0x1", "0x1" ],
"gasUsedRatio": [ "gasUsedRatio": [
0.004079142040086682, 0.004079142040086682,
0.003713085594819442 0.003713085594819442
] ],
"blobGasUsedRatio" : [ 0.0, 0.3333333333333333 ]
} }
}, },
"statusCode": 200 "statusCode": 200

@ -16,6 +16,7 @@ package org.hyperledger.besu.ethereum.transaction;
import org.hyperledger.besu.datatypes.AccessListEntry; import org.hyperledger.besu.datatypes.AccessListEntry;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.VersionedHash;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.core.Transaction; import org.hyperledger.besu.ethereum.core.Transaction;
@ -37,6 +38,7 @@ public class CallParameter {
private final Optional<Wei> maxPriorityFeePerGas; private final Optional<Wei> maxPriorityFeePerGas;
private final Optional<Wei> maxFeePerGas; private final Optional<Wei> maxFeePerGas;
private final Optional<Wei> maxFeePerBlobGas;
private final Wei gasPrice; private final Wei gasPrice;
@ -45,6 +47,7 @@ public class CallParameter {
private final Bytes payload; private final Bytes payload;
private final Optional<List<AccessListEntry>> accessList; private final Optional<List<AccessListEntry>> accessList;
private final Optional<List<VersionedHash>> blobVersionedHashes;
public CallParameter( public CallParameter(
final Address from, final Address from,
@ -62,6 +65,8 @@ public class CallParameter {
this.gasPrice = gasPrice; this.gasPrice = gasPrice;
this.value = value; this.value = value;
this.payload = payload; this.payload = payload;
this.maxFeePerBlobGas = Optional.empty();
this.blobVersionedHashes = Optional.empty();
} }
public CallParameter( public CallParameter(
@ -83,6 +88,33 @@ public class CallParameter {
this.value = value; this.value = value;
this.payload = payload; this.payload = payload;
this.accessList = accessList; this.accessList = accessList;
this.maxFeePerBlobGas = Optional.empty();
this.blobVersionedHashes = Optional.empty();
}
public CallParameter(
final Address from,
final Address to,
final long gasLimit,
final Wei gasPrice,
final Optional<Wei> maxPriorityFeePerGas,
final Optional<Wei> maxFeePerGas,
final Wei value,
final Bytes payload,
final Optional<List<AccessListEntry>> accessList,
final Optional<Wei> maxFeePerBlobGas,
final Optional<List<VersionedHash>> blobVersionedHashes) {
this.from = from;
this.to = to;
this.gasLimit = gasLimit;
this.maxPriorityFeePerGas = maxPriorityFeePerGas;
this.maxFeePerGas = maxFeePerGas;
this.gasPrice = gasPrice;
this.value = value;
this.payload = payload;
this.accessList = accessList;
this.maxFeePerBlobGas = maxFeePerBlobGas;
this.blobVersionedHashes = blobVersionedHashes;
} }
public Address getFrom() { public Address getFrom() {
@ -121,6 +153,14 @@ public class CallParameter {
return accessList; return accessList;
} }
public Optional<Wei> getMaxFeePerBlobGas() {
return maxFeePerBlobGas;
}
public Optional<List<VersionedHash>> getBlobVersionedHashes() {
return blobVersionedHashes;
}
@Override @Override
public boolean equals(final Object o) { public boolean equals(final Object o) {
if (this == o) { if (this == o) {
@ -137,13 +177,26 @@ public class CallParameter {
&& Objects.equals(maxPriorityFeePerGas, that.maxPriorityFeePerGas) && Objects.equals(maxPriorityFeePerGas, that.maxPriorityFeePerGas)
&& Objects.equals(maxFeePerGas, that.maxFeePerGas) && Objects.equals(maxFeePerGas, that.maxFeePerGas)
&& Objects.equals(value, that.value) && Objects.equals(value, that.value)
&& Objects.equals(payload, that.payload); && Objects.equals(payload, that.payload)
&& Objects.equals(accessList, that.accessList)
&& Objects.equals(maxFeePerBlobGas, that.maxFeePerBlobGas)
&& Objects.equals(blobVersionedHashes, that.blobVersionedHashes);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return Objects.hash( return Objects.hash(
from, to, gasLimit, gasPrice, maxPriorityFeePerGas, maxFeePerGas, value, payload); from,
to,
gasLimit,
gasPrice,
maxPriorityFeePerGas,
maxFeePerGas,
value,
payload,
accessList,
maxFeePerBlobGas,
blobVersionedHashes);
} }
public static CallParameter fromTransaction(final Transaction tx) { public static CallParameter fromTransaction(final Transaction tx) {
@ -156,6 +209,8 @@ public class CallParameter {
tx.getMaxFeePerGas(), tx.getMaxFeePerGas(),
Wei.fromQuantity(tx.getValue()), Wei.fromQuantity(tx.getValue()),
tx.getPayload(), tx.getPayload(),
tx.getAccessList()); tx.getAccessList(),
tx.getMaxFeePerBlobGas(),
tx.getVersionedHashes());
} }
} }

@ -294,6 +294,10 @@ public class TransactionSimulator {
// Set access list if present // Set access list if present
callParams.getAccessList().ifPresent(transactionBuilder::accessList); callParams.getAccessList().ifPresent(transactionBuilder::accessList);
// Set versioned hashes if present
callParams.getBlobVersionedHashes().ifPresent(transactionBuilder::versionedHashes);
// Set max fee per blob gas if present
callParams.getMaxFeePerBlobGas().ifPresent(transactionBuilder::maxFeePerBlobGas);
final Wei gasPrice; final Wei gasPrice;
final Wei maxFeePerGas; final Wei maxFeePerGas;

@ -26,10 +26,12 @@ import org.hyperledger.besu.crypto.SECPSignature;
import org.hyperledger.besu.crypto.SignatureAlgorithm; import org.hyperledger.besu.crypto.SignatureAlgorithm;
import org.hyperledger.besu.crypto.SignatureAlgorithmFactory; import org.hyperledger.besu.crypto.SignatureAlgorithmFactory;
import org.hyperledger.besu.datatypes.Address; import org.hyperledger.besu.datatypes.Address;
import org.hyperledger.besu.datatypes.BlobsWithCommitments;
import org.hyperledger.besu.datatypes.Hash; import org.hyperledger.besu.datatypes.Hash;
import org.hyperledger.besu.datatypes.TransactionType; import org.hyperledger.besu.datatypes.TransactionType;
import org.hyperledger.besu.datatypes.Wei; import org.hyperledger.besu.datatypes.Wei;
import org.hyperledger.besu.ethereum.chain.Blockchain; import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlobTestFixture;
import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions; import org.hyperledger.besu.ethereum.core.BlockHeaderFunctions;
import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture; import org.hyperledger.besu.ethereum.core.BlockHeaderTestFixture;
@ -600,6 +602,86 @@ public class TransactionSimulatorTest {
verifyTransactionWasProcessed(expectedTransaction); verifyTransactionWasProcessed(expectedTransaction);
} }
@Test
public void shouldReturnSuccessfulResultWhenBlobTransactionProcessingIsSuccessful() {
final CallParameter callParameter =
blobTransactionCallParameter(Wei.ONE, Wei.ONE, Wei.ONE, 300, 3);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.BLOB)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.maxFeePerBlobGas(callParameter.getMaxFeePerBlobGas().get())
.versionedHashes(callParameter.getBlobVersionedHashes().get())
.signature(FAKE_SIGNATURE)
.build();
final CallParameter reverseEngineeredCallParam =
CallParameter.fromTransaction(expectedTransaction);
assertThat(reverseEngineeredCallParam).isEqualTo(callParameter);
mockProcessorStatusForTransaction(expectedTransaction, Status.SUCCESSFUL);
final Optional<TransactionSimulatorResult> result =
transactionSimulator.process(callParameter, 1L);
assertThat(result.get().isSuccessful()).isTrue();
verifyTransactionWasProcessed(expectedTransaction);
}
@Test
public void shouldReturnFailureResultWhenBlobTransactionProcessingFails() {
final CallParameter callParameter =
blobTransactionCallParameter(Wei.ONE, Wei.ONE, Wei.ONE, 300, 3);
final BlockHeader blockHeader = mockBlockHeader(Hash.ZERO, 1L, Wei.ONE);
mockBlockchainForBlockHeader(blockHeader);
mockWorldStateForAccount(blockHeader, callParameter.getFrom(), 1L);
final Transaction expectedTransaction =
Transaction.builder()
.type(TransactionType.BLOB)
.chainId(BigInteger.ONE)
.nonce(1L)
.gasLimit(callParameter.getGasLimit())
.maxFeePerGas(callParameter.getMaxFeePerGas().orElseThrow())
.maxPriorityFeePerGas(callParameter.getMaxPriorityFeePerGas().orElseThrow())
.to(callParameter.getTo())
.sender(callParameter.getFrom())
.value(callParameter.getValue())
.payload(callParameter.getPayload())
.maxFeePerBlobGas(callParameter.getMaxFeePerBlobGas().get())
.versionedHashes(callParameter.getBlobVersionedHashes().get())
.signature(FAKE_SIGNATURE)
.build();
final CallParameter reverseEngineeredCallParam =
CallParameter.fromTransaction(expectedTransaction);
assertThat(reverseEngineeredCallParam).isEqualTo(callParameter);
mockProcessorStatusForTransaction(expectedTransaction, Status.FAILED);
final Optional<TransactionSimulatorResult> result =
transactionSimulator.process(callParameter, 1L);
assertThat(result.get().isSuccessful()).isFalse();
verifyTransactionWasProcessed(expectedTransaction);
}
private void mockWorldStateForAccount( private void mockWorldStateForAccount(
final BlockHeader blockHeader, final Address address, final long nonce) { final BlockHeader blockHeader, final Address address, final long nonce) {
final Account account = mock(Account.class); final Account account = mock(Account.class);
@ -724,4 +806,25 @@ public class TransactionSimulatorTest {
Bytes.EMPTY, Bytes.EMPTY,
Optional.empty()); Optional.empty());
} }
private CallParameter blobTransactionCallParameter(
final Wei maxFeePerBlobGas,
final Wei maxFeePerGas,
final Wei maxPriorityFeePerGas,
final long gasLimit,
final int numberOfBlobs) {
BlobsWithCommitments bwc = new BlobTestFixture().createBlobsWithCommitments(numberOfBlobs);
return new CallParameter(
Address.fromHexString("0x0"),
Address.fromHexString("0x0"),
gasLimit,
Wei.of(0),
Optional.of(maxFeePerGas),
Optional.of(maxPriorityFeePerGas),
Wei.of(0),
Bytes.EMPTY,
Optional.empty(),
Optional.of(maxFeePerBlobGas),
Optional.of(bwc.getVersionedHashes()));
}
} }

Loading…
Cancel
Save