diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java index fc0f18d7e5b..c57916f744a 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/ExecutionEngineJsonRpcMethods.java @@ -14,6 +14,9 @@ */ package org.hyperledger.besu.ethereum.api.jsonrpc.methods; +import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.CANCUN; +import static org.hyperledger.besu.datatypes.HardforkId.MainnetHardforkId.PRAGUE; + import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; import org.hyperledger.besu.ethereum.ProtocolContext; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; @@ -172,7 +175,7 @@ protected Map create() { new EngineGetBlobsV1( consensusEngineServer, protocolContext, engineQosTimer, transactionPool))); - if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("cancun"))) { + if (protocolSchedule.milestoneFor(CANCUN).isPresent()) { executionEngineApisSupported.add( new EngineGetPayloadV3( consensusEngineServer, @@ -183,7 +186,7 @@ protected Map create() { protocolSchedule)); } - if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("prague"))) { + if (protocolSchedule.milestoneFor(PRAGUE).isPresent()) { executionEngineApisSupported.add( new EngineGetPayloadV4( consensusEngineServer, diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactoryTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactoryTest.java new file mode 100644 index 00000000000..62ba71c75ce --- /dev/null +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/methods/JsonRpcMethodsFactoryTest.java @@ -0,0 +1,152 @@ +/* + * 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.methods; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hyperledger.besu.ethereum.core.ProtocolScheduleFixture.getGenesisConfigOptions; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import org.hyperledger.besu.config.GenesisConfigOptions; +import org.hyperledger.besu.config.StubGenesisConfigOptions; +import org.hyperledger.besu.consensus.merge.blockcreation.MergeMiningCoordinator; +import org.hyperledger.besu.ethereum.ProtocolContext; +import org.hyperledger.besu.ethereum.api.ApiConfiguration; +import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration; +import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod; +import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration; +import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; +import org.hyperledger.besu.ethereum.chain.BadBlockManager; +import org.hyperledger.besu.ethereum.core.MiningConfiguration; +import org.hyperledger.besu.ethereum.core.PrivacyParameters; +import org.hyperledger.besu.ethereum.core.Synchronizer; +import org.hyperledger.besu.ethereum.eth.manager.EthPeers; +import org.hyperledger.besu.ethereum.eth.transactions.TransactionPool; +import org.hyperledger.besu.ethereum.mainnet.MainnetProtocolSchedule; +import org.hyperledger.besu.ethereum.mainnet.ProtocolSchedule; +import org.hyperledger.besu.ethereum.p2p.network.P2PNetwork; +import org.hyperledger.besu.ethereum.p2p.rlpx.wire.Capability; +import org.hyperledger.besu.ethereum.permissioning.AccountLocalConfigPermissioningController; +import org.hyperledger.besu.ethereum.permissioning.NodeLocalConfigPermissioningController; +import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; +import org.hyperledger.besu.metrics.noop.NoOpMetricsSystem; +import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration; +import org.hyperledger.besu.nat.NatService; +import org.hyperledger.besu.testutil.DeterministicEthScheduler; + +import java.math.BigInteger; +import java.nio.file.Path; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Optional; +import java.util.Set; + +import io.vertx.core.Vertx; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class JsonRpcMethodsFactoryTest { + private static final String CLIENT_NODE_NAME = "TestClientVersion/0.1.0"; + private static final String CLIENT_VERSION = "0.1.0"; + private static final String CLIENT_COMMIT = "12345678"; + private static final BigInteger NETWORK_ID = BigInteger.valueOf(123); + + @Mock private BlockchainQueries blockchainQueries; + @Mock private MergeMiningCoordinator mergeCoordinator; + + @TempDir private Path folder; + + final Set supportedCapabilities = new HashSet<>(); + private final NatService natService = new NatService(Optional.empty()); + private final Vertx vertx = Vertx.vertx(); + + private ProtocolSchedule pragueAllMilestonesZeroProtocolSchedule; + private JsonRpcConfiguration configuration; + + @BeforeEach + public void setup() { + configuration = JsonRpcConfiguration.createEngineDefault(); + configuration.setPort(0); + + pragueAllMilestonesZeroProtocolSchedule = + MainnetProtocolSchedule.fromConfig( + getPragueAllZeroMilestonesConfigOptions(), + Optional.empty(), + Optional.empty(), + Optional.empty(), + MiningConfiguration.newDefault(), + new BadBlockManager(), + false, + new NoOpMetricsSystem()); + + when(mergeCoordinator.isCompatibleWithEngineApi()).thenReturn(true); + } + + @Test + public void shouldActivateEngineApisIfMilestonesAreAllZero() { + final Map rpcMethods = + new JsonRpcMethodsFactory() + .methods( + CLIENT_NODE_NAME, + CLIENT_VERSION, + CLIENT_COMMIT, + NETWORK_ID, + new StubGenesisConfigOptions(), + mock(P2PNetwork.class), + blockchainQueries, + mock(Synchronizer.class), + pragueAllMilestonesZeroProtocolSchedule, + mock(ProtocolContext.class), + mock(FilterManager.class), + mock(TransactionPool.class), + mock(MiningConfiguration.class), + mergeCoordinator, + new NoOpMetricsSystem(), + supportedCapabilities, + Optional.of(mock(AccountLocalConfigPermissioningController.class)), + Optional.of(mock(NodeLocalConfigPermissioningController.class)), + configuration.getRpcApis(), + mock(PrivacyParameters.class), + mock(JsonRpcConfiguration.class), + mock(WebSocketConfiguration.class), + mock(MetricsConfiguration.class), + mock(GraphQLConfiguration.class), + natService, + new HashMap<>(), + folder, + mock(EthPeers.class), + vertx, + mock(ApiConfiguration.class), + Optional.empty(), + mock(TransactionSimulator.class), + new DeterministicEthScheduler()); + + assertThat(rpcMethods).containsKey("engine_getPayloadV3"); + assertThat(rpcMethods).containsKey("engine_getPayloadV4"); + assertThat(rpcMethods).containsKey("engine_newPayloadV4"); + } + + private GenesisConfigOptions getPragueAllZeroMilestonesConfigOptions() { + return getGenesisConfigOptions("/prague_all_milestones_zero.json"); + } +} diff --git a/ethereum/api/src/test/resources/prague_all_milestones_zero.json b/ethereum/api/src/test/resources/prague_all_milestones_zero.json new file mode 100644 index 00000000000..4f41c8775c8 --- /dev/null +++ b/ethereum/api/src/test/resources/prague_all_milestones_zero.json @@ -0,0 +1,56 @@ +{ + "config": { + "chainId":20211, + "homesteadBlock":0, + "eip150Block":0, + "eip155Block":0, + "eip158Block":0, + "byzantiumBlock":0, + "constantinopleBlock":0, + "petersburgBlock":0, + "istanbulBlock":0, + "muirGlacierBlock":0, + "berlinBlock":0, + "londonBlock":0, + "terminalTotalDifficulty":0, + "cancunTime":0, + "pragueTime":0, + "blobSchedule": { + "cancun": { + "target": 3, + "max": 6, + "baseFeeUpdateFraction": 3338477 + }, + "prague": { + "target": 6, + "max": 9, + "baseFeeUpdateFraction": 5007716 + }, + "osaka": { + "target": 9, + "max": 12, + "baseFeeUpdateFraction": 5007716 + } + }, + "ethash": { + }, + "depositContractAddress": "0x4242424242424242424242424242424242424242", + "withdrawalRequestContractAddress": "0x00A3ca265EBcb825B45F985A16CEFB49958cE017", + "consolidationRequestContractAddress": "0x00b42dbF2194e931E80326D950320f7d9Dbeac02" + }, + "nonce":"0x42", + "timestamp":"0x0", + "gasLimit":"0x1C9C380", + "difficulty":"0x400000000", + "coinbase":"0x0000000000000000000000000000000000000000", + "alloc":{ + "a05b21E5186Ce93d2a226722b85D6e550Ac7D6E3": { + "privateKey": "3a4ff6d22d7502ef2452368165422861c01a0f72f851793b372b87888dc3c453", + "balance": "90000000000000000000000" + } + }, + "number":"0x0", + "gasUsed":"0x0", + "parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000", + "baseFeePerGas":"0x7" +} \ No newline at end of file diff --git a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java index fc5ca291233..c246066e951 100644 --- a/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java +++ b/ethereum/core/src/test-support/java/org/hyperledger/besu/ethereum/core/ProtocolScheduleFixture.java @@ -45,9 +45,13 @@ public class ProtocolScheduleFixture { new NoOpMetricsSystem()); private static GenesisConfigOptions getMainnetConfigOptions() { + return getGenesisConfigOptions("/mainnet.json"); + } + + public static GenesisConfigOptions getGenesisConfigOptions(final String genesisConfig) { // this method avoids reading all the alloc accounts when all we want is the "config" section try (final JsonParser jsonParser = - new JsonFactory().createParser(GenesisConfig.class.getResource("/mainnet.json"))) { + new JsonFactory().createParser(GenesisConfig.class.getResource(genesisConfig))) { while (jsonParser.nextToken() != JsonToken.END_OBJECT) { if ("config".equals(jsonParser.getCurrentName())) { diff --git a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java index bd5a9e7ec9c..c6e2979520c 100644 --- a/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java +++ b/ethereum/eth/src/test/java/org/hyperledger/besu/ethereum/eth/sync/backwardsync/BackwardSyncAlgSpec.java @@ -189,7 +189,7 @@ public void shouldAwokeWhenConditionReachedAndReady() throws Exception { completionCaptor.getValue().onInitialSyncCompleted(); - voidCompletableFuture.get(800, TimeUnit.MILLISECONDS); + voidCompletableFuture.get(5, TimeUnit.SECONDS); assertThat(voidCompletableFuture).isCompleted(); verify(context.getSyncState()).unsubscribeTTDReached(88L);