Skip to content

Commit

Permalink
Add json-rpc IPC support [hyperledger#535]
Browse files Browse the repository at this point in the history
Signed-off-by: Diego López León <[email protected]>
  • Loading branch information
diega committed Apr 5, 2022
1 parent c195461 commit a26ea45
Show file tree
Hide file tree
Showing 12 changed files with 578 additions and 0 deletions.
12 changes: 12 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import org.hyperledger.besu.controller.BesuController;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLHttpService;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcHttpService;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcService;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketService;
import org.hyperledger.besu.ethereum.api.query.cache.AutoTransactionLogBloomCachingService;
import org.hyperledger.besu.ethereum.api.query.cache.TransactionLogBloomCacher;
Expand Down Expand Up @@ -64,6 +65,7 @@ public class Runner implements AutoCloseable {
private final Optional<JsonRpcHttpService> jsonRpc;
private final Optional<JsonRpcHttpService> engineJsonRpc;
private final Optional<MetricsService> metrics;
private final Optional<JsonRpcIpcService> ipcJsonRpc;
private final Optional<Path> pidPath;
private final Optional<WebSocketService> webSocketRpc;
private final Optional<WebSocketService> engineWebSocketRpc;
Expand All @@ -84,6 +86,7 @@ public class Runner implements AutoCloseable {
final Optional<GraphQLHttpService> graphQLHttp,
final Optional<WebSocketService> webSocketRpc,
final Optional<WebSocketService> engineWebSocketRpc,
final Optional<JsonRpcIpcService> ipcJsonRpc,
final Optional<StratumServer> stratumServer,
final Optional<MetricsService> metrics,
final Optional<EthStatsService> ethStatsService,
Expand All @@ -101,6 +104,7 @@ public class Runner implements AutoCloseable {
this.engineJsonRpc = engineJsonRpc;
this.webSocketRpc = webSocketRpc;
this.engineWebSocketRpc = engineWebSocketRpc;
this.ipcJsonRpc = ipcJsonRpc;
this.metrics = metrics;
this.ethStatsService = ethStatsService;
this.besuController = besuController;
Expand All @@ -123,6 +127,10 @@ public void startExternalServices() {
webSocketRpc.ifPresent(service -> waitForServiceToStart("websocketRpc", service.start()));
engineWebSocketRpc.ifPresent(
service -> waitForServiceToStart("engineWebsocketRpc", service.start()));
ipcJsonRpc.ifPresent(
service ->
waitForServiceToStart(
"ipcJsonRpc", service.start().toCompletionStage().toCompletableFuture()));
stratumServer.ifPresent(server -> waitForServiceToStart("stratum", server.start()));
autoTransactionLogBloomCachingService.ifPresent(AutoTransactionLogBloomCachingService::start);
ethStatsService.ifPresent(EthStatsService::start);
Expand Down Expand Up @@ -158,6 +166,10 @@ public void stop() {
webSocketRpc.ifPresent(service -> waitForServiceToStop("websocketRpc", service.stop()));
engineWebSocketRpc.ifPresent(
service -> waitForServiceToStop("engineWebsocketRpc", service.stop()));
ipcJsonRpc.ifPresent(
service ->
waitForServiceToStop(
"ipcJsonRpc", service.stop().toCompletionStage().toCompletableFuture()));
metrics.ifPresent(service -> waitForServiceToStop("metrics", service.stop()));
ethStatsService.ifPresent(EthStatsService::stop);
besuController.getMiningCoordinator().stop();
Expand Down
49 changes: 49 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManager;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.filter.FilterManagerBuilder;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods.JsonRpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcService;
import org.hyperledger.besu.ethereum.api.jsonrpc.methods.JsonRpcMethodsFactory;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketRequestHandler;
Expand Down Expand Up @@ -188,6 +190,7 @@ public class RunnerBuilder {
private StorageProvider storageProvider;
private Supplier<List<Bytes>> forkIdSupplier;
private RpcEndpointServiceImpl rpcEndpointServiceImpl;
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;

public RunnerBuilder vertx(final Vertx vertx) {
this.vertx = vertx;
Expand Down Expand Up @@ -398,6 +401,12 @@ public RunnerBuilder rpcEndpointService(final RpcEndpointServiceImpl rpcEndpoint
return this;
}

public RunnerBuilder jsonRpcIpcConfiguration(
final JsonRpcIpcConfiguration jsonRpcIpcConfiguration) {
this.jsonRpcIpcConfiguration = jsonRpcIpcConfiguration;
return this;
}

public Runner build() {

Preconditions.checkNotNull(besuController);
Expand Down Expand Up @@ -832,6 +841,45 @@ public Runner build() {
ethStatsService = Optional.empty();
}

final Optional<JsonRpcIpcService> jsonRpcIpcService;
if (jsonRpcIpcConfiguration.isEnabled()) {
Map<String, JsonRpcMethod> nonEngineMethods =
jsonRpcMethods(
protocolSchedule,
context,
besuController,
peerNetwork,
blockchainQueries,
synchronizer,
transactionPool,
miningCoordinator,
metricsSystem,
supportedCapabilities,
jsonRpcConfiguration.getRpcApis().stream()
.filter(apiGroup -> !apiGroup.toLowerCase().startsWith("engine"))
.collect(Collectors.toList()),
filterManager,
accountLocalConfigPermissioningController,
nodeLocalConfigPermissioningController,
privacyParameters,
jsonRpcConfiguration,
webSocketConfiguration,
metricsConfiguration,
natService,
besuPluginContext.getNamedPlugins(),
dataDir,
rpcEndpointServiceImpl);

jsonRpcIpcService =
Optional.of(
new JsonRpcIpcService(
vertx,
jsonRpcIpcConfiguration.getPath(),
new JsonRpcExecutor(new BaseJsonRpcProcessor(), nonEngineMethods)));
} else {
jsonRpcIpcService = Optional.empty();
}

return new Runner(
vertx,
networkRunner,
Expand All @@ -841,6 +889,7 @@ public Runner build() {
graphQLHttpService,
webSocketService,
engineWebSocketService,
jsonRpcIpcService,
stratumServer,
metricsService,
ethStatsService,
Expand Down
22 changes: 22 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import org.hyperledger.besu.cli.options.unstable.DnsOptions;
import org.hyperledger.besu.cli.options.unstable.EthProtocolOptions;
import org.hyperledger.besu.cli.options.unstable.EvmOptions;
import org.hyperledger.besu.cli.options.unstable.IpcOptions;
import org.hyperledger.besu.cli.options.unstable.LauncherOptions;
import org.hyperledger.besu.cli.options.unstable.MergeOptions;
import org.hyperledger.besu.cli.options.unstable.MetricsCLIOptions;
Expand Down Expand Up @@ -111,6 +112,7 @@
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.authentication.JwtAlgorithm;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.api.tls.FileBasedPasswordProvider;
import org.hyperledger.besu.ethereum.api.tls.TlsClientAuthConfiguration;
Expand Down Expand Up @@ -284,6 +286,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable {
final LauncherOptions unstableLauncherOptions = LauncherOptions.create();
private final PrivacyPluginOptions unstablePrivacyPluginOptions = PrivacyPluginOptions.create();
private final EvmOptions unstableEvmOptions = EvmOptions.create();
private final IpcOptions unstableIpcOptions = IpcOptions.create();

// stable CLI options
private final DataStorageOptions dataStorageOptions = DataStorageOptions.create();
Expand Down Expand Up @@ -1275,6 +1278,7 @@ static class TxPoolOptionGroup {
private GraphQLConfiguration graphQLConfiguration;
private WebSocketConfiguration webSocketConfiguration;
private WebSocketConfiguration engineWebSocketConfiguration;
private JsonRpcIpcConfiguration jsonRpcIpcConfiguration;
private ApiConfiguration apiConfiguration;
private MetricsConfiguration metricsConfiguration;
private Optional<PermissioningConfiguration> permissioningConfiguration;
Expand Down Expand Up @@ -1486,6 +1490,7 @@ private void handleUnstableOptions() {
.put("Launcher", unstableLauncherOptions)
.put("Merge", mergeOptions)
.put("EVM Options", unstableEvmOptions)
.put("IPC Options", unstableIpcOptions)
.build();

UnstableOptionsSubCommand.createUnstableOptions(commandLine, unstableOptions);
Expand Down Expand Up @@ -1579,6 +1584,7 @@ private Runner buildRunner() {
engineJsonRpcConfiguration,
webSocketConfiguration,
engineWebSocketConfiguration,
jsonRpcIpcConfiguration,
apiConfiguration,
metricsConfiguration,
permissioningConfiguration,
Expand Down Expand Up @@ -1907,6 +1913,8 @@ private void configure() throws Exception {
engineWebSocketConfiguration =
engineWebSocketConfiguration(
engineRPCOptionGroup.engineRpcWsPort, engineRPCOptionGroup.engineHostsAllowlist);
jsonRpcIpcConfiguration =
jsonRpcIpcConfiguration(unstableIpcOptions.isEnabled(), unstableIpcOptions.getIpcPath());
apiConfiguration = apiConfiguration();
// hostsWhitelist is a hidden option. If it is specified, add the list to hostAllowlist
if (!hostsWhitelist.isEmpty()) {
Expand Down Expand Up @@ -1937,6 +1945,17 @@ private void configure() throws Exception {
instantiateSignatureAlgorithmFactory();
}

private JsonRpcIpcConfiguration jsonRpcIpcConfiguration(
final Boolean enabled, final Path ipcPath) {
final Path actualPath;
if (ipcPath == null) {
actualPath = IpcOptions.getDefaultPath(dataDir());
} else {
actualPath = ipcPath;
}
return new JsonRpcIpcConfiguration(vertx.isNativeTransportEnabled() && enabled, actualPath);
}

private GoQuorumPrivacyParameters configureGoQuorumPrivacy(
final KeyValueStorageProvider storageProvider) {
return new GoQuorumPrivacyParameters(
Expand Down Expand Up @@ -2745,6 +2764,7 @@ private Runner synchronize(
final JsonRpcConfiguration engineJsonRpcConfiguration,
final WebSocketConfiguration webSocketConfiguration,
final WebSocketConfiguration engineWebSocketConfiguration,
final JsonRpcIpcConfiguration jsonRpcIpcConfiguration,
final ApiConfiguration apiConfiguration,
final MetricsConfiguration metricsConfiguration,
final Optional<PermissioningConfiguration> permissioningConfiguration,
Expand Down Expand Up @@ -2781,6 +2801,7 @@ private Runner synchronize(
.engineJsonRpcConfiguration(engineJsonRpcConfiguration)
.webSocketConfiguration(webSocketConfiguration)
.engineWebSocketConfiguration(engineWebSocketConfiguration)
.jsonRpcIpcConfiguration(jsonRpcIpcConfiguration)
.apiConfiguration(apiConfiguration)
.pidPath(pidPath)
.dataDir(dataDir())
Expand Down Expand Up @@ -2810,6 +2831,7 @@ protected Vertx createVertx(final VertxOptions vertxOptions) {

private VertxOptions createVertxOptions(final MetricsSystem metricsSystem) {
return new VertxOptions()
.setPreferNativeTransport(true)
.setMetricsOptions(
new MetricsOptions()
.setEnabled(true)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright contributors to Hyperledger 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.cli.options.unstable;

import java.nio.file.Path;

import picocli.CommandLine;

public class IpcOptions {
private static final String DEFAULT_IPC_FILE = "besu.ipc";

public static IpcOptions create() {
return new IpcOptions();
}

public static Path getDefaultPath(final Path dataDir) {
return dataDir.resolve(DEFAULT_IPC_FILE);
}

@CommandLine.Option(
names = {"--Xrpc-ipc-enabled"},
hidden = true,
description = "Set to start the JSON-RPC IPC service (default: ${DEFAULT-VALUE})")
private final Boolean enabled = false;

@CommandLine.Option(
names = {"--Xrpc-ipc-path"},
hidden = true,
description =
"IPC socket/pipe file (default: a file named \""
+ DEFAULT_IPC_FILE
+ "\" in the Besu data directory)")
private Path ipcPath;

public Boolean isEnabled() {
return enabled;
}

public Path getIpcPath() {
return ipcPath;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.blockcreation.MiningCoordinator;
import org.hyperledger.besu.ethereum.blockcreation.PoWMiningCoordinator;
Expand Down Expand Up @@ -148,6 +149,7 @@ public void enodeUrlShouldHaveAdvertisedHostWhenDiscoveryDisabled() {
.permissioningService(mock(PermissioningServiceImpl.class))
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(mock(WebSocketConfiguration.class))
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(vertx)
.dataDir(dataDir.getRoot().toPath())
Expand Down Expand Up @@ -192,6 +194,7 @@ public void movingAcrossProtocolSpecsUpdatesNodeRecord() {
.jsonRpcConfiguration(mock(JsonRpcConfiguration.class))
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(mock(WebSocketConfiguration.class))
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
Expand Down Expand Up @@ -247,6 +250,7 @@ public void whenEngineApiAddedListensOnDefaultPort() {
.engineJsonRpcConfiguration(engine)
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(mock(WebSocketConfiguration.class))
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
Expand Down Expand Up @@ -285,6 +289,7 @@ public void whenEngineApiAddedWebSocketReadyOnDefaultPort() {
.permissioningService(mock(PermissioningServiceImpl.class))
.jsonRpcConfiguration(JsonRpcConfiguration.createDefault())
.webSocketConfiguration(wsRpc)
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.engineWebSocketConfiguration(engineWsRpc)
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
Expand Down Expand Up @@ -326,6 +331,7 @@ public void noEngineApiNoServiceForMethods() {
.jsonRpcConfiguration(defaultRpcConfig)
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(defaultWebSockConfig)
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
Expand Down Expand Up @@ -372,6 +378,7 @@ public void assertTransitionStratumConfiguration() {
.engineJsonRpcConfiguration(engine)
.graphQLConfiguration(mock(GraphQLConfiguration.class))
.webSocketConfiguration(mock(WebSocketConfiguration.class))
.jsonRpcIpcConfiguration(mock(JsonRpcIpcConfiguration.class))
.metricsConfiguration(mock(MetricsConfiguration.class))
.vertx(Vertx.vertx())
.dataDir(dataDir.getRoot().toPath())
Expand Down
4 changes: 4 additions & 0 deletions besu/src/test/java/org/hyperledger/besu/RunnerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.hyperledger.besu.ethereum.ProtocolContext;
import org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.ipc.JsonRpcIpcConfiguration;
import org.hyperledger.besu.ethereum.api.jsonrpc.websocket.WebSocketConfiguration;
import org.hyperledger.besu.ethereum.core.Block;
import org.hyperledger.besu.ethereum.core.BlockImporter;
Expand Down Expand Up @@ -201,6 +202,8 @@ private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesi
final JsonRpcConfiguration aheadJsonRpcConfiguration = jsonRpcConfiguration();
final GraphQLConfiguration aheadGraphQLConfiguration = graphQLConfiguration();
final WebSocketConfiguration aheadWebSocketConfiguration = wsRpcConfiguration();
final JsonRpcIpcConfiguration aheadJsonRpcIpcConfiguration =
new JsonRpcIpcConfiguration(false, temp.newFile().toPath());
final MetricsConfiguration aheadMetricsConfiguration = metricsConfiguration();
final Path pidPath = temp.getRoot().toPath().resolve("pid");
final RunnerBuilder runnerBuilder =
Expand All @@ -225,6 +228,7 @@ private void syncFromGenesis(final SyncMode mode, final GenesisConfigFile genesi
.jsonRpcConfiguration(aheadJsonRpcConfiguration)
.graphQLConfiguration(aheadGraphQLConfiguration)
.webSocketConfiguration(aheadWebSocketConfiguration)
.jsonRpcIpcConfiguration(aheadJsonRpcIpcConfiguration)
.metricsConfiguration(aheadMetricsConfiguration)
.dataDir(dbAhead)
.pidPath(pidPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ public void initMocks() throws Exception {
when(mockRunnerBuilder.engineWebSocketConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.graphQLConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.webSocketConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.jsonRpcIpcConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.apiConfiguration(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.dataDir(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.bannedNodeIds(any())).thenReturn(mockRunnerBuilder);
Expand Down
3 changes: 3 additions & 0 deletions ethereum/api/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ dependencies {
implementation "org.immutables:value-annotations"

runtimeOnly 'org.bouncycastle:bcpkix-jdk15on'
runtimeOnly 'io.netty:netty-transport-native-epoll'
runtimeOnly 'io.netty:netty-transport-native-kqueue'

testImplementation project(':config')
testImplementation project(path: ':config', configuration: 'testSupportArtifacts')
Expand All @@ -89,6 +91,7 @@ dependencies {

testImplementation 'com.squareup.okhttp3:okhttp'
testImplementation 'io.vertx:vertx-auth-jwt'
testImplementation 'io.vertx:vertx-junit5'
testImplementation 'io.vertx:vertx-unit'
testImplementation 'io.vertx:vertx-web-client'
testImplementation 'junit:junit'
Expand Down
Loading

0 comments on commit a26ea45

Please sign in to comment.