From d75e5b5e670f598b3cde4cc6d71ba4c2786cbf40 Mon Sep 17 00:00:00 2001 From: Matthew Whitehead Date: Wed, 20 Dec 2023 18:04:15 +0000 Subject: [PATCH] Tidy up and tests for the new class Signed-off-by: Matthew Whitehead --- .../org/hyperledger/besu/cli/BesuCommand.java | 25 ++++++- .../hyperledger/besu/cli/BesuCommandTest.java | 20 ++---- .../besu/ethereum/core/VersionMetadata.java | 18 ++--- .../ethereum/core/VersionMetadataTest.java | 65 +++++++++++++++++++ .../besu/plugin/services/BesuService.java | 9 --- 5 files changed, 103 insertions(+), 34 deletions(-) create mode 100644 ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index c217808c06c2..1d0a46472964 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1466,12 +1466,13 @@ public void run() { vertx = createVertx(createVertxOptions(metricsSystem.get())); validateOptions(); + + performDowngradeCheck(); + configure(); configureNativeLibs(); besuController = initController(); - performDowngradeCheck(); - besuPluginContext.beforeExternalServices(); final var runner = buildRunner(); @@ -1491,6 +1492,14 @@ public void run() { } } + /** + * This function is designed to protect a Besu instance from being unintentionally started at a lower + * version than the previous instance. Doing so could cause unexpected data corruption (depending on + * the storage provider that is in use), so this check prompts the user if a downgrade is detected + * and requires them to opt-in by setting --allow-downgrade. The --allow-downgrade flag only needs + * to be passed in once, and then the version information is updated to the lower version number, meaning + * future restarts will pass the check. + */ private void performDowngradeCheck() throws IOException { final VersionMetadata versionMetaData = VersionMetadata.lookUpFrom(dataDir()); if (versionMetaData.getBesuVersion().equals(VersionMetadata.BESU_VERSION_UNKNOWN)) { @@ -1528,7 +1537,7 @@ private void performDowngradeCheck() throws IOException { + " is lower than version " + metadataVersion + " that last started." - + ". Specify --allow-downgrade to allow Besu to start at the lower version (warning - this may have unrecoverable effects on the database)."; + + "Specify --allow-downgrade to allow Besu to start at the lower version (warning - this may have unrecoverable effects on the database)."; logger.error(message); throw new StorageException(message); } @@ -3432,6 +3441,16 @@ String getLogLevel() { return loggingLevelOption.getLogLevel(); } + /** + * Returns the flag indicating that downgrades are allowed. + * + * @return true if downgrades are allowed, otherwise false + */ + @VisibleForTesting + public Boolean getAllowDowngrade() { + return allowDowngrade; + } + private class BesuCommandConfigurationService implements BesuConfiguration { @Override diff --git a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java index bd5f6ceec9a9..a0dd69ce2afa 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1989,19 +1989,6 @@ public void parsesInvalidBonsaiTrieLimitBackLayersOption() { "Invalid value for option '--bonsai-maximum-back-layers-to-load': 'ten' is not a long"); } - @Test - public void parsesValidAllowDowngradeOption() { - parseCommand("--allow-dowgrade", "true"); - verify(mockControllerBuilder) - .dataStorageConfiguration(dataStorageConfigurationArgumentCaptor.capture()); - - final DataStorageConfiguration dataStorageConfiguration = - dataStorageConfigurationArgumentCaptor.getValue(); - assertThat(dataStorageConfiguration.getAllowDowngrade()).isEqualTo(Boolean.valueOf("true")); - assertThat(commandOutput.toString(UTF_8)).isEmpty(); - assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); - } - @Test public void dnsEnabledOptionIsParsedCorrectly() { final TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true"); @@ -2010,6 +1997,13 @@ public void dnsEnabledOptionIsParsedCorrectly() { assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isFalse(); } + @Test + public void allowDowngradeTrueOptionIsParsedCorrectly() { + final TestBesuCommand besuCommand = parseCommand("--allow-downgrade", "true"); + + assertThat(besuCommand.getAllowDowngrade()).isTrue(); + } + @Test public void dnsUpdateEnabledOptionIsParsedCorrectly() { final TestBesuCommand besuCommand = diff --git a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java index bbfc157e2588..9499e34e43bc 100644 --- a/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java +++ b/ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java @@ -1,5 +1,5 @@ /* - * Copyright ConsenSys AG. + * Copyright Hyperledger Besu contributors. * * 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 @@ -29,7 +29,7 @@ public class VersionMetadata { private static final Logger LOG = LoggerFactory.getLogger(VersionMetadata.class); - /** Represents an unknown Besu version in the database metadata file */ + /** Represents an unknown Besu version in the version metadata file */ public static final String BESU_VERSION_UNKNOWN = "UNKNOWN"; private static final String METADATA_FILENAME = "VERSION_METADATA.json"; @@ -56,7 +56,7 @@ public String getBesuVersion() { public static VersionMetadata lookUpFrom(final Path dataDir) throws IOException { LOG.info("Lookup version metadata file in data directory: {}", dataDir.toString()); - return resolveDatabaseMetadata(getDefaultMetadataFile(dataDir)); + return resolveVersionMetadata(getDefaultMetadataFile(dataDir)); } public void writeToDirectory(final Path dataDir) throws IOException { @@ -67,18 +67,18 @@ private static File getDefaultMetadataFile(final Path dataDir) { return dataDir.resolve(METADATA_FILENAME).toFile(); } - private static VersionMetadata resolveDatabaseMetadata(final File metadataFile) + private static VersionMetadata resolveVersionMetadata(final File metadataFile) throws IOException { - VersionMetadata databaseMetadata; + VersionMetadata versionMetadata; try { - databaseMetadata = MAPPER.readValue(metadataFile, VersionMetadata.class); - LOG.info("Existing version data detected. Besu version {}", databaseMetadata.besuVersion); + versionMetadata = MAPPER.readValue(metadataFile, VersionMetadata.class); + LOG.info("Existing version data detected. Besu version {}", versionMetadata.besuVersion); } catch (FileNotFoundException fnfe) { - databaseMetadata = new VersionMetadata(BESU_VERSION_UNKNOWN); + versionMetadata = new VersionMetadata(BESU_VERSION_UNKNOWN); } catch (JsonProcessingException jpe) { throw new IllegalStateException( java.lang.String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); } - return databaseMetadata; + return versionMetadata; } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java new file mode 100644 index 000000000000..e630e4231780 --- /dev/null +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/core/VersionMetadataTest.java @@ -0,0 +1,65 @@ +/* + * Copyright Hyperledger Besu contributors. + * + * 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.ethereum.core; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +class VersionMetadataTest { + @TempDir public Path temporaryFolder; + + @Test + void getVersion() { + final VersionMetadata versionMetadata = new VersionMetadata("23.10.2"); + assertThat(versionMetadata).isNotNull(); + assertThat(versionMetadata.getBesuVersion()).isEqualTo("23.10.2"); + } + + @Test + void metaFileShouldContain() throws Exception { + final Path tempDataDir = + createAndWrite("data", "VERSION_METADATA.json", "{\"besuVersion\":\"23.10.3\"}"); + + final VersionMetadata versionMetadata = VersionMetadata.lookUpFrom(tempDataDir); + assertThat(versionMetadata).isNotNull(); + assertThat(versionMetadata.getBesuVersion()).isEqualTo("23.10.3"); + } + + private Path createAndWrite(final String dir, final String file, final String content) + throws IOException { + return createAndWrite(temporaryFolder, dir, file, content); + } + + private Path createAndWrite( + final Path temporaryFolder, final String dir, final String file, final String content) + throws IOException { + final Path tmpDir = temporaryFolder.resolve(dir); + Files.createDirectories(tmpDir); + createAndWrite(tmpDir.resolve(file), content); + return tmpDir; + } + + private void createAndWrite(final Path path, final String content) throws IOException { + path.toFile().createNewFile(); + Files.writeString(path, content); + } +} diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuService.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuService.java index 212fa477a4e7..5e23bc04fd2e 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuService.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuService.java @@ -22,13 +22,4 @@ * BesuService} */ public interface BesuService { - - /** - * Get the version of Besu that is running. - * - * @return the version of Besu - */ - default String getBesuVersion() { - return BesuService.class.getPackage().getImplementationVersion(); - } }