Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check existence of hardfork milestone to decide if engine APIs should be added or not #8136

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -172,7 +175,7 @@ protected Map<String, JsonRpcMethod> 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,
Expand All @@ -183,7 +186,7 @@ protected Map<String, JsonRpcMethod> create() {
protocolSchedule));
}

if (protocolSchedule.anyMatch(p -> p.spec().getName().equalsIgnoreCase("prague"))) {
if (protocolSchedule.milestoneFor(PRAGUE).isPresent()) {
executionEngineApisSupported.add(
new EngineGetPayloadV4(
consensusEngineServer,
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Capability> 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<String, JsonRpcMethod> 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");
}
}
56 changes: 56 additions & 0 deletions ethereum/api/src/test/resources/prague_all_milestones_zero.json
Original file line number Diff line number Diff line change
@@ -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":{
daniellehrner marked this conversation as resolved.
Show resolved Hide resolved
"a05b21E5186Ce93d2a226722b85D6e550Ac7D6E3": {
"privateKey": "3a4ff6d22d7502ef2452368165422861c01a0f72f851793b372b87888dc3c453",
"balance": "90000000000000000000000"
}
},
"number":"0x0",
"gasUsed":"0x0",
"parentHash":"0x0000000000000000000000000000000000000000000000000000000000000000",
"baseFeePerGas":"0x7"
}
Original file line number Diff line number Diff line change
Expand Up @@ -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())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading