diff --git a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java index d46ba39502..b17cad4f2a 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommand.java @@ -40,6 +40,9 @@ import java.io.PrintStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Optional; import io.vertx.core.Vertx; @@ -122,12 +125,18 @@ public class BlocksSubCommand implements Runnable { @Option( names = "--format", - hidden = true, description = "The type of data to be imported, possible values are: ${COMPLETION-CANDIDATES} (default: ${DEFAULT-VALUE}).", arity = "1..1") private final BlockImportFormat format = BlockImportFormat.RLP; + @Option( + names = "--start-time", + description = + "The timestamp in seconds of the first block for JSON imports. Subsequent blocks will be 1 second later. (default: current time)", + arity = "1..1") + private final Long startTime = System.currentTimeMillis() / 1000; + @SuppressWarnings("unused") @Spec private CommandSpec spec; @@ -141,7 +150,7 @@ public class BlocksSubCommand implements Runnable { checkNotNull(parentCommand.rlpBlockImporter); checkNotNull(parentCommand.jsonBlockImporterFactory); - Optional metricsService = initMetrics(parentCommand); + final Optional metricsService = initMetrics(parentCommand); try { // As blocksImportFile even if initialized as null is injected by PicoCLI and param is @@ -182,6 +191,8 @@ public class BlocksSubCommand implements Runnable { return parentCommand .parentCommand .getControllerBuilder() + // set to mainnet genesis block so validation rules won't reject it. + .clock(Clock.fixed(Instant.ofEpochSecond(startTime), ZoneOffset.UTC)) .miningParameters(getMiningParameters()) .build(); } catch (final Exception e) { @@ -200,7 +211,7 @@ public class BlocksSubCommand implements Runnable { private void importJsonBlocks(final BesuController controller, final Path path) throws IOException { - JsonBlockImporter importer = parentCommand.jsonBlockImporterFactory.get(controller); + final JsonBlockImporter importer = parentCommand.jsonBlockImporterFactory.get(controller); final String jsonData = Files.readString(path); importer.importChain(jsonData); } @@ -270,15 +281,13 @@ public class BlocksSubCommand implements Runnable { final BesuController controller = createBesuController(); try { - switch (format) { - case RLP: - exportRlpFormat(controller); - break; - default: - throw new ParameterException( - spec.commandLine(), "Unsupported format: " + format.toString()); + if (format == BlockExportFormat.RLP) { + exportRlpFormat(controller); + } else { + throw new ParameterException( + spec.commandLine(), "Unsupported format: " + format.toString()); } - } catch (IOException e) { + } catch (final IOException e) { throw new ExecutionException( spec.commandLine(), "An error occurred while exporting blocks.", e); } finally { @@ -292,7 +301,7 @@ public class BlocksSubCommand implements Runnable { private void exportRlpFormat(final BesuController controller) throws IOException { final ProtocolContext context = controller.getProtocolContext(); - RlpBlockExporter exporter = + final RlpBlockExporter exporter = parentCommand.rlpBlockExporterFactory.get(context.getBlockchain()); exporter.exportBlocks(blocksExportFile, getStartBlock(), getEndBlock()); } @@ -339,11 +348,11 @@ public class BlocksSubCommand implements Runnable { } // Error if data directory is empty - Path databasePath = + final Path databasePath = Paths.get( parentCommand.parentCommand.dataDir().toAbsolutePath().toString(), BesuController.DATABASE_PATH); - File databaseDirectory = new File(databasePath.toString()); + final File databaseDirectory = new File(databasePath.toString()); if (!databaseDirectory.isDirectory() || databaseDirectory.list().length == 0) { // Empty data directory, nothing to export throw new CommandLine.ParameterException( diff --git a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java index 656976d40f..9f8bdeec10 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/subcommands/blocks/BlocksSubCommandTest.java @@ -56,22 +56,18 @@ public class BlocksSubCommandTest extends CommandTestAbstract { + System.lineSeparator(); private static final String EXPECTED_BLOCK_IMPORT_USAGE = - "Usage: besu blocks import [-hV] --from=" - // "Usage: besu blocks import [-hV] [--format=] --from=" - + System.lineSeparator() - + "This command imports blocks from a file into the database." - // Hide format for while JSON option is under development - // + System.lineSeparator() - // + " --format= The type of data to be imported, possible values - // are: RLP,\n" - // + " JSON (default: RLP)." - + System.lineSeparator() - + " --from= File containing blocks to import." - + System.lineSeparator() - + " -h, --help Show this help message and exit." - + System.lineSeparator() - + " -V, --version Print version information and exit." - + System.lineSeparator(); + "Usage: besu blocks import [-hV] [--format=] --from=\n" + + " [--start-time=]\n" + + "This command imports blocks from a file into the database.\n" + + " --format= The type of data to be imported, possible values are:\n" + + " RLP, JSON (default: RLP).\n" + + " --from= File containing blocks to import.\n" + + " -h, --help Show this help message and exit.\n" + + " --start-time=\n" + + " The timestamp in seconds of the first block for JSON\n" + + " imports. Subsequent blocks will be 1 second later.\n" + + " (default: current time)\n" + + " -V, --version Print version information and exit.\n"; private static final String EXPECTED_BLOCK_EXPORT_USAGE = "Usage: besu blocks export [-hV] [--end-block=] [--start-block=]" @@ -138,7 +134,7 @@ public class BlocksSubCommandTest extends CommandTestAbstract { @Test public void callingBlockImportSubCommandHelpMustDisplayUsage() { parseCommand(BLOCK_SUBCOMMAND_NAME, BLOCK_IMPORT_SUBCOMMAND_NAME, "--help"); - assertThat(commandOutput.toString()).isEqualToIgnoringWhitespace(EXPECTED_BLOCK_IMPORT_USAGE); + assertThat(commandOutput.toString()).isEqualTo(EXPECTED_BLOCK_IMPORT_USAGE); assertThat(commandErrorOutput.toString()).isEmpty(); }