Software Versions
Version : develop branch (commit 13b68eac0)
Expected behaviour
CLI flags should take priority over config file values. This is the standard convention (CLI > config file > default) and is already correctly implemented for 9 other parameters (e.g. --storage-db-directory, --trust-node) using the Optional pattern.
java -jar FullNode.jar --rpc-thread 16
# Expected: rpcThreadNum = 16
Actual behaviour
For 13 parameters, Args.setParam(Config) unconditionally overwrites the CLI value with the config file value. The CLI flags are silently ignored.
# config.conf contains: node.rpc.thread = 8
java -jar FullNode.jar --rpc-thread 16
# Actual: rpcThreadNum = 8 (CLI value lost)
Root cause — unconditional assignment in Args.setParam():
PARAMETER.rpcThreadNum = config.hasPath(ConfigKey.NODE_RPC_THREAD)
? config.getInt(ConfigKey.NODE_RPC_THREAD)
: Runtime.getRuntime().availableProcessors() / 2;
// JCommander-set value of 16 is overwritten to 8
Frequency
100% — every time a config file key exists for any of the 13 affected parameters.
Steps to reproduce the behaviour
- Set
node.rpc.thread = 8 in config.conf
- Start node with
java -jar FullNode.jar -c config.conf --rpc-thread 16
- Observe that
rpcThreadNum is 8, not 16
Any of the following 13 parameters can reproduce the same issue:
| # |
CLI Flag |
Field |
Config Key |
| 1 |
--support-constant |
supportConstant |
vm.supportConstant |
| 2 |
--max-energy-limit-for-constant |
maxEnergyLimitForConstant |
vm.maxEnergyLimitForConstant |
| 3 |
--lru-cache-size |
lruCacheSize |
vm.lruCacheSize |
| 4 |
--min-time-ratio |
minTimeRatio |
vm.minTimeRatio |
| 5 |
--max-time-ratio |
maxTimeRatio |
vm.maxTimeRatio |
| 6 |
--long-running-time |
longRunningTime |
vm.longRunningTime |
| 7 |
--save-internaltx |
saveInternalTx |
vm.saveInternalTx |
| 8 |
--save-featured-internaltx |
saveFeaturedInternalTx |
vm.saveFeaturedInternalTx |
| 9 |
--max-connect-number |
maxHttpConnectNumber |
node.maxHttpConnectNumber |
| 10 |
--rpc-thread |
rpcThreadNum |
node.rpc.thread |
| 11 |
--solidity-thread |
solidityThreads |
node.solidity.threads |
| 12 |
--validate-sign-thread |
validateSignThreadNum |
node.validateSignThreadNum |
| 13 |
--history-balance-lookup |
historyBalanceLookup |
storage.balance.history.lookup |
Backtrace
Not applicable — no crash or exception. The bug is silent incorrect behavior.
Below is the full findings of all 34 @Parameter CLI flags in CommonParameter and additional findings.
full findings: all 34 CLI parameters by category
Category 1: Startup parameters (6) — No issue
Only control startup flow, no config file overlap.
| CLI Flag |
Field |
Description |
-c, --config |
shellConfFileName |
Config file path |
-d, --output-directory |
outputDirectory |
Data directory |
--log-config |
logbackPath |
Log config file |
-h, --help |
help |
Print help and exit |
-v, --version |
version |
Print version and exit |
--password |
password |
Witness password |
Category 2: CLI-only parameters (10) — No issue
Only set by CLI, setParam(Config) does not override.
| CLI Flag |
Field |
Description |
-w, --witness |
witness |
Witness mode |
-p, --private-key |
privateKey |
Witness private key |
--witness-address |
witnessAddress |
Witness address |
--debug |
debug |
TVM debug mode |
--fast-forward |
fastForward |
Fast forward mode |
--solidity |
solidityNode |
Solidity node mode |
--keystore-factory |
keystoreFactory |
KeystoreFactory mode |
--p2p-disable |
p2pDisable |
Disable P2P module |
--es |
eventSubscribe |
Enable event subscription |
--contract-parse-enable |
contractParseEnable |
Contract parse switch |
Category 3: CLI + Config, CLI priority (9) — Correct
Uses Optional pattern, CLI value takes priority when present.
| CLI Flag |
Field |
Config Key |
--storage-db-directory |
storageDbDirectory |
storage.db.directory |
--storage-db-engine |
storageDbEngine |
storage.db.engine |
--storage-db-synchronous |
storageDbSynchronous |
storage.db.synchronous |
--storage-index-directory |
storageIndexDirectory |
storage.index.directory |
--storage-index-switch |
storageIndexSwitch |
storage.index.switch |
--storage-transactionHistory-switch |
storageTransactionHistorySwitch |
storage.transactionHistory.switch |
--trust-node |
trustNodeAddr |
node.trustNode |
--save-cancel-all-unfreeze-v2-details |
saveCancelAllUnfreezeV2Details |
vm.saveCancelAllUnfreezeV2Details |
--seed-nodes |
seedNodes |
seed.node.ip.list |
Category 4: CLI + Config, config overwrites CLI (13) — BUG
See "Steps to reproduce" section above for full list.
Other issues found during investigation
clearParam() misses 9 fields
clearParam() is used for test state reset, but the following fields are not cleared, which may cause test pollution:
maxEnergyLimitForConstant, lruCacheSize
allowDelegateOptimization, unfreezeDelayDays
allowDynamicEnergy, dynamicEnergyThreshold, dynamicEnergyIncreaseFactor, dynamicEnergyMaxFactor
saveCancelAllUnfreezeV2Details
Inconsistent default value patterns
Two patterns coexist in Args.setParam():
- Pattern A (ternary): default value explicit —
config.hasPath(key) ? config.get(key) : defaultValue
- Pattern B (if-block, no else): default value hidden in
CommonParameter field declaration
Mixing both increases maintenance burden. Suggest unifying to Pattern A.
CommonParameter overloaded
780 lines, ~150 fields, mixing CLI parameters, config file values, and runtime objects. Long-term suggestion: split into domain-specific classes (RpcConfig, StorageConfig, VmConfig, etc.).
Suggested improvement roadmap
Industry comparison
| Project |
CLI/Config Overlap |
Strategy |
Priority Rule |
| Nginx |
Nearly none |
CLI for startup ops only; all business config in file |
CLI > config |
| Hadoop |
Full overlap |
All items overridable via -D key=value; multi-layer XML merge |
CLI > site XML > default XML |
| Kubernetes |
Heavy → deprecating CLI |
Migrating to config file; CLI flags marked deprecated |
CLI > config file |
java-tron's current situation is most similar to early Kubernetes.
Short-term (current release): Fix the priority bug
if (PARAMETER.rpcThreadNum <= 0) {
PARAMETER.rpcThreadNum = config.hasPath(ConfigKey.NODE_RPC_THREAD)
? config.getInt(ConfigKey.NODE_RPC_THREAD)
: Runtime.getRuntime().availableProcessors() / 2;
}
Mid-term (next release): Deprecate overlapping CLI flags
@Deprecated // Use node.rpc.thread in config.conf instead
@Parameter(names = {"--rpc-thread"}, description = "[DEPRECATED] Num of gRPC thread")
public int rpcThreadNum;
Long-term (future release): Converge to Nginx model
Only keep ~8 startup-class CLI parameters (-c, -d, -w, -p, -h, -v, --password, --log-config). All other runtime parameters managed exclusively by config file.
Software Versions
Expected behaviour
CLI flags should take priority over config file values. This is the standard convention (
CLI > config file > default) and is already correctly implemented for 9 other parameters (e.g.--storage-db-directory,--trust-node) using theOptionalpattern.java -jar FullNode.jar --rpc-thread 16 # Expected: rpcThreadNum = 16Actual behaviour
For 13 parameters,
Args.setParam(Config)unconditionally overwrites the CLI value with the config file value. The CLI flags are silently ignored.Root cause — unconditional assignment in
Args.setParam():Frequency
100% — every time a config file key exists for any of the 13 affected parameters.
Steps to reproduce the behaviour
node.rpc.thread = 8inconfig.confjava -jar FullNode.jar -c config.conf --rpc-thread 16rpcThreadNumis 8, not 16Any of the following 13 parameters can reproduce the same issue:
--support-constantsupportConstantvm.supportConstant--max-energy-limit-for-constantmaxEnergyLimitForConstantvm.maxEnergyLimitForConstant--lru-cache-sizelruCacheSizevm.lruCacheSize--min-time-ratiominTimeRatiovm.minTimeRatio--max-time-ratiomaxTimeRatiovm.maxTimeRatio--long-running-timelongRunningTimevm.longRunningTime--save-internaltxsaveInternalTxvm.saveInternalTx--save-featured-internaltxsaveFeaturedInternalTxvm.saveFeaturedInternalTx--max-connect-numbermaxHttpConnectNumbernode.maxHttpConnectNumber--rpc-threadrpcThreadNumnode.rpc.thread--solidity-threadsolidityThreadsnode.solidity.threads--validate-sign-threadvalidateSignThreadNumnode.validateSignThreadNum--history-balance-lookuphistoryBalanceLookupstorage.balance.history.lookupBacktrace
Not applicable — no crash or exception. The bug is silent incorrect behavior.
Below is the full findings of all 34
@ParameterCLI flags inCommonParameterand additional findings.full findings: all 34 CLI parameters by category
Category 1: Startup parameters (6) — No issue
Only control startup flow, no config file overlap.
-c,--configshellConfFileName-d,--output-directoryoutputDirectory--log-configlogbackPath-h,--helphelp-v,--versionversion--passwordpasswordCategory 2: CLI-only parameters (10) — No issue
Only set by CLI,
setParam(Config)does not override.-w,--witnesswitness-p,--private-keyprivateKey--witness-addresswitnessAddress--debugdebug--fast-forwardfastForward--soliditysolidityNode--keystore-factorykeystoreFactory--p2p-disablep2pDisable--eseventSubscribe--contract-parse-enablecontractParseEnableCategory 3: CLI + Config, CLI priority (9) — Correct
Uses
Optionalpattern, CLI value takes priority when present.--storage-db-directorystorageDbDirectorystorage.db.directory--storage-db-enginestorageDbEnginestorage.db.engine--storage-db-synchronousstorageDbSynchronousstorage.db.synchronous--storage-index-directorystorageIndexDirectorystorage.index.directory--storage-index-switchstorageIndexSwitchstorage.index.switch--storage-transactionHistory-switchstorageTransactionHistorySwitchstorage.transactionHistory.switch--trust-nodetrustNodeAddrnode.trustNode--save-cancel-all-unfreeze-v2-detailssaveCancelAllUnfreezeV2Detailsvm.saveCancelAllUnfreezeV2Details--seed-nodesseedNodesseed.node.ip.listCategory 4: CLI + Config, config overwrites CLI (13) — BUG
See "Steps to reproduce" section above for full list.
Other issues found during investigation
clearParam()misses 9 fieldsclearParam()is used for test state reset, but the following fields are not cleared, which may cause test pollution:maxEnergyLimitForConstant,lruCacheSizeallowDelegateOptimization,unfreezeDelayDaysallowDynamicEnergy,dynamicEnergyThreshold,dynamicEnergyIncreaseFactor,dynamicEnergyMaxFactorsaveCancelAllUnfreezeV2DetailsInconsistent default value patterns
Two patterns coexist in
Args.setParam():config.hasPath(key) ? config.get(key) : defaultValueCommonParameterfield declarationMixing both increases maintenance burden. Suggest unifying to Pattern A.
CommonParameteroverloaded780 lines, ~150 fields, mixing CLI parameters, config file values, and runtime objects. Long-term suggestion: split into domain-specific classes (
RpcConfig,StorageConfig,VmConfig, etc.).Suggested improvement roadmap
Industry comparison
-D key=value; multi-layer XML mergejava-tron's current situation is most similar to early Kubernetes.
Short-term (current release): Fix the priority bug
Mid-term (next release): Deprecate overlapping CLI flags
Long-term (future release): Converge to Nginx model
Only keep ~8 startup-class CLI parameters (
-c,-d,-w,-p,-h,-v,--password,--log-config). All other runtime parameters managed exclusively by config file.