From bc2eed19b4678b575f645f018590dd33335e5211 Mon Sep 17 00:00:00 2001 From: Gabriel-Trintinalia Date: Fri, 16 Feb 2024 17:39:07 +1100 Subject: [PATCH] feat: add `eth_blobBaseFee` (#6581) Signed-off-by: Gabriel-Trintinalia --- CHANGELOG.md | 1 + .../besu/ethereum/api/jsonrpc/RpcMethod.java | 1 + .../internal/methods/EthBlobBaseFee.java | 57 ++++++++++++ .../jsonrpc/methods/EthJsonRpcMethods.java | 4 +- .../internal/methods/EthBlobBaseFeeTest.java | 87 +++++++++++++++++++ 5 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java create mode 100644 ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 1f5f3e0fb3c..c37cd834112 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,7 @@ - Experimental feature `--Xbonsai-code-using-code-hash-enabled` for storing Bonsai code storage by code hash [#6505](https://github.com/hyperledger/besu/pull/6505) - More accurate column size `storage rocksdb usage` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) - Adds `storage rocksdb x-stats` subcommand [#6540](https://github.com/hyperledger/besu/pull/6540) +- New `eth_blobBaseFee`JSON-RPC method [#6581](https://github.com/hyperledger/besu/pull/6581) ### Bug fixes - Fix the way an advertised host configured with `--p2p-host` is treated when communicating with the originator of a PING packet [#6225](https://github.com/hyperledger/besu/pull/6225) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java index d719e5b48b5..eb18f1379c1 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/RpcMethod.java @@ -98,6 +98,7 @@ public enum RpcMethod { ETH_CREATE_ACCESS_LIST("eth_createAccessList"), ETH_FEE_HISTORY("eth_feeHistory"), ETH_GAS_PRICE("eth_gasPrice"), + ETH_BLOB_BASE_FEE("eth_blobBaseFee"), ETH_GET_BALANCE("eth_getBalance"), ETH_GET_BLOCK_BY_HASH("eth_getBlockByHash"), ETH_GET_BLOCK_BY_NUMBER("eth_getBlockByNumber"), diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java new file mode 100644 index 00000000000..b1108e815a8 --- /dev/null +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFee.java @@ -0,0 +1,57 @@ +/* + * 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; + +import static org.hyperledger.besu.ethereum.mainnet.feemarket.ExcessBlobGasCalculator.calculateExcessBlobGasForParent; + +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.chain.Blockchain; +import org.hyperledger.besu.ethereum.core.BlockHeader; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSpec; + +public class EthBlobBaseFee implements JsonRpcMethod { + + final Blockchain blockchain; + + private final ProtocolSchedule protocolSchedule; + + public EthBlobBaseFee(final Blockchain blockchain, final ProtocolSchedule protocolSchedule) { + this.blockchain = blockchain; + this.protocolSchedule = protocolSchedule; + } + + @Override + public String getName() { + return RpcMethod.ETH_BLOB_BASE_FEE.getMethodName(); + } + + @Override + public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { + return new JsonRpcSuccessResponse( + requestContext.getRequest().getId(), Quantity.create(computeNextBlobBaseFee())); + } + + private Wei computeNextBlobBaseFee() { + final BlockHeader header = blockchain.getChainHeadHeader(); + ProtocolSpec spec = protocolSchedule.getForNextBlockHeader(header, header.getTimestamp()); + return spec.getFeeMarket().blobGasPricePerGas(calculateExcessBlobGasForParent(spec, header)); + } +} diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java index 88b9348edf0..827aa57c642 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/EthJsonRpcMethods.java @@ -18,6 +18,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthAccounts; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlobBaseFee; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthBlockNumber; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthCall; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.EthChainId; @@ -181,6 +182,7 @@ protected Map create() { new EthSubmitHashRate(miningCoordinator), new EthChainId(protocolSchedule.getChainId()), new EthGetMinerDataByBlockHash(blockchainQueries, protocolSchedule), - new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule)); + new EthGetMinerDataByBlockNumber(blockchainQueries, protocolSchedule), + new EthBlobBaseFee(blockchainQueries.getBlockchain(), protocolSchedule)); } } diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java new file mode 100644 index 00000000000..3e613cc9955 --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthBlobBaseFeeTest.java @@ -0,0 +1,87 @@ +/* + * 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; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.InMemoryKeyValueStorageProvider.createInMemoryBlockchain; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +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.JsonRpcSuccessResponse; +import org.hyperledger.besu.ethereum.chain.MutableBlockchain; +import org.hyperledger.besu.ethereum.core.Block; +import org.hyperledger.besu.ethereum.core.BlockDataGenerator; +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.FeeMarket; +import org.hyperledger.besu.evm.gascalculator.CancunGasCalculator; +import org.hyperledger.besu.evm.gascalculator.GasCalculator; +import org.hyperledger.besu.evm.gascalculator.ShanghaiGasCalculator; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class EthBlobBaseFeeTest { + private final BlockDataGenerator blockDataGenerator = new BlockDataGenerator(); + private MutableBlockchain blockchain; + private EthBlobBaseFee method; + private ProtocolSchedule protocolSchedule; + + @BeforeEach + public void setUp() { + protocolSchedule = mock(ProtocolSchedule.class); + Block genesisBlock = blockDataGenerator.genesisBlock(); + blockchain = createInMemoryBlockchain(genesisBlock); + blockDataGenerator + .blockSequence(genesisBlock, 10) + .forEach(block -> blockchain.appendBlock(block, blockDataGenerator.receipts(block))); + method = new EthBlobBaseFee(blockchain, protocolSchedule); + } + + /** Tests that the method returns the expected blob base fee */ + @Test + public void shouldReturnBlobBaseFee() { + configureProtocolSpec(FeeMarket.cancun(5, Optional.empty()), new CancunGasCalculator()); + assertThat(requestBlobBaseFee().getResult()).isEqualTo("0x1"); + } + + /** Tests that the method returns zero for forks that do not support blob transactions */ + @Test + public void shouldReturnZeroForNonBlobForks() { + configureProtocolSpec(FeeMarket.london(5, Optional.empty()), new ShanghaiGasCalculator()); + assertThat(requestBlobBaseFee().getResult()).isEqualTo("0x0"); + } + + private void configureProtocolSpec( + final BaseFeeMarket feeMarket, final GasCalculator gasCalculator) { + ProtocolSpec spec = mock(ProtocolSpec.class); + when(spec.getFeeMarket()).thenReturn(feeMarket); + when(spec.getGasCalculator()).thenReturn(gasCalculator); + when(protocolSchedule.getForNextBlockHeader( + blockchain.getChainHeadHeader(), blockchain.getChainHeadHeader().getTimestamp())) + .thenReturn(spec); + } + + private JsonRpcSuccessResponse requestBlobBaseFee() { + return (JsonRpcSuccessResponse) + method.response( + new JsonRpcRequestContext(new JsonRpcRequest("2.0", "eth_blobBaseFee", null))); + } +}