diff --git a/CHANGELOG.md b/CHANGELOG.md index e988a70fe74..8c82a904be7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## 22.7.0 ### Additions and Improvements +- Deprecation warning for Ropsten, Rinkeby, Kiln [#4173](https://github.com/hyperledger/besu/pull/4173) ### Bug Fixes diff --git a/besu/build.gradle b/besu/build.gradle index 6252d0bbe29..ffb34ad77d3 100644 --- a/besu/build.gradle +++ b/besu/build.gradle @@ -67,6 +67,7 @@ dependencies { implementation 'info.picocli:picocli' implementation 'io.vertx:vertx-core' implementation 'io.vertx:vertx-web' + implementation 'org.apache.commons:commons-lang3' implementation 'org.apache.logging.log4j:log4j-core' implementation 'org.apache.tuweni:tuweni-bytes' implementation 'org.apache.tuweni:tuweni-config' 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 ce53d8cdb43..0d9097a0f11 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1393,6 +1393,9 @@ public void parse( @Override public void run() { + if (network != null && network.isDeprecated()) { + logger.warn(NetworkDeprecationMessage.generate(network)); + } try { configureLogging(true); diff --git a/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java b/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java new file mode 100644 index 00000000000..d8e59329520 --- /dev/null +++ b/besu/src/main/java/org/hyperledger/besu/cli/NetworkDeprecationMessage.java @@ -0,0 +1,63 @@ +/* + * 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.cli; + +import org.hyperledger.besu.cli.config.NetworkName; + +import org.apache.commons.lang3.StringUtils; + +public class NetworkDeprecationMessage { + private static final int MAX_LINE_LENGTH = 80; + + public static String generate(final NetworkName network) { + if (network.getDeprecationDate().isEmpty()) { + throw new AssertionError("Deprecation date is not set. Cannot print a deprecation message"); + } + + final StringBuilder messageBuilder = new StringBuilder("\n"); + messageBuilder + .append("#".repeat(MAX_LINE_LENGTH)) + .append(emptyLine()) + .append( + String.format( + "#%s#", + StringUtils.center( + deprecationDetails( + network.humanReadableNetworkName(), network.getDeprecationDate().get()), + MAX_LINE_LENGTH - 2))) + .append(emptyLine()) + .append( + String.format( + "#%s#\n", StringUtils.center("For more details please go to", MAX_LINE_LENGTH - 2))) + .append( + String.format( + "#%s#", + StringUtils.center( + "https://blog.ethereum.org/2022/06/21/testnet-deprecation/", + MAX_LINE_LENGTH - 2))) + .append(emptyLine()) + .append("#".repeat(MAX_LINE_LENGTH)); + + return messageBuilder.toString(); + } + + private static String deprecationDetails(final String networkName, final String deprecationDate) { + return networkName + " is deprecated and will be shutdown " + deprecationDate; + } + + private static String emptyLine() { + return String.format("\n#%s#\n", StringUtils.center("", MAX_LINE_LENGTH - 2)); + } +} diff --git a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java index 7aa15d5d3a0..0592fcffc51 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/config/NetworkName.java @@ -15,6 +15,9 @@ package org.hyperledger.besu.cli.config; import java.math.BigInteger; +import java.util.Optional; + +import org.apache.commons.lang3.StringUtils; public enum NetworkName { MAINNET("/mainnet.json", BigInteger.valueOf(1)), @@ -33,17 +36,31 @@ public enum NetworkName { private final String genesisFile; private final BigInteger networkId; private final boolean canFastSync; + private final String deprecationDate; NetworkName(final String genesisFile, final BigInteger networkId) { - this.genesisFile = genesisFile; - this.networkId = networkId; - this.canFastSync = true; + this(genesisFile, networkId, true); } NetworkName(final String genesisFile, final BigInteger networkId, final boolean canFastSync) { this.genesisFile = genesisFile; this.networkId = networkId; this.canFastSync = canFastSync; + + // https://blog.ethereum.org/2022/06/21/testnet-deprecation/ + switch (networkId.intValue()) { + case 3: + deprecationDate = "in Q4 2022"; + break; + case 4: + deprecationDate = "in Q2/Q3 2023"; + break; + case 1337802: + deprecationDate = "after the Mainnet Merge"; + break; + default: + deprecationDate = null; + } } public String getGenesisFile() { @@ -57,4 +74,16 @@ public BigInteger getNetworkId() { public boolean canFastSync() { return canFastSync; } + + public String humanReadableNetworkName() { + return StringUtils.capitalize(name().toLowerCase()); + } + + public boolean isDeprecated() { + return deprecationDate != null; + } + + public Optional getDeprecationDate() { + return Optional.ofNullable(deprecationDate); + } } 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 eedb1c3a562..7608c2e6be9 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -21,11 +21,13 @@ import static org.hyperledger.besu.cli.config.NetworkName.CLASSIC; import static org.hyperledger.besu.cli.config.NetworkName.DEV; import static org.hyperledger.besu.cli.config.NetworkName.GOERLI; +import static org.hyperledger.besu.cli.config.NetworkName.KILN; import static org.hyperledger.besu.cli.config.NetworkName.KOTTI; import static org.hyperledger.besu.cli.config.NetworkName.MAINNET; import static org.hyperledger.besu.cli.config.NetworkName.MORDOR; import static org.hyperledger.besu.cli.config.NetworkName.RINKEBY; import static org.hyperledger.besu.cli.config.NetworkName.ROPSTEN; +import static org.hyperledger.besu.cli.config.NetworkName.SEPOLIA; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPENDENCY_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATED_AND_USELESS_WARNING_MSG; import static org.hyperledger.besu.cli.util.CommandLineUtils.DEPRECATION_WARNING_MSG; @@ -44,11 +46,13 @@ import static org.hyperledger.besu.nat.kubernetes.KubernetesNatManager.DEFAULT_BESU_SERVICE_NAME_FILTER; import static org.junit.Assume.assumeThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.contains; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNotNull; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.atMost; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoInteractions; @@ -996,6 +1000,8 @@ public void testGenesisPathMainnetEthConfig() throws Exception { assertThat(config.getBootNodes()).isEqualTo(MAINNET_BOOTSTRAP_NODES); assertThat(config.getDnsDiscoveryUrl()).isEqualTo(MAINNET_DISCOVERY_URL); assertThat(config.getNetworkId()).isEqualTo(BigInteger.valueOf(1)); + + verify(mockLogger, never()).warn(contains("Mainnet is deprecated and will be shutdown")); } @Test @@ -3829,7 +3835,7 @@ public void devModeOptionMustBeUsed() throws Exception { } @Test - public void rinkebyValuesAreUsed() throws Exception { + public void rinkebyValuesAreUsed() { parseCommand("--network", "rinkeby"); final ArgumentCaptor networkArg = @@ -3842,10 +3848,12 @@ public void rinkebyValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Rinkeby is deprecated and will be shutdown")); } @Test - public void ropstenValuesAreUsed() throws Exception { + public void ropstenValuesAreUsed() { parseCommand("--network", "ropsten"); final ArgumentCaptor networkArg = @@ -3858,10 +3866,30 @@ public void ropstenValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Ropsten is deprecated and will be shutdown")); + } + + @Test + public void kilnValuesAreUsed() { + parseCommand("--network", "kiln"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + + assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(KILN)); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, times(1)).warn(contains("Kiln is deprecated and will be shutdown")); } @Test - public void goerliValuesAreUsed() throws Exception { + public void goerliValuesAreUsed() { parseCommand("--network", "goerli"); final ArgumentCaptor networkArg = @@ -3874,6 +3902,26 @@ public void goerliValuesAreUsed() throws Exception { assertThat(commandOutput.toString(UTF_8)).isEmpty(); assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, never()).warn(contains("Goerli is deprecated and will be shutdown")); + } + + @Test + public void sepoliaValuesAreUsed() { + parseCommand("--network", "sepolia"); + + final ArgumentCaptor networkArg = + ArgumentCaptor.forClass(EthNetworkConfig.class); + + verify(mockControllerBuilderFactory).fromEthNetworkConfig(networkArg.capture(), any()); + verify(mockControllerBuilder).build(); + + assertThat(networkArg.getValue()).isEqualTo(EthNetworkConfig.getNetworkConfig(SEPOLIA)); + + assertThat(commandOutput.toString(UTF_8)).isEmpty(); + assertThat(commandErrorOutput.toString(UTF_8)).isEmpty(); + + verify(mockLogger, never()).warn(contains("Sepolia is deprecated and will be shutdown")); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java new file mode 100644 index 00000000000..f3dbc3b8041 --- /dev/null +++ b/besu/src/test/java/org/hyperledger/besu/cli/NetworkDeprecationMessageTest.java @@ -0,0 +1,54 @@ +/* + * 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.cli; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +import org.hyperledger.besu.cli.config.NetworkName; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; + +class NetworkDeprecationMessageTest { + + @ParameterizedTest + @EnumSource( + value = NetworkName.class, + names = {"RINKEBY", "ROPSTEN", "KILN"}) + void shouldGenerateDeprecationMessageForDeprecatedNetworks(final NetworkName network) { + assertThat(NetworkDeprecationMessage.generate(network)) + .contains(network.humanReadableNetworkName() + " is deprecated and will be shutdown"); + } + + @ParameterizedTest + @EnumSource( + value = NetworkName.class, + names = { + "MAINNET", + "SEPOLIA", + "GOERLI", + "DEV", + "CLASSIC", + "KOTTI", + "MORDOR", + "ECIP1049_DEV", + "ASTOR" + }) + void shouldThrowErrorForNonDeprecatedNetworks(final NetworkName network) { + assertThatThrownBy(() -> NetworkDeprecationMessage.generate(network)) + .isInstanceOf(AssertionError.class); + } +} diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 0ce45ae4032..cd89dfb1c26 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -116,6 +116,7 @@ dependencyManagement { dependency 'net.java.dev.jna:jna:5.11.0' dependency 'org.apache.commons:commons-compress:1.21' + dependency 'org.apache.commons:commons-lang3:3.12.0' dependency 'org.apache.commons:commons-text:1.9' dependency 'org.apache.logging.log4j:log4j-api:2.17.2'