From deb1d759a6f9c2b6c9c6f2abb8445cfb54630e63 Mon Sep 17 00:00:00 2001 From: Matthew Whitehead Date: Wed, 20 Dec 2023 11:56:15 +0000 Subject: [PATCH] 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 --- .../org/hyperledger/besu/cli/BesuCommand.java | 11 +++++ .../besu/services/BesuConfigurationImpl.java | 5 +++ .../bonsai/AbstractIsolationTests.java | 5 +++ gradle/versions.gradle | 2 + .../plugin/services/BesuConfiguration.java | 2 + plugins/rocksdb/build.gradle | 2 +- .../RocksDBKeyValueStorageFactory.java | 40 ++++++++++++++----- 7 files changed, 56 insertions(+), 11 deletions(-) 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 b8b7efca3ab..9830f969afd 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -526,6 +526,12 @@ private InetAddress autoDiscoverDefaultIP() { "Minimum number of peers required before starting fast sync. Has only effect on PoW networks. (default: ${DEFAULT-VALUE})") private final Integer fastSyncMinPeerCount = FAST_SYNC_MIN_PEER_COUNT; + @Option( + names = {"--allow-downgrade"}, + description = + "Allow an older version of Besu to start if it detects that a more recent version last wrote to the database. Warning - this could result in unrecoverable changes to the database so should only be used if a backup of the data has been taken before the downgrade. (default: ${DEFAULT-VALUE})") + private final Boolean allowDowngrade = false; + @Option( names = {"--network"}, paramLabel = MANDATORY_NETWORK_FORMAT_HELP, @@ -3387,6 +3393,11 @@ public Path getDataPath() { public int getDatabaseVersion() { return dataStorageOptions.toDomainObject().getDataStorageFormat().getDatabaseVersion(); } + + @Override + public boolean getDowngradeAllowed() { + return allowDowngrade; + } } private void instantiateSignatureAlgorithmFactory() { diff --git a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java index a2974115522..0a25b54df66 100644 --- a/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java +++ b/besu/src/main/java/org/hyperledger/besu/services/BesuConfigurationImpl.java @@ -44,4 +44,9 @@ public Path getStoragePath() { public Path getDataPath() { return dataPath; } + + @Override + public boolean getDowngradeAllowed() { + return false; // TODO + } } diff --git a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java index 4f40afdb437..73d27971479 100644 --- a/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java +++ b/ethereum/core/src/test/java/org/hyperledger/besu/ethereum/bonsai/AbstractIsolationTests.java @@ -207,6 +207,11 @@ public Path getDataPath() { public int getDatabaseVersion() { return 2; } + + @Override + public boolean getDowngradeAllowed() { + return false; + } }) .withMetricsSystem(new NoOpMetricsSystem()) .build(); diff --git a/gradle/versions.gradle b/gradle/versions.gradle index f239370ab7a..015865fffc5 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -233,5 +233,7 @@ dependencyManagement { dependency 'tech.pegasys.discovery:discovery:22.2.0' dependency 'com.github.oshi:oshi-core:6.4.1' + + dependency 'org.apache.maven:maven-artifact:3.9.6' } } diff --git a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java index 9f830162ecb..8d125753e3c 100644 --- a/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java +++ b/plugin-api/src/main/java/org/hyperledger/besu/plugin/services/BesuConfiguration.java @@ -44,4 +44,6 @@ public interface BesuConfiguration extends BesuService { default int getDatabaseVersion() { return 1; } + + boolean getDowngradeAllowed(); } diff --git a/plugins/rocksdb/build.gradle b/plugins/rocksdb/build.gradle index 818b26e854e..5007049c423 100644 --- a/plugins/rocksdb/build.gradle +++ b/plugins/rocksdb/build.gradle @@ -42,7 +42,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind' implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8' - implementation 'org.apache.maven:maven-artifact:3.9.6' + implementation 'org.apache.maven:maven-artifact' implementation 'com.google.guava:guava' implementation 'info.picocli:picocli' implementation 'io.opentelemetry:opentelemetry-api' diff --git a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java index 90e866fadcd..4cbc792efa4 100644 --- a/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java +++ b/plugins/rocksdb/src/main/java/org/hyperledger/besu/plugin/services/storage/rocksdb/RocksDBKeyValueStorageFactory.java @@ -267,7 +267,7 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr databaseVersion = dbMetaData.getVersion(); besuVersion = dbMetaData.getBesuVersion(); LOG.info( - "Existing database detected at {}. DB version {}. Installed version {}. Compacting database...", + "Existing database detected at {}. DB version {}. Besu version {}. Compacting database...", dataDir, databaseVersion, besuVersion); @@ -280,15 +280,29 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr if (versionComparison == 0) { // Versions match - no-op } else if (versionComparison < 0) { - final String message = - "Besu version " - + installedVersion - + " is lower than version " - + dbBesuVersion - + " that last updated the database." - + ". Specify --downgrade to use different version."; - LOG.error(message); - throw new StorageException(message); + if (commonConfiguration.getDowngradeAllowed()) { + LOG.warn( + "Besu version {} is lower than version {} that last wrote to the database. Allowing startup because --allow-downgrade has been enabled.", + installedVersion, + dbBesuVersion); + // 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. This avoids the need after a successful + // downgrade to keep specifying --allow-downgrade on every startup. + writeDatabaseMetadata( + databaseVersion, Optional.of(commonConfiguration.getBesuVersion()), dataDir); + } else { + final String message = + "Besu version " + + installedVersion + + " is lower than version " + + dbBesuVersion + + " that last updated the database." + + ". Specify --allow-downgrade to allow Besu to start at the lower version (warning - this may have unrecoverable effects on the node database)."; + LOG.error(message); + throw new StorageException(message); + } } else if (versionComparison > 0) { LOG.info( "Besu version {} is higher than version {} that last updated the DB. Updating DB metadata.", @@ -297,6 +311,12 @@ private int readDatabaseVersion(final BesuConfiguration commonConfiguration) thr writeDatabaseMetadata( databaseVersion, Optional.of(commonConfiguration.getBesuVersion()), dataDir); } + } else { + // No besu version information was found in the metadata file, so update it with the current + // version and carry on + LOG.info("Adding Besu version to metadata file."); + writeDatabaseMetadata( + databaseVersion, Optional.of(commonConfiguration.getBesuVersion()), dataDir); } } else { databaseVersion = commonConfiguration.getDatabaseVersion();