diff --git a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java index 7bce5f5de08..ed11de7f035 100644 --- a/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java +++ b/consensus/merge/src/main/java/org/hyperledger/besu/consensus/merge/TransitionProtocolSchedule.java @@ -27,6 +27,7 @@ import java.math.BigInteger; import java.util.List; +import java.util.NavigableSet; import java.util.Optional; import java.util.function.Predicate; @@ -252,4 +253,9 @@ public Optional getNextProtocolSpec(final long currentTim public Optional getLatestProtocolSpec() { return getPostMergeSchedule().getLatestProtocolSpec(); } + + @Override + public NavigableSet getProtocolSpecs() { + return getPostMergeSchedule().getProtocolSpecs(); + } } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfig.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfig.java index 689f2bdb155..5be5b54b33e 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfig.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfig.java @@ -15,10 +15,14 @@ package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.datatypes.HardforkId; 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.exception.InvalidJsonRpcParameters; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonRpcParameter; 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.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.BlockHeader; import org.hyperledger.besu.ethereum.forkid.ForkIdManager; @@ -31,11 +35,13 @@ import java.util.Map; import java.util.Map.Entry; +import java.util.NavigableSet; import java.util.Optional; import java.util.TreeMap; import java.util.function.Supplier; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Suppliers; @@ -46,6 +52,8 @@ public class EthConfig implements JsonRpcMethod { private final BlockchainQueries blockchain; private final ProtocolSchedule protocolSchedule; private final ForkIdManager forkIdManager; + private final Long firstTimestampMilestone; + private final Long firstBlobsMilestone; public EthConfig( final BlockchainQueries blockchain, @@ -59,6 +67,10 @@ public EthConfig( blockchain.getBlockchain(), genesisConfigOptions.getForkBlockNumbers(), genesisConfigOptions.getForkBlockTimestamps()); + firstTimestampMilestone = + protocolSchedule.milestoneFor(HardforkId.MainnetHardforkId.SHANGHAI).orElse(0L); + firstBlobsMilestone = + protocolSchedule.milestoneFor(HardforkId.MainnetHardforkId.CANCUN).orElse(0L); } @Override @@ -68,13 +80,24 @@ public String getName() { @Override public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { + ObjectNode result = mapperSupplier.get().createObjectNode(); + if (showAllForks(requestContext)) { + final ArrayNode allForks = result.putArray("all"); + final NavigableSet protocolSpecs = protocolSchedule.getProtocolSpecs(); + final var it = protocolSpecs.descendingIterator(); + while (it.hasNext()) { + final ScheduledProtocolSpec spec = it.next(); + generateConfig(allForks.addObject(), spec.fork(), spec.spec()); + } + return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result); + } + BlockHeader header = blockchain.getBlockchain().getChainHeadHeader(); long currentTime = System.currentTimeMillis() / 1000; ProtocolSpec current = protocolSchedule.getForNextBlockHeader(header, currentTime); Optional next = protocolSchedule.getNextProtocolSpec(currentTime); Optional last = protocolSchedule.getLatestProtocolSpec(); - ObjectNode result = mapperSupplier.get().createObjectNode(); ObjectNode currentNode = result.putObject("current"); generateConfig(currentNode, current); if (next.isPresent()) { @@ -93,8 +116,23 @@ public JsonRpcResponse response(final JsonRpcRequestContext requestContext) { return new JsonRpcSuccessResponse(requestContext.getRequest().getId(), result); } - private String getForkIdAsHexString(final long currentTime) { - return forkIdManager.getForkIdByTimestamp(currentTime).getHash().toHexString(); + private boolean showAllForks(final JsonRpcRequestContext requestContext) { + try { + final Optional optionalParameter = + requestContext.getOptionalParameter(0, Boolean.class); + return optionalParameter.orElse(false); + } catch (JsonRpcParameter.JsonRpcParameterException e) { + throw new InvalidJsonRpcParameters( + "Invalid showAllForks boolean parameter (index 0)", RpcErrorType.INVALID_PARAMS, e); + } + } + + private String getForkIdAsHexString(final long milestone) { + if (milestone >= firstTimestampMilestone) { + return forkIdManager.getForkIdByTimestamp(milestone).getHash().toHexString(); + } else { + return forkIdManager.getForkIdByBlockNumber(milestone).getHash().toHexString(); + } } void generateConfig(final ObjectNode result, final ScheduledProtocolSpec scheduledSpec) { @@ -106,13 +144,19 @@ void generateConfig(final ObjectNode result, final ProtocolSpec spec) { } void generateConfig(final ObjectNode result, final Hardfork forkId, final ProtocolSpec spec) { - result.put("activationTime", forkId.milestone()); + if (forkId.milestone() < firstTimestampMilestone) { + result.put("activationBlock", forkId.milestone()); + } else { + result.put("activationTime", forkId.milestone()); + } - ObjectNode blobs = result.putObject("blobSchedule"); - blobs.put( - "baseFeeUpdateFraction", spec.getFeeMarket().getBaseFeeUpdateFraction().longValueExact()); - blobs.put("max", spec.getGasLimitCalculator().currentBlobGasLimit() / (128 * 1024)); - blobs.put("target", spec.getGasLimitCalculator().getTargetBlobGasPerBlock() / (128 * 1024)); + if (forkId.milestone() >= firstBlobsMilestone) { + ObjectNode blobs = result.putObject("blobSchedule"); + blobs.put( + "baseFeeUpdateFraction", spec.getFeeMarket().getBaseFeeUpdateFraction().longValueExact()); + blobs.put("max", spec.getGasLimitCalculator().currentBlobGasLimit() / (128 * 1024)); + blobs.put("target", spec.getGasLimitCalculator().getTargetBlobGasPerBlock() / (128 * 1024)); + } result.put( "chainId", protocolSchedule.getChainId().map(c -> "0x" + c.toString(16)).orElse(null)); diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfigTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfigTest.java new file mode 100644 index 00000000000..5532ba8cb9e --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthConfigTest.java @@ -0,0 +1,70 @@ +/* + * Copyright contributors to Besu. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.GenesisConfigOptions; +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.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.core.BlockchainSetupUtil; + +import java.math.BigInteger; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class EthConfigTest { + + private EthConfig method; + + @Mock private BlockchainQueries blockchainQueries; + @Mock private GenesisConfigOptions genesisConfigOptions; + protected BlockchainSetupUtil blockchainSetupUtil; + + @BeforeEach + void setup() { + blockchainSetupUtil = BlockchainSetupUtil.forMainnet(); + when(blockchainQueries.getBlockchain()).thenReturn(blockchainSetupUtil.getBlockchain()); + method = + new EthConfig( + blockchainQueries, blockchainSetupUtil.getProtocolSchedule(), genesisConfigOptions); + } + + @Test + void ethConfigForMainnet() { + final JsonRpcSuccessResponse res = + ((JsonRpcSuccessResponse) + method.response( + new JsonRpcRequestContext( + new JsonRpcRequest("2.0", "eth_config", new Object[] {true})))); + final ObjectNode result = (ObjectNode) res.getResult(); + assertThat(result.has("all")).isTrue(); + assertThat(result.get("all").size()).isGreaterThan(3); + for (JsonNode forkObj : result.get("all")) { + assertThat(forkObj.get("chainId").asText()).isEqualTo("0x" + BigInteger.ONE.toString(16)); + } + System.out.println(result); + } +} diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java index bef743cd2c9..e965fd62641 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/forkid/ForkIdManager.java @@ -240,4 +240,13 @@ public ForkId getForkIdByTimestamp(final long timestamp) { } return allForkIds.isEmpty() ? new ForkId(genesisHashCrc, 0) : allForkIds.getLast(); } + + public ForkId getForkIdByBlockNumber(final long blockNumber) { + for (final ForkId forkId : blockNumbersForkIds) { + if (blockNumber < forkId.getNext()) { + return forkId; + } + } + return allForkIds.isEmpty() ? new ForkId(genesisHashCrc, 0) : allForkIds.getLast(); + } } diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java index 300032a1c90..63a1fb069c2 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/DefaultProtocolSchedule.java @@ -109,6 +109,11 @@ public Optional getLatestProtocolSpec() { return protocolSpecs.stream().max(Comparator.comparing(ScheduledProtocolSpec::fork)); } + @Override + public NavigableSet getProtocolSpecs() { + return protocolSpecs; + } + @Override public Optional getChainId() { return chainId; diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java index 59b61cba50e..cec1a1376a1 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/mainnet/ProtocolSchedule.java @@ -25,6 +25,7 @@ import java.math.BigInteger; import java.util.List; import java.util.Map; +import java.util.NavigableSet; import java.util.Optional; import java.util.function.Predicate; @@ -50,6 +51,8 @@ default ProtocolSpec getForNextBlockHeader( Optional getLatestProtocolSpec(); + NavigableSet getProtocolSpecs(); + Optional getChainId(); String listMilestones();