diff --git a/build.gradle b/build.gradle index 43e70f1b9..a2f81459c 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id 'com.github.ben-manes.versions' version '0.51.0' id 'com.github.hierynomus.license' version '0.16.1' id 'io.spring.dependency-management' version '1.1.5' - id 'net.ltgt.errorprone' version '3.1.0' + id 'net.ltgt.errorprone' version '4.0.1' id 'org.ajoberstar.grgit' version '5.2.2' } diff --git a/gradle/versions.gradle b/gradle/versions.gradle index 9c1c6ede7..ab2db2b6a 100644 --- a/gradle/versions.gradle +++ b/gradle/versions.gradle @@ -1,6 +1,6 @@ dependencyManagement { dependencies { - dependencySet(group: 'com.google.errorprone', version: '2.27.1') { + dependencySet(group: 'com.google.errorprone', version: '2.28.0') { entry 'error_prone_annotation' entry 'error_prone_check_api' entry 'error_prone_core' @@ -9,10 +9,10 @@ dependencyManagement { dependency 'tech.pegasys.tools.epchecks:errorprone-checks:1.1.1' - dependency 'com.google.guava:guava:33.2.0-jre' + dependency 'com.google.guava:guava:33.2.1-jre' - dependency "io.netty:netty-all:4.1.110.Final" - dependency 'io.projectreactor:reactor-core:3.6.6' + dependency "io.netty:netty-all:4.1.111.Final" + dependency 'io.projectreactor:reactor-core:3.6.7' dependencySet(group: 'org.apache.logging.log4j', version: '2.23.1') { entry 'log4j-api' @@ -22,7 +22,7 @@ dependencyManagement { dependency 'org.bouncycastle:bcprov-jdk18on:1.78.1' - dependency 'org.assertj:assertj-core:3.25.3' + dependency 'org.assertj:assertj-core:3.26.0' dependency 'org.mockito:mockito-core:5.12.0' dependencySet(group: 'org.apache.tuweni', version: '2.3.1') { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b82aa23a4..a4413138c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 1aa94a426..b740cf133 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. diff --git a/src/main/java/org/ethereum/beacon/discovery/DiscoverySystemBuilder.java b/src/main/java/org/ethereum/beacon/discovery/DiscoverySystemBuilder.java index d95a21dbb..6f76f0e5b 100644 --- a/src/main/java/org/ethereum/beacon/discovery/DiscoverySystemBuilder.java +++ b/src/main/java/org/ethereum/beacon/discovery/DiscoverySystemBuilder.java @@ -13,6 +13,7 @@ import com.google.common.base.Preconditions; import com.google.common.util.concurrent.ThreadFactoryBuilder; import io.netty.channel.socket.InternetProtocolFamily; +import java.net.Inet6Address; import java.net.InetSocketAddress; import java.time.Clock; import java.time.Duration; @@ -83,9 +84,6 @@ public DiscoverySystemBuilder listen(final String listenAddress, final int liste } public DiscoverySystemBuilder listen(final InetSocketAddress... listenAddresses) { - Preconditions.checkArgument( - listenAddresses.length == 1 || listenAddresses.length == 2, - "Can define only 1 or 2 listen addresses - IPv4/IPv6 or IPv4 and IPv6"); validateListenAddresses(Arrays.stream(listenAddresses).collect(Collectors.toList())); this.listenAddresses = Optional.of(Arrays.asList(listenAddresses)); return this; @@ -161,13 +159,11 @@ public DiscoverySystemBuilder discoveryServer(final NettyDiscoveryServer discove } public DiscoverySystemBuilder discoveryServers(final NettyDiscoveryServer... discoveryServers) { - Preconditions.checkArgument( - discoveryServers.length == 1 || discoveryServers.length == 2, - "Can define only 1 or 2 discovery servers - IPv4/IPv6 or IPv4 and IPv6"); - validateListenAddresses( + final List listenAddresses = Arrays.stream(discoveryServers) .map(NettyDiscoveryServer::getListenAddress) - .collect(Collectors.toList())); + .collect(Collectors.toList()); + validateListenAddresses(listenAddresses); this.discoveryServers = Arrays.asList(discoveryServers); return this; } @@ -184,6 +180,9 @@ public DiscoverySystemBuilder addressAccessPolicy(final AddressAccessPolicy addr } private void validateListenAddresses(final List listenAddresses) { + Preconditions.checkArgument( + listenAddresses.size() == 1 || listenAddresses.size() == 2, + "Can define only 1 or 2 listen addresses - IPv4/IPv6 or IPv4 and IPv6"); if (listenAddresses.size() == 2) { final Set ipFamilies = listenAddresses.stream() @@ -202,12 +201,15 @@ private void createDefaults() { requireNonNullElseGet( newAddressHandler, () -> - (oldRecord, newAddress) -> - Optional.of( - oldRecord.withNewAddress( - newAddress, - oldRecord.getTcpAddress().map(InetSocketAddress::getPort), - secretKey))); + (oldRecord, newAddress) -> { + final Optional oldTcpAddress = + newAddress.getAddress() instanceof Inet6Address + ? oldRecord.getTcp6Address() + : oldRecord.getTcpAddress(); + return Optional.of( + oldRecord.withNewAddress( + newAddress, oldTcpAddress.map(InetSocketAddress::getPort), secretKey)); + }); schedulers = requireNonNullElseGet(schedulers, Schedulers::createDefault); final List serverListenAddresses = listenAddresses.orElseGet( diff --git a/src/main/java/org/ethereum/beacon/discovery/message/handler/DefaultExternalAddressSelector.java b/src/main/java/org/ethereum/beacon/discovery/message/handler/DefaultExternalAddressSelector.java index ca511dfe6..64624d21e 100644 --- a/src/main/java/org/ethereum/beacon/discovery/message/handler/DefaultExternalAddressSelector.java +++ b/src/main/java/org/ethereum/beacon/discovery/message/handler/DefaultExternalAddressSelector.java @@ -7,6 +7,7 @@ import static com.google.common.base.Preconditions.checkState; import com.google.common.annotations.VisibleForTesting; +import java.net.Inet6Address; import java.net.InetSocketAddress; import java.time.Duration; import java.time.Instant; @@ -16,6 +17,7 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; +import org.ethereum.beacon.discovery.schema.NodeRecord; import org.ethereum.beacon.discovery.storage.LocalNodeRecordStore; public class DefaultExternalAddressSelector implements ExternalAddressSelector { @@ -58,8 +60,11 @@ public void onExternalAddressReport( selectExternalAddress() .ifPresent( selectedAddress -> { + final NodeRecord homeNodeRecord = localNodeRecordStore.getLocalNodeRecord(); final Optional currentAddress = - localNodeRecordStore.getLocalNodeRecord().getUdpAddress(); + selectedAddress.getAddress() instanceof Inet6Address + ? homeNodeRecord.getUdp6Address() + : homeNodeRecord.getUdpAddress(); if (currentAddress.map(current -> !current.equals(selectedAddress)).orElse(true)) { localNodeRecordStore.onSocketAddressChanged(selectedAddress); } diff --git a/src/main/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4Interpreter.java b/src/main/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4Interpreter.java index 7e50d5c99..aa9831d8c 100644 --- a/src/main/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4Interpreter.java +++ b/src/main/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4Interpreter.java @@ -11,12 +11,14 @@ import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.common.collect.ImmutableSet; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -29,6 +31,7 @@ import org.ethereum.beacon.discovery.util.Utils; public class IdentitySchemaV4Interpreter implements IdentitySchemaInterpreter { + private static final Logger LOG = LogManager.getLogger(); private final LoadingCache nodeIdCache = @@ -36,8 +39,11 @@ public class IdentitySchemaV4Interpreter implements IdentitySchemaInterpreter { .maximumSize(4000) .build(CacheLoader.from(IdentitySchemaV4Interpreter::calculateNodeId)); - private static final ImmutableSet ADDRESS_FIELD_NAMES = - ImmutableSet.of(EnrField.IP_V4, EnrField.IP_V6, EnrField.UDP, EnrField.UDP_V6); + private static final ImmutableSet ADDRESS_IP_V4_FIELD_NAMES = + ImmutableSet.of(EnrField.IP_V4, EnrField.UDP); + + private static final ImmutableSet ADDRESS_IP_V6_FIELD_NAMES = + ImmutableSet.of(EnrField.IP_V6, EnrField.UDP_V6); @Override public boolean isValid(final NodeRecord nodeRecord) { @@ -115,8 +121,16 @@ public NodeRecord createWithNewAddress( final Optional newTcpPort, final SecretKey secretKey) { final List fields = - getAllFieldsThatMatch(nodeRecord, field -> !ADDRESS_FIELD_NAMES.contains(field.getName())); - + getAllFieldsThatMatch( + nodeRecord, + field -> { + // don't match the address fields that we are going to change + final Set addressFieldsToChange = + newAddress.getAddress() instanceof Inet6Address + ? ADDRESS_IP_V6_FIELD_NAMES + : ADDRESS_IP_V4_FIELD_NAMES; + return !addressFieldsToChange.contains(field.getName()); + }); NodeRecordBuilder.addFieldsForAddress( fields, newAddress.getAddress(), newAddress.getPort(), newTcpPort); final NodeRecord newRecord = NodeRecord.fromValues(this, nodeRecord.getSeq().add(1), fields); diff --git a/src/test/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4InterpreterTest.java b/src/test/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4InterpreterTest.java index 8d4a5f28d..6a3343b49 100644 --- a/src/test/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4InterpreterTest.java +++ b/src/test/java/org/ethereum/beacon/discovery/schema/IdentitySchemaV4InterpreterTest.java @@ -218,7 +218,7 @@ public void shouldUpdateIpV6AddressAndPort() throws Exception { } @Test - public void shouldSwitchFromIpV4ToIpV6() throws Exception { + public void shouldAddIpV6toAlreadyExistingIpV4() throws Exception { final NodeRecord initialRecord = createNodeRecord( new EnrField(EnrField.IP_V4, Bytes.wrap(new byte[4])), @@ -229,28 +229,33 @@ public void shouldSwitchFromIpV4ToIpV6() throws Exception { interpreter.createWithNewAddress( initialRecord, newSocketAddress, Optional.of(5667), SECRET_KEY); - assertThat(newRecord.getUdpAddress()).isEmpty(); + assertThat(newRecord.getUdpAddress()).isEqualTo(initialRecord.getUdpAddress()); assertThat(newRecord.getUdp6Address()).contains(newSocketAddress); - assertThat(newRecord.getTcpAddress()).isEmpty(); + assertThat(newRecord.getTcpAddress()).isEqualTo(initialRecord.getTcpAddress()); assertThat(newRecord.getTcp6Address()) .contains(new InetSocketAddress(newSocketAddress.getAddress(), 5667)); - assertThat(newRecord.get(EnrField.IP_V4)).isNull(); + assertThat(newRecord.get(EnrField.IP_V4)).isEqualTo(initialRecord.get(EnrField.IP_V4)); assertThat(newRecord.get(EnrField.IP_V6)).isEqualTo(IPV6_LOCALHOST); } @Test - public void shouldSwitchFromIpV6ToIpV4() { + public void shouldAddIpV4ToAlreadyExistingIpV6() { final NodeRecord initialRecord = createNodeRecord( - new EnrField(EnrField.IP_V6, IPV6_LOCALHOST), new EnrField(EnrField.UDP_V6, 3030)); + new EnrField(EnrField.IP_V6, IPV6_LOCALHOST), + new EnrField(EnrField.UDP_V6, 3030), + new EnrField(EnrField.TCP_V6, 5666)); final InetSocketAddress newSocketAddress = new InetSocketAddress("127.0.0.1", 40404); final NodeRecord newRecord = interpreter.createWithNewAddress( initialRecord, newSocketAddress, Optional.of(5667), SECRET_KEY); + assertThat(newRecord.getUdp6Address()).isEqualTo(initialRecord.getUdp6Address()); assertThat(newRecord.getUdpAddress()).contains(newSocketAddress); + assertThat(newRecord.getTcp6Address()).isEqualTo(initialRecord.getTcp6Address()); assertThat(newRecord.getTcpAddress()) .contains(new InetSocketAddress(newSocketAddress.getAddress(), 5667)); + assertThat(newRecord.get(EnrField.IP_V6)).isEqualTo(initialRecord.get(EnrField.IP_V6)); assertThat(newRecord.get(EnrField.IP_V4)).isEqualTo(Bytes.wrap(new byte[] {127, 0, 0, 1})); }