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
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 All @@ -13,6 +14,7 @@
import org.tron.common.logsfilter.EventPluginConfig;
import org.tron.common.logsfilter.FilterQuery;
import org.tron.common.setting.RocksDbSettings;
import org.tron.core.Constant;
import org.tron.core.config.args.SeedNode;
import org.tron.core.config.args.Storage;
import org.tron.p2p.P2pConfig;
Expand Down Expand Up @@ -482,6 +484,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 @@ -127,6 +129,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 @@ -251,6 +254,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
31 changes: 30 additions & 1 deletion common/src/main/resources/reference.conf
Original file line number Diff line number Diff line change
Expand Up @@ -430,10 +430,39 @@ node {
maxResponseSize = 26214400
# Allowed maximum number for newFilter, <=0 means no limit
maxLogFilterNum = 20000
# Maximum JSON-RPC request body size in bytes (default 4194304, ~4MB). Independent from rpc.maxMessageSize.
# Maximum public JSON-RPC HTTP and Admin IPC request size in bytes (default 4194304, ~4MB).
# Independent from rpc.maxMessageSize. Setting to 0 rejects all non-empty requests.
maxMessageSize = 4194304
}

# Administrative API settings. Disabled by default.
Comment thread
waynercheung marked this conversation as resolved.
# Batch requests are not supported.
admin {
# Local Unix-domain socket administrative API.
ipc {
# Whether to enable the local Unix-domain socket admin API. Default: false.
enable = false
# Existing absolute parent directory; empty uses output-directory.
# The ipc subdirectory must not exist at startup.
# Full socket path limit: 100 encoded bytes.
socketDirectory = ""
# Request size is controlled by node.jsonrpc.maxMessageSize, shared with JSON-RPC HTTP.
}

# 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 @@ -61,6 +61,8 @@ dependencies {
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 @@ -140,6 +142,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
39 changes: 27 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 @@ -146,19 +146,24 @@ 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);
}

/**
* Initializes node configuration from parsed options. FullNode handles attach mode separately.
*/
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();

// Resolve config file path
configFilePath = StringUtils.isNoneBlank(cmd.shellConfFileName)
Expand All @@ -169,7 +174,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 @@ -560,6 +565,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 @@ -767,14 +782,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 @@ -1290,7 +1304,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 Down
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package org.tron.core.config.args;

import com.beust.jcommander.JCommander;
import com.beust.jcommander.ParameterDescription;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.tron.core.exception.TronError;

/**
* Parses startup options without initializing node configuration or logging. Keep this class
* independent of Args, CommonParameter, and logging so FullNode can dispatch the standalone client.
*/
@Getter
public final class CommandLineArguments {

private final CLIParameter parameters = new CLIParameter();
private final JCommander commander = JCommander.newBuilder().addObject(parameters).build();
private final List<ParameterDescription> assignedParameters;

public CommandLineArguments(String[] args) {
commander.parse(args);
assignedParameters = commander.getParameters().stream()
.filter(ParameterDescription::isAssigned)
.collect(Collectors.toList());
}

public boolean isAttachMode() {
// Preserve the existing help/version precedence over attach validation.
if (parameters.help || parameters.version) {
return false;
}
if (!isAssigned("ipcSocketFile")) {
if (isAssigned("ipcExecCommand")) {
throwAttachParameterError("Error: --exec requires --attach <socket-path>");
}
return false;
}
if (isAssigned("shellConfFileName")) {
throwAttachParameterError("Error: --attach cannot be combined with: --config");
}
if (StringUtils.isBlank(parameters.ipcSocketFile)) {
throwAttachParameterError("Error: --attach requires a non-empty <socket-path>");
}
// Node-only CLI options are irrelevant to the standalone IPC client and are ignored.
return true;
}

private boolean isAssigned(String fieldName) {
return assignedParameters.stream()
.anyMatch(pd -> fieldName.equals(pd.getParameterized().getName()));
}

private static void throwAttachParameterError(String message) {
System.err.println(message);
throw new TronError(message, TronError.ErrCode.PARAMETER_INIT);
}
}
Loading
Loading