From a4b1d1c5f83d6fc335550f2850009058c96bfcba Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 30 Sep 2025 14:44:37 +0800 Subject: [PATCH 01/11] Retrieve the public IPv6 address within a LAN environment --- src/main/java/org/tron/p2p/base/Constant.java | 1 + src/main/java/org/tron/p2p/utils/NetUtil.java | 148 ++++++++++++++---- .../{logback.xml.example => logback.xml} | 0 3 files changed, 117 insertions(+), 32 deletions(-) rename src/main/resources/{logback.xml.example => logback.xml} (100%) 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/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 9a1be29..8ee61c4 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -11,15 +11,14 @@ import java.net.SocketException; import java.net.URL; import java.net.URLConnection; -import java.util.ArrayList; +import java.net.UnknownHostException; 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; @@ -27,14 +26,23 @@ import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.concurrent.BasicThreadFactory; 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,113 @@ 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) { BufferedReader in = null; String ip = null; + String domain = null; try { - URLConnection urlConnection = new URL(url).openConnection(); + URL uri = new URL(url); + domain = uri.getHost(); + URLConnection urlConnection = uri.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; try { - InetAddress.getByName(ip); - } catch (Exception e) { + inetAddress = InetAddress.getByName(ip); + } catch (UnknownHostException e) { + throw new IOException("Invalid address: " + 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:{}", + log.debug("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 (!isAskIpv4 && StringUtils.isEmpty(ip) && StringUtils.isNotEmpty(domain)) { + try { + ip = getExternalIPv6ByDoh(domain); + } catch (Exception e) { + // ignore + } + } + if (StringUtils.isNotEmpty(ip)) { + log.info("Get {} from {} successfully", isAskIpv4 ? "ipv4" : "ipv6", url); + } + 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 +258,15 @@ 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); + //System.setProperty("java.net.preferIPv6Addresses ", "true"); + String ipV6 = getIp(Constant.ipV6Urls, false); if (null == ipV6) { ipV6 = getOuterIPv6Address(); } @@ -212,30 +294,32 @@ public static InetSocketAddress parseInetSocketAddress(String para) { } } - private static String getIp(List multiSrcUrls) { - ExecutorService executor = Executors.newCachedThreadPool( - new BasicThreadFactory.Builder().namingPattern("getIp").build()); + private static String getIp(List multiSrcUrls, boolean isAskIpv4) { + int threadSize = multiSrcUrls.size(); + ExecutorService executor = Executors.newFixedThreadPool(threadSize); 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/main/resources/logback.xml.example b/src/main/resources/logback.xml similarity index 100% rename from src/main/resources/logback.xml.example rename to src/main/resources/logback.xml From ba212a130cb613d59faf8bb7f28737e8c1e44802 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 1 Oct 2025 10:49:43 +0800 Subject: [PATCH 02/11] amend the log level --- src/main/java/org/tron/p2p/example/StartApp.java | 4 +--- src/main/java/org/tron/p2p/utils/NetUtil.java | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) 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 8ee61c4..028bea6 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -145,7 +145,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { } } if (StringUtils.isNotEmpty(ip)) { - log.info("Get {} from {} successfully", isAskIpv4 ? "ipv4" : "ipv6", url); + log.debug("Get {} from {} successfully", isAskIpv4 ? "ipv4" : "ipv6", url); } return ip; } From cc871bf445515f4d00409134247341888394935f Mon Sep 17 00:00:00 2001 From: 317787106 <317787106@qq.com> Date: Wed, 1 Oct 2025 11:03:54 +0800 Subject: [PATCH 03/11] Rename logback.xml to logback.xml.example --- src/main/resources/{logback.xml => logback.xml.example} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/resources/{logback.xml => logback.xml.example} (100%) diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml.example similarity index 100% rename from src/main/resources/logback.xml rename to src/main/resources/logback.xml.example From 5f9502d58fbd1f9cee7aec6c0521c4f73bebceb5 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 9 Oct 2025 17:40:52 +0800 Subject: [PATCH 04/11] add thread name --- src/main/java/org/tron/p2p/utils/NetUtil.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 028bea6..76783e4 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -26,6 +26,7 @@ import java.util.regex.Pattern; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; import org.tron.p2p.base.Constant; import org.tron.p2p.discover.Node; import org.tron.p2p.protos.Discover; @@ -296,7 +297,8 @@ public static InetSocketAddress parseInetSocketAddress(String para) { private static String getIp(List multiSrcUrls, boolean isAskIpv4) { int threadSize = multiSrcUrls.size(); - ExecutorService executor = Executors.newFixedThreadPool(threadSize); + ExecutorService executor = Executors.newFixedThreadPool(threadSize, + BasicThreadFactory.builder().namingPattern("getIp").build()); CompletionService completionService = new ExecutorCompletionService<>(executor); for (String url : multiSrcUrls) { 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 05/11] 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 9d188067c9aae76173aea8457b2aa8ef003227a2 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 10 Oct 2025 14:36:50 +0800 Subject: [PATCH 06/11] drop unnecessary throw Exception --- src/main/java/org/tron/p2p/utils/NetUtil.java | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 76783e4..780d246 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -11,7 +11,6 @@ import java.net.SocketException; import java.net.URL; import java.net.URLConnection; -import java.net.UnknownHostException; import java.util.Enumeration; import java.util.HashSet; import java.util.List; @@ -100,6 +99,7 @@ public static byte[] getNodeId() { } 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; @@ -112,12 +112,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { if (ip == null || ip.trim().isEmpty()) { throw new IOException("Invalid address: " + ip); } - InetAddress inetAddress; - try { - inetAddress = InetAddress.getByName(ip); - } catch (UnknownHostException e) { - throw new IOException("Invalid address: " + ip); - } + InetAddress inetAddress = InetAddress.getByName(ip); if (isAskIpv4 && !validIpV4(inetAddress.getHostAddress())) { throw new IOException("Invalid address: " + ip); } @@ -138,6 +133,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { } } + //if fails to get ipv6 directly, we use alternative method if (!isAskIpv4 && StringUtils.isEmpty(ip) && StringUtils.isNotEmpty(domain)) { try { ip = getExternalIPv6ByDoh(domain); @@ -155,7 +151,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { * 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 { + private 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() @@ -266,7 +262,6 @@ public static String getExternalIpV4() { public static String getExternalIpV6() { long t1 = System.currentTimeMillis(); - //System.setProperty("java.net.preferIPv6Addresses ", "true"); String ipV6 = getIp(Constant.ipV6Urls, false); if (null == ipV6) { ipV6 = getOuterIPv6Address(); From fb23485ab993367f9abbb02f7cd0c633d4a02e19 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 10 Oct 2025 14:58:40 +0800 Subject: [PATCH 07/11] optimize warn log of ipv6 --- src/main/java/org/tron/p2p/utils/NetUtil.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index 780d246..bdcec24 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -103,6 +103,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { BufferedReader in = null; String ip = null; String domain = null; + String errMsg = null; try { URL uri = new URL(url); domain = uri.getHost(); @@ -121,8 +122,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { } ip = inetAddress.getHostAddress(); } catch (Exception e) { - log.debug("Fail to get {} by {}, cause:{}", - Constant.ipV4Urls.contains(url) ? "ipv4" : "ipv6", url, e.getMessage()); + errMsg = e.getMessage(); } finally { if (in != null) { try { @@ -143,6 +143,9 @@ private static String getExternalIp(String url, boolean isAskIpv4) { } 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; } From ea59e56daff7332e1473357cb8f3f94e5f8a9a91 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 14 Oct 2025 11:25:26 +0800 Subject: [PATCH 08/11] add testcase testGetExternalIPv6ByDoh --- src/main/java/org/tron/p2p/utils/NetUtil.java | 2 +- .../java/org/tron/p2p/utils/NetUtilTest.java | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index bdcec24..a73fdbc 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -154,7 +154,7 @@ private static String getExternalIp(String url, boolean isAskIpv4) { * 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 */ - private static String getExternalIPv6ByDoh(String domain) throws Exception { + 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() 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 ef00d43b6d25f822fdca96bbefd878e7da4e41cd Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 14 Oct 2025 15:58:23 +0800 Subject: [PATCH 09/11] set ConnectTimeout and ReadTimeout for URLConnection --- src/main/java/org/tron/p2p/utils/NetUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/tron/p2p/utils/NetUtil.java b/src/main/java/org/tron/p2p/utils/NetUtil.java index a73fdbc..542ae88 100644 --- a/src/main/java/org/tron/p2p/utils/NetUtil.java +++ b/src/main/java/org/tron/p2p/utils/NetUtil.java @@ -108,6 +108,8 @@ private static String getExternalIp(String url, boolean isAskIpv4) { 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()) { 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 10/11] 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 11/11] 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<>();