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

Add ethstats support #1239

Merged
merged 18 commits into from
Aug 4, 2020
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions besu/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ dependencies {
implementation project(':ethereum:retesteth')
implementation project(':ethereum:rlp')
implementation project(':ethereum:stratum')
implementation project(':ethereum:ethstats')
implementation project(':metrics:core')
implementation project(':nat')
implementation project(':plugin-api')
Expand Down
2 changes: 1 addition & 1 deletion besu/src/main/java/org/hyperledger/besu/BesuInfo.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/
package org.hyperledger.besu;

import org.hyperledger.besu.util.PlatformDetector;
import org.hyperledger.besu.util.platform.PlatformDetector;

import java.util.Optional;

Expand Down
7 changes: 7 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import org.hyperledger.besu.ethereum.p2p.network.NetworkRunner;
import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL;
import org.hyperledger.besu.ethereum.stratum.StratumServer;
import org.hyperledger.besu.ethstats.EthStatsService;
import org.hyperledger.besu.metrics.prometheus.MetricsService;
import org.hyperledger.besu.nat.NatService;

Expand Down Expand Up @@ -62,6 +63,7 @@ public class Runner implements AutoCloseable {
private final Optional<GraphQLHttpService> graphQLHttp;
private final Optional<WebSocketService> websocketRpc;
private final Optional<MetricsService> metrics;
private final Optional<EthStatsService> ethStatsService;

private final BesuController besuController;
private final Path dataDir;
Expand All @@ -78,6 +80,7 @@ public class Runner implements AutoCloseable {
final Optional<WebSocketService> websocketRpc,
final Optional<StratumServer> stratumServer,
final Optional<MetricsService> metrics,
final Optional<EthStatsService> ethStatsService,
final BesuController besuController,
final Path dataDir,
final Optional<Path> pidPath,
Expand All @@ -91,6 +94,7 @@ public class Runner implements AutoCloseable {
this.jsonRpc = jsonRpc;
this.websocketRpc = websocketRpc;
this.metrics = metrics;
this.ethStatsService = ethStatsService;
this.besuController = besuController;
this.dataDir = dataDir;
this.stratumServer = stratumServer;
Expand Down Expand Up @@ -122,6 +126,9 @@ public void start() {
writeBesuNetworksToFile();
autoTransactionLogBloomCachingService.ifPresent(AutoTransactionLogBloomCachingService::start);
writePidFile();

ethStatsService.ifPresent(EthStatsService::start);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you missed the stop

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch, I just added it


} catch (final Exception ex) {
LOG.error("Startup failed", ex);
throw new IllegalStateException(ex);
Expand Down
35 changes: 35 additions & 0 deletions besu/src/main/java/org/hyperledger/besu/RunnerBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@
import org.hyperledger.besu.ethereum.stratum.StratumServer;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.worldstate.WorldStateArchive;
import org.hyperledger.besu.ethstats.EthStatsService;
import org.hyperledger.besu.ethstats.util.NetstatsUrl;
import org.hyperledger.besu.metrics.ObservableMetricsSystem;
import org.hyperledger.besu.metrics.prometheus.MetricsConfiguration;
import org.hyperledger.besu.metrics.prometheus.MetricsService;
Expand Down Expand Up @@ -115,6 +117,7 @@

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import graphql.GraphQL;
import io.vertx.core.Vertx;
import org.apache.logging.log4j.LogManager;
Expand Down Expand Up @@ -143,6 +146,8 @@ public class RunnerBuilder {
private float fractionRemoteConnectionsAllowed;
private EthNetworkConfig ethNetworkConfig;

private String ethstatsUrl;
private String ethstatsContact;
private JsonRpcConfiguration jsonRpcConfiguration;
private GraphQLConfiguration graphQLConfiguration;
private WebSocketConfiguration webSocketConfiguration;
Expand Down Expand Up @@ -235,6 +240,16 @@ public RunnerBuilder fractionRemoteConnectionsAllowed(
return this;
}

public RunnerBuilder ethstatsUrl(final String ethstatsUrl) {
this.ethstatsUrl = ethstatsUrl;
return this;
}

public RunnerBuilder ethstatsContact(final String ethstatsContact) {
this.ethstatsContact = ethstatsContact;
return this;
}

public RunnerBuilder jsonRpcConfiguration(final JsonRpcConfiguration jsonRpcConfiguration) {
this.jsonRpcConfiguration = jsonRpcConfiguration;
return this;
Expand Down Expand Up @@ -573,6 +588,25 @@ public Runner build() {
metricsService = Optional.of(createMetricsService(vertx, metricsConfiguration));
}

final Optional<EthStatsService> ethStatsService;
if (!Strings.isNullOrEmpty(ethstatsUrl)) {
ethStatsService =
Optional.of(
new EthStatsService(
NetstatsUrl.fromParams(ethstatsUrl, ethstatsContact),
blockchainQueries,
besuController.getProtocolManager(),
transactionPool,
miningCoordinator,
besuController.getSyncState(),
vertx,
BesuInfo.nodeName(identityString),
besuController.getGenesisConfigOptions(),
network));
} else {
ethStatsService = Optional.empty();
}

return new Runner(
vertx,
networkRunner,
Expand All @@ -582,6 +616,7 @@ public Runner build() {
webSocketService,
stratumServer,
metricsService,
ethStatsService,
besuController,
dataDir,
pidPath,
Expand Down
28 changes: 28 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 @@ -159,6 +159,7 @@
import java.util.stream.Collectors;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableMap;
import com.google.common.io.Resources;
Expand Down Expand Up @@ -1039,6 +1040,21 @@ void setBannedNodeIds(final List<String> values) {
arity = "1")
private final Long wsTimeoutSec = TimeoutOptions.defaultOptions().getTimeoutSeconds();

@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
@Option(
names = {"--ethstats"},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's start these out as --X options and make them standard after one dot-dot release cycle without issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

paramLabel = "<nodename:secret@host:port>",
description = "Reporting URL of a ethstats server",
arity = "1")
private String ethstatsUrl = "";

@SuppressWarnings({"FieldCanBeFinal", "FieldMayBeFinal"})
@Option(
names = {"--ethstats-contact"},
description = "Contact address to send to ethstats server",
arity = "1")
private String ethstatsContact = "";

private EthNetworkConfig ethNetworkConfig;
private JsonRpcConfiguration jsonRpcConfiguration;
private GraphQLConfiguration graphQLConfiguration;
Expand Down Expand Up @@ -1319,6 +1335,7 @@ private BesuCommand validateOptions() {
validateP2PInterface(p2pInterface);
validateMiningParams();
validateNatParams();
validateNetStatsParams();

return this;
}
Expand Down Expand Up @@ -1367,6 +1384,15 @@ private void validateNatParams() {
}
}

private void validateNetStatsParams() {
if (Strings.isNullOrEmpty(ethstatsUrl) && !ethstatsContact.isEmpty()) {
throw new ParameterException(
this.commandLine,
"The `--ethstats-contact` requires that an url to a ethstats server is provided. Either remove --ethstats-contact"
+ " or provide an url (via --ethstats=nodename:secret@host:port)");
}
}

private void issueOptionWarnings() {
// Check that P2P options are able to work
CommandLineUtils.checkOptionDependencies(
Expand Down Expand Up @@ -2047,6 +2073,8 @@ private void synchronize(
.identityString(identityString)
.besuPluginContext(besuPluginContext)
.autoLogBloomCaching(autoLogBloomCachingEnabled)
.ethstatsUrl(ethstatsUrl)
.ethstatsContact(ethstatsContact)
.build();

addShutdownHook(runner);
Expand Down
24 changes: 24 additions & 0 deletions besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -1323,6 +1323,30 @@ public void parsesInvalidNatMethodOptionsShouldFail() {
"Invalid value for option '--nat-method': expected one of [UPNP, DOCKER, KUBERNETES, AUTO, NONE] (case-insensitive) but was 'invalid'");
}

@Test
public void ethStatsOptionIsParsedCorrectly() {
final String url = "besu-node:secret@host:443";
parseCommand("--ethstats", url);
verify(mockRunnerBuilder).ethstatsUrl(url);
}

@Test
public void ethStatsContactOptionIsParsedCorrectly() {
final String contact = "contact@mail.net";
parseCommand("--ethstats", "besu-node:secret@host:443", "--ethstats-contact", contact);
verify(mockRunnerBuilder).ethstatsContact(contact);
}

@Test
public void ethStatsContactOptionCannotBeUsedWithoutEthStatsServerProvided() {
parseCommand("--ethstats-contact", "besu-updated");
Mockito.verifyZeroInteractions(mockRunnerBuilder);
assertThat(commandOutput.toString()).isEmpty();
assertThat(commandErrorOutput.toString())
.contains(
"The `--ethstats-contact` requires that an url to a ethstats server is provided. Either remove --ethstats-contact or provide an url (via --ethstats=nodename:secret@host:port)");
}

@Test
public void helpShouldDisplayNatMethodInfo() {
parseCommand("--help");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ public void initMocks() throws Exception {
when(mockRunnerBuilder.besuPluginContext(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.autoLogBloomCaching(anyBoolean())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.pidPath(any())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.ethstatsUrl(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.ethstatsContact(anyString())).thenReturn(mockRunnerBuilder);
when(mockRunnerBuilder.build()).thenReturn(mockRunner);

final Bytes32 keyPairPrvKey =
Expand Down
4 changes: 4 additions & 0 deletions besu/src/test/resources/everything_config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,10 @@ target-gas-limit=8000000
# transaction log bloom filter caching
auto-log-bloom-caching-enabled=true

# ethstats
ethstats="nodename:secret@host:1234"
ethstats-contact="contact@mail.n"

# feature flags
Xsecp256k1-native-enabled=false
Xaltbn128-native-enabled=false
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,22 @@ public CliqueMiningCoordinator(

@Override
public void onResumeMining() {
if (miningTracker.isSigner(blockchain.getChainHeadHeader())) {
if (isSigner()) {
LOG.info("Resuming block production operations");
}
}

@Override
public void onPauseMining() {
if (miningTracker.isSigner(blockchain.getChainHeadHeader())) {
if (isSigner()) {
LOG.info("Pausing block production while behind chain head");
}
}

public boolean isSigner() {
return miningTracker.isSigner(blockchain.getChainHeadHeader());
}

@Override
protected boolean newChainHeadInvalidatesMiningOperation(final BlockHeader newChainHeadHeader) {
if (currentRunningMiner.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ public CompletableFuture<Void> scheduleFutureTask(
return promise;
}

public ScheduledFuture<?> scheduleFutureTaskWithFixedDelay(
final Runnable command, final Duration initialDelay, final Duration duration) {
return scheduler.scheduleWithFixedDelay(
command::run, initialDelay.toMillis(), duration.toMillis(), TimeUnit.MILLISECONDS);
}

public <T> CompletableFuture<T> scheduleFutureTask(
final Supplier<CompletableFuture<T>> future, final Duration duration) {
final CompletableFuture<T> promise = new CompletableFuture<>();
Expand Down
60 changes: 60 additions & 0 deletions ethereum/ethstats/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright ConsenSys AG.
*
* 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
*/

apply plugin: 'java-library'

jar {
archiveBaseName = 'besu-ethereum-ethstats'
manifest {
attributes(
'Specification-Title': archiveBaseName,
'Specification-Version': project.version,
'Implementation-Title': archiveBaseName,
'Implementation-Version': calculateVersion()
)
}
}

dependencies {

implementation 'com.fasterxml.jackson.core:jackson-databind'
implementation 'com.google.guava:guava'
implementation 'com.squareup.okhttp3:okhttp'
implementation 'org.apache.logging.log4j:log4j-api'
implementation 'io.vertx:vertx-core'
implementation 'org.apache.tuweni:tuweni-bytes'

implementation project(':consensus:clique')
implementation project(':config')
implementation project(':util')
implementation project(':ethereum:api')
implementation project(':ethereum:blockcreation')
implementation project(':ethereum:core')
implementation project(':ethereum:eth')
implementation project(':ethereum:p2p')
implementation project(':plugin-api')

runtimeOnly 'org.apache.logging.log4j:log4j-core'

// test dependencies.
testImplementation project(path: ':ethereum:core', configuration: 'testArtifacts')
testImplementation project(path: ':ethereum:core', configuration: 'testSupportArtifacts')
testImplementation project(':testutil')
testImplementation project(':metrics:core')

testImplementation 'junit:junit'
testImplementation 'org.assertj:assertj-core'
testImplementation 'org.mockito:mockito-core'
}
Loading