From d0058505d4eebef6c8f195a4551402f1bd6cb917 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Fri, 22 Aug 2025 14:37:50 +0800 Subject: [PATCH 01/20] feat(dependencies): update grpc avoid CVE-2025-55163,MadeYouReset 1. bump grpc from 1.60.0 to 1.75.0 2. bump protobuf from 3.25.5 to 3.25.8 --- README.md | 6 +- build.gradle | 6 +- gradle/verification-metadata.xml | 441 ++++++++++++++----------------- 3 files changed, 208 insertions(+), 245 deletions(-) diff --git a/README.md b/README.md index 1957285..38749cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ libp2p is a p2p network SDK implemented in java language. The functional modules * support compressed message transmission among nodes # Note -Starting from version 2.2.6, `libp2p` has removed the logback component and adopted the logger facade. If logging is required, you need to introduce a logging framework manually. +Starting from version 2.2.7, `libp2p` has removed the logback component and adopted the logger facade. If logging is required, you need to introduce a logging framework manually. Here’s how to include logback in your project using Gradle: 1. Add the following dependencies to your build.gradle file @@ -69,7 +69,7 @@ repositories { Then add the required packages as dependencies. Please add dependencies locally. ```bash dependencies { - implementation group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.6' + implementation group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7' } ``` Or if you are using the jar files as your dependencies: @@ -92,7 +92,7 @@ dependencies { io.github.tronprotocol libp2p - 2.2.6 + 2.2.7 ``` diff --git a/build.gradle b/build.gradle index f33867e..258b9d3 100644 --- a/build.gradle +++ b/build.gradle @@ -1,5 +1,5 @@ group 'io.github.tronprotocol' -version '2.2.6' +version '2.2.7' buildscript { repositories { @@ -17,8 +17,8 @@ apply plugin: 'com.google.protobuf' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'application' -def protobufVersion = "3.25.5" -def grpcVersion = "1.60.0" +def protobufVersion = "3.25.8" +def grpcVersion = "1.75.0" mainClassName = 'org.tron.p2p.example.StartApp' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index f56282f..c789e5a 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -122,12 +122,12 @@ - - - + + + - - + + @@ -143,9 +143,9 @@ - - - + + + @@ -163,20 +163,12 @@ - - - + + + - - - - - - - - - - + + @@ -184,14 +176,9 @@ - - - - - - - - + + + @@ -210,12 +197,12 @@ - - - + + + - - + + @@ -226,21 +213,35 @@ + + + + + + + + + + + + + + - - - - - + + + + + @@ -249,14 +250,6 @@ - - - - - - - - @@ -265,9 +258,17 @@ - - - + + + + + + + + + + + @@ -278,49 +279,48 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - - - + + + - - + + - - + + - - + + - + - + - - + + @@ -409,14 +409,6 @@ - - - - - - - - @@ -441,169 +433,171 @@ - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - - + + + - - + + - - + + - - + + - + - + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + - - - + + + - - + + + + + @@ -699,11 +693,6 @@ - - - - - @@ -733,11 +722,6 @@ - - - - - @@ -844,14 +828,6 @@ - - - - - - - - @@ -860,40 +836,33 @@ - - - + + + - - + + - - - - - - - + + - - - + + + - - - - + + - - - + + + - - - + + + @@ -916,9 +885,6 @@ - - - @@ -967,12 +933,9 @@ - - - - - - + + + From 495483bf83543bbb3c7190b4ff01610df21ba160 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Fri, 22 Aug 2025 15:26:53 +0800 Subject: [PATCH 02/20] feat(gradle): upgrade the maven publishing --- build.gradle | 27 +++++++++++++++++++++++++++ gradle/verification-metadata.xml | 3 +++ jitpack.yml | 2 ++ 3 files changed, 32 insertions(+) create mode 100644 jitpack.yml diff --git a/build.gradle b/build.gradle index 258b9d3..e066e67 100644 --- a/build.gradle +++ b/build.gradle @@ -16,6 +16,7 @@ apply plugin: 'java' apply plugin: 'com.google.protobuf' apply plugin: 'com.github.johnrengelman.shadow' apply plugin: 'application' +apply plugin: 'maven-publish' def protobufVersion = "3.25.8" def grpcVersion = "1.75.0" @@ -176,3 +177,29 @@ artifacts { } processResources.dependsOn(generateProto) // explicit_dependency + +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + artifact sourcesJar + artifact javadocJar + pom { + name = 'libp2p' + description = 'libp2p is a p2p network SDK implemented in java language.' + url = 'https://github.com/tronprotocol/libp2p' + licenses { + license { + name = 'The Apache Software License, Version 2.0' + url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' + } + } + scm { + url = 'https://github.com/tronprotocol/libp2p' + connection = 'scm:git:git://github.com/tronprotocol/libp2p.git' + developerConnection = 'scm:git:ssh://git@github.com:tronprotocol/libp2p.git' + } + } + } + } +} \ No newline at end of file diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index c789e5a..682e0f0 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -934,6 +934,9 @@ + + + diff --git a/jitpack.yml b/jitpack.yml new file mode 100644 index 0000000..4065d43 --- /dev/null +++ b/jitpack.yml @@ -0,0 +1,2 @@ +install: + - ./gradlew clean -xtest -xlint -xcheck -PbinaryRelease=false publishToMavenLocal From 371b655f11277cbd5240ea9b8ffed5ccbd19b112 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Fri, 22 Aug 2025 15:36:04 +0800 Subject: [PATCH 03/20] fix(gradle): fix verify metadata for windows --- gradle/verification-metadata.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 682e0f0..9a144bd 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -313,10 +313,10 @@ - + - + @@ -486,10 +486,10 @@ - + - + From 4b5004b682a26a80d03f9d189b83d8d696cf3d89 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Fri, 22 Aug 2025 15:46:31 +0800 Subject: [PATCH 04/20] fix(gradle): fix jitpack build --- jitpack.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jitpack.yml b/jitpack.yml index 4065d43..512d5a1 100644 --- a/jitpack.yml +++ b/jitpack.yml @@ -1,2 +1,2 @@ install: - - ./gradlew clean -xtest -xlint -xcheck -PbinaryRelease=false publishToMavenLocal + - ./gradlew clean -xtest -xcheck publishToMavenLocal From 986e0e5d9b9ae9e7243a0221558a4137ce4a85a7 Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Tue, 26 Aug 2025 10:54:21 +0800 Subject: [PATCH 05/20] feat(proto): keep protocGenVersion to 1.60 --- build.gradle | 3 ++- gradle/verification-metadata.xml | 31 ++++++++++++++++--------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/build.gradle b/build.gradle index e066e67..1c60957 100644 --- a/build.gradle +++ b/build.gradle @@ -20,6 +20,7 @@ apply plugin: 'maven-publish' def protobufVersion = "3.25.8" def grpcVersion = "1.75.0" +def protocGenVersion = '1.60.0' // https://github.com/grpc/grpc-java/pull/11371 , 1.64.x is not supported CentOS 7. mainClassName = 'org.tron.p2p.example.StartApp' @@ -104,7 +105,7 @@ protobuf { plugins { grpc { - artifact = "io.grpc:protoc-gen-grpc-java:$grpcVersion" + artifact = "io.grpc:protoc-gen-grpc-java:$protocGenVersion" } } generateProtoTasks { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 9a144bd..7d56b17 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -473,27 +473,28 @@ - - - + + + + - - + + - - + + - - + + - - + + - - + + - - + + From 143a204f336a3fd1def3ec7cf540805b0679a89e Mon Sep 17 00:00:00 2001 From: halibobo1205 Date: Tue, 26 Aug 2025 11:24:19 +0800 Subject: [PATCH 06/20] bump commons-lang3 from 3.4 to 3.18.0 --- build.gradle | 2 +- gradle/verification-metadata.xml | 28 +++++++++++++++++++++++----- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/build.gradle b/build.gradle index 1c60957..77a6ac4 100644 --- a/build.gradle +++ b/build.gradle @@ -66,7 +66,7 @@ dependencies { implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.79' implementation group: 'org.bouncycastle', name: 'bcpkix-jdk18on', version: '1.79' - implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.4' + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.18.0' implementation group: 'commons-cli', name: 'commons-cli', version: '1.5.0' compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.12' diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 7d56b17..77bcb9c 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -694,6 +694,11 @@ + + + + + @@ -715,12 +720,12 @@ - - - + + + - - + + @@ -748,6 +753,11 @@ + + + + + @@ -942,6 +952,14 @@ + + + + + + + + From 79d9f740430f6c7875d3c33efa26b7f1f3dcb886 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 26 Sep 2025 11:02:50 +0800 Subject: [PATCH 07/20] add instruction of how to use log correctly --- README.md | 23 +++++--------- build.gradle | 13 +++++++- src/main/resources/logback.xml.example | 42 ++++++++++++++++++++++++++ 3 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 src/main/resources/logback.xml.example diff --git a/README.md b/README.md index 38749cb..8aac7e7 100644 --- a/README.md +++ b/README.md @@ -9,26 +9,19 @@ libp2p is a p2p network SDK implemented in java language. The functional modules Starting from version 2.2.7, `libp2p` has removed the logback component and adopted the logger facade. If logging is required, you need to introduce a logging framework manually. Here’s how to include logback in your project using Gradle: -1. Add the following dependencies to your build.gradle file +1. Uncomment the ch.qos.logback:logback-classic dependency in build.gradle file ``` dependencies { - implementation group: 'ch.qos.logback', name: 'logback-classic', version: 'x.x.xx' + implementation("ch.qos.logback:logback-classic:1.2.13") { + ... + } } ``` -2. Create or edit logback.xml in src/main/resources to configure logging. Here is an example of logback.xml: - ```xml - - - - - %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n - - - - - - +2. To fix DependencyVerificationException: Dependency verification failed for configuration ':xxx' x artifacts failed verification +```bash +$ ./gradlew clean --refresh-dependencies --write-verification-metadata sha256 ``` +3. Rename logback.xml.example in src/main/resources to logback.xml. # Build diff --git a/build.gradle b/build.gradle index 77a6ac4..ba8c5e0 100644 --- a/build.gradle +++ b/build.gradle @@ -86,10 +86,21 @@ dependencies { exclude group: 'io.netty', module: 'netty-transport-classes-epoll' exclude group: 'io.netty', module: 'netty-transport-native-unix-common' }) - implementation group: 'com.aliyun', name: 'alidns20150109', version: '3.0.1',{ + implementation group: 'com.aliyun', name: 'alidns20150109', version: '3.0.1', { exclude group: 'org.bouncycastle', module: 'bcprov-jdk15on' exclude group: 'org.bouncycastle', module: 'bcpkix-jdk15on' + exclude group: 'pull-parser', module: 'pull-parser' + exclude group: 'xpp3', module: 'xpp3' } + + //If logging is required, uncomment this dependency + //implementation("ch.qos.logback:logback-classic:1.2.13") { + // exclude group: 'jaxen', module: 'jaxen' + // exclude group: 'javax.xml.stream', module: 'stax-api' + // exclude group: 'net.java.dev.msv', module: 'xsdlib' + // exclude group: 'pull-parser', module: 'pull-parser' + // exclude group: 'xpp3', module: 'xpp3' + //} } tasks.matching { it instanceof Test }.all { diff --git a/src/main/resources/logback.xml.example b/src/main/resources/logback.xml.example new file mode 100644 index 0000000..ef52dc1 --- /dev/null +++ b/src/main/resources/logback.xml.example @@ -0,0 +1,42 @@ + + + + + + + + + %d{HH:mm:ss.SSS} %-5level [%t] [%c{1}]\(%F:%L\) %m%n + + + INFO + + + + + ./logs/server.log + + + ./logs/server-%d{yyyy-MM-dd}.%i.log.gz + + 500MB + 7 + 50GB + + + %d{HH:mm:ss.SSS} %-5level [%t] [%c{1}]\(%F:%L\) %m%n + + + TRACE + + + + + + + + + + + From 4d1854ff7be05689f31fa28e9c13de64614a99e4 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 30 Sep 2025 14:30:04 +0800 Subject: [PATCH 08/20] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8aac7e7..b1ded6b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Here’s how to include logback in your project using Gradle: } } ``` -2. To fix DependencyVerificationException: Dependency verification failed for configuration ':xxx' x artifacts failed verification +2. Refresh the dependency verification metadata to prevent verification failures ```bash $ ./gradlew clean --refresh-dependencies --write-verification-metadata sha256 ``` From 32acb8422bd8c31a6b6f784cf48569676a1842da Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 30 Sep 2025 17:31:47 +0800 Subject: [PATCH 09/20] bump lombok from 1.18.12 to 1.18.34 to support JDK17 --- build.gradle | 6 +++--- gradle/verification-metadata.xml | 9 ++++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index ba8c5e0..93d37ca 100644 --- a/build.gradle +++ b/build.gradle @@ -69,9 +69,9 @@ dependencies { implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.18.0' implementation group: 'commons-cli', name: 'commons-cli', version: '1.5.0' - compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.12' - testImplementation group: 'org.projectlombok', name: 'lombok', version: '1.18.12' - annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.12' + compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.34' + testImplementation group: 'org.projectlombok', name: 'lombok', version: '1.18.34' + annotationProcessor group: 'org.projectlombok', name: 'lombok', version: '1.18.34' implementation group: 'dnsjava', name: 'dnsjava', version: '3.6.2' implementation('software.amazon.awssdk:route53:2.18.41', { diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index 77bcb9c..382b1f4 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -474,7 +474,6 @@ - @@ -1005,6 +1004,14 @@ + + + + + + + + From 3902fba50ab532d6e01a2024c5f38be83e4196c0 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 10 Oct 2025 11:03:27 +0800 Subject: [PATCH 10/20] Merge pull request #115 from 317787106/hotfix/fix_print_hellomessage fix(log): format hellomessage's nodeId using hex --- .../message/handshake/HelloMessage.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/tron/p2p/connection/message/handshake/HelloMessage.java b/src/main/java/org/tron/p2p/connection/message/handshake/HelloMessage.java index fc42116..a3727d2 100644 --- a/src/main/java/org/tron/p2p/connection/message/handshake/HelloMessage.java +++ b/src/main/java/org/tron/p2p/connection/message/handshake/HelloMessage.java @@ -7,6 +7,7 @@ import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Connect; import org.tron.p2p.protos.Discover; +import org.tron.p2p.utils.ByteArray; import org.tron.p2p.utils.NetUtil; public class HelloMessage extends Message { @@ -52,7 +53,7 @@ public Node getFrom() { @Override public String toString() { - return "[HelloMessage: " + helloMessage; + return "[HelloMessage: " + format(); } @Override @@ -60,4 +61,17 @@ public boolean valid() { return NetUtil.validNode(getFrom()); } + public String format() { + String[] lines = helloMessage.toString().split("\n"); + StringBuilder sb = new StringBuilder(); + for (String line : lines) { + if (line.contains("nodeId")) { + String nodeId = ByteArray.toHexString(helloMessage.getFrom().getNodeId().toByteArray()); + line = " nodeId: \"" + nodeId + "\""; + } + sb.append(line).append("\n"); + } + return sb.toString(); + } + } From 206e5ec6b952f294a9508316d2a240bc88b95558 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 17 Oct 2025 16:02:05 +0800 Subject: [PATCH 11/20] update readme to support JDK 17 (#117) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b1ded6b..d6f93bd 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ Here’s how to include logback in your project using Gradle: ```bash $ ./gradlew clean --refresh-dependencies --write-verification-metadata sha256 ``` -3. Rename logback.xml.example in src/main/resources to logback.xml. +3. Rename or copy logback.xml.example in src/main/resources to logback.xml. # Build -Building libp2p requires `git` and `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. Make sure you operate on `Linux` and `MacOS` operating systems. +Building libp2p requires `git`, `JDK 17` or `Oracle JDK 1.8` to be installed, other JDK versions are not supported yet. Make sure you operate on `Linux` and `MacOS` operating systems. Clone the repo and switch to the `main` branch @@ -43,12 +43,12 @@ $ ./gradlew clean build -x test libp2p can run independently or be imported into other projects. ## Run independently -Running libp2p requires Oracle JDK 1.8 to be installed, other JDK versions are not supported yet. Make sure you operate on Linux and MacOS operating systems. +Running libp2p requires JDK 17 or Oracle JDK 1.8 to be installed, other JDK versions are not supported yet. Make sure you operate on Linux and MacOS operating systems. then run the following command to start the node: ```bash $ nohup java -jar libp2p.jar [options] >> start.log 2>&1 & ``` -See the manual for details on [options](https://github.com/tronprotocol/libp2p/tree/develop/src/main/java/org/tron/p2p/example/README.md) +See the manual for details on [options](src/main/java/org/tron/p2p/example/README.md) ## How to include the dependency ### Gradle Setting @@ -90,11 +90,11 @@ dependencies { ``` ## Example -For some examples please check our [example package](https://github.com/tronprotocol/libp2p/tree/develop/src/main/java/org/tron/p2p/example). +For some examples please check our [example package](src/main/java/org/tron/p2p/example). # Integrity Check * After February 21, 2023, releases are signed the gpg key: ``` pub: 1254 F859 D2B1 BD9F 66E7 107D F859 BCB4 4A28 290B uid: build@tron.network - ``` \ No newline at end of file + ``` From 59040eaf2fdf7c962a9da6c1e533ad05fb11b008 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 17 Oct 2025 16:31:23 +0800 Subject: [PATCH 12/20] feat(net): Don't sumbit new task when connection pool's queue size is too large (#116) * restict connPool task size --- .../java/org/tron/p2p/base/Parameter.java | 2 ++ .../business/detect/NodeDetectService.java | 2 +- .../business/keepalive/KeepAliveService.java | 2 +- .../business/pool/ConnPoolService.java | 21 ++++++++++---- .../p2p/connection/socket/PeerClient.java | 2 +- .../p2p/connection/socket/PeerServer.java | 4 +-- src/main/java/org/tron/p2p/discover/Node.java | 29 +++++-------------- .../discover/protocol/kad/DiscoverTask.java | 2 +- .../p2p/discover/protocol/kad/KadService.java | 2 +- .../java/org/tron/p2p/dns/sync/Client.java | 3 +- .../tron/p2p/dns/update/PublishService.java | 2 +- src/main/java/org/tron/p2p/utils/NetUtil.java | 2 +- 12 files changed, 34 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/tron/p2p/base/Parameter.java b/src/main/java/org/tron/p2p/base/Parameter.java index 7a80884..5005594 100644 --- a/src/main/java/org/tron/p2p/base/Parameter.java +++ b/src/main/java/org/tron/p2p/base/Parameter.java @@ -24,6 +24,8 @@ public class Parameter { public static final int UDP_NETTY_WORK_THREAD_NUM = 1; + public static final int CONN_MAX_QUEUE_SIZE = 10; + public static final int NODE_CONNECTION_TIMEOUT = 2000; public static final int KEEP_ALIVE_TIMEOUT = 20_000; diff --git a/src/main/java/org/tron/p2p/connection/business/detect/NodeDetectService.java b/src/main/java/org/tron/p2p/connection/business/detect/NodeDetectService.java index 4752aca..3ef53b5 100644 --- a/src/main/java/org/tron/p2p/connection/business/detect/NodeDetectService.java +++ b/src/main/java/org/tron/p2p/connection/business/detect/NodeDetectService.java @@ -36,7 +36,7 @@ public class NodeDetectService implements MessageProcess { .newBuilder().maximumSize(5000).expireAfterWrite(1, TimeUnit.HOURS).build(); private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("nodeDetectService").build()); + BasicThreadFactory.builder().namingPattern("nodeDetectService").build()); private final long NODE_DETECT_THRESHOLD = 5 * 60 * 1000; diff --git a/src/main/java/org/tron/p2p/connection/business/keepalive/KeepAliveService.java b/src/main/java/org/tron/p2p/connection/business/keepalive/KeepAliveService.java index 4855096..19eea3b 100644 --- a/src/main/java/org/tron/p2p/connection/business/keepalive/KeepAliveService.java +++ b/src/main/java/org/tron/p2p/connection/business/keepalive/KeepAliveService.java @@ -21,7 +21,7 @@ public class KeepAliveService implements MessageProcess { private final ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("keepAlive").build()); + BasicThreadFactory.builder().namingPattern("keepAlive").build()); public void init() { executor.scheduleWithFixedDelay(() -> { diff --git a/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java b/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java index 663afd4..81523d6 100644 --- a/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java +++ b/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java @@ -14,6 +14,7 @@ import java.util.Set; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; @@ -42,7 +43,7 @@ public class ConnPoolService extends P2pEventHandler { private final List activePeers = Collections.synchronizedList(new ArrayList<>()); - private Cache peerClientCache = CacheBuilder.newBuilder() + private final Cache peerClientCache = CacheBuilder.newBuilder() .maximumSize(1000).expireAfterWrite(120, TimeUnit.SECONDS).recordStats().build(); @Getter private final AtomicInteger passivePeersCount = new AtomicInteger(0); @@ -50,14 +51,15 @@ public class ConnPoolService extends P2pEventHandler { private final AtomicInteger activePeersCount = new AtomicInteger(0); @Getter private final AtomicInteger connectingPeersCount = new AtomicInteger(0); - private final ScheduledExecutorService poolLoopExecutor = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("connPool").build()); - private final ScheduledExecutorService disconnectExecutor = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("randomDisconnect").build()); + private final ScheduledThreadPoolExecutor poolLoopExecutor = new ScheduledThreadPoolExecutor(1, + BasicThreadFactory.builder().namingPattern("connPool").build()); + private final ScheduledExecutorService disconnectExecutor = + Executors.newSingleThreadScheduledExecutor( + BasicThreadFactory.builder().namingPattern("randomDisconnect").build()); public P2pConfig p2pConfig = Parameter.p2pConfig; private PeerClient peerClient; - private List configActiveNodes = new ArrayList<>(); + private final List configActiveNodes = new ArrayList<>(); public ConnPoolService() { this.messageTypes = new HashSet<>(); //no message type registers @@ -65,6 +67,7 @@ public ConnPoolService() { Parameter.addP2pEventHandle(this); configActiveNodes.addAll(p2pConfig.getActiveNodes()); } catch (P2pException e) { + //no exception will throw } } @@ -268,6 +271,10 @@ public void triggerConnect(InetSocketAddress address) { return; } connectingPeersCount.decrementAndGet(); + if (poolLoopExecutor.getQueue().size() >= Parameter.CONN_MAX_QUEUE_SIZE) { + log.warn("ConnPool task' size is greater than or equal to {}", Parameter.CONN_MAX_QUEUE_SIZE); + return; + } try { if (!ChannelManager.isShutdown) { poolLoopExecutor.submit(() -> { @@ -311,6 +318,7 @@ public synchronized void onDisconnect(Channel peer) { @Override public void onMessage(Channel channel, byte[] data) { + //do nothing } public void close() { @@ -323,6 +331,7 @@ public void close() { } }); poolLoopExecutor.shutdownNow(); + disconnectExecutor.shutdownNow(); } catch (Exception e) { log.warn("Problems shutting down executor", e); } diff --git a/src/main/java/org/tron/p2p/connection/socket/PeerClient.java b/src/main/java/org/tron/p2p/connection/socket/PeerClient.java index 0e3c8fb..2f0bd94 100644 --- a/src/main/java/org/tron/p2p/connection/socket/PeerClient.java +++ b/src/main/java/org/tron/p2p/connection/socket/PeerClient.java @@ -23,7 +23,7 @@ public class PeerClient { public void init() { workerGroup = new NioEventLoopGroup(0, - new BasicThreadFactory.Builder().namingPattern("peerClient-%d").build()); + BasicThreadFactory.builder().namingPattern("peerClient-%d").build()); } public void close() { diff --git a/src/main/java/org/tron/p2p/connection/socket/PeerServer.java b/src/main/java/org/tron/p2p/connection/socket/PeerServer.java index d3b1b9d..8a1b7d9 100644 --- a/src/main/java/org/tron/p2p/connection/socket/PeerServer.java +++ b/src/main/java/org/tron/p2p/connection/socket/PeerServer.java @@ -39,10 +39,10 @@ public void close() { public void start(int port) { EventLoopGroup bossGroup = new NioEventLoopGroup(1, - new BasicThreadFactory.Builder().namingPattern("peerBoss").build()); + BasicThreadFactory.builder().namingPattern("peerBoss").build()); //if threads = 0, it is number of core * 2 EventLoopGroup workerGroup = new NioEventLoopGroup(Parameter.TCP_NETTY_WORK_THREAD_NUM, - new BasicThreadFactory.Builder().namingPattern("peerWorker-%d").build()); + BasicThreadFactory.builder().namingPattern("peerWorker-%d").build()); P2pChannelInitializer p2pChannelInitializer = new P2pChannelInitializer("", false, true); try { ServerBootstrap b = new ServerBootstrap(); diff --git a/src/main/java/org/tron/p2p/discover/Node.java b/src/main/java/org/tron/p2p/discover/Node.java index 028336f..51156d2 100644 --- a/src/main/java/org/tron/p2p/discover/Node.java +++ b/src/main/java/org/tron/p2p/discover/Node.java @@ -16,6 +16,8 @@ public class Node implements Serializable, Cloneable { private static final long serialVersionUID = -4267600517925770636L; + @Setter + @Getter private byte[] id; @Getter @@ -24,6 +26,8 @@ public class Node implements Serializable, Cloneable { @Getter protected String hostV6; + @Setter + @Getter protected int port; @Setter @@ -32,6 +36,7 @@ public class Node implements Serializable, Cloneable { @Setter private int p2pVersion; + @Getter private long updateTime; public Node(InetSocketAddress address) { @@ -111,26 +116,10 @@ public String getHexIdShort() { return getIdShort(getHexId()); } - public byte[] getId() { - return id; - } - - public void setId(byte[] id) { - this.id = id; - } - public String getHostKey() { return getPreferInetSocketAddress().getAddress().getHostAddress(); } - public int getPort() { - return port; - } - - public void setPort(int port) { - this.port = port; - } - public String getIdString() { if (id == null) { return null; @@ -138,10 +127,6 @@ public String getIdString() { return new String(id); } - public long getUpdateTime() { - return updateTime; - } - public void touch() { updateTime = System.currentTimeMillis(); } @@ -179,8 +164,8 @@ public boolean equals(Object o) { return false; } - private String getIdShort(String Id) { - return Id == null ? "" : Id.substring(0, 8); + private String getIdShort(String hexId) { + return hexId == null ? "" : hexId.substring(0, 8); } public InetSocketAddress getInetSocketAddressV4() { diff --git a/src/main/java/org/tron/p2p/discover/protocol/kad/DiscoverTask.java b/src/main/java/org/tron/p2p/discover/protocol/kad/DiscoverTask.java index d633b78..4ab23ec 100644 --- a/src/main/java/org/tron/p2p/discover/protocol/kad/DiscoverTask.java +++ b/src/main/java/org/tron/p2p/discover/protocol/kad/DiscoverTask.java @@ -15,7 +15,7 @@ public class DiscoverTask { private ScheduledExecutorService discoverer = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("discoverTask").build()); + BasicThreadFactory.builder().namingPattern("discoverTask").build()); private KadService kadService; diff --git a/src/main/java/org/tron/p2p/discover/protocol/kad/KadService.java b/src/main/java/org/tron/p2p/discover/protocol/kad/KadService.java index 7f2051e..1a137c4 100644 --- a/src/main/java/org/tron/p2p/discover/protocol/kad/KadService.java +++ b/src/main/java/org/tron/p2p/discover/protocol/kad/KadService.java @@ -57,7 +57,7 @@ public void init() { bootNodes.add(new Node(address)); } this.pongTimer = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("pongTimer").build()); + BasicThreadFactory.builder().namingPattern("pongTimer").build()); this.homeNode = new Node(Parameter.p2pConfig.getNodeID(), Parameter.p2pConfig.getIp(), Parameter.p2pConfig.getIpv6(), Parameter.p2pConfig.getPort()); this.table = new NodeTable(homeNode); diff --git a/src/main/java/org/tron/p2p/dns/sync/Client.java b/src/main/java/org/tron/p2p/dns/sync/Client.java index 064e0da..95781ec 100644 --- a/src/main/java/org/tron/p2p/dns/sync/Client.java +++ b/src/main/java/org/tron/p2p/dns/sync/Client.java @@ -10,7 +10,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import lombok.Getter; import lombok.extern.slf4j.Slf4j; @@ -42,7 +41,7 @@ public class Client { private final Map clientTrees = new HashMap<>(); private final ScheduledExecutorService syncer = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("dnsSyncer").build()); + BasicThreadFactory.builder().namingPattern("dnsSyncer").build()); public Client() { this.cache = CacheBuilder.newBuilder() diff --git a/src/main/java/org/tron/p2p/dns/update/PublishService.java b/src/main/java/org/tron/p2p/dns/update/PublishService.java index 7a94543..5fd7cb4 100644 --- a/src/main/java/org/tron/p2p/dns/update/PublishService.java +++ b/src/main/java/org/tron/p2p/dns/update/PublishService.java @@ -25,7 +25,7 @@ public class PublishService { private static final long publishDelay = 1 * 60 * 60; private ScheduledExecutorService publisher = Executors.newSingleThreadScheduledExecutor( - new BasicThreadFactory.Builder().namingPattern("publishService").build()); + BasicThreadFactory.builder().namingPattern("publishService").build()); private Publish publish; public void init() { diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 9a1be29..72db69e 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -214,7 +214,7 @@ public static InetSocketAddress parseInetSocketAddress(String para) { private static String getIp(List multiSrcUrls) { ExecutorService executor = Executors.newCachedThreadPool( - new BasicThreadFactory.Builder().namingPattern("getIp").build()); + BasicThreadFactory.builder().namingPattern("getIp").build()); CompletionService completionService = new ExecutorCompletionService<>(executor); List> tasks = new ArrayList<>(); From df2756c92381f0eb0152a41fb2d7eb2ce0c2948a Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 17 Oct 2025 17:00:11 +0800 Subject: [PATCH 13/20] feat(net): retrieve the public IPv6 address within a LAN environment (#114) * Retrieve the public IPv6 address within a LAN environment --- src/main/java/org/tron/p2p/base/Constant.java | 1 + .../java/org/tron/p2p/example/StartApp.java | 4 +- src/main/java/org/tron/p2p/utils/NetUtil.java | 150 ++++++++++++++---- .../java/org/tron/p2p/utils/NetUtilTest.java | 17 +- 4 files changed, 134 insertions(+), 38 deletions(-) diff --git a/src/main/java/org/tron/p2p/base/Constant.java b/src/main/java/org/tron/p2p/base/Constant.java index cea5c1f..a0e3acb 100644 --- a/src/main/java/org/tron/p2p/base/Constant.java +++ b/src/main/java/org/tron/p2p/base/Constant.java @@ -10,6 +10,7 @@ public class Constant { "http://checkip.amazonaws.com", "https://ifconfig.me/ip", "https://4.ipw.cn/"); public static final List ipV6Urls = Arrays.asList( "https://v6.ident.me", "http://6.ipw.cn/"); + public static final String dnsResolver = "https://dns.alidns.com/dns-query"; public static final String ipV4Hex = "00000000"; //32 bit public static final String ipV6Hex = "00000000000000000000000000000000"; //128 bit } diff --git a/src/main/java/org/tron/p2p/example/StartApp.java b/src/main/java/org/tron/p2p/example/StartApp.java index 0ca5402..9579710 100644 --- a/src/main/java/org/tron/p2p/example/StartApp.java +++ b/src/main/java/org/tron/p2p/example/StartApp.java @@ -377,9 +377,7 @@ private List parseInetSocketAddressList(String paras) { List nodes = new ArrayList<>(); for (String para : paras.split(",")) { InetSocketAddress inetSocketAddress = NetUtil.parseInetSocketAddress(para); - if (inetSocketAddress != null) { - nodes.add(inetSocketAddress); - } + nodes.add(inetSocketAddress); } return nodes; } diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 72db69e..542ae88 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -11,15 +11,13 @@ import java.net.SocketException; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; -import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionService; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -31,10 +29,20 @@ import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; +import org.xbill.DNS.AAAARecord; +import org.xbill.DNS.DohResolver; +import org.xbill.DNS.Name; +import org.xbill.DNS.Record; +import org.xbill.DNS.Resolver; +import org.xbill.DNS.Type; +import org.xbill.DNS.lookup.LookupResult; +import org.xbill.DNS.lookup.LookupSession; @Slf4j(topic = "net") public class NetUtil { + static Random gen = new Random(); + public static final Pattern PATTERN_IPv4 = Pattern.compile("^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\" + ".(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\" @@ -85,40 +93,115 @@ public static Node getNode(Discover.Endpoint endpoint) { } public static byte[] getNodeId() { - Random gen = new Random(); byte[] id = new byte[Constant.NODE_ID_LEN]; gen.nextBytes(id); return id; } - private static String getExternalIp(String url) { + private static String getExternalIp(String url, boolean isAskIpv4) { + // try to get ipv4 or ipv6 by url directly first BufferedReader in = null; String ip = null; + String domain = null; + String errMsg = null; try { - URLConnection urlConnection = new URL(url).openConnection(); + URL uri = new URL(url); + domain = uri.getHost(); + URLConnection urlConnection = uri.openConnection(); + urlConnection.setConnectTimeout(30_000); //ms + urlConnection.setReadTimeout(30_000); //ms in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); ip = in.readLine(); if (ip == null || ip.trim().isEmpty()) { throw new IOException("Invalid address: " + ip); } - try { - InetAddress.getByName(ip); - } catch (Exception e) { + InetAddress inetAddress = InetAddress.getByName(ip); + if (isAskIpv4 && !validIpV4(inetAddress.getHostAddress())) { + throw new IOException("Invalid address: " + ip); + } + if (!isAskIpv4 && !validIpV6(inetAddress.getHostAddress())) { throw new IOException("Invalid address: " + ip); } - return ip; + ip = inetAddress.getHostAddress(); } catch (Exception e) { - log.warn("Fail to get {} by {}, cause:{}", - Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, e.getMessage()); - return ip; + errMsg = e.getMessage(); } finally { if (in != null) { try { in.close(); } catch (IOException e) { + //ignore } } } + + //if fails to get ipv6 directly, we use alternative method + if (!isAskIpv4 && StringUtils.isEmpty(ip) && StringUtils.isNotEmpty(domain)) { + try { + ip = getExternalIPv6ByDoh(domain); + } catch (Exception e) { + // ignore + } + } + if (StringUtils.isNotEmpty(ip)) { + log.debug("Get {} from {} successfully", isAskIpv4 ? "ipv4" : "ipv6", url); + } else if (StringUtils.isNotEmpty(errMsg)) { + log.warn("Fail to get {} by {}, cause:{}", + Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, errMsg); + } + return ip; + } + + /** + * get external ipv6 through dns server. Ask the ipv6 of specified domain through dns resolver + * first, and then execute `curl [ipv6]` to get the ipv6 of localhost + */ + public static String getExternalIPv6ByDoh(String domain) throws Exception { + log.debug("Try to get ipv6 by {} through doh {}", domain, Constant.dnsResolver); + Resolver resolver = new DohResolver(Constant.dnsResolver); + LookupSession session = LookupSession.defaultBuilder() + .resolver(resolver) + .build(); + + Name name = Name.fromString(domain + "."); + CompletableFuture future = + session.lookupAsync(name, Type.AAAA).toCompletableFuture(); + + LookupResult result = future.get(); + + InetAddress ipv6 = null; + for (Record recordItem : result.getRecords()) { + if (recordItem instanceof AAAARecord) { + ipv6 = ((AAAARecord) recordItem).getAddress(); + break; + } + } + if (ipv6 == null) { + return null; + } + if (!(ipv6 instanceof Inet6Address)) { + return null; + } + log.debug("ipv6 of domain {} is {}", domain, ipv6.getHostAddress()); + + // use timeout 3s + String command = String.format("curl --max-time 3 http://[%s]", ipv6.getHostAddress()); + + Process process = Runtime.getRuntime().exec(command); + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String ipv6Str = null; + String line; + while ((line = reader.readLine()) != null) { + ipv6Str = line.trim(); + } + reader.close(); + + int exitCode = process.waitFor(); + if (exitCode == 0 && validIpV6(ipv6Str)) { + return ipv6Str; + } + + return null; } private static String getOuterIPv6Address() { @@ -177,14 +260,14 @@ private static boolean isReservedAddress(InetAddress inetAddress) { public static String getExternalIpV4() { long t1 = System.currentTimeMillis(); - String ipV4 = getIp(Constant.ipV4Urls); + String ipV4 = getIp(Constant.ipV4Urls, true); log.debug("GetExternalIpV4 cost {} ms", System.currentTimeMillis() - t1); return ipV4; } public static String getExternalIpV6() { long t1 = System.currentTimeMillis(); - String ipV6 = getIp(Constant.ipV6Urls); + String ipV6 = getIp(Constant.ipV6Urls, false); if (null == ipV6) { ipV6 = getOuterIPv6Address(); } @@ -212,30 +295,33 @@ public static InetSocketAddress parseInetSocketAddress(String para) { } } - private static String getIp(List multiSrcUrls) { - ExecutorService executor = Executors.newCachedThreadPool( + private static String getIp(List multiSrcUrls, boolean isAskIpv4) { + int threadSize = multiSrcUrls.size(); + ExecutorService executor = Executors.newFixedThreadPool(threadSize, BasicThreadFactory.builder().namingPattern("getIp").build()); CompletionService completionService = new ExecutorCompletionService<>(executor); - List> tasks = new ArrayList<>(); - multiSrcUrls.forEach(url -> tasks.add(() -> getExternalIp(url))); - - for (Callable task : tasks) { - completionService.submit(task); + for (String url : multiSrcUrls) { + completionService.submit(() -> getExternalIp(url, isAskIpv4)); } - Future future; - String result = null; - try { - future = completionService.take(); - result = future.get(); - } catch (InterruptedException | ExecutionException e) { - //ignore - } finally { - executor.shutdownNow(); + String ip = null; + for (int i = 0; i < threadSize; i++) { + try { + //block until any result return + Future f = completionService.take(); + String result = f.get(); + if (StringUtils.isNotEmpty(result)) { + ip = result; + break; + } + } catch (Exception ignored) { + //ignore + } } - return result; + executor.shutdownNow(); + return ip; } public static String getLanIP() { diff --git a/src/test/java/org/tron/p2p/utils/NetUtilTest.java b/src/test/java/org/tron/p2p/utils/NetUtilTest.java index 78fb5b5..f634c54 100644 --- a/src/test/java/org/tron/p2p/utils/NetUtilTest.java +++ b/src/test/java/org/tron/p2p/utils/NetUtilTest.java @@ -1,15 +1,14 @@ package org.tron.p2p.utils; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Test; import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; -import java.net.InetSocketAddress; - public class NetUtilTest { @Test @@ -190,4 +189,16 @@ public void testParseIpv6() { Assert.assertNotNull(address5); } + @Test + public void testGetExternalIPv6ByDoh() { + try { + String ipV6OfDomain = NetUtil.getExternalIPv6ByDoh("v6.ident.me"); + if (StringUtils.isNotEmpty(ipV6OfDomain)) { + Assert.assertTrue(NetUtil.validIpV6(ipV6OfDomain)); + } + } catch (Exception e) { + Assert.fail(); + } + } + } From 8abf6fa4a632c54dadadb1c4323b4aec9593bef4 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Tue, 21 Oct 2025 13:55:43 +0800 Subject: [PATCH 14/20] =?UTF-8?q?Revert=20"feat(net):=20retrieve=20the=20p?= =?UTF-8?q?ublic=20IPv6=20address=20within=20a=20LAN=20environment=20?= =?UTF-8?q?=E2=80=A6"=20(#119)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit df2756c92381f0eb0152a41fb2d7eb2ce0c2948a. --- src/main/java/org/tron/p2p/base/Constant.java | 1 - .../java/org/tron/p2p/example/StartApp.java | 4 +- src/main/java/org/tron/p2p/utils/NetUtil.java | 150 ++++-------------- .../java/org/tron/p2p/utils/NetUtilTest.java | 17 +- 4 files changed, 38 insertions(+), 134 deletions(-) diff --git a/src/main/java/org/tron/p2p/base/Constant.java b/src/main/java/org/tron/p2p/base/Constant.java index a0e3acb..cea5c1f 100644 --- a/src/main/java/org/tron/p2p/base/Constant.java +++ b/src/main/java/org/tron/p2p/base/Constant.java @@ -10,7 +10,6 @@ public class Constant { "http://checkip.amazonaws.com", "https://ifconfig.me/ip", "https://4.ipw.cn/"); public static final List ipV6Urls = Arrays.asList( "https://v6.ident.me", "http://6.ipw.cn/"); - public static final String dnsResolver = "https://dns.alidns.com/dns-query"; public static final String ipV4Hex = "00000000"; //32 bit public static final String ipV6Hex = "00000000000000000000000000000000"; //128 bit } diff --git a/src/main/java/org/tron/p2p/example/StartApp.java b/src/main/java/org/tron/p2p/example/StartApp.java index 9579710..0ca5402 100644 --- a/src/main/java/org/tron/p2p/example/StartApp.java +++ b/src/main/java/org/tron/p2p/example/StartApp.java @@ -377,7 +377,9 @@ private List parseInetSocketAddressList(String paras) { List nodes = new ArrayList<>(); for (String para : paras.split(",")) { InetSocketAddress inetSocketAddress = NetUtil.parseInetSocketAddress(para); - nodes.add(inetSocketAddress); + if (inetSocketAddress != null) { + nodes.add(inetSocketAddress); + } } return nodes; } diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 542ae88..72db69e 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -11,13 +11,15 @@ import java.net.SocketException; import java.net.URL; import java.net.URLConnection; +import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; -import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; +import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -29,20 +31,10 @@ import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; -import org.xbill.DNS.AAAARecord; -import org.xbill.DNS.DohResolver; -import org.xbill.DNS.Name; -import org.xbill.DNS.Record; -import org.xbill.DNS.Resolver; -import org.xbill.DNS.Type; -import org.xbill.DNS.lookup.LookupResult; -import org.xbill.DNS.lookup.LookupSession; @Slf4j(topic = "net") public class NetUtil { - static Random gen = new Random(); - public static final Pattern PATTERN_IPv4 = Pattern.compile("^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])\\" + ".(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)\\" @@ -93,115 +85,40 @@ public static Node getNode(Discover.Endpoint endpoint) { } public static byte[] getNodeId() { + Random gen = new Random(); byte[] id = new byte[Constant.NODE_ID_LEN]; gen.nextBytes(id); return id; } - private static String getExternalIp(String url, boolean isAskIpv4) { - // try to get ipv4 or ipv6 by url directly first + private static String getExternalIp(String url) { BufferedReader in = null; String ip = null; - String domain = null; - String errMsg = null; try { - URL uri = new URL(url); - domain = uri.getHost(); - URLConnection urlConnection = uri.openConnection(); - urlConnection.setConnectTimeout(30_000); //ms - urlConnection.setReadTimeout(30_000); //ms + URLConnection urlConnection = new URL(url).openConnection(); in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); ip = in.readLine(); if (ip == null || ip.trim().isEmpty()) { throw new IOException("Invalid address: " + ip); } - InetAddress inetAddress = InetAddress.getByName(ip); - if (isAskIpv4 && !validIpV4(inetAddress.getHostAddress())) { - throw new IOException("Invalid address: " + ip); - } - if (!isAskIpv4 && !validIpV6(inetAddress.getHostAddress())) { + try { + InetAddress.getByName(ip); + } catch (Exception e) { throw new IOException("Invalid address: " + ip); } - ip = inetAddress.getHostAddress(); + return ip; } catch (Exception e) { - errMsg = e.getMessage(); + log.warn("Fail to get {} by {}, cause:{}", + Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, e.getMessage()); + return ip; } finally { if (in != null) { try { in.close(); } catch (IOException e) { - //ignore } } } - - //if fails to get ipv6 directly, we use alternative method - if (!isAskIpv4 && StringUtils.isEmpty(ip) && StringUtils.isNotEmpty(domain)) { - try { - ip = getExternalIPv6ByDoh(domain); - } catch (Exception e) { - // ignore - } - } - if (StringUtils.isNotEmpty(ip)) { - log.debug("Get {} from {} successfully", isAskIpv4 ? "ipv4" : "ipv6", url); - } else if (StringUtils.isNotEmpty(errMsg)) { - log.warn("Fail to get {} by {}, cause:{}", - Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, errMsg); - } - return ip; - } - - /** - * get external ipv6 through dns server. Ask the ipv6 of specified domain through dns resolver - * first, and then execute `curl [ipv6]` to get the ipv6 of localhost - */ - public static String getExternalIPv6ByDoh(String domain) throws Exception { - log.debug("Try to get ipv6 by {} through doh {}", domain, Constant.dnsResolver); - Resolver resolver = new DohResolver(Constant.dnsResolver); - LookupSession session = LookupSession.defaultBuilder() - .resolver(resolver) - .build(); - - Name name = Name.fromString(domain + "."); - CompletableFuture future = - session.lookupAsync(name, Type.AAAA).toCompletableFuture(); - - LookupResult result = future.get(); - - InetAddress ipv6 = null; - for (Record recordItem : result.getRecords()) { - if (recordItem instanceof AAAARecord) { - ipv6 = ((AAAARecord) recordItem).getAddress(); - break; - } - } - if (ipv6 == null) { - return null; - } - if (!(ipv6 instanceof Inet6Address)) { - return null; - } - log.debug("ipv6 of domain {} is {}", domain, ipv6.getHostAddress()); - - // use timeout 3s - String command = String.format("curl --max-time 3 http://[%s]", ipv6.getHostAddress()); - - Process process = Runtime.getRuntime().exec(command); - BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - String ipv6Str = null; - String line; - while ((line = reader.readLine()) != null) { - ipv6Str = line.trim(); - } - reader.close(); - - int exitCode = process.waitFor(); - if (exitCode == 0 && validIpV6(ipv6Str)) { - return ipv6Str; - } - - return null; } private static String getOuterIPv6Address() { @@ -260,14 +177,14 @@ private static boolean isReservedAddress(InetAddress inetAddress) { public static String getExternalIpV4() { long t1 = System.currentTimeMillis(); - String ipV4 = getIp(Constant.ipV4Urls, true); + String ipV4 = getIp(Constant.ipV4Urls); log.debug("GetExternalIpV4 cost {} ms", System.currentTimeMillis() - t1); return ipV4; } public static String getExternalIpV6() { long t1 = System.currentTimeMillis(); - String ipV6 = getIp(Constant.ipV6Urls, false); + String ipV6 = getIp(Constant.ipV6Urls); if (null == ipV6) { ipV6 = getOuterIPv6Address(); } @@ -295,33 +212,30 @@ public static InetSocketAddress parseInetSocketAddress(String para) { } } - private static String getIp(List multiSrcUrls, boolean isAskIpv4) { - int threadSize = multiSrcUrls.size(); - ExecutorService executor = Executors.newFixedThreadPool(threadSize, + private static String getIp(List multiSrcUrls) { + ExecutorService executor = Executors.newCachedThreadPool( BasicThreadFactory.builder().namingPattern("getIp").build()); CompletionService completionService = new ExecutorCompletionService<>(executor); - for (String url : multiSrcUrls) { - completionService.submit(() -> getExternalIp(url, isAskIpv4)); + List> tasks = new ArrayList<>(); + multiSrcUrls.forEach(url -> tasks.add(() -> getExternalIp(url))); + + for (Callable task : tasks) { + completionService.submit(task); } - String ip = null; - for (int i = 0; i < threadSize; i++) { - try { - //block until any result return - Future f = completionService.take(); - String result = f.get(); - if (StringUtils.isNotEmpty(result)) { - ip = result; - break; - } - } catch (Exception ignored) { - //ignore - } + Future future; + String result = null; + try { + future = completionService.take(); + result = future.get(); + } catch (InterruptedException | ExecutionException e) { + //ignore + } finally { + executor.shutdownNow(); } - executor.shutdownNow(); - return ip; + return result; } public static String getLanIP() { diff --git a/src/test/java/org/tron/p2p/utils/NetUtilTest.java b/src/test/java/org/tron/p2p/utils/NetUtilTest.java index f634c54..78fb5b5 100644 --- a/src/test/java/org/tron/p2p/utils/NetUtilTest.java +++ b/src/test/java/org/tron/p2p/utils/NetUtilTest.java @@ -1,14 +1,15 @@ package org.tron.p2p.utils; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.net.InetSocketAddress; -import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Test; import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; +import java.net.InetSocketAddress; + public class NetUtilTest { @Test @@ -189,16 +190,4 @@ public void testParseIpv6() { Assert.assertNotNull(address5); } - @Test - public void testGetExternalIPv6ByDoh() { - try { - String ipV6OfDomain = NetUtil.getExternalIPv6ByDoh("v6.ident.me"); - if (StringUtils.isNotEmpty(ipV6OfDomain)) { - Assert.assertTrue(NetUtil.validIpV6(ipV6OfDomain)); - } - } catch (Exception e) { - Assert.fail(); - } - } - } From 04a9d87b08a6be5889c4a3ff478356f2fcbc5c63 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Tue, 21 Oct 2025 16:41:10 +0800 Subject: [PATCH 15/20] hotfix(net): fix the bug of completionService used in getIp (#120) * fix the bug of completionService used in getIp --- src/main/java/org/tron/p2p/utils/NetUtil.java | 59 ++++++++++--------- .../java/org/tron/p2p/utils/NetUtilTest.java | 12 ++-- 2 files changed, 37 insertions(+), 34 deletions(-) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 72db69e..7f85cfc 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -11,15 +11,12 @@ import java.net.SocketException; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; import java.util.Enumeration; import java.util.HashSet; import java.util.List; import java.util.Random; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.CompletionService; -import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -91,19 +88,23 @@ public static byte[] getNodeId() { return id; } - private static String getExternalIp(String url) { + private static String getExternalIp(String url, boolean isAskIpv4) { BufferedReader in = null; String ip = null; try { URLConnection urlConnection = new URL(url).openConnection(); + urlConnection.setConnectTimeout(30_000); //ms + urlConnection.setReadTimeout(30_000); //ms in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); ip = in.readLine(); if (ip == null || ip.trim().isEmpty()) { throw new IOException("Invalid address: " + ip); } - try { - InetAddress.getByName(ip); - } catch (Exception e) { + InetAddress inetAddress = InetAddress.getByName(ip); + if (isAskIpv4 && !validIpV4(inetAddress.getHostAddress())) { + throw new IOException("Invalid address: " + ip); + } + if (!isAskIpv4 && !validIpV6(inetAddress.getHostAddress())) { throw new IOException("Invalid address: " + ip); } return ip; @@ -116,6 +117,7 @@ private static String getExternalIp(String url) { try { in.close(); } catch (IOException e) { + //ignore } } } @@ -177,14 +179,14 @@ private static boolean isReservedAddress(InetAddress inetAddress) { public static String getExternalIpV4() { long t1 = System.currentTimeMillis(); - String ipV4 = getIp(Constant.ipV4Urls); + String ipV4 = getIp(Constant.ipV4Urls, true); log.debug("GetExternalIpV4 cost {} ms", System.currentTimeMillis() - t1); return ipV4; } public static String getExternalIpV6() { long t1 = System.currentTimeMillis(); - String ipV6 = getIp(Constant.ipV6Urls); + String ipV6 = getIp(Constant.ipV6Urls, false); if (null == ipV6) { ipV6 = getOuterIPv6Address(); } @@ -212,30 +214,33 @@ public static InetSocketAddress parseInetSocketAddress(String para) { } } - private static String getIp(List multiSrcUrls) { - ExecutorService executor = Executors.newCachedThreadPool( - BasicThreadFactory.builder().namingPattern("getIp").build()); + private static String getIp(List multiSrcUrls, boolean isAskIpv4) { + int threadSize = multiSrcUrls.size(); + ExecutorService executor = Executors.newFixedThreadPool(threadSize, + BasicThreadFactory.builder().namingPattern("getIp-%d").build()); CompletionService completionService = new ExecutorCompletionService<>(executor); - List> tasks = new ArrayList<>(); - multiSrcUrls.forEach(url -> tasks.add(() -> getExternalIp(url))); - - for (Callable task : tasks) { - completionService.submit(task); + for (String url : multiSrcUrls) { + completionService.submit(() -> getExternalIp(url, isAskIpv4)); } - Future future; - String result = null; - try { - future = completionService.take(); - result = future.get(); - } catch (InterruptedException | ExecutionException e) { - //ignore - } finally { - executor.shutdownNow(); + String ip = null; + for (int i = 0; i < threadSize; i++) { + try { + //block until any result return + Future f = completionService.take(); + String result = f.get(); + if (StringUtils.isNotEmpty(result)) { + ip = result; + break; + } + } catch (Exception ignored) { + //ignore + } } - return result; + executor.shutdownNow(); + return ip; } public static String getLanIP() { diff --git a/src/test/java/org/tron/p2p/utils/NetUtilTest.java b/src/test/java/org/tron/p2p/utils/NetUtilTest.java index 78fb5b5..1240465 100644 --- a/src/test/java/org/tron/p2p/utils/NetUtilTest.java +++ b/src/test/java/org/tron/p2p/utils/NetUtilTest.java @@ -1,15 +1,13 @@ package org.tron.p2p.utils; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.InetSocketAddress; import org.junit.Assert; import org.junit.Test; import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; -import java.net.InetSocketAddress; - public class NetUtilTest { @Test @@ -83,11 +81,11 @@ public void testGetIP() { //notice: please check that you only have one externalIP String ip1 = null, ip2 = null, ip3 = null; try { - Method method = NetUtil.class.getDeclaredMethod("getExternalIp", String.class); + Method method = NetUtil.class.getDeclaredMethod("getExternalIp", String.class, boolean.class); method.setAccessible(true); - ip1 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(0)); - ip2 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(1)); - ip3 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(2)); + ip1 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(0), true); + ip2 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(1), true); + ip3 = (String) method.invoke(NetUtil.class, Constant.ipV4Urls.get(2), true); } catch (Exception e) { Assert.fail(); } From d3f1aaf49d63ab8937e1bc093daf2a33c14b6615 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 24 Oct 2025 17:19:32 +0800 Subject: [PATCH 16/20] hotfix(net): return null if ip is invalid (#121) * return null if ip is invalid --- src/main/java/org/tron/p2p/example/README.md | 6 +++--- src/main/java/org/tron/p2p/utils/NetUtil.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/tron/p2p/example/README.md b/src/main/java/org/tron/p2p/example/README.md index fded407..4968735 100644 --- a/src/main/java/org/tron/p2p/example/README.md +++ b/src/main/java/org/tron/p2p/example/README.md @@ -226,10 +226,10 @@ New p2p config instance P2pConfig config = new P2pConfig(); ``` -Set p2p version +Set p2p networkId (also called p2p version) ```bash -config.setVersion(11111); +config.setNetworkId(11111); ``` Set TCP and UDP listen port @@ -416,6 +416,6 @@ p2pService.start(config); ``` For details please -check [ImportUsing](https://github.com/tronprotocol/libp2p/blob/develop/src/main/java/org/tron/p2p/example/ImportUsing.java), [DnsExample1](https://github.com/tronprotocol/libp2p/blob/develop/src/main/java/org/tron/p2p/example/DnsExample1.java), [DnsExample2](https://github.com/tronprotocol/libp2p/blob/develop/src/main/java/org/tron/p2p/example/DnsExample2.java) +check [ImportUsing](ImportUsing.java), [DnsExample1](DnsExample1.java), [DnsExample2](DnsExample2.java) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 7f85cfc..f9ad9c1 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -93,8 +93,8 @@ private static String getExternalIp(String url, boolean isAskIpv4) { String ip = null; try { URLConnection urlConnection = new URL(url).openConnection(); - urlConnection.setConnectTimeout(30_000); //ms - urlConnection.setReadTimeout(30_000); //ms + urlConnection.setConnectTimeout(10_000); //ms + urlConnection.setReadTimeout(10_000); //ms in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream())); ip = in.readLine(); if (ip == null || ip.trim().isEmpty()) { @@ -111,7 +111,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { } catch (Exception e) { log.warn("Fail to get {} by {}, cause:{}", Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, e.getMessage()); - return ip; + return null; } finally { if (in != null) { try { From 61cba5e8d9ed3841b4d2898773f866992d956fcb Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Fri, 24 Oct 2025 17:19:58 +0800 Subject: [PATCH 17/20] feature(net): use networkInterfaces to get lan ip (#122) * use networkInterfaces to get lan ip * add 2 more ipV6Urls * add testcase to compare old lan ip with new lan ip --- src/main/java/org/tron/p2p/base/Constant.java | 3 +- src/main/java/org/tron/p2p/utils/NetUtil.java | 38 +++++++++++++++---- .../java/org/tron/p2p/utils/NetUtilTest.java | 14 +++++++ 3 files changed, 47 insertions(+), 8 deletions(-) diff --git a/src/main/java/org/tron/p2p/base/Constant.java b/src/main/java/org/tron/p2p/base/Constant.java index cea5c1f..b87cfa2 100644 --- a/src/main/java/org/tron/p2p/base/Constant.java +++ b/src/main/java/org/tron/p2p/base/Constant.java @@ -9,7 +9,8 @@ public class Constant { public static final List ipV4Urls = Arrays.asList( "http://checkip.amazonaws.com", "https://ifconfig.me/ip", "https://4.ipw.cn/"); public static final List ipV6Urls = Arrays.asList( - "https://v6.ident.me", "http://6.ipw.cn/"); + "https://v6.ident.me", "http://6.ipw.cn/", "https://api6.ipify.org", + "https://ipv6.icanhazip.com"); public static final String ipV4Hex = "00000000"; //32 bit public static final String ipV6Hex = "00000000000000000000000000000000"; //128 bit } diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index f9ad9c1..d1682df 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -3,6 +3,7 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; +import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; @@ -42,6 +43,8 @@ public class NetUtil { public static final Pattern PATTERN_IPv6 = Pattern.compile( "^\\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}))|:)))(%.+)?\\s*$"); + private static final String IPADDRESS_LOCALHOST = "127.0.0.1"; + public static boolean validIpV4(String ip) { if (StringUtils.isEmpty(ip)) { return false; @@ -244,13 +247,34 @@ private static String getIp(List multiSrcUrls, boolean isAskIpv4) { } public static String getLanIP() { - String lanIP; - try (Socket s = new Socket("www.baidu.com", 80)) { - lanIP = s.getLocalAddress().getHostAddress(); - } catch (IOException e) { - log.warn("Can't get lan IP. Fall back to 127.0.0.1: " + e); - lanIP = "127.0.0.1"; + Enumeration networkInterfaces; + try { + networkInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (SocketException e) { + log.warn("Can't get lan IP. Fall back to {}", IPADDRESS_LOCALHOST, e); + return IPADDRESS_LOCALHOST; + } + while (networkInterfaces.hasMoreElements()) { + NetworkInterface ni = networkInterfaces.nextElement(); + try { + if (!ni.isUp() || ni.isLoopback() || ni.isVirtual()) { + continue; + } + } catch (SocketException e) { + continue; + } + Enumeration inetAds = ni.getInetAddresses(); + while (inetAds.hasMoreElements()) { + InetAddress inetAddress = inetAds.nextElement(); + if (inetAddress instanceof Inet4Address && !isReservedAddress(inetAddress)) { + String ipAddress = inetAddress.getHostAddress(); + if (PATTERN_IPv4.matcher(ipAddress).find()) { + return ipAddress; + } + } + } } - return lanIP; + log.warn("Can't get lan IP. Fall back to {}", IPADDRESS_LOCALHOST); + return IPADDRESS_LOCALHOST; } } diff --git a/src/test/java/org/tron/p2p/utils/NetUtilTest.java b/src/test/java/org/tron/p2p/utils/NetUtilTest.java index 1240465..f78f8fa 100644 --- a/src/test/java/org/tron/p2p/utils/NetUtilTest.java +++ b/src/test/java/org/tron/p2p/utils/NetUtilTest.java @@ -1,7 +1,9 @@ package org.tron.p2p.utils; +import java.io.IOException; import java.lang.reflect.Method; import java.net.InetSocketAddress; +import java.net.Socket; import org.junit.Assert; import org.junit.Test; import org.tron.p2p.base.Constant; @@ -95,10 +97,22 @@ public void testGetIP() { Assert.assertEquals(ip3, ip4); } + private String getLanIP2() { + String lanIP; + try (Socket s = new Socket("www.baidu.com", 80)) { + lanIP = s.getLocalAddress().getHostAddress(); + } catch (IOException e) { + lanIP = "127.0.0.1"; + } + return lanIP; + } + @Test public void testGetLanIP() { String lanIpv4 = NetUtil.getLanIP(); Assert.assertNotNull(lanIpv4); + String lanIpv4Old = getLanIP2(); + Assert.assertEquals(lanIpv4, lanIpv4Old); } @Test From 79f9225766b0e52e76bcf2a07e34cd481e5e2e9f Mon Sep 17 00:00:00 2001 From: halibobo1205 <82020050+halibobo1205@users.noreply.github.com> Date: Fri, 7 Nov 2025 18:17:08 +0800 Subject: [PATCH 18/20] feat(CI): add publish (#124) --- .../gradle-generate-publish-artifacts.yml | 388 ++++++++++++++++++ build.gradle | 7 + 2 files changed, 395 insertions(+) create mode 100644 .github/workflows/gradle-generate-publish-artifacts.yml diff --git a/.github/workflows/gradle-generate-publish-artifacts.yml b/.github/workflows/gradle-generate-publish-artifacts.yml new file mode 100644 index 0000000..753a2de --- /dev/null +++ b/.github/workflows/gradle-generate-publish-artifacts.yml @@ -0,0 +1,388 @@ +name: Build - Artifacts + +on: + workflow_dispatch: + inputs: + ref: + description: 'Git ref (branch/tag/commit)' + required: false + default: 'main' + type: string + +permissions: + id-token: write + contents: read + +env: + # build.gradle $buildDir/repo + CUSTOM_REPO_PATH: ${{ github.workspace }}/build/repo + CUSTOM_DOWNLOAD_PATH: ${{ github.workspace }}/download/artifacts + +jobs: + build: + runs-on: ubuntu-latest + outputs: + group: ${{ steps.set-outputs.outputs.group }} + project: ${{ steps.set-outputs.outputs.project }} + version: ${{ steps.set-outputs.outputs.version }} + + steps: + - name: Validate trigger source + run: | + set -euo pipefail + if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then + echo "✅: Manual workflow dispatch" + else + echo "❌: This workflow should only be manually dispatched" + exit 1 + fi + + - name: Checkout repository + uses: actions/checkout@v5 + with: + ref: ${{ inputs.ref }} + + - name: Set up JDK 8 + uses: actions/setup-java@v5 + with: + java-version: '8' + distribution: 'temurin' + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-read-only: false + + - name: Extract Project Info + run: | + set -euo pipefail + GROUP=$(grep -E "^group\s+'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true) + VERSION=$(grep -E "^version\s+'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true) + PROJECT=$(grep -E "^rootProject\.name\s*=\s*'[^']+'" build.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true) + if [ -z "$PROJECT" ] && [ -f "settings.gradle" ]; then + PROJECT=$(grep -E "^rootProject\.name\s*=\s*'[^']+'" settings.gradle | sed -E "s/.*'([^']+)'.*/\1/" || true) + fi + + if [ -z "$GROUP" ] || [ -z "$PROJECT" ] || [ -z "$VERSION" ]; then + echo "❌: Missing group/project/version in build.gradle" + exit 1 + fi + + echo "group=$GROUP" >> $GITHUB_ENV + echo "project=$PROJECT" >> $GITHUB_ENV + echo "version=$VERSION" >> $GITHUB_ENV + + GROUP_PATH=$(echo "$GROUP" | tr '.' '/') + echo "MAVEN_GROUP_PATH=$GROUP_PATH" >> $GITHUB_ENV + + ARTIFACT_PATH="${{ env.CUSTOM_REPO_PATH }}/$GROUP_PATH/$PROJECT/$VERSION" + echo "ARTIFACT_PATH=$ARTIFACT_PATH" >> $GITHUB_ENV + + echo "✅ Project: $PROJECT, Version: $VERSION, Group: $GROUP" + + - name: Publish to CI Maven repository + run: ./gradlew clean -xtest -xcheck --refresh-dependencies publishAllPublicationsToCiLocalRepository + + - name: Verify artifacts and checksums + run: | + set -euo pipefail + if [ ! -d "${{ env.ARTIFACT_PATH }}" ]; then + echo "❌: Artifacts not found at ${{ env.ARTIFACT_PATH }}" + exit 1 + fi + + REQUIRED_FILES=( + "${{ env.project }}-${{ env.version }}.jar" + "${{ env.project }}-${{ env.version }}.jar.md5" + "${{ env.project }}-${{ env.version }}.jar.sha1" + "${{ env.project }}-${{ env.version }}.jar.sha256" + "${{ env.project }}-${{ env.version }}.jar.sha512" + "${{ env.project }}-${{ env.version }}.module" + "${{ env.project }}-${{ env.version }}.module.md5" + "${{ env.project }}-${{ env.version }}.module.sha1" + "${{ env.project }}-${{ env.version }}.module.sha256" + "${{ env.project }}-${{ env.version }}.module.sha512" + "${{ env.project }}-${{ env.version }}.pom" + "${{ env.project }}-${{ env.version }}.pom.md5" + "${{ env.project }}-${{ env.version }}.pom.sha1" + "${{ env.project }}-${{ env.version }}.pom.sha256" + "${{ env.project }}-${{ env.version }}.pom.sha512" + "${{ env.project }}-${{ env.version }}-javadoc.jar" + "${{ env.project }}-${{ env.version }}-javadoc.jar.md5" + "${{ env.project }}-${{ env.version }}-javadoc.jar.sha1" + "${{ env.project }}-${{ env.version }}-javadoc.jar.sha256" + "${{ env.project }}-${{ env.version }}-javadoc.jar.sha512" + "${{ env.project }}-${{ env.version }}-sources.jar" + "${{ env.project }}-${{ env.version }}-sources.jar.md5" + "${{ env.project }}-${{ env.version }}-sources.jar.sha1" + "${{ env.project }}-${{ env.version }}-sources.jar.sha256" + "${{ env.project }}-${{ env.version }}-sources.jar.sha512" + ) + + MISSING_FILES=() + for file in "${REQUIRED_FILES[@]}"; do + if [ ! -f "${{ env.ARTIFACT_PATH }}/$file" ]; then + MISSING_FILES+=("$file") + fi + done + + if [ ${#MISSING_FILES[@]} -gt 0 ]; then + echo "❌ Missing required files:" + for f in "${MISSING_FILES[@]}"; do echo " - $f"; done + exit 1 + fi + + echo "✅ All required files verified (${#REQUIRED_FILES[@]} files)" + + - name: Remove Maven metadata files + run: | + set -euo pipefail + DELETED_COUNT=$(find ${{ env.CUSTOM_REPO_PATH }} -name "maven-metadata*" -type f -delete -print | wc -l) + echo "✅ Removed $DELETED_COUNT Maven metadata files" + + - name: Upload publish files + uses: actions/upload-artifact@v4 + with: + name: ${{ env.project }}-${{ env.version }}-artifacts + path: ${{ env.CUSTOM_REPO_PATH }}/ + if-no-files-found: error + retention-days: 30 + + - name: Set Outputs + id: set-outputs + run: | + set -euo pipefail + echo "group=${{ env.MAVEN_GROUP_PATH }}" >> $GITHUB_OUTPUT + echo "project=${{ env.project }}" >> $GITHUB_OUTPUT + echo "version=${{ env.version }}" >> $GITHUB_OUTPUT + + - name: Generate summary + run: | + set -euo pipefail + COMMIT_ID=$(git rev-parse HEAD) + COMMIT_MSG=$(git log -1 --pretty=%B) + echo "## Build Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Project:** ${{ env.project }}" >> $GITHUB_STEP_SUMMARY + echo "- **Version:** ${{ env.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Group:** ${{ env.MAVEN_GROUP_PATH }}" >> $GITHUB_STEP_SUMMARY + echo "- **Git Ref:** ${{ inputs.ref }}" >> $GITHUB_STEP_SUMMARY + echo "- **Commit ID:** $COMMIT_ID" >> $GITHUB_STEP_SUMMARY + echo "- **Commit Message:** $COMMIT_MSG" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + echo "### Local Repository Files" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + ls -lh "${{ env.ARTIFACT_PATH }}" >> $GITHUB_STEP_SUMMARY + echo "\`\`\`" >> $GITHUB_STEP_SUMMARY + echo "- **Artifact Check:** ✓ All required files present" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + sign-and-upload: + runs-on: self-hosted + needs: build + steps: + - name: Validate secrets + run: | + set -euo pipefail + if [ -z "${{ secrets.GPG_FINGERPRINT }}" ]; then + echo "❌: GPG_FINGERPRINT secret not configured" + exit 1 + fi + if [ -z "${{ secrets.S3_BUCKET_PRE_STAGE }}" ]; then + echo "❌: S3_BUCKET_PRE_STAGE secret not configured" + exit 1 + fi + if [ -z "${{ secrets.AWS_ROLE_ARN_PRE_STAGE_UPLOAD }}" ]; then + echo "❌: AWS_ROLE_ARN_PRE_STAGE_UPLOAD secret not configured" + exit 1 + fi + if [ -z "${{ secrets.AWS_REGION }}" ]; then + echo "❌: AWS_REGION secret not configured" + exit 1 + fi + echo "✅ All required secrets configured" + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-artifacts + path: ${{ env.CUSTOM_DOWNLOAD_PATH }} + + - name: Verify downloaded artifacts + run: | + set -euo pipefail + FULL_PATH="${{ env.CUSTOM_DOWNLOAD_PATH }}/${{ needs.build.outputs.group }}/${{ needs.build.outputs.project }}/${{ needs.build.outputs.version }}" + if [ ! -d "$FULL_PATH" ]; then + echo "❌: Downloaded artifacts not found at expected path" + exit 1 + fi + FILE_COUNT=$(find "$FULL_PATH" -type f | wc -l) + echo "✅: Downloaded $FILE_COUNT files to $FULL_PATH" + echo "FULL_PATH=$FULL_PATH" >> $GITHUB_ENV + + - name: Wait for hardware key (YubiKey/HSM) + run: | + set -euo pipefail + echo "⏳ Waiting for GPG hardware key..." + MAX_RETRIES=60 + RETRY_INTERVAL=2 + for i in $(seq 1 $MAX_RETRIES); do + if gpg --card-status > /dev/null 2>&1; then + echo "✅: GPG hardware key detected and ready (after $((i*RETRY_INTERVAL))s)" + break + fi + echo "[$i/$MAX_RETRIES] Hardware key not detected, retrying in ${RETRY_INTERVAL}s..." + sleep $RETRY_INTERVAL + done + + if ! gpg --card-status > /dev/null 2>&1; then + echo "❌ Timeout waiting for hardware key after $((MAX_RETRIES*RETRY_INTERVAL)) seconds" + exit 1 + fi + + - name: Sign artifacts + run: | + set -euo pipefail + cd "${{ env.FULL_PATH }}" + + PREFIX="${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}" + FILES=( + "${PREFIX}.jar" + "${PREFIX}.module" + "${PREFIX}-sources.jar" + "${PREFIX}-javadoc.jar" + "${PREFIX}.pom" + ) + + compute_md5() { + if command -v md5sum >/dev/null 2>&1; then + md5sum "$1" | awk '{print $1}' + else + md5 "$1" | awk '{print $4}' + fi + } + + SIGNED_COUNT=0 + for file in "${FILES[@]}"; do + if [ ! -f "$file" ]; then + echo "❌ Missing file to sign: $file" + exit 1 + fi + echo "Signing $file..." + gpg --quiet --batch --yes --local-user ${{ secrets.GPG_FINGERPRINT }} --armor --detach-sign "$file" + compute_md5 ${file}.asc > ${file}.asc.md5 + shasum -a 1 ${file}.asc | awk '{print $1}' > ${file}.asc.sha1 + shasum -a 256 ${file}.asc | awk '{print $1}' > ${file}.asc.sha256 + shasum -a 512 ${file}.asc | awk '{print $1}' > ${file}.asc.sha512 + SIGNED_COUNT=$((SIGNED_COUNT + 1)) + done + echo "✓ Successfully signed $SIGNED_COUNT files" + + - name: Verify signatures + run: | + set -euo pipefail + cd "${{ env.FULL_PATH }}" + VERIFIED_COUNT=0 + FAILED_SIGS=() + for sig in *.asc; do + if [ -f "$sig" ]; then + echo "Verifying $sig..." + if ! gpg --verify "$sig" "${sig%.asc}" > /dev/null 2>&1; then + FAILED_SIGS+=("$sig") + else + VERIFIED_COUNT=$((VERIFIED_COUNT + 1)) + fi + fi + done + + if [ ${#FAILED_SIGS[@]} -gt 0 ]; then + echo "❌ Signature verification failed for: ${FAILED_SIGS[*]}" + exit 1 + fi + echo "✅ All $VERIFIED_COUNT signatures verified" + + - name: Zip signed artifacts + run: | + set -euo pipefail + cd ${{ env.CUSTOM_DOWNLOAD_PATH }} + BUNDLE_NAME="${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-bundle.zip" + zip -r "$BUNDLE_NAME" ${{ needs.build.outputs.group }} >/dev/null + if [ ! -f "$BUNDLE_NAME" ]; then + echo "❌ Error: Bundle file not created" + exit 1 + fi + + BUNDLE_SIZE=$(du -h "$BUNDLE_NAME" | cut -f1) + echo "✓ Bundle created: $BUNDLE_NAME (${BUNDLE_SIZE})" + echo "BUNDLE_NAME=$BUNDLE_NAME" >> $GITHUB_ENV + echo "BUNDLE_SIZE=$BUNDLE_SIZE" >> $GITHUB_ENV + + - name: Verify bundle contents + run: | + set -euo pipefail + cd ${{ env.CUSTOM_DOWNLOAD_PATH }} + echo "Bundle contents:" + unzip -l "${{ env.BUNDLE_NAME }}" | head -50 + + ASC_COUNT=$(unzip -l "${{ env.BUNDLE_NAME }}" | grep -c "\.asc$" || true) + if [ "$ASC_COUNT" -lt 5 ]; then + echo "❌ Bundle missing signature files (found $ASC_COUNT)" + exit 1 + fi + echo "✅ Bundle verified: contains $ASC_COUNT signature files" + + - name: Upload signed bundle + uses: actions/upload-artifact@v4 + with: + name: ${{ needs.build.outputs.project }}-${{ needs.build.outputs.version }}-bundle + path: ${{ env.CUSTOM_DOWNLOAD_PATH }}/${{ env.BUNDLE_NAME }} + retention-days: 30 + + - name: Configure AWS Credentials (OIDC) + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN_PRE_STAGE_UPLOAD }} + aws-region: ${{ secrets.AWS_REGION }} + + - name: Upload artifacts to S3 + run: | + set -euo pipefail + cd ${{ env.CUSTOM_DOWNLOAD_PATH }} + + DEST="s3://${{ secrets.S3_BUCKET_PRE_STAGE }}" + if [ -n "${{ secrets.S3_PREFIX }}" ]; then + DEST="$DEST/${{ secrets.S3_PREFIX }}" + fi + DEST="$DEST/${{ needs.build.outputs.version }}" + echo "Uploading ${{ env.BUNDLE_NAME }}" + aws s3 cp "${{ env.BUNDLE_NAME }}" "$DEST/" --only-show-errors + echo "✅ Successfully uploaded to S3" + + - name: Generate upload summary + if: success() + run: | + set -euo pipefail + echo "## ✅ Artifact Signing & Upload Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Project Information" >> $GITHUB_STEP_SUMMARY + echo "- **Project:** ${{ needs.build.outputs.project }}" >> $GITHUB_STEP_SUMMARY + echo "- **Version:** ${{ needs.build.outputs.version }}" >> $GITHUB_STEP_SUMMARY + echo "- **Group Path:** ${{ needs.build.outputs.group }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Bundle Details" >> $GITHUB_STEP_SUMMARY + echo "- **Bundle Name:** \`${{ env.BUNDLE_NAME }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Bundle Size:** ${{ env.BUNDLE_SIZE }}" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "### Signed Files" >> $GITHUB_STEP_SUMMARY + find "${{ env.FULL_PATH }}" -type f -name "*.asc" -exec basename {} \; | sed 's/^/- /' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "**Upload Time:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + - name: Cleanup downloaded artifacts + if: always() + run: | + set -euo pipefail + rm -rf "${{ env.CUSTOM_DOWNLOAD_PATH }}" || true + echo "✅ Cleaned up downloaded artifacts" diff --git a/build.gradle b/build.gradle index 93d37ca..115a68e 100644 --- a/build.gradle +++ b/build.gradle @@ -191,6 +191,13 @@ artifacts { processResources.dependsOn(generateProto) // explicit_dependency publishing { + repositories { + // CI + maven { + name = 'ciLocal' + url = "$buildDir/repo" + } + } publications { mavenJava(MavenPublication) { from components.java From 490cc46bd38577a497e2567589c06fb27271ab15 Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Mon, 10 Nov 2025 17:29:02 +0800 Subject: [PATCH 19/20] hotfix(gradle): add developers for publishing on maven (#125) * add developers to publish --- build.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/build.gradle b/build.gradle index 115a68e..914ca9b 100644 --- a/build.gradle +++ b/build.gradle @@ -213,6 +213,12 @@ publishing { url = 'http://www.apache.org/licenses/LICENSE-2.0.txt' } } + developers { + developer { + name = 'chengtx01' + email = 'ctxhorse@gmail.com' + } + } scm { url = 'https://github.com/tronprotocol/libp2p' connection = 'scm:git:git://github.com/tronprotocol/libp2p.git' From a2c289dd61b82fb70351d26528d0fb71a70d9db9 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 11 Nov 2025 18:18:27 +0800 Subject: [PATCH 20/20] merge main into 2.2.8 --- .../business/pool/ConnPoolService.java | 6 ++++ .../discover/protocol/kad/NodeHandler.java | 12 ++++++++ .../protocol/kad/table/NodeTable.java | 19 +++++++++++-- .../protocol/kad/NodeHandlerTest.java | 28 +++++++++++++++++++ 4 files changed, 63 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java b/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java index 81523d6..6996f86 100644 --- a/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java +++ b/src/main/java/org/tron/p2p/connection/business/pool/ConnPoolService.java @@ -60,6 +60,7 @@ public class ConnPoolService extends P2pEventHandler { public P2pConfig p2pConfig = Parameter.p2pConfig; private PeerClient peerClient; private final List configActiveNodes = new ArrayList<>(); + private int minCandidateSize = 50; public ConnPoolService() { this.messageTypes = new HashSet<>(); //no message type registers @@ -217,6 +218,11 @@ public List getNodes(Set nodesInUse, Set inetIn } filtered.sort(Comparator.comparingLong(node -> -node.getUpdateTime())); + int candidateSize = Math.max(limit * 10, minCandidateSize); + if (filtered.size() > candidateSize) { + filtered = filtered.subList(0, candidateSize); + } + Collections.shuffle(filtered); return CollectionUtils.truncate(filtered, limit); } diff --git a/src/main/java/org/tron/p2p/discover/protocol/kad/NodeHandler.java b/src/main/java/org/tron/p2p/discover/protocol/kad/NodeHandler.java index de42c5f..5206a6b 100644 --- a/src/main/java/org/tron/p2p/discover/protocol/kad/NodeHandler.java +++ b/src/main/java/org/tron/p2p/discover/protocol/kad/NodeHandler.java @@ -24,6 +24,8 @@ public class NodeHandler { private AtomicInteger pingTrials = new AtomicInteger(3); private volatile boolean waitForPong = false; private volatile boolean waitForNeighbors = false; + private volatile int findNodeFail; + private static int maxFindNodeFailures = 5; public NodeHandler(Node node, KadService kadService) { this.node = node; @@ -130,6 +132,7 @@ public void handleNeighbours(NeighborsMessage msg, InetSocketAddress sender) { log.warn("Receive neighbors from {} without send find nodes", sender); return; } + findNodeFail = 0; waitForNeighbors = false; for (Node n : msg.getNodes()) { if (!kadService.getPublicHomeNode().getHexId().equals(n.getHexId())) { @@ -182,6 +185,15 @@ public void sendPong() { } public void sendFindNode(byte[] target) { + if (waitForNeighbors) { + findNodeFail++; + if (findNodeFail >= maxFindNodeFailures) { + if (kadService.getTable().failFindNode(node)) { + changeState(State.DEAD); + return; + } + } + } waitForNeighbors = true; FindNodeMessage msg = new FindNodeMessage(kadService.getPublicHomeNode(), target); sendMessage(msg); diff --git a/src/main/java/org/tron/p2p/discover/protocol/kad/table/NodeTable.java b/src/main/java/org/tron/p2p/discover/protocol/kad/table/NodeTable.java index 274f5ca..da0544a 100644 --- a/src/main/java/org/tron/p2p/discover/protocol/kad/table/NodeTable.java +++ b/src/main/java/org/tron/p2p/discover/protocol/kad/table/NodeTable.java @@ -7,6 +7,8 @@ import java.util.Map; import org.tron.p2p.discover.Node; +import static org.tron.p2p.discover.protocol.kad.table.KademliaOptions.BUCKET_SIZE; + public class NodeTable { private final Node node; // our node private transient NodeBucket[] buckets; @@ -91,6 +93,19 @@ public synchronized List getAllNodes() { return new ArrayList<>(nodes.values()); } + public synchronized boolean failFindNode(Node n) { + NodeEntry entry = nodes.get(n.getHostKey()); + if (entry == null) { + return false; + } + if (buckets[getBucketId(entry)].getNodes().size() >= BUCKET_SIZE / 4) { + nodes.remove(n.getHostKey()); + buckets[getBucketId(entry)].dropNode(entry); + return true; + } + return false; + } + public synchronized List getClosestNodes(byte[] targetId) { List closestEntries = getAllNodes(); List closestNodes = new ArrayList<>(); @@ -98,8 +113,8 @@ public synchronized List getClosestNodes(byte[] targetId) { closestNodes.add((Node) e.getNode().clone()); } Collections.sort(closestNodes, new DistanceComparator(targetId)); - if (closestNodes.size() > KademliaOptions.BUCKET_SIZE) { - closestNodes = closestNodes.subList(0, KademliaOptions.BUCKET_SIZE); + if (closestNodes.size() > BUCKET_SIZE) { + closestNodes = closestNodes.subList(0, BUCKET_SIZE); } return closestNodes; } diff --git a/src/test/java/org/tron/p2p/discover/protocol/kad/NodeHandlerTest.java b/src/test/java/org/tron/p2p/discover/protocol/kad/NodeHandlerTest.java index 215e419..d9f1ff9 100644 --- a/src/test/java/org/tron/p2p/discover/protocol/kad/NodeHandlerTest.java +++ b/src/test/java/org/tron/p2p/discover/protocol/kad/NodeHandlerTest.java @@ -1,5 +1,6 @@ package org.tron.p2p.discover.protocol.kad; +import org.checkerframework.checker.units.qual.N; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -9,6 +10,7 @@ import org.tron.p2p.discover.Node; import org.tron.p2p.discover.message.kad.PingMessage; import org.tron.p2p.discover.message.kad.PongMessage; +import org.tron.p2p.utils.NetUtil; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -81,6 +83,32 @@ public void testChangeState() throws Exception { Assert.assertTrue(kadService.getTable().contains(replaceNode)); } + @Test + public void testSendFindNode() throws Exception { + byte[] nodeId = NetUtil.getNodeId(); + Node node = new Node(nodeId, "127.0.0.1", "", 1); + NodeHandler handler = new NodeHandler(node, kadService); + + kadService.getTable().addNode(node); + + for (int i = 0; i < 2; i++) { + String ip = "127.0.1." + i; + kadService.getTable().addNode(new Node(nodeId, ip, "", 1)); + } + + for (int i = 0; i < 6; i++) { + handler.sendFindNode(NetUtil.getNodeId()); + } + + Assert.assertFalse(handler.getState().equals(NodeHandler.State.DEAD)); + + kadService.getTable().addNode(new Node(nodeId, "127.0.1.4", "", 1)); + + handler.sendFindNode(NetUtil.getNodeId()); + + Assert.assertTrue(handler.getState().equals(NodeHandler.State.DEAD)); + } + @AfterClass public static void destroy() { kadService.close();