-
Notifications
You must be signed in to change notification settings - Fork 840
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add Besu version to DB metadata. Check for downgrades and reject if version < version recorded in DB metadata. Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add --allow-downgrade CLI arg. If set it allows the downgrade and updates the Besu version in the metadata file to the downgraded version. Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Update gradle verification XML Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add and update tests Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Refactoring Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Remove versioning from RocksDB, now in separate VERSION_DATADATA.json Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Tidy up and tests for the new class Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Move downgrade logic into VersionMetadata as BesuCommand is already very big Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Add more tests Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Refactor the naming of the option to version-compatibility-protection Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Remove remaining references to allow-downgrade Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Rename test Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Update comments Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Metadata verification update Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * gradle fix Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Enable version downgrade protection by default for non-named networks Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Fix default logic Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> * Update ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> * Update ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> * mock-maker-inline no longer needed Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> --------- Signed-off-by: Matthew Whitehead <matthew1001@gmail.com> Signed-off-by: Matt Whitehead <matthew.whitehead@kaleido.io> Signed-off-by: Matt Whitehead <matthew1001@hotmail.com> Co-authored-by: Fabio Di Fabio <fabio.difabio@consensys.net>
- Loading branch information
1 parent
f921ddc
commit 59da092
Showing
9 changed files
with
455 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
147 changes: 147 additions & 0 deletions
147
ethereum/core/src/main/java/org/hyperledger/besu/ethereum/core/VersionMetadata.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
/* | ||
* 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 java.io.File; | ||
import java.io.FileNotFoundException; | ||
import java.io.IOException; | ||
import java.nio.file.Path; | ||
|
||
import com.fasterxml.jackson.annotation.JsonCreator; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import org.apache.maven.artifact.versioning.ComparableVersion; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class VersionMetadata { | ||
private static final Logger LOG = LoggerFactory.getLogger(VersionMetadata.class); | ||
|
||
/** 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"; | ||
private static final ObjectMapper MAPPER = new ObjectMapper(); | ||
private final String besuVersion; | ||
|
||
/** | ||
* Get the version of Besu that is running. | ||
* | ||
* @return the version of Besu | ||
*/ | ||
public static String getRuntimeVersion() { | ||
return VersionMetadata.class.getPackage().getImplementationVersion() == null | ||
? BESU_VERSION_UNKNOWN | ||
: VersionMetadata.class.getPackage().getImplementationVersion(); | ||
} | ||
|
||
@JsonCreator | ||
public VersionMetadata(@JsonProperty("besuVersion") final String besuVersion) { | ||
this.besuVersion = besuVersion; | ||
} | ||
|
||
public String getBesuVersion() { | ||
return besuVersion; | ||
} | ||
|
||
public static VersionMetadata lookUpFrom(final Path dataDir) throws IOException { | ||
LOG.info("Lookup version metadata file in data directory: {}", dataDir); | ||
return resolveVersionMetadata(getDefaultMetadataFile(dataDir)); | ||
} | ||
|
||
public void writeToDirectory(final Path dataDir) throws IOException { | ||
MAPPER.writeValue(getDefaultMetadataFile(dataDir), this); | ||
} | ||
|
||
private static File getDefaultMetadataFile(final Path dataDir) { | ||
return dataDir.resolve(METADATA_FILENAME).toFile(); | ||
} | ||
|
||
private static VersionMetadata resolveVersionMetadata(final File metadataFile) | ||
throws IOException { | ||
VersionMetadata versionMetadata; | ||
try { | ||
versionMetadata = MAPPER.readValue(metadataFile, VersionMetadata.class); | ||
LOG.info("Existing version data detected. Besu version {}", versionMetadata.besuVersion); | ||
} catch (FileNotFoundException fnfe) { | ||
versionMetadata = new VersionMetadata(BESU_VERSION_UNKNOWN); | ||
} catch (JsonProcessingException jpe) { | ||
throw new IllegalStateException( | ||
String.format("Invalid metadata file %s", metadataFile.getAbsolutePath()), jpe); | ||
} | ||
return versionMetadata; | ||
} | ||
|
||
/** | ||
* This function is designed to protect a Besu instance from being unintentionally started at a | ||
* version of Besu that might be incompatible with the version that last modified the specified | ||
* data directory. Currently this check is limited to checking that the version is >= the previous | ||
* version, to avoid accidentally running a lower version of Besu and potentially corrupting data, | ||
* but the method could be extended to perform any other version-to-version compatibility checks | ||
* necessary. If the --version-compatibility-protection flag is set to true and the compatibilty | ||
* checks pass, the version metadata is updated to the current version of Besu. | ||
*/ | ||
public static void versionCompatibilityChecks( | ||
final boolean enforceCompatibilityProtection, final Path dataDir) throws IOException { | ||
final VersionMetadata versionMetaData = VersionMetadata.lookUpFrom(dataDir); | ||
if (versionMetaData.getBesuVersion().equals(VersionMetadata.BESU_VERSION_UNKNOWN)) { | ||
// The version isn't known, potentially because the file doesn't exist. Write the latest | ||
// version to the metadata file. | ||
LOG.info( | ||
"No version data detected. Writing Besu version {} to metadata file", | ||
VersionMetadata.getRuntimeVersion()); | ||
new VersionMetadata(VersionMetadata.getRuntimeVersion()).writeToDirectory(dataDir); | ||
} else { | ||
// Check the runtime version against the most recent version as recorded in the version | ||
// metadata file | ||
final String installedVersion = VersionMetadata.getRuntimeVersion().split("-", 2)[0]; | ||
final String metadataVersion = versionMetaData.getBesuVersion().split("-", 2)[0]; | ||
final int versionComparison = | ||
new ComparableVersion(installedVersion).compareTo(new ComparableVersion(metadataVersion)); | ||
if (versionComparison == 0) { | ||
// Versions match - no-op | ||
} else if (versionComparison < 0) { | ||
if (!enforceCompatibilityProtection) { | ||
LOG.warn( | ||
"Besu version {} is lower than version {} that last started. Allowing startup because --version-compatibility-protection has been disabled.", | ||
installedVersion, | ||
metadataVersion); | ||
// We've allowed startup at an older version of Besu. Since the version in the metadata | ||
// file records the latest version of | ||
// Besu to write to the database we'll update the metadata version to this | ||
// downgraded-version. | ||
new VersionMetadata(VersionMetadata.getRuntimeVersion()).writeToDirectory(dataDir); | ||
} else { | ||
final String message = | ||
"Besu version " | ||
+ installedVersion | ||
+ " is lower than version " | ||
+ metadataVersion | ||
+ " that last started. Remove --version-compatibility-protection option to allow Besu to start at " | ||
+ " the lower version (warning - this may have unrecoverable effects on the database)."; | ||
LOG.error(message, installedVersion, metadataVersion); | ||
throw new IllegalStateException(message); | ||
} | ||
} else { | ||
LOG.info( | ||
"Besu version {} is higher than version {} that last started. Updating version metadata.", | ||
installedVersion, | ||
metadataVersion); | ||
new VersionMetadata(VersionMetadata.getRuntimeVersion()).writeToDirectory(dataDir); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.