Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ dependencies {
api 'org.aspectj:aspectjrt:1.9.8'
api 'org.aspectj:aspectjweaver:1.9.8'
api 'org.aspectj:aspectjtools:1.9.8'
api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{
api group: 'com.github.317787106', name: 'libp2p', version: 'v0.10.0',{
//api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{
Comment on lines +24 to +25
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

Does the io.github.tronprotocol:libp2p Maven artifact have a 2.2.8 release that exposes LookUpTxt.lookUpIp?

💡 Result:

No, the io.github.tronprotocol:libp2p Maven artifact does not have a 2.2.8 release. The latest available version is 2.2.7, released on November 12, 2025. No sources mention a 2.2.8 release on Maven Central, Sonatype Central, mvnrepository.com, or the project's GitHub releases page. No evidence was found for a class or method named LookUpTxt.lookUpIp in the libp2p codebase or documentation across all versions.

Citations:


🏁 Script executed:

#!/bin/bash
# Check what the new fork coordinate actually resolves to on JitPack and whether
# LookUpTxt.lookUpIp is referenced anywhere in this repo's sources.
rg -nP -C2 '\bLookUpTxt\b|lookUpIp\s*\('
# Show every Gradle file referencing libp2p to confirm no other module pins the old coord.
rg -nP --type=gradle -C1 'libp2p'

Repository: 317787106/java-tron

Length of output: 2290


Do not ship a personal JitPack fork of libp2p as the production dependency.

This replaces the official io.github.tronprotocol:libp2p:2.2.7 with com.github.317787106:libp2p:v0.10.0. The new group coordinate com.github.317787106 is a JitPack path that resolves to a personal GitHub account (user id 317787106), not the tronprotocol organization. Several critical problems:

  1. PR summary is incorrect. The PR description states the bump is libp2p 2.2.7 -> 2.2.8 to acquire LookUpTxt.lookUpIp, but this is misleading: io.github.tronprotocol:libp2p has no 2.2.8 release (latest is 2.2.7), and LookUpTxt.lookUpIp does not exist in the official libp2p codebase. The method exists only in the fork (com.github.317787106). The actual change is 2.2.7 -> v0.10.0 from a personal account — this is a material difference from what the commit message promises.

  2. The fork is not optional, making supply chain risk acute. Because LookUpTxt.lookUpIp is used in this codebase (see framework/src/main/java/org/tron/core/config/args/InetUtil.java lines 112, 114, 141, 143) and exists nowhere else, the fork dependency is not a temporary workaround—it is a production requirement for a mainnet node's core P2P configuration. This means the trust anchor is permanently anchored to an individual contributor's GitHub account rather than the Tron Protocol organization.

  3. Commented-out coordinate. Line 25 retains the old io.github.tronprotocol dependency as a comment. Dead config should not be merged. Its presence is a strong signal that this change was a development workaround that was never properly resolved upstream.

Recommended: Coordinate with the libp2p maintainers to release LookUpTxt.lookUpIp under the official io.github.tronprotocol org (e.g., as 2.2.8 or later), then revert to the official dependency. If that is not feasible in the release timeline, gate the fork behind a clearly labeled non-default profile and document the limitation and timeline for resolution in the PR. Do not merge commented-out code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@common/build.gradle` around lines 24 - 25, The build currently depends on a
personal JitPack fork (com.github.317787106:libp2p:v0.10.0) instead of the
official io.github.tronprotocol libp2p artifact; revert common/build.gradle to
use the official dependency (replace the com.github... coordinate with
io.github.tronprotocol:libp2p at the appropriate released version) or, if the
forked API (LookUpTxt.lookUpIp) is truly required and not yet upstream, move the
fork dependency behind a clearly named non-default Gradle profile (e.g.,
"jitpack-fork") and document that exception, and remove the commented-out
io.github.tronprotocol line so no dead config remains; also create a ticket to
coordinate with the libp2p maintainers to upstream LookUpTxt.lookUpIp (or get an
official 2.2.8+ release) so the fork can be removed.

exclude group: 'io.grpc', module: 'grpc-context'
exclude group: 'io.grpc', module: 'grpc-core'
exclude group: 'io.grpc', module: 'grpc-netty'
Expand Down
88 changes: 69 additions & 19 deletions framework/src/main/java/org/tron/common/backup/BackupManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@
import static org.tron.common.backup.BackupManager.BackupStatusEnum.MASTER;
import static org.tron.common.backup.BackupManager.BackupStatusEnum.SLAVER;
import static org.tron.common.backup.message.UdpMessageTypeEnum.BACKUP_KEEP_ALIVE;
import static org.tron.core.config.args.InetUtil.resolveInetAddress;

import io.netty.util.internal.ConcurrentSet;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.tron.common.backup.message.KeepAliveMessage;
Expand All @@ -20,46 +25,46 @@
import org.tron.common.backup.socket.UdpEvent;
import org.tron.common.es.ExecutorServiceManager;
import org.tron.common.parameter.CommonParameter;
import org.tron.p2p.utils.NetUtil;

@Slf4j(topic = "backup")
@Component
public class BackupManager implements EventHandler {

private CommonParameter parameter = CommonParameter.getInstance();
private final CommonParameter parameter = CommonParameter.getInstance();

private int priority = parameter.getBackupPriority();
private final int priority = parameter.getBackupPriority();

private int port = parameter.getBackupPort();
private final int port = parameter.getBackupPort();

private int keepAliveInterval = parameter.getKeepAliveInterval();
private final int keepAliveInterval = parameter.getKeepAliveInterval();

private int keepAliveTimeout = keepAliveInterval * 6;
private final int keepAliveTimeout = keepAliveInterval * 6;

private String localIp = "";

private Set<String> members = new ConcurrentSet<>();
private final Set<String> members = new ConcurrentSet<>();

private final String esName = "backup-manager";
private final Map<String, String> domainIpCache = new ConcurrentHashMap<>();

private ScheduledExecutorService executorService =
private final String esName = "backup-manager";
private final ScheduledExecutorService executorService =
ExecutorServiceManager.newSingleThreadScheduledExecutor(esName);

private final String dnsEsName = "backup-dns-refresh";
private final ScheduledExecutorService dnsExecutorService =
ExecutorServiceManager.newSingleThreadScheduledExecutor(dnsEsName);

@Setter
private MessageHandler messageHandler;

@Getter
private BackupStatusEnum status = MASTER;

private volatile long lastKeepAliveTime;

private volatile boolean isInit = false;

public void setMessageHandler(MessageHandler messageHandler) {
this.messageHandler = messageHandler;
}

public BackupStatusEnum getStatus() {
return status;
}

public void setStatus(BackupStatusEnum status) {
logger.info("Change backup status to {}", status);
this.status = status;
Expand All @@ -78,10 +83,20 @@ public void init() {
logger.warn("Failed to get local ip");
}

for (String member : parameter.getBackupMembers()) {
if (!localIp.equals(member)) {
members.add(member);
for (String ipOrDomain : parameter.getBackupMembers()) {
InetAddress inetAddress = resolveInetAddress(ipOrDomain);
if (inetAddress == null) {
logger.warn("Failed to resolve backup member domain: {}", ipOrDomain);
continue;
}
String ip = inetAddress.getHostAddress();
if (localIp.equals(ip)) {
continue;
}
if (!NetUtil.validIpV4(ipOrDomain) && !NetUtil.validIpV6(ipOrDomain)) {
domainIpCache.put(ipOrDomain, ip);
}
members.add(ip);
Comment on lines +93 to +99
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Domains resolving to localIp at startup are skipped before being cached, so later DNS changes for those domains are never picked up.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/main/java/org/tron/common/backup/BackupManager.java, line 93:

<comment>Domains resolving to `localIp` at startup are skipped before being cached, so later DNS changes for those domains are never picked up.</comment>

<file context>
@@ -78,10 +83,20 @@ public void init() {
+        continue;
+      }
+      String ip = inetAddress.getHostAddress();
+      if (localIp.equals(ip)) {
+        continue;
+      }
</file context>
Suggested change
if (localIp.equals(ip)) {
continue;
}
if (!NetUtil.validIpV4(ipOrDomain) && !NetUtil.validIpV6(ipOrDomain)) {
domainIpCache.put(ipOrDomain, ip);
}
members.add(ip);
if (!NetUtil.validIpV4(ipOrDomain) && !NetUtil.validIpV6(ipOrDomain)) {
domainIpCache.put(ipOrDomain, ip);
}
if (localIp.equals(ip)) {
continue;
}
members.add(ip);
Fix with Cubic

}
Comment on lines +86 to 100
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Domains resolving to localIp at startup are never tracked for DNS refresh.

When a configured backup member is a domain name that currently resolves to localIp, the continue at line 94 fires before domainIpCache.put(...). If that DNS record later points to a non-local IP, the change will never be picked up by refreshMemberIps() — the only way to recover is a process restart.

Unless that's intentional, cache the domain first and only skip adding it to members:

🛠️ Suggested fix
     for (String ipOrDomain : parameter.getBackupMembers()) {
       InetAddress inetAddress = resolveInetAddress(ipOrDomain);
       if (inetAddress == null) {
         logger.warn("Failed to resolve backup member domain: {}", ipOrDomain);
         continue;
       }
       String ip = inetAddress.getHostAddress();
-      if (localIp.equals(ip)) {
-        continue;
-      }
       if (!NetUtil.validIpV4(ipOrDomain) && !NetUtil.validIpV6(ipOrDomain)) {
         domainIpCache.put(ipOrDomain, ip);
       }
+      if (localIp.equals(ip)) {
+        continue;
+      }
       members.add(ip);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/src/main/java/org/tron/common/backup/BackupManager.java` around
lines 86 - 100, The loop over parameter.getBackupMembers() skips caching domain
names that resolve to localIp, so later DNS changes are never detected by
refreshMemberIps(); change the logic in the loop (around resolveInetAddress,
localIp, domainIpCache, members and NetUtil.validIpV4/validIpV6) to always
populate domainIpCache.put(ipOrDomain, ip) for domain names (i.e., when
!NetUtil.validIpV4(ipOrDomain) && !NetUtil.validIpV6(ipOrDomain)) before the
localIp check/continue, and only then skip adding the ip to members when
ip.equals(localIp).


logger.info("Backup localIp:{}, members: size= {}, {}", localIp, members.size(), members);
Expand Down Expand Up @@ -111,6 +126,16 @@ public void init() {
logger.error("Exception in send keep alive", t);
}
}, 1000, keepAliveInterval, TimeUnit.MILLISECONDS);

if (!domainIpCache.isEmpty()) {
dnsExecutorService.scheduleWithFixedDelay(() -> {
try {
refreshMemberIps();
} catch (Throwable t) {
logger.error("Exception in backup DNS refresh", t);
}
}, 60_000L, 60_000L, TimeUnit.MILLISECONDS);
}
}

@Override
Expand Down Expand Up @@ -149,6 +174,7 @@ public void handleEvent(UdpEvent udpEvent) {

public void stop() {
ExecutorServiceManager.shutdownAndAwaitTermination(executorService, esName);
ExecutorServiceManager.shutdownAndAwaitTermination(dnsExecutorService, dnsEsName);
}

@Override
Expand All @@ -162,4 +188,28 @@ public enum BackupStatusEnum {
MASTER
}

/**
* Re-resolves all tracked domain entries. If an IP has changed, the old IP is
* removed from {@link #members} and the new IP is added.
*/
private void refreshMemberIps() {
for (Map.Entry<String, String> entry : domainIpCache.entrySet()) {
String domain = entry.getKey();
String oldIp = entry.getValue();
InetAddress inetAddress = resolveInetAddress(domain);
if (inetAddress == null) {
logger.warn("DNS refresh: failed to re-resolve backup member domain {}, keep it", domain);
continue;
}
String newIp = inetAddress.getHostAddress();
if (!newIp.equals(oldIp)) {
logger.info("DNS refresh: backup member {} IP changed {} -> {}", domain, oldIp, newIp);
members.remove(oldIp);
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Removing oldIp unconditionally can drop a still-active backup member when multiple domains share the same IP.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At framework/src/main/java/org/tron/common/backup/BackupManager.java, line 207:

<comment>Removing `oldIp` unconditionally can drop a still-active backup member when multiple domains share the same IP.</comment>

<file context>
@@ -162,4 +188,28 @@ public enum BackupStatusEnum {
+      String newIp = inetAddress.getHostAddress();
+      if (!newIp.equals(oldIp)) {
+        logger.info("DNS refresh: backup member {} IP changed {} -> {}", domain, oldIp, newIp);
+        members.remove(oldIp);
+        if (!localIp.equals(newIp)) {
+          members.add(newIp);
</file context>
Suggested change
members.remove(oldIp);
if (domainIpCache.entrySet().stream().noneMatch(e -> !e.getKey().equals(domain) && oldIp.equals(e.getValue()))) {
members.remove(oldIp);
}
Fix with Cubic

if (!localIp.equals(newIp)) {
members.add(newIp);
}
domainIpCache.put(domain, newIp);
}
}
}
Comment on lines +195 to +214
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

refreshMemberIps may drop an IP that is still in use by another tracked domain.

members.remove(oldIp) is unconditional. If two backup-member domains currently resolve to the same IP and only one of them rotates to a new address, the shared IP is removed from members even though the second domain still depends on it — keepalive messages will stop flowing to that peer until the other domain is also refreshed (or a restart happens).

Consider keeping oldIp only if no other entry in domainIpCache (or a plain IP-literal member) still maps to it:

🛠️ Sketch
       if (!newIp.equals(oldIp)) {
         logger.info("DNS refresh: backup member {} IP changed {} -> {}", domain, oldIp, newIp);
-        members.remove(oldIp);
+        boolean stillReferenced = domainIpCache.entrySet().stream()
+            .anyMatch(e -> !e.getKey().equals(domain) && oldIp.equals(e.getValue()));
+        if (!stillReferenced) {
+          members.remove(oldIp);
+        }
         if (!localIp.equals(newIp)) {
           members.add(newIp);
         }
         domainIpCache.put(domain, newIp);
       }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@framework/src/main/java/org/tron/common/backup/BackupManager.java` around
lines 195 - 214, refreshMemberIps currently unconditionally removes oldIp from
members which can drop an IP still referenced by another domain; change the
removal logic to only remove oldIp when no other domain in domainIpCache maps to
that same IP and the oldIp is not present as an explicit IP-literal member or
the localIp. Specifically, inside refreshMemberIps (using domainIpCache,
members, localIp), before calling members.remove(oldIp) check: (1) iterate
domainIpCache.values() to see if any other domain (key != current domain) still
resolves to oldIp, and (2) ensure oldIp is not equal to localIp and not present
in members as an explicit IP-literal that should be preserved; only call
members.remove(oldIp) if both checks indicate it is no longer referenced. Also
ensure you still add newIp (unless it equals localIp) and update
domainIpCache.put(domain, newIp) as before.

}
44 changes: 32 additions & 12 deletions framework/src/main/java/org/tron/core/config/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static org.tron.core.Constant.MIN_PROPOSAL_EXPIRE_TIME;
import static org.tron.core.config.Parameter.ChainConstant.BLOCK_PRODUCE_TIMEOUT_PERCENT;
import static org.tron.core.config.Parameter.ChainConstant.MAX_ACTIVE_WITNESS_NUM;
import static org.tron.core.config.args.InetUtil.resolveInetAddress;
import static org.tron.core.exception.TronError.ErrCode.PARAMETER_INIT;

import com.beust.jcommander.JCommander;
Expand All @@ -37,7 +38,6 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.BlockingQueue;
Expand Down Expand Up @@ -1301,15 +1301,12 @@ private static RateLimiterInitialization getRateLimiterFromConfig(
return initialization;
}


public static List<InetSocketAddress> getInetSocketAddress(
final com.typesafe.config.Config config, String path, boolean filter) {
List<InetSocketAddress> ret = new ArrayList<>();
if (!config.hasPath(path)) {
return ret;
}
List<String> list = config.getStringList(path);
for (String configString : list) {
InetSocketAddress inetSocketAddress = NetUtil.parseInetSocketAddress(configString);
List<InetSocketAddress> socketAddressList = getInetSockerAddress(config, path);
for (InetSocketAddress inetSocketAddress : socketAddressList) {
if (filter) {
String ip = inetSocketAddress.getAddress().getHostAddress();
int port = inetSocketAddress.getPort();
Expand All @@ -1326,15 +1323,27 @@ public static List<InetSocketAddress> getInetSocketAddress(
return ret;
}

public static List<InetAddress> getInetAddress(
private static List<InetSocketAddress> getInetSockerAddress(
final com.typesafe.config.Config config, String path) {
List<InetAddress> ret = new ArrayList<>();
List<InetSocketAddress> socketAddressList = new ArrayList<>();
if (!config.hasPath(path)) {
return ret;
return socketAddressList;
}
List<String> list = config.getStringList(path);
for (String configString : list) {
InetSocketAddress inetSocketAddress = NetUtil.parseInetSocketAddress(configString);
try {
socketAddressList = InetUtil.resolveInetSocketAddressList(list);
} catch (RuntimeException e) {
throw new TronError(String.format("config %s contains %s", path, e.getMessage()),
TronError.ErrCode.PARAMETER_INIT);
}
return socketAddressList;
}

public static List<InetAddress> getInetAddress(
final com.typesafe.config.Config config, String path) {
List<InetAddress> ret = new ArrayList<>();
List<InetSocketAddress> socketAddressList = getInetSockerAddress(config, path);
for (InetSocketAddress inetSocketAddress : socketAddressList) {
ret.add(inetSocketAddress.getAddress());
}
return ret;
Expand Down Expand Up @@ -1660,6 +1669,17 @@ private static void initBackupProperty(Config config) {

PARAMETER.backupMembers = config.hasPath(ConfigKey.NODE_BACKUP_MEMBERS)
? config.getStringList(ConfigKey.NODE_BACKUP_MEMBERS) : new ArrayList<>();
checkBackupMembers();
}

private static void checkBackupMembers() {
for (String member : PARAMETER.backupMembers) {
InetAddress inetAddress = resolveInetAddress(member);
if (inetAddress == null) {
throw new TronError("Failed to resolve backup member: " + member,
TronError.ErrCode.PARAMETER_INIT);
}
}
}

public static void logConfig() {
Expand Down
Loading
Loading