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

shut down VC when no keys #8355

Merged
merged 8 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,23 @@ void shouldFailWithNoValidatorKeysWhenExitOptionEnabledOnBeaconNode() throws Exc
"No loaded validators when --exit-when-no-validator-keys-enabled option is true");
}

@Test
void shouldFailWithNoValidatorKeysSourceProvidedOnValidatorClient() throws Exception {
final TekuBeaconNode beaconNode = createTekuBeaconNode();

final TekuValidatorNode validatorClient =
createValidatorNode(
TekuNodeConfigBuilder.createValidatorClient()
.withInteropModeDisabled()
.withBeaconNodes(beaconNode)
.build());
beaconNode.start();
validatorClient.startWithFailure(
"No validator keys source provided, should provide local or remote keys otherwise enable the key-manager"
+ " api to start the validator client");
beaconNode.stop();
}

@Test
void bn_shouldFailIfValidatorKeyLocked(@TempDir final Path tempDir) throws Exception {
final String networkName = "swift";
Expand Down Expand Up @@ -145,6 +162,7 @@ void shouldFailWithNoValidatorKeysWhenExitOptionEnabledOnValidatorClient() throw
TekuNodeConfigBuilder.createValidatorClient()
.withInteropModeDisabled()
.withBeaconNodes(beaconNode)
.withValidatorApiEnabled()
.withExitWhenNoValidatorKeysEnabled(true)
.build());
beaconNode.start();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,22 +84,31 @@ public void setup(final ClientAndServer server) {
getMockBeaconServerEndpoint(failoverMockBeaconServer);

argsNetworkOptDefault =
new String[] {"vc", "--beacon-node-api-endpoint", mockBeaconServerEndpoint};
new String[] {
"vc", "--validator-keys=keys:pass", "--beacon-node-api-endpoint", mockBeaconServerEndpoint
mehdi-aouadi marked this conversation as resolved.
Show resolved Hide resolved
};
argsNetworkOptAuto =
new String[] {
"vc", "--network", "auto", "--beacon-node-api-endpoint", mockBeaconServerEndpoint
"vc",
"--network",
"auto",
"--validator-keys=keys:pass",
"--beacon-node-api-endpoint",
mockBeaconServerEndpoint
};
argsNetworkOptAutoWithFailover =
new String[] {
"vc",
"--network",
"auto",
"--validator-keys=keys:pass",
"--beacon-node-api-endpoints",
mockBeaconServerEndpoint + "," + failoverMockBeaconServerEndpoint
};
argsNetworkOptAutoInConfig =
new String[] {
"vc",
"--validator-keys=keys:pass",
"--config-file",
networkAutoConfigFile,
"--beacon-node-api-endpoint",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import tech.pegasys.teku.infrastructure.logging.LoggingConfig;
import tech.pegasys.teku.infrastructure.logging.LoggingConfigurator;
import tech.pegasys.teku.networks.Eth2NetworkConfiguration;
import tech.pegasys.teku.validator.api.ValidatorConfig;

@Command(
name = "validator-client",
Expand Down Expand Up @@ -95,6 +96,7 @@ public Integer call() {
try {
startLogging();
final TekuConfiguration globalConfiguration = tekuConfiguration();
checkValidatorKeysConfig(globalConfiguration);
parentCommand.getStartAction().start(globalConfiguration, true);
return 0;
} catch (final Throwable t) {
Expand Down Expand Up @@ -136,6 +138,25 @@ private void configureEth2Network(final TekuConfiguration.Builder builder) {
}
}

private static void checkValidatorKeysConfig(final TekuConfiguration globalConfiguration) {
if (!globalConfiguration.validatorClient().getInteropConfig().isInteropEnabled()) {
final ValidatorConfig validatorConfig =
globalConfiguration.validatorClient().getValidatorConfig();
final boolean localValidatorKeysProvided =
validatorConfig.getValidatorKeys() != null
&& !validatorConfig.getValidatorKeys().isEmpty();
final boolean validatorRestApiEnabled =
globalConfiguration.validatorRestApiConfig().isRestApiEnabled();
final boolean externalSignerUrlProvided =
validatorConfig.getValidatorExternalSignerUrl() != null;
if (!localValidatorKeysProvided && !validatorRestApiEnabled && !externalSignerUrlProvided) {
throw new InvalidConfigurationException(
"No validator keys source provided, should provide local or remote keys otherwise enable the key-manager"
+ " api to start the validator client");
}
}
}

public TekuConfiguration tekuConfiguration() {
final TekuConfiguration.Builder builder = TekuConfiguration.builder();
configureEth2Network(builder);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
import static tech.pegasys.teku.networks.Eth2NetworkConfiguration.DEFAULT_VALIDATOR_EXECUTOR_THREADS;

import com.google.common.io.Resources;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.util.List;
import java.util.Optional;
import org.assertj.core.api.AssertionsForClassTypes;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import tech.pegasys.teku.cli.AbstractBeaconNodeCommandTest;
import tech.pegasys.teku.config.TekuConfiguration;
import tech.pegasys.teku.infrastructure.logging.LoggingConfig;
Expand All @@ -37,9 +41,7 @@ void setUp() {
@Test
public void networkOption_ShouldFail_IfSpecifiedOnParentCommand() {
final String[] argsNetworkOptOnParent =
new String[] {
"--network", "auto", "vc",
};
new String[] {"--network", "auto", "vc", "--validator-keys=keys:pass"};
int parseResult = beaconNodeCommand.parse(argsNetworkOptOnParent);
assertThat(parseResult).isEqualTo(2);
String cmdOutput = getCommandLineOutput();
Expand All @@ -51,15 +53,15 @@ public void networkOption_ShouldFail_IfSpecifiedOnParentCommand() {
void loggingOptions_shouldUseLoggingOptionsFromBeforeSubcommand() {
final LoggingConfig config =
getLoggingConfigurationFromArguments(
"--log-destination=console", "vc", "--network=mainnet");
"--log-destination=console", "vc", "--network=mainnet", "--validator-keys=keys:pass");
assertThat(config.getDestination()).isEqualTo(LoggingDestination.CONSOLE);
}

@Test
void loggingOptions_shouldUseLoggingOptionsFromAfterSubcommand() {
final LoggingConfig config =
getLoggingConfigurationFromArguments(
"vc", "--network=mainnet", "--log-destination=console");
"vc", "--validator-keys=keys:pass", "--network=mainnet", "--log-destination=console");
assertThat(config.getDestination()).isEqualTo(LoggingDestination.CONSOLE);
}

Expand All @@ -77,7 +79,12 @@ public void sentryConfigOption_shouldBuildExpectedConfigWhenOptionHasFileNamePar
final String sentryConfigPath = pathFor("sentry_node_config.json");
final String[] argsWithSentryConfig =
new String[] {
"vc", "--network", "minimal", "--sentry-config-file", sentryConfigPath,
"vc",
"--network",
"minimal",
"--validator-keys=keys:pass",
"--sentry-config-file",
sentryConfigPath,
};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(argsWithSentryConfig);
Expand All @@ -89,9 +96,7 @@ public void sentryConfigOption_shouldBuildExpectedConfigWhenOptionHasFileNamePar
@Test
public void sentryConfigOption_emptyConfigWhenMissingSentryConfigFileParam() {
final String[] argsWithoutSentryConfig =
new String[] {
"vc", "--network", "minimal",
};
new String[] {"vc", "--network", "minimal", "--validator-keys=keys:pass"};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(argsWithoutSentryConfig);

Expand All @@ -103,7 +108,7 @@ public void sentryConfigOption_emptyConfigWhenMissingSentryConfigFileParam() {
public void sentryConfigOption_shouldFailWhenOptionIsMissingRequiredFileNameParam() {
final String[] argsWithSentryConfigMissingParam =
new String[] {
"vc", "--network", "minimal", "--sentry-config-file",
"vc", "--network", "minimal", "--validator-keys=keys:pass", "--sentry-config-file",
};

int parseResult = beaconNodeCommand.parse(argsWithSentryConfigMissingParam);
Expand All @@ -119,6 +124,7 @@ public void shouldThrowErrorWhenUsingBeaconNodeEndpointAndSentryNodesConfig() {
"vc",
"--network",
"minimal",
"--validator-keys=keys:pass",
"--beacon-node-api-endpoint",
"http://127.0.0.1:1234",
"--sentry-config-file",
Expand All @@ -141,7 +147,12 @@ public void dutiesProviderSentryNodeEndpointIsUsedAsMainBeaconNodeApiEndpoint()
final URI expectedBeaconNodeApiEndpoint = URI.create("http://duties:5051");

final String[] args = {
"vc", "--network", "minimal", "--sentry-config-file", pathFor("sentry_node_config.json")
"vc",
"--network",
"minimal",
"--validator-keys=keys:pass",
"--sentry-config-file",
pathFor("sentry_node_config.json")
};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(args);
Expand All @@ -153,7 +164,7 @@ public void dutiesProviderSentryNodeEndpointIsUsedAsMainBeaconNodeApiEndpoint()
@Test
public void doppelgangerDetectionShouldBeDisabledByDefault() {

final String[] args = {"vc", "--network", "minimal"};
final String[] args = {"vc", "--network", "minimal", "--validator-keys=keys:pass"};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(args);

Expand All @@ -165,7 +176,12 @@ public void doppelgangerDetectionShouldBeDisabledByDefault() {
public void shouldEnableDoppelgangerDetection() {

final String[] args = {
"vc", "--network", "minimal", "--doppelganger-detection-enabled", "true"
"vc",
"--network",
"minimal",
"--validator-keys=keys:pass",
"--doppelganger-detection-enabled",
"true"
};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(args);
Expand All @@ -177,7 +193,7 @@ public void shouldEnableDoppelgangerDetection() {
@Test
public void clientExecutorThreadsShouldBeDefaultValue() {

final String[] args = {"vc", "--network", "minimal"};
final String[] args = {"vc", "--network", "minimal", "--validator-keys=keys:pass"};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(args);

Expand All @@ -190,7 +206,12 @@ public void clientExecutorThreadsShouldBeDefaultValue() {
public void clientExecutorThreadsShouldBeSetValue() {

final String[] args = {
"vc", "--network", "minimal", "--Xvalidator-client-executor-threads", "1000"
"vc",
"--validator-keys=keys:pass",
"--network",
"minimal",
"--Xvalidator-client-executor-threads",
"1000"
};

final TekuConfiguration tekuConfig = getTekuConfigurationFromArguments(args);
Expand All @@ -202,7 +223,12 @@ public void clientExecutorThreadsShouldBeSetValue() {
@Test
public void clientExecutorThreadsShouldThrowOverLimit() {
final String[] args = {
"vc", "--network", "minimal", "--Xvalidator-client-executor-threads", "6000"
"vc",
"--network",
"minimal",
"--validator-keys=keys:pass",
"--Xvalidator-client-executor-threads",
"6000"
};

int parseResult = beaconNodeCommand.parse(args);
Expand All @@ -215,7 +241,9 @@ public void clientExecutorThreadsShouldThrowOverLimit() {

@Test
public void shouldSetUseObolDvtSelectionsEndpoint() {
final String[] args = {"vc", "--network", "minimal", "--Xobol-dvt-integration-enabled"};
final String[] args = {
"vc", "--network", "minimal", "--validator-keys=keys:pass", "--Xobol-dvt-integration-enabled"
};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);

assertThat(config.validatorClient().getValidatorConfig().isDvtSelectionsEndpointEnabled())
Expand All @@ -224,12 +252,55 @@ public void shouldSetUseObolDvtSelectionsEndpoint() {

@Test
public void shouldNotUseObolDvtSelectionsEndpointByDefault() {
final String[] args = {"vc", "--network", "minimal"};
final String[] args = {"vc", "--network", "minimal", "--validator-keys=keys:pass"};
final TekuConfiguration config = getTekuConfigurationFromArguments(args);
assertThat(config.validatorClient().getValidatorConfig().isDvtSelectionsEndpointEnabled())
.isFalse();
}

@Test
public void shouldFail_IfNoValidatorKeysSourceProvided() {
final String[] argsNetworkOptOnParent = new String[] {"vc", "--network", "minimal"};
int parseResult = beaconNodeCommand.parse(argsNetworkOptOnParent);
assertThat(parseResult).isEqualTo(2);
String cmdOutput = getCommandLineOutput();
assertThat(cmdOutput)
.contains(
"No validator keys source provided, should provide local or remote keys otherwise enable the key-manager"
+ " api to start the validator client");
}

@Test
public void shouldNotFail_IfNoLocalValidatorKeys_ValidatorRestApiEnabled(
@TempDir final Path tempPath) throws IOException {
AssertionsForClassTypes.assertThat(tempPath.resolve("keystore").toFile().createNewFile())
.isTrue();
AssertionsForClassTypes.assertThat(tempPath.resolve("pass").toFile().createNewFile()).isTrue();
final String[] argsNetworkOptOnParent =
new String[] {
"vc",
"--network",
"minimal",
"--validator-api-enabled=true",
"--validator-api-keystore-file",
tempPath.resolve("keystore").toString(),
"--validator-api-keystore-password-file",
tempPath.resolve("pass").toString()
};
int parseResult = beaconNodeCommand.parse(argsNetworkOptOnParent);
assertThat(parseResult).isEqualTo(0);
}

@Test
public void shouldNotFail_IfNoLocalValidatorKeys_ExternalSignerUrlProvided() {
final String[] argsNetworkOptOnParent =
new String[] {
"vc", "--network", "minimal", "--validators-external-signer-url=http://localhost"
};
int parseResult = beaconNodeCommand.parse(argsNetworkOptOnParent);
assertThat(parseResult).isEqualTo(0);
}

private String pathFor(final String filename) {
return Resources.getResource(ValidatorClientCommandTest.class, filename).toString();
}
Expand Down