Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.

Commit

Permalink
Remove DB init need to use public key subcommand (#1049)
Browse files Browse the repository at this point in the history
fixes PAN-2259 prevent public key export subcommands to create the database

Creation of the database is useless at this stage, so don't create it as it's
usually necessary to remove it if created as we want to use the output of
this subcommand to change the genesis that makes the created database useless.
  • Loading branch information
NicolasMassart authored Mar 6, 2019
1 parent 7355e01 commit 4d4b89c
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import tech.pegasys.pantheon.Runner;
import tech.pegasys.pantheon.RunnerBuilder;
import tech.pegasys.pantheon.cli.PublicKeySubCommand.KeyLoader;
import tech.pegasys.pantheon.cli.custom.CorsAllowedOriginsProperty;
import tech.pegasys.pantheon.cli.custom.EnodeToURIPropertyConverter;
import tech.pegasys.pantheon.cli.custom.JsonRPCWhitelistHostsProperty;
Expand Down Expand Up @@ -139,6 +140,10 @@ public static class RpcApisConversionException extends Exception {
private final SynchronizerConfiguration.Builder synchronizerConfigurationBuilder;
private final RunnerBuilder runnerBuilder;

protected KeyLoader getKeyLoader() {
return KeyPairUtil::loadKeyPair;
}

// Public IP stored to prevent having to research it each time we need it.
private InetAddress autoDiscoveredDefaultIP = null;

Expand Down Expand Up @@ -522,7 +527,8 @@ public void parse(
commandLine.addSubcommand(
BlocksSubCommand.COMMAND_NAME, new BlocksSubCommand(blockImporter, resultHandler.out()));
commandLine.addSubcommand(
PublicKeySubCommand.COMMAND_NAME, new PublicKeySubCommand(resultHandler.out()));
PublicKeySubCommand.COMMAND_NAME,
new PublicKeySubCommand(resultHandler.out(), getKeyLoader()));
commandLine.addSubcommand(
PasswordSubCommand.COMMAND_NAME, new PasswordSubCommand(resultHandler.out()));
commandLine.addSubcommand(
Expand Down Expand Up @@ -977,7 +983,7 @@ private Path dataDir() {
}
}

private File nodePrivateKeyFile() {
File nodePrivateKeyFile() {
File nodePrivateKeyFile = null;
if (isFullInstantiation()) {
nodePrivateKeyFile = standaloneCommands.nodePrivateKeyFile;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import tech.pegasys.pantheon.cli.PublicKeySubCommand.AddressSubCommand;
import tech.pegasys.pantheon.cli.PublicKeySubCommand.ExportSubCommand;
import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Address;
import tech.pegasys.pantheon.ethereum.core.Util;
Expand All @@ -30,6 +30,7 @@
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
Expand Down Expand Up @@ -59,16 +60,27 @@ class PublicKeySubCommand implements Runnable {
private CommandSpec spec; // Picocli injects reference to command spec

private final PrintStream out;
private final KeyLoader keyLoader;

PublicKeySubCommand(final PrintStream out) {
PublicKeySubCommand(final PrintStream out, final KeyLoader keyLoader) {
this.out = out;
this.keyLoader = keyLoader;
}

@Override
public void run() {
spec.commandLine().usage(out);
}

private Optional<KeyPair> getKeyPair() {
try {
return Optional.of(keyLoader.load(parentCommand.nodePrivateKeyFile()));
} catch (IOException e) {
LOG.error("An error occurred while trying to read the private key", e);
return Optional.empty();
}
}

/**
* Public key export sub-command
*
Expand Down Expand Up @@ -99,9 +111,10 @@ public void run() {
checkNotNull(parentCommand);
checkNotNull(parentCommand.parentCommand);

final PantheonController<?> controller = parentCommand.parentCommand.buildController();
final KeyPair keyPair = controller.getLocalNodeKeyPair();
parentCommand.getKeyPair().ifPresent(this::outputPublicKey);
}

private void outputPublicKey(final KeyPair keyPair) {
// if we have an output file defined, print to it
// otherwise print to standard output.
if (publicKeyExportFile != null) {
Expand Down Expand Up @@ -150,8 +163,10 @@ public void run() {
checkNotNull(parentCommand);
checkNotNull(parentCommand.parentCommand);

final PantheonController<?> controller = parentCommand.parentCommand.buildController();
final KeyPair keyPair = controller.getLocalNodeKeyPair();
parentCommand.getKeyPair().ifPresent(this::outputAddress);
}

private void outputAddress(final KeyPair keyPair) {
final Address address = Util.publicKeyToAddress(keyPair.getPublicKey());

// if we have an output file defined, print to it
Expand All @@ -169,4 +184,9 @@ public void run() {
}
}
}

@FunctionalInterface
public interface KeyLoader {
SECP256K1.KeyPair load(final File keyFile) throws IOException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@

import tech.pegasys.pantheon.Runner;
import tech.pegasys.pantheon.RunnerBuilder;
import tech.pegasys.pantheon.cli.PublicKeySubCommand.KeyLoader;
import tech.pegasys.pantheon.controller.PantheonController;
import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.eth.sync.SynchronizerConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.JsonRpcConfiguration;
import tech.pegasys.pantheon.ethereum.jsonrpc.websocket.WebSocketConfiguration;
Expand Down Expand Up @@ -141,7 +143,17 @@ protected CommandLine.Model.CommandSpec parseCommand(final String... args) {
return parseCommand(System.in, args);
}

protected CommandLine.Model.CommandSpec parseCommand(
final KeyLoader keyLoader, final String... args) {
return parseCommand(keyLoader, System.in, args);
}

protected CommandLine.Model.CommandSpec parseCommand(final InputStream in, final String... args) {
return parseCommand(f -> KeyPair.generate(), in, args);
}

private CommandLine.Model.CommandSpec parseCommand(
final KeyLoader keyLoader, final InputStream in, final String... args) {
// turn off ansi usage globally in picocli
System.setProperty("picocli.ansi", "false");

Expand All @@ -151,7 +163,8 @@ protected CommandLine.Model.CommandSpec parseCommand(final InputStream in, final
mockBlockImporter,
mockRunnerBuilder,
mockControllerBuilder,
mockSyncConfBuilder);
mockSyncConfBuilder,
keyLoader);

// parse using Ansi.OFF to be able to assert on non formatted output results
pantheonCommand.parse(
Expand All @@ -165,19 +178,27 @@ protected CommandLine.Model.CommandSpec parseCommand(final InputStream in, final
@CommandLine.Command
static class TestPantheonCommand extends PantheonCommand {
@CommandLine.Spec CommandLine.Model.CommandSpec spec;
private final KeyLoader keyLoader;

@Override
protected KeyLoader getKeyLoader() {
return keyLoader;
}

TestPantheonCommand(
final Logger mockLogger,
final BlockImporter mockBlockImporter,
final RunnerBuilder mockRunnerBuilder,
final PantheonControllerBuilder mockControllerBuilder,
final SynchronizerConfiguration.Builder mockSyncConfBuilder) {
final SynchronizerConfiguration.Builder mockSyncConfBuilder,
final KeyLoader keyLoader) {
super(
mockLogger,
mockBlockImporter,
mockRunnerBuilder,
mockControllerBuilder,
mockSyncConfBuilder);
this.keyLoader = keyLoader;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.contentOf;
import static org.mockito.Mockito.when;

import tech.pegasys.pantheon.crypto.SECP256K1.KeyPair;
import tech.pegasys.pantheon.ethereum.core.Util;
Expand Down Expand Up @@ -103,37 +102,38 @@ public void callingPublicKeySubCommandHelpMustDisplayUsage() {
}

// Export public key sub-sub-command
@Test
public void callingPublicKeyExportSubCommandHelpMustDisplayUsage() {
parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME, "--help");
assertThat(commandOutput.toString()).startsWith(EXPECTED_PUBLIC_KEY_EXPORT_USAGE);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportSubCommandWithoutPathMustWriteKeyToStandardOutput() {
final KeyPair keyPair = KeyPair.generate();
when(mockController.getLocalNodeKeyPair()).thenReturn(keyPair);

parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME);
parseCommand(f -> keyPair, PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME);

final String expectedOutputStart = keyPair.getPublicKey().toString();
assertThat(commandOutput.toString()).startsWith(expectedOutputStart);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportSubCommandHelpMustDisplayUsage() {
parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME, "--help");
assertThat(commandOutput.toString()).startsWith(EXPECTED_PUBLIC_KEY_EXPORT_USAGE);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportSubCommandWithFilePathMustWritePublicKeyInThisFile()
throws Exception {

final KeyPair keyPair = KeyPair.generate();

when(mockController.getLocalNodeKeyPair()).thenReturn(keyPair);

final File file = File.createTempFile("public", "key");

parseCommand(
PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME, "--to", file.getPath());
f -> keyPair,
PUBLIC_KEY_SUBCOMMAND_NAME,
PUBLIC_KEY_EXPORT_SUBCOMMAND_NAME,
"--to",
file.getPath());

assertThat(contentOf(file))
.startsWith(keyPair.getPublicKey().toString())
Expand All @@ -144,36 +144,35 @@ public void callingPublicKeyExportSubCommandWithFilePathMustWritePublicKeyInThis
}

// Export address sub-sub-command
@Test
public void callingPublicKeyExportAddressSubCommandHelpMustDisplayUsage() {
parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_ADDRESS_SUBCOMMAND_NAME, "--help");
assertThat(commandOutput.toString()).startsWith(EXPECTED_PUBLIC_KEY_EXPORT_ADDRESS_USAGE);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportAddressSubCommandWithoutPathMustWriteAddressToStandardOutput() {
final KeyPair keyPair = KeyPair.generate();
when(mockController.getLocalNodeKeyPair()).thenReturn(keyPair);

parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_ADDRESS_SUBCOMMAND_NAME);
parseCommand(
f -> keyPair, PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_ADDRESS_SUBCOMMAND_NAME);

final String expectedOutputStart = Util.publicKeyToAddress(keyPair.getPublicKey()).toString();
assertThat(commandOutput.toString()).startsWith(expectedOutputStart);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportAddressSubCommandHelpMustDisplayUsage() {
parseCommand(PUBLIC_KEY_SUBCOMMAND_NAME, PUBLIC_KEY_EXPORT_ADDRESS_SUBCOMMAND_NAME, "--help");
assertThat(commandOutput.toString()).startsWith(EXPECTED_PUBLIC_KEY_EXPORT_ADDRESS_USAGE);
assertThat(commandErrorOutput.toString()).isEmpty();
}

@Test
public void callingPublicKeyExportAddressSubCommandWithFilePathMustWriteAddressInThisFile()
throws Exception {

final KeyPair keyPair = KeyPair.generate();

when(mockController.getLocalNodeKeyPair()).thenReturn(keyPair);

final File file = File.createTempFile("public", "address");

parseCommand(
f -> keyPair,
PUBLIC_KEY_SUBCOMMAND_NAME,
PUBLIC_KEY_EXPORT_ADDRESS_SUBCOMMAND_NAME,
"--to",
Expand Down

0 comments on commit 4d4b89c

Please sign in to comment.