Skip to content
Closed
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
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
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
4 changes: 4 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 Expand Up @@ -131,6 +133,8 @@ def configureTestTask = { Task t ->
System.getProperty('runPrecompileBenchmark', 'false')
t.doFirst {
t.forkEvery = 100
// Fresh-JVM startup tests must use production resources, including logback.xml.
t.systemProperty 'fullNode.runtimeClasspath', sourceSets.main.runtimeClasspath.asPath
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import org.eclipse.jetty.server.ConnectionLimit;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.server.handler.SizeLimitHandler;
import org.eclipse.jetty.servlet.ServletContextHandler;
Expand All @@ -39,6 +40,8 @@ public abstract class HttpService extends AbstractService {

protected Server apiServer;

protected String listenAddress;

protected String contextPath;

protected long maxRequestSize = 4 * 1024 * 1024; // 4MB
Expand Down Expand Up @@ -77,7 +80,13 @@ public CompletableFuture<Boolean> start() {
}

protected void initServer() {
this.apiServer = new Server(this.port);
this.apiServer = new Server();
ServerConnector connector = new ServerConnector(this.apiServer);
connector.setPort(this.port);
if (this.listenAddress != null) {
connector.setHost(this.listenAddress);
}
this.apiServer.addConnector(connector);
int maxHttpConnectNumber = Args.getInstance().getMaxHttpConnectNumber();
if (maxHttpConnectNumber > 0) {
this.apiServer.addBean(new ConnectionLimit(maxHttpConnectNumber, this.apiServer));
Expand Down
56 changes: 43 additions & 13 deletions framework/src/main/java/org/tron/core/config/args/Args.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ public class Args extends CommonParameter {
@Getter
private static String configFilePath = "";

@Getter
private static String ipcSocketFile;

@Getter
private static String ipcExecCommand;

// Singleton config beans — populated at startup, read-only after init.
// New code can read directly from these beans instead of CommonParameter.
@Getter
Expand Down Expand Up @@ -146,19 +152,32 @@ public class Args extends CommonParameter {
* set parameters.
*/
public static void setParam(final String[] args, final String confFileName) {
// 1. Parse CLI args into a separate object
CLIParameter cmd = new CLIParameter();
JCommander jc = JCommander.newBuilder().addObject(cmd).build();
jc.parse(args);
setParam(new CommandLineArguments(args), confFileName);
}

/**
* Reuses the options parsed by FullNode before it chooses client or node startup.
*/
public static void setParam(CommandLineArguments arguments, final String confFileName) {
CLIParameter cmd = arguments.getParameters();

if (cmd.version) {
printVersion();
exit(0);
}
if (cmd.help) {
Args.printHelp(jc);
Args.printHelp(arguments.getCommander());
exit(0);
}
List<ParameterDescription> assignedParameters = arguments.getAssignedParameters();
if (arguments.isAttachMode()) {
ipcSocketFile = cmd.ipcSocketFile;
ipcExecCommand = cmd.ipcExecCommand;
if (StringUtils.isNotEmpty(cmd.logbackPath)) {
PARAMETER.logbackPath = cmd.logbackPath;
}
return;
}

// Resolve config file path
configFilePath = StringUtils.isNoneBlank(cmd.shellConfFileName)
Expand All @@ -169,7 +188,7 @@ public static void setParam(final String[] args, final String confFileName) {
applyConfigParams(config);

// 3. CLI overrides Config (highest priority, including --es → eventSubscribe)
applyCLIParams(cmd, jc);
applyCLIParams(cmd, assignedParameters);

// 4. Apply event config after CLI
applyEventConfig(eventConfig);
Expand Down Expand Up @@ -561,6 +580,16 @@ private static void applyNodeConfig(NodeConfig nc) {
PARAMETER.jsonRpcMaxLogFilterNum = jsonrpc.getMaxLogFilterNum();
PARAMETER.jsonRpcMaxMessageSize = jsonrpc.getMaxMessageSize();

// ---- Admin HTTP / IPC ----
NodeConfig.AdminIpcConfig adminIpc = nc.getAdmin().getIpc();
NodeConfig.AdminHttpConfig adminHttp = nc.getAdmin().getHttp();
PARAMETER.adminHttpEnable = adminHttp.isEnable();
PARAMETER.adminHttpListenAddress = adminHttp.getListenAddress();
PARAMETER.adminHttpListenPort = adminHttp.getPort();
PARAMETER.adminHttpVirtualHosts = new ArrayList<>(adminHttp.getVirtualHosts());
PARAMETER.ipcEnable = adminIpc.isEnable();
PARAMETER.ipcSocketDirectory = adminIpc.getSocketDirectory();

// ---- P2P sub-bean ----
PARAMETER.nodeP2pVersion = nc.getP2p().getVersion();

Expand Down Expand Up @@ -769,14 +798,13 @@ public static void applyConfigParams(
* Apply CLI parameters that were explicitly passed.
* Only assigned parameters override Config values.
*/
private static void applyCLIParams(CLIParameter cmd, JCommander jc) {
Set<String> assigned = jc.getParameters().stream()
.filter(ParameterDescription::isAssigned)
private static void applyCLIParams(CLIParameter cmd,
List<ParameterDescription> assignedParameters) {
Set<String> assigned = assignedParameters.stream()
.map(ParameterDescription::getLongestName)
.collect(Collectors.toSet());

jc.getParameters().stream()
.filter(ParameterDescription::isAssigned)
assignedParameters.stream()
.filter(pd -> {
try {
return CLIParameter.class.getDeclaredField(pd.getParameterized().getName())
Expand Down Expand Up @@ -946,6 +974,8 @@ public static void clearParam() {
rateLimiterConfig = null;
metricsConfig = null;
eventConfig = null;
ipcSocketFile = null;
ipcExecCommand = null;
}

// getProposalExpirationTime removed — logic moved to BlockConfig.fromConfig()
Expand Down Expand Up @@ -1292,7 +1322,8 @@ private static String getCommitIdAbbrev() {

private static Map<String, String[]> getOptionGroup() {
String[] tronOption = new String[] {"version", "help", "shellConfFileName", "logbackPath",
"eventSubscribe", "solidityNode", "keystoreFactory"};
"eventSubscribe", "solidityNode", "keystoreFactory", "ipcSocketFile",
"ipcExecCommand"};
String[] dbOption = new String[] {"outputDirectory"};
String[] witnessOption = new String[] {"witness", "privateKey"};
String[] vmOption = new String[] {"debug"};
Expand All @@ -1315,4 +1346,3 @@ private static Map<String, String[]> getOptionGroup() {
return optionGroupMap;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ public class CLIParameter {
@Parameter(names = {"--keystore-factory"}, description = "running KeystoreFactory")
public boolean keystoreFactory;

@Parameter(names = {"--attach"},
description = "running an IPC client to interact with FullNode")
public String ipcSocketFile;

@Parameter(names = {"--exec"},
description = "execute one Admin IPC command and exit (requires --attach)")
public String ipcExecCommand;

@Deprecated
@Parameter(names = {"--fast-forward"})
public boolean fastForward;
Expand Down
Loading
Loading