Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a068c83
feat(framework): support admin RPC
317787106 Aug 4, 2026
cbdb3d7
Merge branch 'develop' into feature/admin_rpc
317787106 Aug 4, 2026
38fc2bd
support multi client
317787106 Aug 4, 2026
e93fdad
Merge branch 'develop' into feature/admin_rpc
317787106 Aug 6, 2026
cf7307c
log warn if admin listen address not restirct on 127.0.0.1
317787106 Aug 6, 2026
667c7f4
extract annoation; add Exportable; remove committee from Exportable; …
317787106 Aug 6, 2026
95828db
fix bug from claude
317787106 Aug 7, 2026
95437eb
use isLoopbackListenAddress instead of 127.0.0.1; add sleep for ipcse…
317787106 Aug 7, 2026
75b4061
move IpcClient.start ahead of LogService.load; write sock file in out…
317787106 Aug 7, 2026
96964b5
fix the UNAVAILABLE of p2pConfig when export it
317787106 Aug 7, 2026
5731609
simply IpcService
317787106 Aug 7, 2026
a709dd6
refactor(api): split runtime parameters into follow-up
317787106 Aug 7, 2026
50b41c2
create directory for sock file; reorg admin config, add ipc.socketDir…
317787106 Aug 12, 2026
66b60f4
reorg admin config, add ipc.socketDirectory
317787106 Aug 12, 2026
300fd6e
add admin.rpc.virtualHosts; output error message if --attach is invalid
317787106 Aug 12, 2026
f0a6a91
add read timeout for client; set isRunning = false when inits;
317787106 Aug 13, 2026
ac1516b
optimize getSocketPathLength; IpcClient don't use Slf4j
317787106 Aug 13, 2026
0dc70a4
Merge branch 'develop' into feature/admin_rpc
317787106 Aug 21, 2026
906fb18
rename node.admin.rpc to node.admin.http
317787106 Aug 21, 2026
c569402
update some comment
317787106 Aug 21, 2026
8bdfb71
optimize shutdownExecutors
317787106 Aug 21, 2026
a219222
chore(deps): upgrade grpc, jackson, logback, commons and drop joda-ti…
halibobo1205 Sep 14, 2026
0d19485
feat(api): sanitize HTTP API error responses (#6954)
halibobo1205 Sep 14, 2026
ecd86a3
Merge branch 'release_v4.8.3' into feature/admin_rpc
317787106 Sep 16, 2026
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
16 changes: 7 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ plugins {
}

ext {
grpcVersion = "1.83.0"
grpcVersion = "1.83.1"
}

allprojects {
Expand Down Expand Up @@ -91,16 +91,14 @@ subprojects {
}

dependencies {
implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.36'
implementation group: 'org.slf4j', name: 'jcl-over-slf4j', version: '1.7.36'
implementation group: 'org.slf4j', name: 'jul-to-slf4j', version: '1.7.36'
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.13'
implementation group: 'org.slf4j', name: 'slf4j-api', version: '2.0.17'
implementation group: 'org.slf4j', name: 'jcl-over-slf4j', version: '2.0.17'
implementation group: 'org.slf4j', name: 'jul-to-slf4j', version: '2.0.17'
implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.3.16'
implementation "com.google.code.findbugs:jsr305:3.0.0"
implementation group: 'org.springframework', name: 'spring-context', version: "${springVersion}"
implementation "org.apache.commons:commons-lang3:3.4"
implementation group: 'org.apache.commons', name: 'commons-math', version: '2.2'
implementation "org.apache.commons:commons-collections4:4.1"
implementation group: 'joda-time', name: 'joda-time', version: '2.3'
implementation "org.apache.commons:commons-lang3:3.20.0"
implementation "org.apache.commons:commons-collections4:4.6.0"
implementation group: 'org.bouncycastle', name: 'bcprov-jdk18on', version: '1.84'

compileOnly 'org.projectlombok:lombok:1.18.34'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
import java.util.stream.IntStream;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.Time;
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.config.Parameter.ChainConstant;
import org.tron.core.db.TronStoreWithRevoking;
Expand Down Expand Up @@ -2261,8 +2261,8 @@ public void updateNextMaintenanceTime(long blockTime) {
logger.info(
"Do update nextMaintenanceTime, currentMaintenanceTime: {}, blockTime: {}, "
+ "nextMaintenanceTime: {}.",
new DateTime(currentMaintenanceTime), new DateTime(blockTime),
new DateTime(nextMaintenanceTime)
Time.getIsoTimeString(currentMaintenanceTime), Time.getIsoTimeString(blockTime),
Time.getIsoTimeString(nextMaintenanceTime)
);
}

Expand Down
4 changes: 3 additions & 1 deletion common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ sourceCompatibility = 1.8


dependencies {
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.6' // https://github.com/FasterXML/jackson-databind/issues/3627
// avoid x.y.z.w micro-patches, they may ship broken Gradle module metadata:
// https://github.com/FasterXML/jackson-databind/issues/3627
api group: 'com.fasterxml.jackson.core', name: 'jackson-databind', version: '2.18.10'
api "com.cedarsoftware:java-util:3.2.0"
api group: 'org.apache.httpcomponents', name: 'httpasyncclient', version: '4.1.1'
api group: 'commons-codec', name: 'commons-codec', version: '1.11'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
Expand Down Expand Up @@ -490,6 +491,25 @@ public class CommonParameter {
public int jsonRpcMaxLogFilterNum = 20000;
@Getter
@Setter
public boolean adminHttpEnable = false;
@Getter
@Setter
public String adminHttpListenAddress = Constant.LOCAL_HOST;
@Getter
@Setter
public int adminHttpListenPort = 8575;
@Getter
@Setter
public List<String> adminHttpVirtualHosts =
new ArrayList<>(Collections.singletonList("localhost"));
@Getter
@Setter
public boolean ipcEnable = false;
@Getter
@Setter
public String ipcSocketDirectory = "";
@Getter
@Setter
public int maxTransactionPendingSize;
@Getter
@Setter
Expand Down
12 changes: 12 additions & 0 deletions common/src/main/java/org/tron/common/utils/Time.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
package org.tron.common.utils;

import java.sql.Timestamp;
import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;

public class Time {

// Matches joda-time's DateTime.toString() output, byte for byte: fixed
// 3-digit millis, offset as +08:00, and Z when the system zone is UTC.
private static final DateTimeFormatter ISO_MILLIS_FORMAT =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

public static long getCurrentMillis() {
return System.currentTimeMillis();
}

public static String getTimeString(long time) {
return new Timestamp(time).toString();
}

public static String getIsoTimeString(long time) {
return Instant.ofEpochMilli(time).atZone(ZoneId.systemDefault()).format(ISO_MILLIS_FORMAT);
}
}
29 changes: 29 additions & 0 deletions common/src/main/java/org/tron/core/config/args/NodeConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import com.typesafe.config.ConfigBeanFactory;
import com.typesafe.config.ConfigValueFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.tron.core.Constant;
import org.tron.core.exception.TronError;

// Node configuration bean for the "node" section of config.conf.
Expand Down Expand Up @@ -128,6 +130,7 @@ public int getValidContractProtoThreads() {
private HttpConfig http = new HttpConfig();
private RpcConfig rpc = new RpcConfig();
private JsonRpcConfig jsonrpc = new JsonRpcConfig();
private AdminConfig admin = new AdminConfig();
private NodeBackupConfig backup = new NodeBackupConfig();
private DynamicConfigSection dynamicConfig = new DynamicConfigSection();
private DnsConfig dns = new DnsConfig();
Expand Down Expand Up @@ -252,6 +255,32 @@ public static class JsonRpcConfig {
private long maxMessageSize = 4194304;
}

@Getter
@Setter
public static class AdminConfig {

private AdminIpcConfig ipc = new AdminIpcConfig();
private AdminHttpConfig http = new AdminHttpConfig();
}

@Getter
@Setter
public static class AdminIpcConfig {

private boolean enable = false;
private String socketDirectory = "";
}

@Getter
@Setter
public static class AdminHttpConfig {

private boolean enable = false;
private String listenAddress = Constant.LOCAL_HOST;
private int port = 8575;
private List<String> virtualHosts = new ArrayList<>(Collections.singletonList("localhost"));
}

@Getter
@Setter
public static class NodeBackupConfig {
Expand Down
26 changes: 26 additions & 0 deletions common/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,32 @@ node {
maxMessageSize = 4194304
}

# Administrative API settings. Disabled by default.
admin {
# Local Unix-domain socket administrative API.
ipc {
# Whether to enable the local Unix-domain socket admin API. Default: false.
enable = false
# Parent directory for the private .ipc directory. It must be an absolute path
# when set. Empty means output-directory. The node fails to start if the resulting socket
# path exceeds the portable Unix-domain socket path limit.
socketDirectory = ""
}

# Administrative JSON-RPC HTTP API.
http {
# Whether to enable the administrative JSON-RPC HTTP service. Default: false.
enable = false
# Address on which the service listens. Keep the default loopback address for security.
listenAddress = "127.0.0.1"
# TCP port on which the administrative JSON-RPC HTTP service listens. Default: 8575.
port = 8575
# Allowed HTTP Host header names. Matching is case-insensitive and ignores the port.
# IP address literals are always allowed. Use ["*"] only to explicitly allow any hostname.
virtualHosts = ["localhost"]
}
}

# Disabled API list (works for http, rpc and pbft, not jsonrpc). Case insensitive.
disabledApi = [
# "getaccount",
Expand Down
25 changes: 25 additions & 0 deletions common/src/test/java/org/tron/core/config/args/NodeConfigTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import java.util.Arrays;
import java.util.Collections;
import org.junit.Test;
import org.tron.core.exception.TronError;

Expand All @@ -30,6 +32,13 @@ public void testDefaults() {
assertEquals(8, nc.getMinConnections());
assertEquals(4, nc.getMaxFastForwardNum());
assertFalse(nc.isOpenFullTcpDisconnect());
assertFalse(nc.getAdmin().getIpc().isEnable());
assertEquals("", nc.getAdmin().getIpc().getSocketDirectory());
assertFalse(nc.getAdmin().getHttp().isEnable());
assertEquals("127.0.0.1", nc.getAdmin().getHttp().getListenAddress());
assertEquals(8575, nc.getAdmin().getHttp().getPort());
assertEquals(Collections.singletonList("localhost"),
nc.getAdmin().getHttp().getVirtualHosts());
// reference.conf matches code default: discovery disabled when not configured
assertFalse(nc.isDiscoveryEnable());
assertFalse(nc.isDiscoveryPersist());
Expand Down Expand Up @@ -79,6 +88,22 @@ public void testRpcSubBean() {
assertEquals(60071, nc.getRpc().getPBFTPort());
}

@Test
public void testAdminHttpAndIpcBinding() {
Config config = withRef(
"node.admin { ipc { enable = true, socketDirectory = \"/tmp/tron-ipc\" },"
+ " http { enable = true, listenAddress = \"127.0.0.2\", port = 18575,"
+ " virtualHosts = [\"admin.example.com\", \"localhost\"] } }");
NodeConfig nc = NodeConfig.fromConfig(config);
assertTrue(nc.getAdmin().getIpc().isEnable());
assertEquals("/tmp/tron-ipc", nc.getAdmin().getIpc().getSocketDirectory());
assertTrue(nc.getAdmin().getHttp().isEnable());
assertEquals("127.0.0.2", nc.getAdmin().getHttp().getListenAddress());
assertEquals(18575, nc.getAdmin().getHttp().getPort());
assertEquals(Arrays.asList("admin.example.com", "localhost"),
nc.getAdmin().getHttp().getVirtualHosts());
}

@Test
public void testBackupSubBean() {
Config config = withRef(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.tron.common.args.GenesisBlock;
import org.tron.common.parameter.CommonParameter;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Time;
import org.tron.consensus.ConsensusDelegate;
import org.tron.consensus.base.BlockHandle;
import org.tron.consensus.base.ConsensusInterface;
Expand Down Expand Up @@ -134,14 +134,14 @@ public boolean validBlock(BlockCapsule blockCapsule) {
if (slot == 0
&& consensusDelegate.getDynamicPropertiesStore().allowConsensusLogicOptimization()) {
logger.warn("ValidBlock failed: slot error, witness: {}, timeStamp: {}",
ByteArray.toHexString(witnessAddress.toByteArray()), new DateTime(timeStamp));
ByteArray.toHexString(witnessAddress.toByteArray()), Time.getIsoTimeString(timeStamp));
return false;
}
final ByteString scheduledWitness = dposSlot.getScheduledWitness(slot);
if (!scheduledWitness.equals(witnessAddress)) {
logger.warn("ValidBlock failed: sWitness: {}, bWitness: {}, bTimeStamp: {}, slot: {}",
ByteArray.toHexString(scheduledWitness.toByteArray()),
ByteArray.toHexString(witnessAddress.toByteArray()), new DateTime(timeStamp), slot);
ByteArray.toHexString(witnessAddress.toByteArray()), Time.getIsoTimeString(timeStamp), slot);
return false;
}

Expand Down
4 changes: 2 additions & 2 deletions consensus/src/main/java/org/tron/consensus/dpos/DposTask.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.concurrent.ExecutorService;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
Expand All @@ -15,6 +14,7 @@
import org.tron.common.parameter.CommonParameter;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.Time;
import org.tron.consensus.ConsensusDelegate;
import org.tron.consensus.base.Param.Miner;
import org.tron.consensus.base.State;
Expand Down Expand Up @@ -123,7 +123,7 @@ private State produceBlock() {
BlockHeader.raw raw = blockCapsule.getInstance().getBlockHeader().getRawData();
logger.info("Produce block successfully, num: {}, time: {}, witness: {}, ID:{}, parentID:{}",
raw.getNumber(),
new DateTime(raw.getTimestamp()),
Time.getIsoTimeString(raw.getTimestamp()),
ByteArray.toHexString(raw.getWitnessAddress().toByteArray()),
new Sha256Hash(raw.getNumber(), Sha256Hash.of(CommonParameter
.getInstance().isECKeyCryptoEngine(), raw.toByteArray())),
Expand Down
2 changes: 2 additions & 0 deletions framework/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ dependencies {
testImplementation group: 'org.springframework', name: 'spring-test', version: "${springVersion}"
testImplementation group: 'javax.portlet', name: 'portlet-api', version: '3.0.1'
implementation group: 'org.zeromq', name: 'jeromq', version: '0.5.3'
implementation group: 'com.kohlschutter.junixsocket', name: 'junixsocket-core', version: '2.10.1'
implementation group: 'org.jline', name: 'jline', version: '3.21.0'
api project(":chainbase")
api project(":protocol")
api project(":actuator")
Expand Down
Loading
Loading