From c8f8832cbc0343eabe6d6a52285a04335b14265d Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Wed, 22 Jul 2020 17:41:04 +0200 Subject: [PATCH 01/11] add dns support Signed-off-by: Karim TAAM --- .../org/hyperledger/besu/cli/BesuCommand.java | 66 +++++++++++----- ethereum/p2p/build.gradle | 3 + .../besu/ethereum/p2p/peers/EnodeURL.java | 78 +++++++++++++++---- .../ethereum/p2p/peers/StaticNodesParser.java | 15 ++-- .../p2p/peers/StaticNodesParserTest.java | 12 +-- ...untLocalConfigPermissioningController.java | 1 + .../LocalPermissioningConfiguration.java | 11 +++ ...odeLocalConfigPermissioningController.java | 1 + .../PermissioningConfigurationBuilder.java | 9 ++- gradle/versions.gradle | 3 + 10 files changed, 150 insertions(+), 49 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 e3c90950eee..75b661860f9 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -94,7 +94,9 @@ import org.hyperledger.besu.ethereum.eth.transactions.TransactionPoolConfiguration; import org.hyperledger.besu.ethereum.mainnet.precompiles.AltBN128PairingPrecompiledContract; import org.hyperledger.besu.ethereum.p2p.config.DiscoveryConfiguration; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; +import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.StaticNodesParser; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import org.hyperledger.besu.ethereum.permissioning.PermissioningConfiguration; @@ -306,20 +308,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { + "Default is a predefined list.", split = ",", arity = "0..*") - void setBootnodes(final List values) { - try { - bootNodes = - values.stream() - .filter(value -> !value.isEmpty()) - .map(EnodeURL::fromString) - .collect(Collectors.toList()); - DiscoveryConfiguration.assertValidBootnodes(bootNodes); - } catch (final IllegalArgumentException e) { - throw new ParameterException(commandLine, e.getMessage()); - } - } - - private List bootNodes = null; + private final List bootnodes = null; @Option( names = {"--max-peers"}, @@ -1039,6 +1028,20 @@ void setBannedNodeIds(final List values) { arity = "1") private final Long wsTimeoutSec = TimeoutOptions.defaultOptions().getTimeoutSeconds(); + @CommandLine.Option( + hidden = true, + names = {"--dns-enabled"}, + description = "Enabled DNS support", + arity = "1") + private final Boolean dnsEnabled = Boolean.FALSE; + + @CommandLine.Option( + hidden = true, + names = {"--dns-update-enabled"}, + description = "Allow to detect an IP update automatically", + arity = "1") + private final Boolean dnsUpdateEnabled = Boolean.FALSE; + private EthNetworkConfig ethNetworkConfig; private JsonRpcConfiguration jsonRpcConfiguration; private GraphQLConfiguration graphQLConfiguration; @@ -1051,6 +1054,7 @@ void setBannedNodeIds(final List values) { private final Supplier metricsSystem = Suppliers.memoize(() -> PrometheusMetricsSystem.init(metricsConfiguration())); private Vertx vertx; + private EnodeDnsConfiguration enodeDnsConfiguration; public BesuCommand( final Logger logger, @@ -1421,12 +1425,15 @@ private BesuCommand configure() throws Exception { genesisFile == null && !isPrivacyEnabled && network != NetworkName.DEV ? SyncMode.FAST : SyncMode.FULL); + ethNetworkConfig = updateNetworkConfig(getNetwork()); jsonRpcConfiguration = jsonRpcConfiguration(); graphQLConfiguration = graphQLConfiguration(); webSocketConfiguration = webSocketConfiguration(); + permissioningConfiguration = permissioningConfiguration(); staticNodes = loadStaticNodes(); + logger.info("Connecting to {} static nodes.", staticNodes.size()); logger.trace("Static Nodes = {}", staticNodes); final List enodeURIs = @@ -1761,6 +1768,7 @@ private Optional permissioningConfiguration() throws final LocalPermissioningConfiguration localPermissioningConfiguration = PermissioningConfigurationBuilder.permissioningConfiguration( permissionsNodesEnabled, + getEnodeDnsConfiguration(), nodePermissioningConfigFile.orElse(getDefaultPermissioningFilePath()), permissionsAccountsEnabled, accountPermissioningConfigFile.orElse(getDefaultPermissioningFilePath())); @@ -2151,7 +2159,7 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { } } - if (bootNodes == null) { + if (bootnodes == null) { // We default to an empty bootnodes list if the option is not provided on CLI // because // mainnet bootnodes won't work as the default value for a custom genesis, @@ -2166,8 +2174,19 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { builder.setNetworkId(networkId); } - if (bootNodes != null) { - builder.setBootNodes(bootNodes); + if (bootnodes != null) { + try { + + final List listBootNodes = + bootnodes.stream() + .filter(value -> !value.isEmpty()) + .map(url -> EnodeURL.fromString(url, getEnodeDnsConfiguration())) + .collect(Collectors.toList()); + DiscoveryConfiguration.assertValidBootnodes(listBootNodes); + builder.setBootNodes(listBootNodes); + } catch (final IllegalArgumentException e) { + throw new ParameterException(commandLine, e.getMessage()); + } } return builder.build(); @@ -2245,13 +2264,24 @@ private Set loadStaticNodes() throws IOException { final String staticNodesFilename = "static-nodes.json"; final Path staticNodesPath = dataDir().resolve(staticNodesFilename); - return StaticNodesParser.fromPath(staticNodesPath); + return StaticNodesParser.fromPath(staticNodesPath, getEnodeDnsConfiguration()); } public BesuExceptionHandler exceptionHandler() { return new BesuExceptionHandler(this::getLogLevel); } + public EnodeDnsConfiguration getEnodeDnsConfiguration() { + if (enodeDnsConfiguration == null) { + enodeDnsConfiguration = + ImmutableEnodeDnsConfiguration.builder() + .dnsEnabled(dnsEnabled) + .updateEnabled(dnsUpdateEnabled) + .build(); + } + return enodeDnsConfiguration; + } + @VisibleForTesting Level getLogLevel() { return logLevel; diff --git a/ethereum/p2p/build.gradle b/ethereum/p2p/build.gradle index 21ef7a49eb4..f683326e1fd 100644 --- a/ethereum/p2p/build.gradle +++ b/ethereum/p2p/build.gradle @@ -42,6 +42,9 @@ dependencies { implementation 'org.apache.tuweni:tuweni-units' implementation 'org.xerial.snappy:snappy-java' + annotationProcessor "org.immutables:value" + implementation "org.immutables:value-annotations" + runtimeOnly 'org.apache.logging.log4j:log4j-core' // test dependencies. diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 80063890d68..475ea59d37a 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -21,7 +21,9 @@ import java.net.InetAddress; import java.net.URI; +import java.net.UnknownHostException; import java.util.Objects; +import java.util.Optional; import java.util.OptionalInt; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -39,13 +41,15 @@ public class EnodeURL { private static final Pattern NODE_ID_PATTERN = Pattern.compile("^[0-9a-fA-F]{128}$"); private final Bytes nodeId; - private final InetAddress ip; + private InetAddress ip; + private final Optional maybeHostname; private final OptionalInt listeningPort; private final OptionalInt discoveryPort; private EnodeURL( final Bytes nodeId, final InetAddress address, + final Optional maybeHostname, final OptionalInt listeningPort, final OptionalInt discoveryPort) { checkArgument( @@ -59,6 +63,7 @@ private EnodeURL( this.nodeId = nodeId; this.ip = address; + this.maybeHostname = maybeHostname; this.listeningPort = listeningPort; this.discoveryPort = discoveryPort; } @@ -68,9 +73,14 @@ public static Builder builder() { } public static EnodeURL fromString(final String value) { + return fromString(value, EnodeDnsConfiguration.dnsDisabled()); + } + + public static EnodeURL fromString( + final String value, final EnodeDnsConfiguration enodeDnsConfiguration) { try { checkStringArgumentNotEmpty(value, "Invalid empty value."); - return fromURI(URI.create(value)); + return fromURI(URI.create(value), enodeDnsConfiguration); } catch (IllegalArgumentException e) { String message = "Invalid enode URL syntax. Enode URL should have the following format 'enode://@:[?discport=]'."; @@ -82,6 +92,10 @@ public static EnodeURL fromString(final String value) { } public static EnodeURL fromURI(final URI uri) { + return fromURI(uri, EnodeDnsConfiguration.dnsDisabled()); + } + + public static EnodeURL fromURI(final URI uri, final EnodeDnsConfiguration enodeDnsConfiguration) { checkArgument(uri != null, "URI cannot be null"); checkStringArgumentNotEmpty(uri.getScheme(), "Missing 'enode' scheme."); checkStringArgumentNotEmpty(uri.getHost(), "Missing or invalid ip address."); @@ -112,7 +126,7 @@ public static EnodeURL fromURI(final URI uri) { } return builder() - .ipAddress(host) + .ipAddress(host, enodeDnsConfiguration) .nodeId(id) .listeningPort(tcpPort) .discoveryPort(discoveryPort) @@ -128,9 +142,9 @@ public static boolean sameListeningEndpoint(final EnodeURL enodeA, final EnodeUR return false; } - return Objects.equals(enodeA.nodeId, enodeB.nodeId) - && Objects.equals(enodeA.ip, enodeB.ip) - && Objects.equals(enodeA.listeningPort, enodeB.listeningPort); + return Objects.equals(enodeA.getNodeId(), enodeB.getNodeId()) + && Objects.equals(enodeA.getIp(), enodeB.getIp()) + && Objects.equals(enodeA.getListeningPort(), enodeB.getListeningPort()); } public static Bytes parseNodeId(final String nodeId) { @@ -149,7 +163,7 @@ public URI toURI() { String.format( "enode://%s@%s:%d", nodeId.toUnprefixedHexString(), - InetAddresses.toUriString(ip), + InetAddresses.toUriString(getIp()), getListeningPortOrZero()); final OptionalInt discPort = getDiscPortQueryParam(); if (discPort.isPresent()) { @@ -164,7 +178,7 @@ public URI toURIWithoutDiscoveryPort() { String.format( "enode://%s@%s:%d", nodeId.toUnprefixedHexString(), - InetAddresses.toUriString(ip), + InetAddresses.toUriString(getIp()), getListeningPortOrZero()); return URI.create(uri); @@ -185,7 +199,11 @@ private OptionalInt getDiscPortQueryParam() { } public static URI asURI(final String url) { - return fromString(url).toURI(); + return asURI(url, EnodeDnsConfiguration.dnsDisabled()); + } + + public static URI asURI(final String url, final EnodeDnsConfiguration enodeDnsConfiguration) { + return fromString(url, enodeDnsConfiguration).toURI(); } public Bytes getNodeId() { @@ -193,10 +211,21 @@ public Bytes getNodeId() { } public String getIpAsString() { - return ip.getHostAddress(); + return getIp().getHostAddress(); } public InetAddress getIp() { + this.ip = + maybeHostname + .map( + hostname -> { + try { + return InetAddress.getByName(hostname); + } catch (UnknownHostException e) { + return ip; + } + }) + .orElse(ip); return ip; } @@ -233,15 +262,15 @@ public boolean equals(final Object o) { return false; } EnodeURL enodeURL = (EnodeURL) o; - return Objects.equals(nodeId, enodeURL.nodeId) - && Objects.equals(ip, enodeURL.ip) - && Objects.equals(listeningPort, enodeURL.listeningPort) - && Objects.equals(discoveryPort, enodeURL.discoveryPort); + return Objects.equals(getNodeId(), enodeURL.getNodeId()) + && Objects.equals(getIp(), enodeURL.getIp()) + && Objects.equals(getListeningPort(), enodeURL.getListeningPort()) + && Objects.equals(getDiscoveryPort(), enodeURL.getDiscoveryPort()); } @Override public int hashCode() { - return Objects.hash(nodeId, ip, listeningPort, discoveryPort); + return Objects.hash(getNodeId(), getIp(), getListeningPort(), getDiscoveryPort()); } @Override @@ -254,13 +283,14 @@ public static class Builder { private Bytes nodeId; private OptionalInt listeningPort; private OptionalInt discoveryPort; + private Optional maybeHostname = Optional.empty(); private InetAddress ip; private Builder() {}; public EnodeURL build() { validate(); - return new EnodeURL(nodeId, ip, listeningPort, discoveryPort); + return new EnodeURL(nodeId, ip, maybeHostname, listeningPort, discoveryPort); } private void validate() { @@ -298,12 +328,26 @@ public Builder ipAddress(final InetAddress ip) { } public Builder ipAddress(final String ip) { + return ipAddress(ip, EnodeDnsConfiguration.dnsDisabled()); + } + + public Builder ipAddress(final String ip, final EnodeDnsConfiguration enodeDnsConfiguration) { if (InetAddresses.isUriInetAddress(ip)) { this.ip = InetAddresses.forUriString(ip); } else if (InetAddresses.isInetAddress(ip)) { this.ip = InetAddresses.forString(ip); + } else if (enodeDnsConfiguration.dnsEnabled()) { + try { + System.out.println("ALLO " + enodeDnsConfiguration.updateEnabled() + " " + ip); + this.ip = InetAddress.getByName(ip); + if (enodeDnsConfiguration.updateEnabled()) { + this.maybeHostname = Optional.of(ip); + } + } catch (UnknownHostException e) { + throw new IllegalArgumentException("Invalid ip or hostname."); + } } else { - throw new IllegalArgumentException("Invalid ip address."); + throw new IllegalArgumentException("Invalid ip."); } return this; } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParser.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParser.java index 7c24bd00fcd..28b7ff80bc7 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParser.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParser.java @@ -35,11 +35,12 @@ public class StaticNodesParser { private static final Logger LOG = LogManager.getLogger(); - public static Set fromPath(final Path path) + public static Set fromPath( + final Path path, final EnodeDnsConfiguration enodeDnsConfiguration) throws IOException, IllegalArgumentException { try { - return readEnodesFromPath(path); + return readEnodesFromPath(path, enodeDnsConfiguration); } catch (FileNotFoundException | NoSuchFileException ex) { LOG.info("StaticNodes file {} does not exist, no static connections will be created.", path); return emptySet(); @@ -55,7 +56,8 @@ public static Set fromPath(final Path path) } } - private static Set readEnodesFromPath(final Path path) throws IOException { + private static Set readEnodesFromPath( + final Path path, final EnodeDnsConfiguration enodeDnsConfiguration) throws IOException { final byte[] staticNodesContent = Files.readAllBytes(path); if (staticNodesContent.length == 0) { return emptySet(); @@ -63,13 +65,14 @@ private static Set readEnodesFromPath(final Path path) throws IOExcept final JsonArray enodeJsonArray = new JsonArray(new String(staticNodesContent, UTF_8)); return enodeJsonArray.stream() - .map(obj -> decodeString((String) obj)) + .map(obj -> decodeString((String) obj, enodeDnsConfiguration)) .collect(Collectors.toSet()); } - private static EnodeURL decodeString(final String input) { + private static EnodeURL decodeString( + final String input, final EnodeDnsConfiguration enodeDnsConfiguration) { try { - final EnodeURL enode = EnodeURL.fromString(input); + final EnodeURL enode = EnodeURL.fromString(input, enodeDnsConfiguration); checkArgument( enode.isListening(), "Static node must be configured with a valid listening port."); return enode; diff --git a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParserTest.java b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParserTest.java index 8b8aedc1213..b9b9a73f0a0 100644 --- a/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParserTest.java +++ b/ethereum/p2p/src/test/java/org/hyperledger/besu/ethereum/p2p/peers/StaticNodesParserTest.java @@ -73,7 +73,7 @@ public class StaticNodesParserTest { public void validFileLoadsWithExpectedEnodes() throws IOException, URISyntaxException { final URL resource = StaticNodesParserTest.class.getResource("valid_static_nodes.json"); final File validFile = new File(resource.getFile()); - final Set enodes = StaticNodesParser.fromPath(validFile.toPath()); + final Set enodes = StaticNodesParser.fromPath(validFile.toPath(), false); assertThat(enodes) .containsExactlyInAnyOrder(validFileItems.toArray(new EnodeURL[validFileItems.size()])); @@ -84,7 +84,7 @@ public void invalidFileThrowsAnException() { final URL resource = StaticNodesParserTest.class.getResource("invalid_static_nodes.json"); final File invalidFile = new File(resource.getFile()); - assertThatThrownBy(() -> StaticNodesParser.fromPath(invalidFile.toPath())) + assertThatThrownBy(() -> StaticNodesParser.fromPath(invalidFile.toPath(), false)) .isInstanceOf(IllegalArgumentException.class); } @@ -94,7 +94,7 @@ public void fromPath_withNonListeningNodesThrowsException() { StaticNodesParserTest.class.getResource("invalid_static_nodes_no_listening_port.json"); final File invalidFile = new File(resource.getFile()); - assertThatThrownBy(() -> StaticNodesParser.fromPath(invalidFile.toPath())) + assertThatThrownBy(() -> StaticNodesParser.fromPath(invalidFile.toPath(), false)) .isInstanceOf(IllegalArgumentException.class) .hasMessageContaining("Static node must be configured with a valid listening port"); } @@ -105,7 +105,7 @@ public void nonJsonFileThrowsAnException() throws IOException { tempFile.deleteOnExit(); Files.write(tempFile.toPath(), "This Is Not Json".getBytes(Charset.forName("UTF-8"))); - assertThatThrownBy(() -> StaticNodesParser.fromPath(tempFile.toPath())) + assertThatThrownBy(() -> StaticNodesParser.fromPath(tempFile.toPath(), false)) .isInstanceOf(DecodeException.class); } @@ -113,7 +113,7 @@ public void nonJsonFileThrowsAnException() throws IOException { public void anEmptyCacheIsCreatedIfTheFileDoesNotExist() throws IOException { final Path path = Paths.get("./arbirtraryFilename.txt"); - final Set enodes = StaticNodesParser.fromPath(path); + final Set enodes = StaticNodesParser.fromPath(path, false); assertThat(enodes.size()).isZero(); } @@ -122,7 +122,7 @@ public void cacheIsCreatedIfFileExistsButIsEmpty() throws IOException { final File tempFile = testFolder.newFile("file.txt"); tempFile.deleteOnExit(); - final Set enodes = StaticNodesParser.fromPath(tempFile.toPath()); + final Set enodes = StaticNodesParser.fromPath(tempFile.toPath(), false); assertThat(enodes.size()).isZero(); } } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java index 89a6ac25435..f9020b3545e 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/AccountLocalConfigPermissioningController.java @@ -209,6 +209,7 @@ public synchronized void reload() throws RuntimeException { final LocalPermissioningConfiguration updatedConfig = PermissioningConfigurationBuilder.permissioningConfiguration( configuration.isNodeAllowlistEnabled(), + configuration.getEnodeDnsConfiguration(), configuration.getNodePermissioningConfigFilePath(), configuration.isAccountAllowlistEnabled(), configuration.getAccountPermissioningConfigFilePath()); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java index 27c3d001bf6..466326515ef 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java @@ -14,6 +14,8 @@ */ package org.hyperledger.besu.ethereum.permissioning; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; + import java.net.URI; import java.util.ArrayList; import java.util.Collection; @@ -23,6 +25,7 @@ public class LocalPermissioningConfiguration { private List nodeAllowlist; private List accountAllowlist; private boolean nodeAllowlistEnabled; + private EnodeDnsConfiguration enodeDnsConfiguration = EnodeDnsConfiguration.dnsDisabled(); private String nodePermissioningConfigFilePath; private boolean accountAllowlistEnabled; private String accountPermissioningConfigFilePath; @@ -38,6 +41,10 @@ public static LocalPermissioningConfiguration createDefault() { return config; } + public void setEnodeDnsConfiguration(final EnodeDnsConfiguration enodeDnsConfiguration) { + this.enodeDnsConfiguration = enodeDnsConfiguration; + } + public void setNodeAllowlist(final Collection nodeAllowlist) { if (nodeAllowlist != null) { this.nodeAllowlist.addAll(nodeAllowlist); @@ -45,6 +52,10 @@ public void setNodeAllowlist(final Collection nodeAllowlist) { } } + public EnodeDnsConfiguration getEnodeDnsConfiguration() { + return enodeDnsConfiguration; + } + public boolean isNodeAllowlistEnabled() { return nodeAllowlistEnabled; } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java index 9e93380819d..b16c0705a8d 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java @@ -250,6 +250,7 @@ public synchronized void reload() throws RuntimeException { final LocalPermissioningConfiguration updatedConfig = PermissioningConfigurationBuilder.permissioningConfiguration( configuration.isNodeAllowlistEnabled(), + configuration.getEnodeDnsConfiguration(), configuration.getNodePermissioningConfigFilePath(), configuration.isAccountAllowlistEnabled(), configuration.getAccountPermissioningConfigFilePath()); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java index c62a82fcd4b..793b2fb6f98 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.permissioning; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import java.net.URI; @@ -41,6 +42,7 @@ public static SmartContractPermissioningConfiguration smartContractPermissioning public static LocalPermissioningConfiguration permissioningConfiguration( final boolean nodePermissioningEnabled, + final EnodeDnsConfiguration enodeDnsConfiguration, final String nodePermissioningConfigFilepath, final boolean accountPermissioningEnabled, final String accountPermissioningConfigFilepath) @@ -48,7 +50,7 @@ public static LocalPermissioningConfiguration permissioningConfiguration( final LocalPermissioningConfiguration permissioningConfiguration = LocalPermissioningConfiguration.createDefault(); - + permissioningConfiguration.setEnodeDnsConfiguration(enodeDnsConfiguration); loadNodePermissioning( permissioningConfiguration, nodePermissioningEnabled, nodePermissioningConfigFilepath); loadAccountPermissioning( @@ -73,13 +75,16 @@ private static LocalPermissioningConfiguration loadNodePermissioning( permissioningConfiguration.setNodePermissioningConfigFilePath( nodePermissioningConfigFilepath); + // ICI if (nodeAllowlistTomlArray != null) { List nodesAllowlistToml = nodeAllowlistTomlArray .toList() .parallelStream() .map(Object::toString) - .map(EnodeURL::asURI) + .map( + url -> + EnodeURL.asURI(url, permissioningConfiguration.getEnodeDnsConfiguration())) .collect(Collectors.toList()); permissioningConfiguration.setNodeAllowlist(nodesAllowlistToml); } else { diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 10eefaefa9f..d191a99e205 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -120,6 +120,9 @@ dependencyManagement { dependency 'org.yaml:snakeyaml:1.26' + dependency "org.immutables:value:2.8.8" + dependency "org.immutables:value-annotations:2.8.8" + dependency 'tech.pegasys.ethsigner.internal:core:0.4.0' dependency 'tech.pegasys.ethsigner.internal:file-based:0.4.0' dependency 'tech.pegasys.ethsigner.internal:signing-api:0.4.0' From f39f52828805c619e079c906f5a88e01ba91d91c Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Wed, 22 Jul 2020 18:03:59 +0200 Subject: [PATCH 02/11] update error message Signed-off-by: Karim TAAM --- .../p2p/peers/EnodeDnsConfiguration.java | 32 +++++++++++++++++++ .../besu/ethereum/p2p/peers/EnodeURL.java | 4 +-- 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeDnsConfiguration.java diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeDnsConfiguration.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeDnsConfiguration.java new file mode 100644 index 00000000000..1ee49120eaa --- /dev/null +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeDnsConfiguration.java @@ -0,0 +1,32 @@ +/* + * Copyright ConsenSys AG. + * + * 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.p2p.peers; + +import org.immutables.value.Value; + +@Value.Immutable +public interface EnodeDnsConfiguration { + + EnodeDnsConfiguration DEFAULT_CONFIG = + ImmutableEnodeDnsConfiguration.builder().dnsEnabled(false).updateEnabled(false).build(); + + static EnodeDnsConfiguration dnsDisabled() { + return DEFAULT_CONFIG; + } + + boolean dnsEnabled(); + + boolean updateEnabled(); +} diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 475ea59d37a..82561c3fda7 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -344,10 +344,10 @@ public Builder ipAddress(final String ip, final EnodeDnsConfiguration enodeDnsCo this.maybeHostname = Optional.of(ip); } } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid ip or hostname."); + throw new IllegalArgumentException("Invalid ip address or hostname."); } } else { - throw new IllegalArgumentException("Invalid ip."); + throw new IllegalArgumentException("Invalid ip address."); } return this; } From f943765fa3edd6ef42c55851420913553a90444d Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Wed, 22 Jul 2020 18:24:03 +0200 Subject: [PATCH 03/11] fix tests Signed-off-by: Karim TAAM --- ...PermissioningConfigurationBuilderTest.java | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java index a9d99928169..39358ba44f4 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java @@ -17,6 +17,7 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; +import static org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration.dnsDisabled; import java.io.IOException; import java.net.URI; @@ -101,7 +102,11 @@ public void permissioningConfigWithOnlyNodeAllowlistSet() throws Exception { LocalPermissioningConfiguration permissioningConfiguration = PermissioningConfigurationBuilder.permissioningConfiguration( - true, toml.toAbsolutePath().toString(), false, toml.toAbsolutePath().toString()); + true, + dnsDisabled(), + toml.toAbsolutePath().toString(), + false, + toml.toAbsolutePath().toString()); assertThat(permissioningConfiguration.isAccountAllowlistEnabled()).isFalse(); assertThat(permissioningConfiguration.isNodeAllowlistEnabled()).isTrue(); @@ -115,7 +120,11 @@ public void permissioningConfigWithOnlyAccountAllowlistSet() throws Exception { LocalPermissioningConfiguration permissioningConfiguration = PermissioningConfigurationBuilder.permissioningConfiguration( - false, toml.toAbsolutePath().toString(), true, toml.toAbsolutePath().toString()); + false, + dnsDisabled(), + toml.toAbsolutePath().toString(), + true, + toml.toAbsolutePath().toString()); assertThat(permissioningConfiguration.isNodeAllowlistEnabled()).isFalse(); assertThat(permissioningConfiguration.isAccountAllowlistEnabled()).isTrue(); @@ -200,7 +209,7 @@ public void permissioningConfigFromFileMustSetFilePath() throws Exception { LocalPermissioningConfiguration permissioningConfiguration = PermissioningConfigurationBuilder.permissioningConfiguration( - true, toml.toString(), true, toml.toString()); + true, dnsDisabled(), toml.toString(), true, toml.toString()); assertThat(permissioningConfiguration.getNodePermissioningConfigFilePath()) .isEqualTo(toml.toString()); @@ -224,7 +233,7 @@ public void permissioningConfigFromMultilineFileMustParseCorrectly() throws Exce this.getClass().getResource(PERMISSIONING_CONFIG_NODE_ALLOWLIST_ONLY_MULTILINE); final LocalPermissioningConfiguration permissioningConfiguration = PermissioningConfigurationBuilder.permissioningConfiguration( - true, configFile.getPath(), false, configFile.getPath()); + true, dnsDisabled(), configFile.getPath(), false, configFile.getPath()); assertThat(permissioningConfiguration.isNodeAllowlistEnabled()).isTrue(); assertThat(permissioningConfiguration.getNodeAllowlist().size()).isEqualTo(5); @@ -233,18 +242,22 @@ public void permissioningConfigFromMultilineFileMustParseCorrectly() throws Exce private LocalPermissioningConfiguration accountOnlyPermissioningConfig(final Path toml) throws Exception { return PermissioningConfigurationBuilder.permissioningConfiguration( - false, null, true, toml.toAbsolutePath().toString()); + false, dnsDisabled(), null, true, toml.toAbsolutePath().toString()); } private LocalPermissioningConfiguration nodeOnlyPermissioningConfig(final Path toml) throws Exception { return PermissioningConfigurationBuilder.permissioningConfiguration( - true, toml.toAbsolutePath().toString(), false, null); + true, dnsDisabled(), toml.toAbsolutePath().toString(), false, null); } private LocalPermissioningConfiguration permissioningConfig(final Path toml) throws Exception { return PermissioningConfigurationBuilder.permissioningConfiguration( - true, toml.toAbsolutePath().toString(), true, toml.toAbsolutePath().toString()); + true, + dnsDisabled(), + toml.toAbsolutePath().toString(), + true, + toml.toAbsolutePath().toString()); } private Path createTempFile(final String filename, final byte[] contents) throws IOException { From ffbff03ce0a09a0b73a9f1310050609e53c83299 Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Thu, 23 Jul 2020 10:45:35 +0200 Subject: [PATCH 04/11] clean code Signed-off-by: Karim TAAM --- .../java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 82561c3fda7..59460f6fc08 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -338,7 +338,6 @@ public Builder ipAddress(final String ip, final EnodeDnsConfiguration enodeDnsCo this.ip = InetAddresses.forString(ip); } else if (enodeDnsConfiguration.dnsEnabled()) { try { - System.out.println("ALLO " + enodeDnsConfiguration.updateEnabled() + " " + ip); this.ip = InetAddress.getByName(ip); if (enodeDnsConfiguration.updateEnabled()) { this.maybeHostname = Optional.of(ip); From 1adca545321f483d89333bd80af9800286e0a59e Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Mon, 17 Aug 2020 18:36:00 +0200 Subject: [PATCH 05/11] update hostname detection Signed-off-by: Karim TAAM --- .../org/hyperledger/besu/cli/BesuCommand.java | 7 ++-- .../PermissioningConfigurationValidator.java | 33 +++++-------------- .../besu/ethereum/p2p/peers/EnodeURL.java | 14 +++++--- .../LocalPermissioningConfiguration.java | 7 ++-- ...odeLocalConfigPermissioningController.java | 4 +-- .../PermissioningConfigurationBuilder.java | 11 ++++--- 6 files changed, 33 insertions(+), 43 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 75b661860f9..6fbcce2fa37 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1436,8 +1436,7 @@ private BesuCommand configure() throws Exception { logger.info("Connecting to {} static nodes.", staticNodes.size()); logger.trace("Static Nodes = {}", staticNodes); - final List enodeURIs = - ethNetworkConfig.getBootNodes().stream().map(EnodeURL::toURI).collect(Collectors.toList()); + final List enodeURIs = ethNetworkConfig.getBootNodes(); permissioningConfiguration .flatMap(PermissioningConfiguration::getLocalConfig) .ifPresent(p -> ensureAllNodesAreInAllowlist(enodeURIs, p)); @@ -1447,7 +1446,7 @@ private BesuCommand configure() throws Exception { .ifPresent( p -> ensureAllNodesAreInAllowlist( - staticNodes.stream().map(EnodeURL::toURI).collect(Collectors.toList()), p)); + staticNodes, p)); metricsConfiguration = metricsConfiguration(); logger.info("Security Module: {}", securityModuleName); @@ -1461,7 +1460,7 @@ private NetworkName getNetwork() { } private void ensureAllNodesAreInAllowlist( - final Collection enodeAddresses, + final Collection enodeAddresses, final LocalPermissioningConfiguration permissioningConfiguration) { try { PermissioningConfigurationValidator.areAllNodesAreInAllowlist( diff --git a/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java b/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java index 3d0f269212e..9d3c67d927b 100644 --- a/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java +++ b/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java @@ -14,6 +14,7 @@ */ package org.hyperledger.besu.util; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; import java.net.URI; @@ -25,20 +26,17 @@ public class PermissioningConfigurationValidator { public static void areAllNodesAreInAllowlist( - final Collection nodeURIs, + final Collection nodeURIs, final LocalPermissioningConfiguration permissioningConfiguration) throws Exception { if (permissioningConfiguration.isNodeAllowlistEnabled() && nodeURIs != null) { - final List allowlistNodesWithoutQueryParam = - permissioningConfiguration.getNodeAllowlist().stream() - .map(PermissioningConfigurationValidator::removeQueryFromURI) - .collect(Collectors.toList()); + final List allowlistNodesWithoutQueryParam = + permissioningConfiguration.getNodeAllowlist(); - final List nodeURIsNotInAllowlist = + final List nodeURIsNotInAllowlist = nodeURIs.stream() - .map(PermissioningConfigurationValidator::removeQueryFromURI) - .filter(uri -> !allowlistNodesWithoutQueryParam.contains(uri)) + .filter(enodeURL -> !allowlistNodesWithoutQueryParam.contains(enodeURL)) .collect(Collectors.toList()); if (!nodeURIsNotInAllowlist.isEmpty()) { @@ -48,22 +46,7 @@ public static void areAllNodesAreInAllowlist( } } - private static URI removeQueryFromURI(final URI uri) { - try { - return new URI( - uri.getScheme(), - uri.getUserInfo(), - uri.getHost(), - uri.getPort(), - uri.getPath(), - null, - uri.getFragment()); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - - private static Collection enodesAsStrings(final List enodes) { - return enodes.parallelStream().map(URI::toASCIIString).collect(Collectors.toList()); + private static Collection enodesAsStrings(final List enodes) { + return enodes.parallelStream().map(EnodeURL::toString).collect(Collectors.toList()); } } diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 59460f6fc08..0f441e8d49b 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -159,11 +159,12 @@ public static Bytes parseNodeId(final String nodeId) { } public URI toURI() { + final String uri = String.format( "enode://%s@%s:%d", nodeId.toUnprefixedHexString(), - InetAddresses.toUriString(getIp()), + maybeHostname.orElse(InetAddresses.toUriString(getIp())), getListeningPortOrZero()); final OptionalInt discPort = getDiscPortQueryParam(); if (discPort.isPresent()) { @@ -178,7 +179,7 @@ public URI toURIWithoutDiscoveryPort() { String.format( "enode://%s@%s:%d", nodeId.toUnprefixedHexString(), - InetAddresses.toUriString(getIp()), + maybeHostname.orElse(InetAddresses.toUriString(getIp())), getListeningPortOrZero()); return URI.create(uri); @@ -229,6 +230,7 @@ public InetAddress getIp() { return ip; } + public boolean isListening() { return listeningPort.isPresent(); } @@ -338,12 +340,16 @@ public Builder ipAddress(final String ip, final EnodeDnsConfiguration enodeDnsCo this.ip = InetAddresses.forString(ip); } else if (enodeDnsConfiguration.dnsEnabled()) { try { - this.ip = InetAddress.getByName(ip); if (enodeDnsConfiguration.updateEnabled()) { this.maybeHostname = Optional.of(ip); } + this.ip = InetAddress.getByName(ip); } catch (UnknownHostException e) { - throw new IllegalArgumentException("Invalid ip address or hostname."); + if(!enodeDnsConfiguration.updateEnabled()){ + throw new IllegalArgumentException("Invalid ip address or hostname."); + }else{ + this.ip = InetAddresses.forString("127.0.0.1"); + } } } else { throw new IllegalArgumentException("Invalid ip address."); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java index 466326515ef..7ae94ae69e0 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java @@ -15,6 +15,7 @@ package org.hyperledger.besu.ethereum.permissioning; import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import java.net.URI; import java.util.ArrayList; @@ -22,7 +23,7 @@ import java.util.List; public class LocalPermissioningConfiguration { - private List nodeAllowlist; + private List nodeAllowlist; private List accountAllowlist; private boolean nodeAllowlistEnabled; private EnodeDnsConfiguration enodeDnsConfiguration = EnodeDnsConfiguration.dnsDisabled(); @@ -30,7 +31,7 @@ public class LocalPermissioningConfiguration { private boolean accountAllowlistEnabled; private String accountPermissioningConfigFilePath; - public List getNodeAllowlist() { + public List getNodeAllowlist() { return nodeAllowlist; } @@ -45,7 +46,7 @@ public void setEnodeDnsConfiguration(final EnodeDnsConfiguration enodeDnsConfigu this.enodeDnsConfiguration = enodeDnsConfiguration; } - public void setNodeAllowlist(final Collection nodeAllowlist) { + public void setNodeAllowlist(final Collection nodeAllowlist) { if (nodeAllowlist != null) { this.nodeAllowlist.addAll(nodeAllowlist); this.nodeAllowlistEnabled = true; diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java index b16c0705a8d..34453972572 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java @@ -100,8 +100,8 @@ public NodeLocalConfigPermissioningController( private void readNodesFromConfig(final LocalPermissioningConfiguration configuration) { if (configuration.isNodeAllowlistEnabled() && configuration.getNodeAllowlist() != null) { - for (URI uri : configuration.getNodeAllowlist()) { - addNode(EnodeURL.fromString(uri.toString())); + for (EnodeURL enodeURL : configuration.getNodeAllowlist()) { + addNode(enodeURL); } } } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java index 793b2fb6f98..d988e0c5b2e 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java @@ -61,6 +61,7 @@ public static LocalPermissioningConfiguration permissioningConfiguration( return permissioningConfiguration; } + private static LocalPermissioningConfiguration loadNodePermissioning( final LocalPermissioningConfiguration permissioningConfiguration, final boolean localConfigNodePermissioningEnabled, @@ -75,16 +76,15 @@ private static LocalPermissioningConfiguration loadNodePermissioning( permissioningConfiguration.setNodePermissioningConfigFilePath( nodePermissioningConfigFilepath); - // ICI if (nodeAllowlistTomlArray != null) { - List nodesAllowlistToml = + List nodesAllowlistToml = nodeAllowlistTomlArray .toList() .parallelStream() - .map(Object::toString) - .map( + .map(Object::toString) + .map( url -> - EnodeURL.asURI(url, permissioningConfiguration.getEnodeDnsConfiguration())) + EnodeURL.fromString(url, permissioningConfiguration.getEnodeDnsConfiguration())) .collect(Collectors.toList()); permissioningConfiguration.setNodeAllowlist(nodesAllowlistToml); } else { @@ -171,4 +171,5 @@ private static TomlParseResult readToml(final String filepath) throws Exception } return toml; } + } From 634e7e95962a7d9f9a41622199f94fa4082975fb Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Wed, 19 Aug 2020 22:27:00 +0200 Subject: [PATCH 06/11] spotlessApply Signed-off-by: Karim TAAM --- .../java/org/hyperledger/besu/cli/BesuCommand.java | 7 ++----- .../besu/util/PermissioningConfigurationValidator.java | 2 -- .../hyperledger/besu/ethereum/p2p/peers/EnodeURL.java | 7 +++---- .../permissioning/LocalPermissioningConfiguration.java | 1 - .../NodeLocalConfigPermissioningController.java | 1 - .../PermissioningConfigurationBuilder.java | 10 ++++------ 6 files changed, 9 insertions(+), 19 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 6fbcce2fa37..61398cdb758 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1436,17 +1436,14 @@ private BesuCommand configure() throws Exception { logger.info("Connecting to {} static nodes.", staticNodes.size()); logger.trace("Static Nodes = {}", staticNodes); - final List enodeURIs = ethNetworkConfig.getBootNodes(); + final List enodeURIs = ethNetworkConfig.getBootNodes(); permissioningConfiguration .flatMap(PermissioningConfiguration::getLocalConfig) .ifPresent(p -> ensureAllNodesAreInAllowlist(enodeURIs, p)); permissioningConfiguration .flatMap(PermissioningConfiguration::getLocalConfig) - .ifPresent( - p -> - ensureAllNodesAreInAllowlist( - staticNodes, p)); + .ifPresent(p -> ensureAllNodesAreInAllowlist(staticNodes, p)); metricsConfiguration = metricsConfiguration(); logger.info("Security Module: {}", securityModuleName); diff --git a/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java b/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java index 9d3c67d927b..6bbd5e39287 100644 --- a/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java +++ b/besu/src/main/java/org/hyperledger/besu/util/PermissioningConfigurationValidator.java @@ -17,8 +17,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; -import java.net.URI; -import java.net.URISyntaxException; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 0f441e8d49b..0b0119476bc 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -179,7 +179,7 @@ public URI toURIWithoutDiscoveryPort() { String.format( "enode://%s@%s:%d", nodeId.toUnprefixedHexString(), - maybeHostname.orElse(InetAddresses.toUriString(getIp())), + maybeHostname.orElse(InetAddresses.toUriString(getIp())), getListeningPortOrZero()); return URI.create(uri); @@ -230,7 +230,6 @@ public InetAddress getIp() { return ip; } - public boolean isListening() { return listeningPort.isPresent(); } @@ -345,9 +344,9 @@ public Builder ipAddress(final String ip, final EnodeDnsConfiguration enodeDnsCo } this.ip = InetAddress.getByName(ip); } catch (UnknownHostException e) { - if(!enodeDnsConfiguration.updateEnabled()){ + if (!enodeDnsConfiguration.updateEnabled()) { throw new IllegalArgumentException("Invalid ip address or hostname."); - }else{ + } else { this.ip = InetAddresses.forString("127.0.0.1"); } } diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java index 7ae94ae69e0..410d5cddd08 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfiguration.java @@ -17,7 +17,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java index 34453972572..632822810de 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java @@ -24,7 +24,6 @@ import org.hyperledger.besu.util.Subscribers; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java index d988e0c5b2e..32769579947 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/PermissioningConfigurationBuilder.java @@ -18,7 +18,6 @@ import org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; -import java.net.URI; import java.util.List; import java.util.stream.Collectors; @@ -61,7 +60,6 @@ public static LocalPermissioningConfiguration permissioningConfiguration( return permissioningConfiguration; } - private static LocalPermissioningConfiguration loadNodePermissioning( final LocalPermissioningConfiguration permissioningConfiguration, final boolean localConfigNodePermissioningEnabled, @@ -81,10 +79,11 @@ private static LocalPermissioningConfiguration loadNodePermissioning( nodeAllowlistTomlArray .toList() .parallelStream() - .map(Object::toString) - .map( + .map(Object::toString) + .map( url -> - EnodeURL.fromString(url, permissioningConfiguration.getEnodeDnsConfiguration())) + EnodeURL.fromString( + url, permissioningConfiguration.getEnodeDnsConfiguration())) .collect(Collectors.toList()); permissioningConfiguration.setNodeAllowlist(nodesAllowlistToml); } else { @@ -171,5 +170,4 @@ private static TomlParseResult readToml(final String filepath) throws Exception } return toml; } - } From d60de83220ad807a6bbab3d54c45464854b350e6 Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Fri, 21 Aug 2020 10:26:37 +0200 Subject: [PATCH 07/11] add tests Signed-off-by: Karim TAAM --- .../PermissionedNodeBuilder.java | 8 ++++-- .../org/hyperledger/besu/cli/BesuCommand.java | 14 ++++++++-- .../hyperledger/besu/cli/BesuCommandTest.java | 27 +++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java index c6a246ae99d..1456d894f7b 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java @@ -21,6 +21,7 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApi; import org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis; import org.hyperledger.besu.ethereum.core.Address; +import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; import org.hyperledger.besu.ethereum.permissioning.AllowlistPersistor; import org.hyperledger.besu.ethereum.permissioning.AllowlistPersistor.ALLOWLIST_TYPE; import org.hyperledger.besu.ethereum.permissioning.LocalPermissioningConfiguration; @@ -209,12 +210,15 @@ private LocalPermissioningConfiguration localConfigPermissioningConfiguration() localConfigNodesPermissioningFile = createTemporaryPermissionsFile(); } - List nodesAsListOfStrings = + final List nodesAsListOfStrings = localConfigPermittedNodes.stream().map(URI::toASCIIString).collect(Collectors.toList()); + final List nodesAsListOfEnodeUrl = + localConfigPermittedNodes.stream().map(EnodeURL::fromURI).collect(Collectors.toList()); + initPermissioningConfigurationFile( ALLOWLIST_TYPE.NODES, nodesAsListOfStrings, localConfigNodesPermissioningFile); - localPermissioningConfiguration.setNodeAllowlist(localConfigPermittedNodes); + localPermissioningConfiguration.setNodeAllowlist(nodesAsListOfEnodeUrl); localPermissioningConfiguration.setNodePermissioningConfigFilePath( localConfigNodesPermissioningFile.toAbsolutePath().toString()); } 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 03a3eaaf7c4..c19550918ec 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -1038,14 +1038,14 @@ void setBannedNodeIds(final List values) { @CommandLine.Option( hidden = true, - names = {"--dns-enabled"}, + names = {"--Xdns-enabled"}, description = "Enabled DNS support", arity = "1") private final Boolean dnsEnabled = Boolean.FALSE; @CommandLine.Option( hidden = true, - names = {"--dns-update-enabled"}, + names = {"--Xdns-update-enabled"}, description = "Allow to detect an IP update automatically", arity = "1") private final Boolean dnsUpdateEnabled = Boolean.FALSE; @@ -1333,6 +1333,7 @@ private BesuCommand validateOptions() { validateMiningParams(); validateNatParams(); validateNetStatsParams(); + validateDnsOptionsParams(); return this; } @@ -1391,6 +1392,15 @@ private void validateNetStatsParams() { } } + private void validateDnsOptionsParams() { + if (!dnsEnabled && dnsUpdateEnabled) { + throw new ParameterException( + this.commandLine, + "The `--Xdns-update-enabled` requires dns to be enabled. Either remove --Xdns-update-enabled" + + " or specify dns is enabled (--Xdns-enabled)"); + } + } + private void issueOptionWarnings() { // Check that P2P options are able to work CommandLineUtils.checkOptionDependencies( 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 7951003e599..bdf013b7778 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1347,6 +1347,33 @@ public void ethStatsContactOptionCannotBeUsedWithoutEthStatsServerProvided() { "The `--Xethstats-contact` requires ethstats server URL to be provided. Either remove --Xethstats-contact or provide an url (via --Xethstats=nodename:secret@host:port)"); } + @Test + public void dnsEnabledOptionIsParsedCorrectly() { + TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true"); + + assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isEqualTo(true); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isEqualTo(false); + } + + @Test + public void dnsUpdateEnabledOptionIsParsedCorrectly() { + TestBesuCommand besuCommand = + parseCommand("--Xdns-enabled", "true", "--Xdns-update-enabled", "true"); + + assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isEqualTo(true); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isEqualTo(true); + } + + @Test + public void dnsUpdateEnabledOptionCannotBeUsedWithoutDnsEnabled() { + parseCommand("--Xdns-update-enabled", "true"); + Mockito.verifyZeroInteractions(mockRunnerBuilder); + assertThat(commandOutput.toString()).isEmpty(); + assertThat(commandErrorOutput.toString()) + .contains( + "The `--Xdns-update-enabled` requires dns to be enabled. Either remove --Xdns-update-enabled or specify dns is enabled (--Xdns-enabled)"); + } + @Test public void helpShouldDisplayNatMethodInfo() { parseCommand("--help"); From 3910077a081d59b9d84c6f66c0c1480bc1c23ebf Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Fri, 21 Aug 2020 10:44:04 +0200 Subject: [PATCH 08/11] update CHANGELOG.md Signed-off-by: Karim TAAM --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 145962c284a..b6d2ad22a44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Additions and Improvements * The EvmTool now processes State Tests from the Ethereum Reference Tests. [\#1311](https://github.com/hyperledger/besu/pull/1311) +* Experimental dns support added via the `Xdns-enabled` and `Xdns-update-enabled` CLI commands. [\#1247](https://github.com/hyperledger/besu/pull/1247) ### Bug Fixes From b250ae8a9c124a64a61ed1be45e468c6383a6bbc Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Tue, 25 Aug 2020 14:24:55 +0200 Subject: [PATCH 09/11] fix review issues and add acceptance tests Signed-off-by: Karim TAAM --- .../tests/acceptance/dsl/node/BesuNode.java | 7 ++ .../dsl/node/ProcessBesuNodeRunner.java | 7 ++ .../configuration/BesuNodeConfiguration.java | 7 ++ .../BesuNodeConfigurationBuilder.java | 7 ++ .../node/configuration/BesuNodeFactory.java | 1 + .../PermissionedNodeBuilder.java | 18 +++-- .../acceptance/dsl/privacy/PrivacyNode.java | 1 + .../AllowlistPersistorAcceptanceTest.java | 11 +++ ...lowlistWithDnsPersistorAcceptanceTest.java | 79 +++++++++++++++++++ .../hyperledger/besu/cli/BesuCommandTest.java | 8 +- ...rmissioningConfigurationValidatorTest.java | 2 +- ...odeLocalConfigPermissioningController.java | 10 ++- ...PermissioningConfigurationBuilderTest.java | 46 ++++++++++- ...ioning_config_node_allowlist_with_dns.toml | 3 + 14 files changed, 193 insertions(+), 14 deletions(-) create mode 100644 acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistWithDnsPersistorAcceptanceTest.java create mode 100644 ethereum/permissioning/src/test/resources/permissioning_config_node_allowlist_with_dns.toml diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java index b58af0269c6..5ea854b3fa5 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/BesuNode.java @@ -109,6 +109,7 @@ public class BesuNode implements NodeConfiguration, RunnableNode, AutoCloseable private final List plugins = new ArrayList<>(); private final List extraCLIOptions; private final List staticNodes; + private boolean isDnsEnabled = false; private Optional exitCode = Optional.empty(); public BesuNode( @@ -132,6 +133,7 @@ public BesuNode( final List plugins, final List extraCLIOptions, final List staticNodes, + final boolean isDnsEnabled, final Optional privacyParameters, final List runCommand) throws IOException { @@ -174,6 +176,7 @@ public BesuNode( }); this.extraCLIOptions = extraCLIOptions; this.staticNodes = staticNodes; + this.isDnsEnabled = isDnsEnabled; privacyParameters.ifPresent(this::setPrivacyParameters); LOG.info("Created BesuNode {}", this.toString()); } @@ -609,6 +612,10 @@ public List getStaticNodes() { return staticNodes; } + public boolean isDnsEnabled() { + return isDnsEnabled; + } + public boolean hasStaticNodes() { return staticNodes != null && !staticNodes.isEmpty(); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java index da1c78b0430..b544ed666a2 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/ProcessBesuNodeRunner.java @@ -138,6 +138,13 @@ public void startNode(final BesuNode node) { createStaticNodes(node); } + if (node.isDnsEnabled()) { + params.add("--Xdns-enabled"); + params.add("true"); + params.add("--Xdns-update-enabled"); + params.add("true"); + } + if (node.isJsonRpcEnabled()) { params.add("--rpc-http-enabled"); params.add("--rpc-http-host"); diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java index 7170896f626..10646daddce 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfiguration.java @@ -49,6 +49,7 @@ public class BesuNodeConfiguration { private final List plugins; private final List extraCLIOptions; private final List staticNodes; + private final boolean isDnsEnabled; private final Optional privacyParameters; private final List runCommand; @@ -73,6 +74,7 @@ public class BesuNodeConfiguration { final List plugins, final List extraCLIOptions, final List staticNodes, + final boolean isDnsEnabled, final Optional privacyParameters, final List runCommand) { this.name = name; @@ -95,6 +97,7 @@ public class BesuNodeConfiguration { this.plugins = plugins; this.extraCLIOptions = extraCLIOptions; this.staticNodes = staticNodes; + this.isDnsEnabled = isDnsEnabled; this.privacyParameters = privacyParameters; this.runCommand = runCommand; } @@ -179,6 +182,10 @@ public List getStaticNodes() { return staticNodes; } + public boolean isDnsEnabled() { + return isDnsEnabled; + } + public Optional getPrivacyParameters() { return privacyParameters; } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java index b6951bdf047..86c780cd9de 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeConfigurationBuilder.java @@ -60,6 +60,7 @@ public class BesuNodeConfigurationBuilder { private final List plugins = new ArrayList<>(); private final List extraCLIOptions = new ArrayList<>(); private List staticNodes = new ArrayList<>(); + private boolean isDnsEnabled = false; private Optional privacyParameters = Optional.empty(); private List runCommand = new ArrayList<>(); @@ -268,6 +269,11 @@ public BesuNodeConfigurationBuilder staticNodes(final List staticNodes) return this; } + public BesuNodeConfigurationBuilder dnsEnabled(final boolean isDnsEnabled) { + this.isDnsEnabled = isDnsEnabled; + return this; + } + public BesuNodeConfigurationBuilder privacyParameters(final PrivacyParameters privacyParameters) { this.privacyParameters = Optional.ofNullable(privacyParameters); return this; @@ -300,6 +306,7 @@ public BesuNodeConfiguration build() { plugins, extraCLIOptions, staticNodes, + isDnsEnabled, privacyParameters, runCommand); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java index 4f60c6acf88..2eafb47b94f 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/BesuNodeFactory.java @@ -68,6 +68,7 @@ public BesuNode create(final BesuNodeConfiguration config) throws IOException { config.getPlugins(), config.getExtraCLIOptions(), config.getStaticNodes(), + config.isDnsEnabled(), config.getPrivacyParameters(), config.getRunCommand()); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java index 1456d894f7b..7aed3975906 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/node/configuration/permissioning/PermissionedNodeBuilder.java @@ -72,6 +72,7 @@ public class PermissionedNodeBuilder { private String accountPermissioningSmartContractAddress = null; private List staticNodes = new ArrayList<>(); + private boolean isDnsEnabled = false; private boolean mining = true; public PermissionedNodeBuilder name(final String name) { @@ -140,6 +141,11 @@ public PermissionedNodeBuilder staticNodes(final List staticNodes) { return this; } + public PermissionedNodeBuilder dnsEnabled(final boolean isDnsEnabled) { + this.isDnsEnabled = isDnsEnabled; + return this; + } + public PermissionedNodeBuilder disableMining() { this.mining = false; return this; @@ -189,6 +195,8 @@ public BesuNode build() { builder.staticNodes(staticNodes); } + builder.dnsEnabled(isDnsEnabled); + if (genesisFile != null) { builder.genesisConfigProvider((a) -> Optional.of(genesisFile)); builder.devMode(false); @@ -210,15 +218,15 @@ private LocalPermissioningConfiguration localConfigPermissioningConfiguration() localConfigNodesPermissioningFile = createTemporaryPermissionsFile(); } - final List nodesAsListOfStrings = - localConfigPermittedNodes.stream().map(URI::toASCIIString).collect(Collectors.toList()); - final List nodesAsListOfEnodeUrl = + final List nodeAllowList = localConfigPermittedNodes.stream().map(EnodeURL::fromURI).collect(Collectors.toList()); initPermissioningConfigurationFile( - ALLOWLIST_TYPE.NODES, nodesAsListOfStrings, localConfigNodesPermissioningFile); + ALLOWLIST_TYPE.NODES, + nodeAllowList.stream().map(EnodeURL::toString).collect(Collectors.toList()), + localConfigNodesPermissioningFile); - localPermissioningConfiguration.setNodeAllowlist(nodesAsListOfEnodeUrl); + localPermissioningConfiguration.setNodeAllowlist(nodeAllowList); localPermissioningConfiguration.setNodePermissioningConfigFilePath( localConfigNodesPermissioningFile.toAbsolutePath().toString()); } diff --git a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java index 17194c786d9..2cbe57ff1d3 100644 --- a/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java +++ b/acceptance-tests/dsl/src/main/java/org/hyperledger/besu/tests/acceptance/dsl/privacy/PrivacyNode.java @@ -103,6 +103,7 @@ public PrivacyNode(final PrivacyNodeConfiguration privacyConfiguration, final Ve besuConfig.getPlugins(), besuConfig.getExtraCLIOptions(), Collections.emptyList(), + besuConfig.isDnsEnabled(), besuConfig.getPrivacyParameters(), List.of()); } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistPersistorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistPersistorAcceptanceTest.java index 9c97eb2a591..e9c1ff12c9a 100644 --- a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistPersistorAcceptanceTest.java +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistPersistorAcceptanceTest.java @@ -25,8 +25,10 @@ import java.util.ArrayList; import java.util.Collections; +import org.assertj.core.api.Assertions; import org.junit.Before; import org.junit.Test; +import org.web3j.protocol.exceptions.ClientConnectionException; public class AllowlistPersistorAcceptanceTest extends AcceptanceTestBase { @@ -36,6 +38,8 @@ public class AllowlistPersistorAcceptanceTest extends AcceptanceTestBase { "enode://5f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.10:4567"; private static final String ENODE_THREE = "enode://4f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.10:4567"; + private static final String ENODE_FOURTH = + "enode://4f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@localhost:4567"; private Node node; private Account senderA; @@ -99,4 +103,11 @@ public void manipulatedNodesWhitelistIsPersisted() { perm.expectPermissioningAllowlistFileKeyValue( ALLOWLIST_TYPE.NODES, tempFile, ENODE_TWO, ENODE_ONE, ENODE_THREE)); } + + @Test + public void manipulatedNodesWhitelistWithHostnameShouldNotWorkWhenDnsDisabled() { + Assertions.assertThatThrownBy(() -> node.verify(perm.addNodesToAllowlist(ENODE_FOURTH))) + .isInstanceOf(ClientConnectionException.class) + .hasMessageContaining("Request contains an invalid node"); + } } diff --git a/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistWithDnsPersistorAcceptanceTest.java b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistWithDnsPersistorAcceptanceTest.java new file mode 100644 index 00000000000..dc51fc5d0f4 --- /dev/null +++ b/acceptance-tests/tests/src/test/java/org/hyperledger/besu/tests/acceptance/permissioning/AllowlistWithDnsPersistorAcceptanceTest.java @@ -0,0 +1,79 @@ +/* + * Copyright ConsenSys AG. + * + * 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.tests.acceptance.permissioning; + +import static org.hyperledger.besu.ethereum.permissioning.AllowlistPersistor.ALLOWLIST_TYPE; + +import org.hyperledger.besu.tests.acceptance.dsl.AcceptanceTestBase; +import org.hyperledger.besu.tests.acceptance.dsl.account.Account; +import org.hyperledger.besu.tests.acceptance.dsl.node.Node; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Collections; + +import org.junit.Before; +import org.junit.Test; + +public class AllowlistWithDnsPersistorAcceptanceTest extends AcceptanceTestBase { + + private static final String ENODE_ONE = + "enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@localhost:4567"; + private static final String ENODE_TWO = + "enode://5f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.10:4567"; + private static final String ENODE_THREE = + "enode://4f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@192.168.0.11:4567"; + + private Node node; + private Account senderA; + private Path tempFile; + + @Before + public void setUp() throws Exception { + senderA = accounts.getPrimaryBenefactor(); + tempFile = Files.createTempFile("test", "test"); + + this.node = + permissionedNodeBuilder + .name("node") + .nodesConfigFile(tempFile) + .nodesPermittedInConfig(new ArrayList<>()) + .accountsConfigFile(tempFile) + .accountsPermittedInConfig(Collections.singletonList(senderA.getAddress())) + .dnsEnabled(true) + .build(); + + cluster.start(this.node); + } + + @Test + public void manipulatedNodesWhitelistWithHostnameShouldWorkWhenDnsEnabled() { + + node.verify(perm.addNodesToAllowlist(ENODE_ONE, ENODE_TWO)); + node.verify( + perm.expectPermissioningAllowlistFileKeyValue( + ALLOWLIST_TYPE.NODES, tempFile, ENODE_ONE, ENODE_TWO)); + + node.verify(perm.removeNodesFromAllowlist(ENODE_ONE)); + node.verify( + perm.expectPermissioningAllowlistFileKeyValue(ALLOWLIST_TYPE.NODES, tempFile, ENODE_TWO)); + + node.verify(perm.addNodesToAllowlist(ENODE_ONE, ENODE_THREE)); + node.verify( + perm.expectPermissioningAllowlistFileKeyValue( + ALLOWLIST_TYPE.NODES, tempFile, ENODE_TWO, ENODE_ONE, ENODE_THREE)); + } +} 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 bdf013b7778..382be475f60 100644 --- a/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java +++ b/besu/src/test/java/org/hyperledger/besu/cli/BesuCommandTest.java @@ -1351,8 +1351,8 @@ public void ethStatsContactOptionCannotBeUsedWithoutEthStatsServerProvided() { public void dnsEnabledOptionIsParsedCorrectly() { TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true"); - assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isEqualTo(true); - assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isEqualTo(false); + assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isTrue(); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isFalse(); } @Test @@ -1360,8 +1360,8 @@ public void dnsUpdateEnabledOptionIsParsedCorrectly() { TestBesuCommand besuCommand = parseCommand("--Xdns-enabled", "true", "--Xdns-update-enabled", "true"); - assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isEqualTo(true); - assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isEqualTo(true); + assertThat(besuCommand.getEnodeDnsConfiguration().dnsEnabled()).isTrue(); + assertThat(besuCommand.getEnodeDnsConfiguration().updateEnabled()).isTrue(); } @Test diff --git a/besu/src/test/java/org/hyperledger/besu/util/LocalPermissioningConfigurationValidatorTest.java b/besu/src/test/java/org/hyperledger/besu/util/LocalPermissioningConfigurationValidatorTest.java index 03e84ea279c..e46e10ac3e7 100644 --- a/besu/src/test/java/org/hyperledger/besu/util/LocalPermissioningConfigurationValidatorTest.java +++ b/besu/src/test/java/org/hyperledger/besu/util/LocalPermissioningConfigurationValidatorTest.java @@ -138,7 +138,7 @@ public void nodeAllowlistCheckShouldIgnoreDiscoveryPortParam() throws Exception } @Test - public void nodeAllowlistCheckShouldWorkWithHostnameIfDndEnabled() throws Exception { + public void nodeAllowlistCheckShouldWorkWithHostnameIfDnsEnabled() throws Exception { final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_VALID_HOSTNAME); final Path toml = Files.createTempFile("toml", ""); toml.toFile().deleteOnExit(); diff --git a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java index 632822810de..98b09629609 100644 --- a/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java +++ b/ethereum/permissioning/src/main/java/org/hyperledger/besu/ethereum/permissioning/NodeLocalConfigPermissioningController.java @@ -111,7 +111,9 @@ public NodesAllowlistResult addNodes(final List enodeURLs) { return inputValidationResult; } final List peers = - enodeURLs.stream().map(EnodeURL::fromString).collect(Collectors.toList()); + enodeURLs.stream() + .map(url -> EnodeURL.fromString(url, configuration.getEnodeDnsConfiguration())) + .collect(Collectors.toList()); for (EnodeURL peer : peers) { if (nodesAllowlist.contains(peer)) { @@ -143,7 +145,9 @@ public NodesAllowlistResult removeNodes(final List enodeURLs) { return inputValidationResult; } final List peers = - enodeURLs.stream().map(EnodeURL::fromString).collect(Collectors.toList()); + enodeURLs.stream() + .map(url -> EnodeURL.fromString(url, configuration.getEnodeDnsConfiguration())) + .collect(Collectors.toList()); boolean anyBootnode = peers.stream().anyMatch(fixedNodes::contains); if (anyBootnode) { @@ -227,7 +231,7 @@ private Collection peerToEnodeURI(final Collection peers) { } public boolean isPermitted(final String enodeURL) { - return isPermitted(EnodeURL.fromString(enodeURL)); + return isPermitted(EnodeURL.fromString(enodeURL, configuration.getEnodeDnsConfiguration())); } public boolean isPermitted(final EnodeURL node) { diff --git a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java index 206dfc2597d..21dc7785f9e 100644 --- a/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java +++ b/ethereum/permissioning/src/test/java/org/hyperledger/besu/ethereum/permissioning/LocalPermissioningConfigurationBuilderTest.java @@ -16,10 +16,12 @@ import static java.nio.charset.StandardCharsets.UTF_8; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.assertj.core.api.Assertions.catchThrowable; import static org.hyperledger.besu.ethereum.p2p.peers.EnodeDnsConfiguration.dnsDisabled; import org.hyperledger.besu.ethereum.p2p.peers.EnodeURL; +import org.hyperledger.besu.ethereum.p2p.peers.ImmutableEnodeDnsConfiguration; import java.io.IOException; import java.net.URL; @@ -54,7 +56,8 @@ public class LocalPermissioningConfigurationBuilderTest { "/permissioning_config_unrecognized_key.toml"; private static final String PERMISSIONING_CONFIG_NODE_ALLOWLIST_ONLY_MULTILINE = "/permissioning_config_node_allowlist_only_multiline.toml"; - + private static final String PERMISSIONING_CONFIG_NODE_ALLOWLIST_WITH_DNS = + "/permissioning_config_node_allowlist_with_dns.toml"; private final String VALID_NODE_ID = "6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0"; @@ -115,6 +118,47 @@ public void permissioningConfigWithOnlyNodeAllowlistSet() throws Exception { .containsExactly(EnodeURL.fromString(uri)); } + @Test + public void permissioningConfigWithNodeAllowlistSetWithDnsEnabled() throws Exception { + final String uri = "enode://" + VALID_NODE_ID + "@127.0.0.1:4567"; + + final URL configFile = + this.getClass().getResource(PERMISSIONING_CONFIG_NODE_ALLOWLIST_WITH_DNS); + final Path toml = createTempFile("toml", Resources.toByteArray(configFile)); + + LocalPermissioningConfiguration permissioningConfiguration = + PermissioningConfigurationBuilder.permissioningConfiguration( + true, + ImmutableEnodeDnsConfiguration.builder().dnsEnabled(true).updateEnabled(false).build(), + toml.toAbsolutePath().toString(), + false, + toml.toAbsolutePath().toString()); + + assertThat(permissioningConfiguration.isAccountAllowlistEnabled()).isFalse(); + assertThat(permissioningConfiguration.isNodeAllowlistEnabled()).isTrue(); + assertThat(permissioningConfiguration.getNodeAllowlist()) + .containsExactly(EnodeURL.fromString(uri)); + } + + @Test + public void permissioningConfigWithNodeAllowlistSetWithDnsDisabled() throws Exception { + + final URL configFile = + this.getClass().getResource(PERMISSIONING_CONFIG_NODE_ALLOWLIST_WITH_DNS); + final Path toml = createTempFile("toml", Resources.toByteArray(configFile)); + + assertThatThrownBy( + () -> + PermissioningConfigurationBuilder.permissioningConfiguration( + true, + dnsDisabled(), + toml.toAbsolutePath().toString(), + false, + toml.toAbsolutePath().toString())) + .hasMessageContaining("Invalid enode URL syntax") + .isInstanceOf(IllegalArgumentException.class); + } + @Test public void permissioningConfigWithOnlyAccountAllowlistSet() throws Exception { final URL configFile = this.getClass().getResource(PERMISSIONING_CONFIG_ACCOUNT_ALLOWLIST_ONLY); diff --git a/ethereum/permissioning/src/test/resources/permissioning_config_node_allowlist_with_dns.toml b/ethereum/permissioning/src/test/resources/permissioning_config_node_allowlist_with_dns.toml new file mode 100644 index 00000000000..a76886f9213 --- /dev/null +++ b/ethereum/permissioning/src/test/resources/permissioning_config_node_allowlist_with_dns.toml @@ -0,0 +1,3 @@ +# Permissioning TOML file (node allowlist with dns only) + +nodes-allowlist=["enode://6f8a80d14311c39f35f516fa664deaaaa13e85b2f7493f37f6144d86991ec012937307647bd3b9a82abe2974e1407241d54947bbb39763a4cac9f77166ad92a0@localhost:4567"] From abf0db52b2b97f236d6570a989c59023d8c2aeaa Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Tue, 25 Aug 2020 17:46:05 +0200 Subject: [PATCH 10/11] fix review issues Signed-off-by: Karim TAAM --- .../java/org/hyperledger/besu/cli/BesuCommand.java | 8 ++++---- .../hyperledger/besu/ethereum/p2p/peers/EnodeURL.java | 11 +++++++++++ 2 files changed, 15 insertions(+), 4 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 c19550918ec..b629b26c5a5 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -312,7 +312,7 @@ public class BesuCommand implements DefaultCommandValues, Runnable { + "Default is a predefined list.", split = ",", arity = "0..*") - private final List bootnodes = null; + private final List bootNodes = null; @Option( names = {"--max-peers"}, @@ -2187,7 +2187,7 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { } } - if (bootnodes == null) { + if (bootNodes == null) { // We default to an empty bootnodes list if the option is not provided on CLI // because // mainnet bootnodes won't work as the default value for a custom genesis, @@ -2202,11 +2202,11 @@ private EthNetworkConfig updateNetworkConfig(final NetworkName network) { builder.setNetworkId(networkId); } - if (bootnodes != null) { + if (bootNodes != null) { try { final List listBootNodes = - bootnodes.stream() + bootNodes.stream() .filter(value -> !value.isEmpty()) .map(url -> EnodeURL.fromString(url, getEnodeDnsConfiguration())) .collect(Collectors.toList()); diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 6769f50e05b..65a0712c45c 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -210,6 +210,17 @@ public String getIpAsString() { return getIp().getHostAddress(); } + /** + * Get IP of the EnodeURL + * + *

If "dns" and "dns-update" are enabled -> DNS lookup every time to have the IP up to date and + * not to rely on an invalid cache + * + *

If the "dns" is enabled but "dns-update" is disabled -> IP is retrieved only one time and + * the hostname is no longer stored (maybeHostname is empty). + * + * @return ip + */ public InetAddress getIp() { this.ip = maybeHostname From d769a4c20a530c91996e3e807edba97d169da3a9 Mon Sep 17 00:00:00 2001 From: Karim TAAM Date: Tue, 25 Aug 2020 18:55:54 +0200 Subject: [PATCH 11/11] fix javadoc Signed-off-by: Karim TAAM --- .../org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java index 65a0712c45c..0d4e592b151 100644 --- a/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java +++ b/ethereum/p2p/src/main/java/org/hyperledger/besu/ethereum/p2p/peers/EnodeURL.java @@ -213,10 +213,10 @@ public String getIpAsString() { /** * Get IP of the EnodeURL * - *

If "dns" and "dns-update" are enabled -> DNS lookup every time to have the IP up to date and - * not to rely on an invalid cache + *

If "dns" and "dns-update" are enabled -> DNS lookup every time to have the IP up to date + * and not to rely on an invalid cache * - *

If the "dns" is enabled but "dns-update" is disabled -> IP is retrieved only one time and + *

If the "dns" is enabled but "dns-update" is disabled -> IP is retrieved only one time and * the hostname is no longer stored (maybeHostname is empty). * * @return ip