From b6939fd72a221635f18fd9358a2bfd4ba0e50d3e Mon Sep 17 00:00:00 2001 From: vividcoder Date: Tue, 3 Mar 2026 18:07:58 +0800 Subject: [PATCH 1/8] refactor(config): extract CLI parameters into CLIParameter Extract all @Parameter annotations from CommonParameter into a new CLIParameter class, removing JCommander dependency from common module. Refactor Args.setParam() into a four-step flow: parse CLI, apply config, apply CLI overrides via isAssigned(), init witness. Simplify clearParam() from ~160 lines to CommonParameter.reset(). --- common/build.gradle | 1 - .../common/parameter/CommonParameter.java | 255 ++++-------- framework/build.gradle | 1 + .../java/org/tron/core/config/args/Args.java | 362 +++++++++--------- .../tron/core/config/args/CLIParameter.java | 194 ++++++++++ .../core/config/args/WitnessInitializer.java | 25 +- .../org/tron/common/config/args/ArgsTest.java | 3 +- .../java/org/tron/core/WalletMockTest.java | 2 +- .../org/tron/core/config/args/ArgsTest.java | 2 - .../core/config/args/DynamicArgsTest.java | 2 - .../config/args/WitnessInitializerTest.java | 6 +- .../tron/core/db/TransactionExpireTest.java | 2 +- 12 files changed, 476 insertions(+), 379 deletions(-) create mode 100644 framework/src/main/java/org/tron/core/config/args/CLIParameter.java diff --git a/common/build.gradle b/common/build.gradle index 8ea91ecd5b1..98fc3257190 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -12,7 +12,6 @@ dependencies { 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' - api group: 'com.beust', name: 'jcommander', version: '1.78' api group: 'com.typesafe', name: 'config', version: '1.3.2' api group: 'io.prometheus', name: 'simpleclient', version: '0.15.0' api group: 'io.prometheus', name: 'simpleclient_httpserver', version: '0.15.0' diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index d1210b27d6c..bbf44900d63 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -1,6 +1,6 @@ package org.tron.common.parameter; -import com.beust.jcommander.Parameter; +import com.google.common.annotations.VisibleForTesting; import java.net.InetAddress; import java.net.InetSocketAddress; import java.util.ArrayList; @@ -24,118 +24,77 @@ public class CommonParameter { public static final String IGNORE_WRONG_WITNESS_ADDRESS_FORMAT = - "The localWitnessAccountAddress format is incorrect, ignored"; - public static CommonParameter PARAMETER = new CommonParameter(); + "The localWitnessAccountAddress format is incorrect," + + " ignored"; + + protected static CommonParameter PARAMETER = new CommonParameter(); + @Setter public static boolean ENERGY_LIMIT_HARD_FORK = false; + + // ── Config / path ──────────────────────────────── @Getter - @Parameter(names = {"-c", "--config"}, description = "Config file (default:config.conf)") - public String shellConfFileName = ""; - @Getter - @Setter public String configFilePath = ""; @Getter - @Parameter(names = {"-d", "--output-directory"}, - description = "Data directory for the databases (default:output-directory)") public String outputDirectory = "output-directory"; @Getter - @Parameter(names = {"--log-config"}, description = "Logback config file") public String logbackPath = ""; + + // ── CLI-only flags ─────────────────────────────── @Getter - @Parameter(names = {"-h", "--help"}, help = true, description = "Show help message") public boolean help = false; @Getter @Setter - @Parameter(names = {"-w", "--witness"}, description = "Is witness node") public boolean witness = false; @Getter @Setter - @Parameter(names = {"--support-constant"}, description = "Support constant calling for TVM. " - + "(defalut: false)") public boolean supportConstant = false; @Getter @Setter - @Parameter(names = {"--max-energy-limit-for-constant"}, description = "Max energy limit for " - + "constant calling. (default: 100,000,000)") public long maxEnergyLimitForConstant = 100_000_000L; @Getter @Setter - @Parameter(names = {"--lru-cache-size"}, description = "Max LRU size for caching bytecode and " - + "result of JUMPDEST analysis. (default: 500)") public int lruCacheSize = 500; @Getter @Setter - @Parameter(names = {"--debug"}, description = "Switch for TVM debug mode. In debug model, TVM " - + "will not check for timeout. (default: false)") public boolean debug = false; @Getter @Setter - @Parameter(names = {"--min-time-ratio"}, description = "Minimum CPU tolerance when executing " - + "timeout transactions while synchronizing blocks. (default: 0.0)") public double minTimeRatio = 0.0; @Getter @Setter - @Parameter(names = {"--max-time-ratio"}, description = "Maximum CPU tolerance when executing " - + "non-timeout transactions while synchronizing blocks. (default: 5.0)") public double maxTimeRatio = calcMaxTimeRatio(); @Getter @Setter - @Parameter(names = {"--save-internaltx"}, description = "Save internal transactions generated " - + "during TVM execution, such as create, call and suicide. (default: false)") public boolean saveInternalTx; @Getter @Setter - @Parameter(names = {"--save-featured-internaltx"}, description = "Save featured internal " - + "transactions generated during TVM execution, such as freeze, vote and so on. " - + "(default: false)") public boolean saveFeaturedInternalTx; @Getter @Setter - @Parameter(names = {"--save-cancel-all-unfreeze-v2-details"}, description = "Record the details of the internal " - + "transactions generated by the CANCELALLUNFREEZEV2 opcode, such as bandwidth/energy/tronpower cancel amount. " - + "(default: false)") public boolean saveCancelAllUnfreezeV2Details; @Getter @Setter - @Parameter(names = {"--long-running-time"}) public int longRunningTime = 10; @Getter @Setter - @Parameter(names = {"--max-connect-number"}, description = "Http server max connect number " - + "(default:50)") public int maxHttpConnectNumber = 50; @Getter - @Parameter(description = "--seed-nodes") public List seedNodes = new ArrayList<>(); - @Parameter(names = {"-p", "--private-key"}, description = "Witness private key") public String privateKey = ""; - @Parameter(names = {"--witness-address"}, description = "witness-address") public String witnessAddress = ""; - @Parameter(names = {"--password"}, description = "password") public String password; - @Parameter(names = {"--storage-db-directory"}, description = "Storage db directory") public String storageDbDirectory = ""; - @Parameter(names = { - "--storage-db-engine"}, description = "Storage db engine.(leveldb or rocksdb)") public String storageDbEngine = ""; - @Parameter(names = { - "--storage-db-synchronous"}, - description = "Storage db is synchronous or not.(true or false)") public String storageDbSynchronous = ""; - @Parameter(names = {"--contract-parse-enable"}, description = "Switch for contract parses in " + - "java-tron. (default: true)") public String contractParseEnable = ""; - @Parameter(names = {"--storage-index-directory"}, - description = "Storage index directory") public String storageIndexDirectory = ""; - @Parameter(names = {"--storage-index-switch"}, description = "Storage index switch.(on or off)") public String storageIndexSwitch = ""; - @Parameter(names = {"--storage-transactionHistory-switch"}, - description = "Storage transaction history switch.(on or off)") public String storageTransactionHistorySwitch = ""; @Getter - @Parameter(names = {"--fast-forward"}) public boolean fastForward = false; + + // ── Network / P2P ─────────────────────────────── @Getter @Setter public String chainId; @@ -153,7 +112,7 @@ public class CommonParameter { public boolean nodeEffectiveCheckEnable; @Getter @Setter - public int nodeConnectionTimeout; + public int nodeConnectionTimeout = 2000; // from clearParam(), consistent with mainnet.conf @Getter @Setter public int fetchBlockTimeout; @@ -162,19 +121,19 @@ public class CommonParameter { public int nodeChannelReadTimeout; @Getter @Setter - public int maxConnections; + public int maxConnections = 30; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public int minConnections; + public int minConnections = 8; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public int minActiveConnections; + public int minActiveConnections = 3; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public int maxConnectionsWithSameIp; + public int maxConnectionsWithSameIp = 2; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public int maxTps; + public int maxTps; // clearParam: 1000 @Getter @Setter public int minParticipationRate; @@ -197,26 +156,27 @@ public class CommonParameter { public boolean nodeEnableIpv6 = false; @Getter @Setter - public List dnsTreeUrls; + public List dnsTreeUrls; // clearParam: new ArrayList<>() @Getter @Setter public PublishConfig dnsPublishConfig; @Getter @Setter - public long syncFetchBatchNum; + public long syncFetchBatchNum; // clearParam: 2000 - //If you are running a solidity node for java tron, this flag is set to true + // If you are running a solidity node for java tron, + // this flag is set to true @Getter @Setter - @Parameter(names = {"--solidity"}, description = "running a solidity node for java tron") public boolean solidityNode = false; - //If you are running KeystoreFactory, this flag is set to true + // If you are running KeystoreFactory, + // this flag is set to true @Getter @Setter - @Parameter(names = {"--keystore-factory"}, description = "running KeystoreFactory") public boolean keystoreFactory = false; + // ── RPC / HTTP ────────────────────────────────── @Getter @Setter public int rpcPort; @@ -240,11 +200,9 @@ public class CommonParameter { public int jsonRpcHttpPBFTPort; @Getter @Setter - @Parameter(names = {"--rpc-thread"}, description = "Num of gRPC thread") public int rpcThreadNum; @Getter @Setter - @Parameter(names = {"--solidity-thread"}, description = "Num of solidity thread") public int solidityThreads; @Getter @Setter @@ -252,12 +210,9 @@ public class CommonParameter { @Getter @Setter public int flowControlWindow; - // the positive limit of RST_STREAM frames per connection per period for grpc, - // 0 or Integer.MAX_VALUE for unlimited, by default there is no limit. @Getter @Setter public int rpcMaxRstStream; - // the positive number of seconds per period for grpc @Getter @Setter public int rpcSecondsPerWindow; @@ -284,42 +239,44 @@ public class CommonParameter { public boolean isRpcReflectionServiceEnable; @Getter @Setter - @Parameter(names = {"--validate-sign-thread"}, description = "Num of validate thread") public int validateSignThreadNum; @Getter @Setter - public long maintenanceTimeInterval; // (ms) + public long maintenanceTimeInterval; @Getter @Setter - public long proposalExpireTime; // (ms) + public long proposalExpireTime; @Getter @Setter - public int checkFrozenTime; // for test only + public int checkFrozenTime; // clearParam: 1 + + // ── Committee parameters ──────────────────────── @Getter @Setter - public long allowCreationOfContracts; //committee parameter + public long allowCreationOfContracts; @Getter @Setter - public long allowAdaptiveEnergy; //committee parameter + public long allowAdaptiveEnergy; @Getter @Setter - public long allowDelegateResource; //committee parameter + public long allowDelegateResource; @Getter @Setter - public long allowSameTokenName; //committee parameter + public long allowSameTokenName; @Getter @Setter - public long allowTvmTransferTrc10; //committee parameter + public long allowTvmTransferTrc10; @Getter @Setter - public long allowTvmConstantinople; //committee parameter + public long allowTvmConstantinople; @Getter @Setter - public long allowTvmSolidity059; //committee parameter + public long allowTvmSolidity059; @Getter @Setter - public long forbidTransferToContract; //committee parameter + public long forbidTransferToContract; + // ── Netty ─────────────────────────────────────── @Getter @Setter public int tcpNettyWorkThreadNum; @@ -328,8 +285,7 @@ public class CommonParameter { public int udpNettyWorkThreadNum; @Getter @Setter - @Parameter(names = {"--trust-node"}, description = "Trust node addr") - public String trustNodeAddr; + public String trustNodeAddr; // clearParam: "" @Getter @Setter public boolean walletExtensionApi; @@ -338,7 +294,7 @@ public class CommonParameter { public boolean estimateEnergy; @Getter @Setter - public int estimateEnergyMaxRetry; + public int estimateEnergyMaxRetry = 3; // from clearParam(), consistent with mainnet.conf @Getter @Setter public int backupPriority; @@ -353,13 +309,13 @@ public class CommonParameter { public List backupMembers; @Getter @Setter - public long receiveTcpMinDataLength; + public long receiveTcpMinDataLength; // clearParam: 2048 @Getter @Setter public boolean isOpenFullTcpDisconnect; @Getter @Setter - public int inactiveThreshold; + public int inactiveThreshold = 600; // from clearParam(), consistent with mainnet.conf @Getter @Setter public boolean nodeDetectEnable; @@ -383,42 +339,33 @@ public class CommonParameter { public boolean trxCacheEnable; @Getter @Setter - public long allowMarketTransaction; //committee parameter - + public long allowMarketTransaction; @Getter @Setter public long allowTransactionFeePool; - @Getter @Setter public long allowBlackHoleOptimization; - @Getter @Setter public long allowNewResourceModel; - // @Getter - // @Setter - // public long allowShieldedTransaction; //committee parameter - // full node used this parameter to close shielded transaction @Getter @Setter - public boolean allowShieldedTransactionApi; + public boolean allowShieldedTransactionApi; // clearParam: true @Getter @Setter public long blockNumForEnergyLimit; @Getter @Setter - @Parameter(names = {"--es"}, description = "Start event subscribe server") public boolean eventSubscribe = false; @Getter @Setter - public long trxExpirationTimeInMilliseconds; // (ms) - @Parameter(names = {"-v", "--version"}, description = "Output code version", help = true) + public long trxExpirationTimeInMilliseconds; public boolean version; @Getter @Setter - public String zenTokenId; + public String zenTokenId; // clearParam: "000000" @Getter @Setter public long allowProtoFilterNum; @@ -430,7 +377,7 @@ public class CommonParameter { public int validContractProtoThreadNum = 1; @Getter @Setter - public int shieldedTransInPendingMaxCounts; + public int shieldedTransInPendingMaxCounts; // clearParam: 10 @Getter @Setter public long changedDelegation; @@ -442,21 +389,21 @@ public class CommonParameter { public RateLimiterInitialization rateLimiterInitialization; @Getter @Setter - public int rateLimiterGlobalQps; + public int rateLimiterGlobalQps = 50000; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public int rateLimiterGlobalIpQps; + public int rateLimiterGlobalIpQps = 10000; // from clearParam(), consistent with mainnet.conf @Getter - public int rateLimiterGlobalApiQps; + public int rateLimiterGlobalApiQps = 1000; // from clearParam(), consistent with mainnet.conf @Getter @Setter - public double rateLimiterSyncBlockChain; + public double rateLimiterSyncBlockChain; // clearParam: 3.0 @Getter @Setter - public double rateLimiterFetchInvData; + public double rateLimiterFetchInvData; // clearParam: 3.0 @Getter @Setter - public double rateLimiterDisconnect; + public double rateLimiterDisconnect; // clearParam: 1.0 @Getter public DbBackupConfig dbBackupConfig; @Getter @@ -465,19 +412,17 @@ public class CommonParameter { public GenesisBlock genesisBlock; @Getter @Setter - @Parameter(names = {"--p2p-disable"}, description = "Switch for p2p module initialization. " - + "(defalut: false)", arity = 1) public boolean p2pDisable = false; @Getter @Setter - public List activeNodes; + public List activeNodes = new ArrayList<>(); // from clearParam(), consistent with mainnet.conf @Getter @Setter - public List passiveNodes; + public List passiveNodes = new ArrayList<>(); // from clearParam(), consistent with mainnet.conf @Getter - public List fastForwardNodes; + public List fastForwardNodes; // clearParam: new ArrayList<>() @Getter - public int maxFastForwardNum; + public int maxFastForwardNum; // clearParam: 4 @Getter public Storage storage; @Getter @@ -495,26 +440,21 @@ public class CommonParameter { @Getter @Setter public boolean rpcEnable = true; - @Getter @Setter public boolean rpcSolidityEnable = true; - @Getter @Setter public boolean rpcPBFTEnable = true; - @Getter @Setter public boolean fullNodeHttpEnable = true; @Getter @Setter public boolean solidityNodeHttpEnable = true; - @Getter @Setter public boolean pBFTHttpEnable = true; - @Getter @Setter public boolean jsonRpcHttpFullNodeEnable = false; @@ -543,39 +483,30 @@ public class CommonParameter { @Getter @Setter public boolean nodeMetricsEnable = false; - @Getter @Setter public boolean metricsStorageEnable = false; - @Getter @Setter public String influxDbIp; - @Getter @Setter public int influxDbPort; - @Getter @Setter public String influxDbDatabase; - @Getter @Setter public int metricsReportInterval = 10; - @Getter @Setter public boolean metricsPrometheusEnable = false; - @Getter @Setter public int metricsPrometheusPort; - @Getter @Setter public int agreeNodeCount; - @Getter @Setter public long allowPBFT; @@ -587,177 +518,136 @@ public class CommonParameter { public int pBFTHttpPort; @Getter @Setter - public long pBFTExpireNum; + public long pBFTExpireNum; // clearParam: 20 @Getter @Setter public long oldSolidityBlockNum = -1; - @Getter/**/ + @Getter @Setter public long allowShieldedTRC20Transaction; - - @Getter/**/ + @Getter @Setter public long allowTvmIstanbul; - @Getter @Setter public long allowTvmFreeze; - @Getter @Setter public long allowTvmVote; - @Getter @Setter public long allowTvmLondon; - @Getter @Setter public long allowTvmCompatibleEvm; - @Getter @Setter public long allowHigherLimitForMaxCpuTimeOfOneTx; - @Getter @Setter public boolean openHistoryQueryWhenLiteFN = false; - @Getter @Setter - @Parameter(names = {"--history-balance-lookup"}) public boolean historyBalanceLookup = false; - @Getter @Setter public boolean openPrintLog = true; @Getter @Setter public boolean openTransactionSort = false; - @Getter @Setter public long allowAccountAssetOptimization; - @Getter @Setter public long allowAssetOptimization; - @Getter @Setter - public List disabledApiList; - + public List disabledApiList; // clearParam: Collections.emptyList() @Getter @Setter public CronExpression shutdownBlockTime = null; - @Getter @Setter public long shutdownBlockHeight = -1; - @Getter @Setter public long shutdownBlockCount = -1; - @Getter @Setter public long blockCacheTimeout = 60; - @Getter @Setter public long allowNewRewardAlgorithm; - @Getter @Setter public long allowNewReward = 0L; - @Getter @Setter public long memoFee = 0L; - @Getter @Setter public long allowDelegateOptimization = 0L; - @Getter @Setter public long unfreezeDelayDays = 0L; - @Getter @Setter public long allowOptimizedReturnValueOfChainId = 0L; - @Getter @Setter public long allowDynamicEnergy = 0L; - @Getter @Setter public long dynamicEnergyThreshold = 0L; - @Getter @Setter public long dynamicEnergyIncreaseFactor = 0L; - @Getter @Setter public long dynamicEnergyMaxFactor = 0L; - @Getter @Setter public boolean dynamicConfigEnable; - @Getter @Setter - public long dynamicConfigCheckInterval; - + public long dynamicConfigCheckInterval; // clearParam: 600 @Getter @Setter public long allowTvmShangHai; - @Getter @Setter public long allowCancelAllUnfreezeV2; - @Getter @Setter public boolean unsolidifiedBlockCheck; - @Getter @Setter - public int maxUnsolidifiedBlocks; - + public int maxUnsolidifiedBlocks; // clearParam: 54 @Getter @Setter public long allowOldRewardOpt; - @Getter @Setter public long allowEnergyAdjustment; - @Getter @Setter public long maxCreateAccountTxSize = 1000L; - @Getter @Setter public long allowStrictMath; - @Getter @Setter - public long consensusLogicOptimization; - + public long consensusLogicOptimization; @Getter @Setter public long allowTvmCancun; - @Getter @Setter public long allowTvmBlob; private static double calcMaxTimeRatio() { - //return max(2.0, min(5.0, 5 * 4.0 / max(Runtime.getRuntime().availableProcessors(), 1))); return 5.0; } @@ -765,13 +655,24 @@ public static CommonParameter getInstance() { return PARAMETER; } - public boolean isECKeyCryptoEngine() { + /** + * Reset to a fresh instance. Test-only. + */ + @VisibleForTesting + public static void reset() { + if (PARAMETER.storage != null) { + PARAMETER.storage.deleteAllStoragePaths(); + } + PARAMETER = new CommonParameter(); + } + public boolean isECKeyCryptoEngine() { return cryptoEngine.equalsIgnoreCase(Constant.ECKey_ENGINE); } public boolean isJsonRpcFilterEnabled() { - return jsonRpcHttpFullNodeEnable || jsonRpcHttpSolidityNodeEnable; + return jsonRpcHttpFullNodeEnable + || jsonRpcHttpSolidityNodeEnable; } public int getSafeLruCacheSize() { diff --git a/framework/build.gradle b/framework/build.gradle index 59d070e066d..f781b74617b 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -38,6 +38,7 @@ dependencies { //local libraries implementation fileTree(dir: 'libs', include: '*.jar') // end local libraries + implementation group: 'com.beust', name: 'jcommander', version: '1.78' implementation group: 'io.dropwizard.metrics', name: 'metrics-core', version: '3.1.2' implementation group: 'com.github.davidb', name: 'metrics-influxdb', version: '0.8.2' // http diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 38f1fe4f959..4359cf91c0c 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -100,163 +100,8 @@ public class Args extends CommonParameter { public static void clearParam() { - PARAMETER.shellConfFileName = ""; - PARAMETER.configFilePath = ""; - PARAMETER.outputDirectory = "output-directory"; - PARAMETER.help = false; - PARAMETER.witness = false; - PARAMETER.seedNodes = new ArrayList<>(); - PARAMETER.privateKey = ""; - PARAMETER.witnessAddress = ""; - PARAMETER.storageDbDirectory = ""; - PARAMETER.storageIndexDirectory = ""; - PARAMETER.storageIndexSwitch = ""; - - // FIXME: PARAMETER.storage maybe null ? - if (PARAMETER.storage != null) { - // WARNING: WILL DELETE DB STORAGE PATHS - PARAMETER.storage.deleteAllStoragePaths(); - PARAMETER.storage = null; - } - - PARAMETER.overlay = null; - PARAMETER.seedNode = null; - PARAMETER.genesisBlock = null; - PARAMETER.chainId = null; + CommonParameter.reset(); localWitnesses = null; - PARAMETER.needSyncCheck = false; - PARAMETER.nodeDiscoveryEnable = false; - PARAMETER.nodeDiscoveryPersist = false; - PARAMETER.nodeEffectiveCheckEnable = false; - PARAMETER.nodeConnectionTimeout = 2000; - PARAMETER.activeNodes = new ArrayList<>(); - PARAMETER.passiveNodes = new ArrayList<>(); - PARAMETER.fastForwardNodes = new ArrayList<>(); - PARAMETER.maxFastForwardNum = 4; - PARAMETER.nodeChannelReadTimeout = 0; - PARAMETER.maxConnections = 30; - PARAMETER.minConnections = 8; - PARAMETER.minActiveConnections = 3; - PARAMETER.maxConnectionsWithSameIp = 2; - PARAMETER.maxTps = 1000; - PARAMETER.minParticipationRate = 0; - PARAMETER.nodeListenPort = 0; - PARAMETER.nodeLanIp = ""; - PARAMETER.nodeExternalIp = ""; - PARAMETER.nodeP2pVersion = 0; - PARAMETER.nodeEnableIpv6 = false; - PARAMETER.dnsTreeUrls = new ArrayList<>(); - PARAMETER.dnsPublishConfig = null; - PARAMETER.syncFetchBatchNum = 2000; - PARAMETER.rpcPort = 0; - PARAMETER.rpcOnSolidityPort = 0; - PARAMETER.rpcOnPBFTPort = 0; - PARAMETER.fullNodeHttpPort = 0; - PARAMETER.solidityHttpPort = 0; - PARAMETER.pBFTHttpPort = 0; - PARAMETER.pBFTExpireNum = 20; - PARAMETER.jsonRpcHttpFullNodePort = 0; - PARAMETER.jsonRpcHttpSolidityPort = 0; - PARAMETER.jsonRpcHttpPBFTPort = 0; - PARAMETER.maintenanceTimeInterval = 0; - PARAMETER.proposalExpireTime = 0; - PARAMETER.checkFrozenTime = 1; - PARAMETER.allowCreationOfContracts = 0; - PARAMETER.allowAdaptiveEnergy = 0; - PARAMETER.allowTvmTransferTrc10 = 0; - PARAMETER.allowTvmConstantinople = 0; - PARAMETER.allowDelegateResource = 0; - PARAMETER.allowSameTokenName = 0; - PARAMETER.allowTvmSolidity059 = 0; - PARAMETER.forbidTransferToContract = 0; - PARAMETER.tcpNettyWorkThreadNum = 0; - PARAMETER.udpNettyWorkThreadNum = 0; - PARAMETER.solidityNode = false; - PARAMETER.keystoreFactory = false; - PARAMETER.trustNodeAddr = ""; - PARAMETER.walletExtensionApi = false; - PARAMETER.estimateEnergy = false; - PARAMETER.estimateEnergyMaxRetry = 3; - PARAMETER.receiveTcpMinDataLength = 2048; - PARAMETER.isOpenFullTcpDisconnect = false; - PARAMETER.nodeDetectEnable = false; - PARAMETER.inactiveThreshold = 600; - PARAMETER.supportConstant = false; - PARAMETER.debug = false; - PARAMETER.minTimeRatio = 0.0; - PARAMETER.maxTimeRatio = 5.0; - PARAMETER.longRunningTime = 10; - // PARAMETER.allowShieldedTransaction = 0; - PARAMETER.maxHttpConnectNumber = 50; - PARAMETER.allowMultiSign = 0; - PARAMETER.trxExpirationTimeInMilliseconds = 0; - PARAMETER.allowShieldedTransactionApi = true; - PARAMETER.zenTokenId = "000000"; - PARAMETER.allowProtoFilterNum = 0; - PARAMETER.allowAccountStateRoot = 0; - PARAMETER.validContractProtoThreadNum = 1; - PARAMETER.shieldedTransInPendingMaxCounts = 10; - PARAMETER.changedDelegation = 0; - PARAMETER.rpcEnable = true; - PARAMETER.rpcSolidityEnable = true; - PARAMETER.rpcPBFTEnable = true; - PARAMETER.fullNodeHttpEnable = true; - PARAMETER.solidityNodeHttpEnable = true; - PARAMETER.pBFTHttpEnable = true; - PARAMETER.jsonRpcHttpFullNodeEnable = false; - PARAMETER.jsonRpcHttpSolidityNodeEnable = false; - PARAMETER.jsonRpcHttpPBFTNodeEnable = false; - PARAMETER.jsonRpcMaxBlockRange = 5000; - PARAMETER.jsonRpcMaxSubTopics = 1000; - PARAMETER.jsonRpcMaxBlockFilterNum = 50000; - PARAMETER.nodeMetricsEnable = false; - PARAMETER.metricsStorageEnable = false; - PARAMETER.metricsPrometheusEnable = false; - PARAMETER.agreeNodeCount = MAX_ACTIVE_WITNESS_NUM * 2 / 3 + 1; - PARAMETER.allowPBFT = 0; - PARAMETER.allowShieldedTRC20Transaction = 0; - PARAMETER.allowMarketTransaction = 0; - PARAMETER.allowTransactionFeePool = 0; - PARAMETER.allowBlackHoleOptimization = 0; - PARAMETER.allowNewResourceModel = 0; - PARAMETER.allowTvmIstanbul = 0; - PARAMETER.allowTvmFreeze = 0; - PARAMETER.allowTvmVote = 0; - PARAMETER.allowTvmLondon = 0; - PARAMETER.allowTvmCompatibleEvm = 0; - PARAMETER.historyBalanceLookup = false; - PARAMETER.openPrintLog = true; - PARAMETER.openTransactionSort = false; - PARAMETER.allowAccountAssetOptimization = 0; - PARAMETER.allowAssetOptimization = 0; - PARAMETER.disabledApiList = Collections.emptyList(); - PARAMETER.shutdownBlockTime = null; - PARAMETER.shutdownBlockHeight = -1; - PARAMETER.shutdownBlockCount = -1; - PARAMETER.blockCacheTimeout = 60; - PARAMETER.allowNewRewardAlgorithm = 0; - PARAMETER.allowNewReward = 0; - PARAMETER.memoFee = 0; - PARAMETER.rateLimiterGlobalQps = 50000; - PARAMETER.rateLimiterGlobalIpQps = 10000; - PARAMETER.rateLimiterGlobalApiQps = 1000; - PARAMETER.rateLimiterSyncBlockChain = 3.0; - PARAMETER.rateLimiterFetchInvData = 3.0; - PARAMETER.rateLimiterDisconnect = 1.0; - PARAMETER.p2pDisable = false; - PARAMETER.dynamicConfigEnable = false; - PARAMETER.dynamicConfigCheckInterval = 600; - PARAMETER.allowTvmShangHai = 0; - PARAMETER.unsolidifiedBlockCheck = false; - PARAMETER.maxUnsolidifiedBlocks = 54; - PARAMETER.allowOldRewardOpt = 0; - PARAMETER.allowEnergyAdjustment = 0; - PARAMETER.allowStrictMath = 0; - PARAMETER.consensusLogicOptimization = 0; - PARAMETER.allowTvmCancun = 0; - PARAMETER.allowTvmBlob = 0; - PARAMETER.rpcMaxRstStream = 0; - PARAMETER.rpcSecondsPerWindow = 0; } /** @@ -366,7 +211,7 @@ private static Map getOptionGroup() { for (String[] optionList : optionGroupMap.values()) { for (String option : optionList) { try { - CommonParameter.class.getField(option); + CLIParameter.class.getField(option); } catch (NoSuchFieldException e) { logger.warn("NoSuchFieldException:{},{}", option, e.getMessage()); } @@ -378,36 +223,48 @@ private static Map getOptionGroup() { /** * set parameters. */ - public static void setParam(final String[] args, final String confFileName) { + public static void setParam(final String[] args, + final String confFileName) { try { Arch.throwIfUnsupportedJavaVersion(); } catch (UnsupportedOperationException e) { AnsiConsole.systemInstall(); - // To avoid confusion caused by silent execution when using -h or -v flags, - // errors are explicitly logged to the console in this context. - // Console output is not required for errors in other scenarios. - System.out.println(ansi().fgRed().a(e.getMessage()).reset()); + System.out.println( + ansi().fgRed().a(e.getMessage()).reset()); AnsiConsole.systemUninstall(); throw new TronError(e, TronError.ErrCode.JDK_VERSION); } - JCommander.newBuilder().addObject(PARAMETER).build().parse(args); - if (PARAMETER.version) { + + // 1. Parse CLI args into a separate object + CLIParameter cmd = new CLIParameter(); + JCommander jc = + JCommander.newBuilder().addObject(cmd).build(); + jc.parse(args); + + if (cmd.version) { printVersion(); exit(0); } - - if (PARAMETER.isHelp()) { - JCommander jCommander = JCommander.newBuilder().addObject(Args.PARAMETER).build(); - jCommander.parse(args); - Args.printHelp(jCommander); + if (cmd.help) { + Args.printHelp(jc); exit(0); } - PARAMETER.setConfigFilePath( - StringUtils.isNoneBlank(PARAMETER.shellConfFileName) - ? PARAMETER.shellConfFileName : confFileName); - Config config = Configuration.getByFileName(PARAMETER.shellConfFileName, confFileName); + // Resolve config file path + PARAMETER.configFilePath = + StringUtils.isNoneBlank(cmd.shellConfFileName) + ? cmd.shellConfFileName : confFileName; + Config config = Configuration.getByFileName( + cmd.shellConfFileName, confFileName); + + // 2. Config overrides defaults setParam(config); + + // 3. CLI overrides Config (highest priority) + setCommandParam(cmd, jc); + + // 4. Init witness (depends on CLI witness flag) + initLocalWitnesses(config); } /** @@ -421,13 +278,6 @@ public static void setParam(final Config config) { PARAMETER.cryptoEngine = config.hasPath(ConfigKey.CRYPTO_ENGINE) ? config .getString(ConfigKey.CRYPTO_ENGINE) : Constant.ECKey_ENGINE; - localWitnesses = new WitnessInitializer(config).initLocalWitnesses(); - if (PARAMETER.isWitness() - && CollectionUtils.isEmpty(localWitnesses.getPrivateKeys())) { - throw new TronError("This is a witness node, but localWitnesses is null", - TronError.ErrCode.WITNESS_INIT); - } - if (config.hasPath(ConfigKey.VM_SUPPORT_CONSTANT)) { PARAMETER.supportConstant = config.getBoolean(ConfigKey.VM_SUPPORT_CONSTANT); } @@ -1292,6 +1142,158 @@ public static void setParam(final Config config) { logConfig(); } + /** + * Apply CLI parameters that were explicitly passed. + * Only assigned parameters override Config values. + */ + private static void setCommandParam(CLIParameter cmd, + JCommander jc) { + Map assigned = + jc.getParameters().stream() + .filter(ParameterDescription::isAssigned) + .collect(Collectors.toMap( + ParameterDescription::getLongestName, + p -> p)); + + if (assigned.containsKey("--output-directory")) { + PARAMETER.outputDirectory = cmd.outputDirectory; + } + if (assigned.containsKey("--witness")) { + PARAMETER.witness = cmd.witness; + } + if (assigned.containsKey("--support-constant")) { + PARAMETER.supportConstant = cmd.supportConstant; + } + if (assigned.containsKey( + "--max-energy-limit-for-constant")) { + PARAMETER.maxEnergyLimitForConstant = + cmd.maxEnergyLimitForConstant; + } + if (assigned.containsKey("--lru-cache-size")) { + PARAMETER.lruCacheSize = cmd.lruCacheSize; + } + if (assigned.containsKey("--debug")) { + PARAMETER.debug = cmd.debug; + } + if (assigned.containsKey("--min-time-ratio")) { + PARAMETER.minTimeRatio = cmd.minTimeRatio; + } + if (assigned.containsKey("--max-time-ratio")) { + PARAMETER.maxTimeRatio = cmd.maxTimeRatio; + } + if (assigned.containsKey("--save-internaltx")) { + PARAMETER.saveInternalTx = cmd.saveInternalTx; + } + if (assigned.containsKey( + "--save-featured-internaltx")) { + PARAMETER.saveFeaturedInternalTx = + cmd.saveFeaturedInternalTx; + } + if (assigned.containsKey( + "--save-cancel-all-unfreeze-v2-details")) { + PARAMETER.saveCancelAllUnfreezeV2Details = + cmd.saveCancelAllUnfreezeV2Details; + } + if (assigned.containsKey("--long-running-time")) { + PARAMETER.longRunningTime = cmd.longRunningTime; + } + if (assigned.containsKey("--max-connect-number")) { + PARAMETER.maxHttpConnectNumber = + cmd.maxHttpConnectNumber; + } + if (assigned.containsKey("--storage-db-directory")) { + PARAMETER.storageDbDirectory = + cmd.storageDbDirectory; + } + if (assigned.containsKey("--storage-db-engine")) { + PARAMETER.storageDbEngine = cmd.storageDbEngine; + } + if (assigned.containsKey( + "--storage-db-synchronous")) { + PARAMETER.storageDbSynchronous = + cmd.storageDbSynchronous; + } + if (assigned.containsKey( + "--contract-parse-enable")) { + PARAMETER.contractParseEnable = + cmd.contractParseEnable; + } + if (assigned.containsKey( + "--storage-index-directory")) { + PARAMETER.storageIndexDirectory = + cmd.storageIndexDirectory; + } + if (assigned.containsKey( + "--storage-index-switch")) { + PARAMETER.storageIndexSwitch = + cmd.storageIndexSwitch; + } + if (assigned.containsKey( + "--storage-transactionHistory-switch")) { + PARAMETER.storageTransactionHistorySwitch = + cmd.storageTransactionHistorySwitch; + } + if (assigned.containsKey("--fast-forward")) { + PARAMETER.fastForward = cmd.fastForward; + } + if (assigned.containsKey("--solidity")) { + PARAMETER.solidityNode = cmd.solidityNode; + } + if (assigned.containsKey("--keystore-factory")) { + PARAMETER.keystoreFactory = cmd.keystoreFactory; + } + if (assigned.containsKey("--rpc-thread")) { + PARAMETER.rpcThreadNum = cmd.rpcThreadNum; + } + if (assigned.containsKey("--solidity-thread")) { + PARAMETER.solidityThreads = cmd.solidityThreads; + } + if (assigned.containsKey( + "--validate-sign-thread")) { + PARAMETER.validateSignThreadNum = + cmd.validateSignThreadNum; + } + if (assigned.containsKey("--trust-node")) { + PARAMETER.trustNodeAddr = cmd.trustNodeAddr; + } + if (assigned.containsKey("--es")) { + PARAMETER.eventSubscribe = cmd.eventSubscribe; + } + if (assigned.containsKey("--p2p-disable")) { + PARAMETER.p2pDisable = cmd.p2pDisable; + } + if (assigned.containsKey( + "--history-balance-lookup")) { + PARAMETER.historyBalanceLookup = + cmd.historyBalanceLookup; + } + if (assigned.containsKey("--log-config")) { + PARAMETER.logbackPath = cmd.logbackPath; + } + if (assigned.containsKey("--private-key")) { + PARAMETER.privateKey = cmd.privateKey; + } + if (assigned.containsKey("--witness-address")) { + PARAMETER.witnessAddress = cmd.witnessAddress; + } + if (assigned.containsKey("--password")) { + PARAMETER.password = cmd.password; + } + } + + private static void initLocalWitnesses(Config config) { + localWitnesses = + new WitnessInitializer(config).initLocalWitnesses(); + if (PARAMETER.isWitness() + && CollectionUtils.isEmpty( + localWitnesses.getPrivateKeys())) { + throw new TronError( + "This is a witness node, " + + "but localWitnesses is null", + TronError.ErrCode.WITNESS_INIT); + } + } + private static long getProposalExpirationTime(final Config config) { if (config.hasPath(ConfigKey.COMMITTEE_PROPOSAL_EXPIRE_TIME)) { throw new TronError("It is not allowed to configure committee.proposalExpireTime in " diff --git a/framework/src/main/java/org/tron/core/config/args/CLIParameter.java b/framework/src/main/java/org/tron/core/config/args/CLIParameter.java new file mode 100644 index 00000000000..2dfec98e942 --- /dev/null +++ b/framework/src/main/java/org/tron/core/config/args/CLIParameter.java @@ -0,0 +1,194 @@ +package org.tron.core.config.args; + +import com.beust.jcommander.Parameter; +import java.util.ArrayList; +import java.util.List; +import lombok.NoArgsConstructor; + +/** + * CLI parameter definitions parsed by JCommander. + * Fields here have NO default values — defaults live in CommonParameter. + * JCommander only populates fields that are explicitly passed on the + * command line. + */ +@NoArgsConstructor +public class CLIParameter { + + // ── Startup parameters ────────────────────────── + + @Parameter(names = {"-c", "--config"}, + description = "Config file (default:config.conf)") + public String shellConfFileName; + + @Parameter(names = {"-d", "--output-directory"}, + description = "Data directory for the databases" + + " (default:output-directory)") + public String outputDirectory; + + @Parameter(names = {"--log-config"}, + description = "Logback config file") + public String logbackPath; + + @Parameter(names = {"-h", "--help"}, help = true, + description = "Show help message") + public boolean help; + + @Parameter(names = {"-v", "--version"}, + description = "Output code version", help = true) + public boolean version; + + @Parameter(names = {"-w", "--witness"}, + description = "Is witness node") + public boolean witness; + + @Parameter(names = {"-p", "--private-key"}, + description = "Witness private key") + public String privateKey; + + @Parameter(names = {"--witness-address"}, + description = "witness-address") + public String witnessAddress; + + @Parameter(names = {"--password"}, + description = "password") + public String password; + + @Parameter(names = {"--solidity"}, + description = "running a solidity node for java tron") + public boolean solidityNode; + + @Parameter(names = {"--keystore-factory"}, + description = "running KeystoreFactory") + public boolean keystoreFactory; + + @Parameter(names = {"--fast-forward"}) + public boolean fastForward; + + @Parameter(names = {"--es"}, + description = "Start event subscribe server") + public boolean eventSubscribe; + + @Parameter(names = {"--p2p-disable"}, + description = "Switch for p2p module initialization." + + " (defalut: false)", arity = 1) + public boolean p2pDisable; + + @Parameter(description = "--seed-nodes") + public List seedNodes = new ArrayList<>(); + + // ── Storage parameters ────────────────────────── + + @Parameter(names = {"--storage-db-directory"}, + description = "Storage db directory") + public String storageDbDirectory; + + @Parameter(names = {"--storage-db-engine"}, + description = "Storage db engine." + + "(leveldb or rocksdb)") + public String storageDbEngine; + + @Parameter(names = {"--storage-db-synchronous"}, + description = "Storage db is synchronous or not." + + "(true or false)") + public String storageDbSynchronous; + + @Parameter(names = {"--storage-index-directory"}, + description = "Storage index directory") + public String storageIndexDirectory; + + @Parameter(names = {"--storage-index-switch"}, + description = "Storage index switch.(on or off)") + public String storageIndexSwitch; + + @Parameter(names = {"--storage-transactionHistory-switch"}, + description = "Storage transaction history switch." + + "(on or off)") + public String storageTransactionHistorySwitch; + + @Parameter(names = {"--contract-parse-enable"}, + description = "Switch for contract parses in" + + " java-tron. (default: true)") + public String contractParseEnable; + + // ── Runtime parameters ────────────────────────── + + @Parameter(names = {"--support-constant"}, + description = "Support constant calling for TVM." + + " (defalut: false)") + public boolean supportConstant; + + @Parameter(names = {"--max-energy-limit-for-constant"}, + description = "Max energy limit for constant calling." + + " (default: 100,000,000)") + public long maxEnergyLimitForConstant; + + @Parameter(names = {"--lru-cache-size"}, + description = "Max LRU size for caching bytecode and" + + " result of JUMPDEST analysis. (default: 500)") + public int lruCacheSize; + + @Parameter(names = {"--debug"}, + description = "Switch for TVM debug mode. In debug" + + " model, TVM will not check for timeout." + + " (default: false)") + public boolean debug; + + @Parameter(names = {"--min-time-ratio"}, + description = "Minimum CPU tolerance when executing" + + " timeout transactions while synchronizing" + + " blocks. (default: 0.0)") + public double minTimeRatio; + + @Parameter(names = {"--max-time-ratio"}, + description = "Maximum CPU tolerance when executing" + + " non-timeout transactions while synchronizing" + + " blocks. (default: 5.0)") + public double maxTimeRatio; + + @Parameter(names = {"--save-internaltx"}, + description = "Save internal transactions generated" + + " during TVM execution, such as create, call" + + " and suicide. (default: false)") + public boolean saveInternalTx; + + @Parameter(names = {"--save-featured-internaltx"}, + description = "Save featured internal transactions" + + " generated during TVM execution, such as" + + " freeze, vote and so on. (default: false)") + public boolean saveFeaturedInternalTx; + + @Parameter(names = {"--save-cancel-all-unfreeze-v2-details"}, + description = "Record the details of the internal" + + " transactions generated by the" + + " CANCELALLUNFREEZEV2 opcode, such as" + + " bandwidth/energy/tronpower cancel amount." + + " (default: false)") + public boolean saveCancelAllUnfreezeV2Details; + + @Parameter(names = {"--long-running-time"}) + public int longRunningTime; + + @Parameter(names = {"--max-connect-number"}, + description = "Http server max connect number" + + " (default:50)") + public int maxHttpConnectNumber; + + @Parameter(names = {"--rpc-thread"}, + description = "Num of gRPC thread") + public int rpcThreadNum; + + @Parameter(names = {"--solidity-thread"}, + description = "Num of solidity thread") + public int solidityThreads; + + @Parameter(names = {"--validate-sign-thread"}, + description = "Num of validate thread") + public int validateSignThreadNum; + + @Parameter(names = {"--trust-node"}, + description = "Trust node addr") + public String trustNodeAddr; + + @Parameter(names = {"--history-balance-lookup"}) + public boolean historyBalanceLookup; +} diff --git a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java index 2a97b6ab631..be5817407f5 100644 --- a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java +++ b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java @@ -8,6 +8,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.tron.common.crypto.SignInterface; +import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.Commons; import org.tron.common.utils.LocalWitnesses; @@ -29,7 +30,7 @@ public WitnessInitializer(Config config) { } public LocalWitnesses initLocalWitnesses() { - if (!Args.PARAMETER.isWitness()) { + if (!Args.getInstance().isWitness()) { return localWitnesses; } @@ -47,14 +48,15 @@ public LocalWitnesses initLocalWitnesses() { } private boolean tryInitFromCommandLine() { - if (StringUtils.isBlank(Args.PARAMETER.privateKey)) { + CommonParameter parameter = Args.getInstance(); + if (StringUtils.isBlank(parameter.privateKey)) { return false; } byte[] witnessAddress = null; - this.localWitnesses = new LocalWitnesses(Args.PARAMETER.privateKey); - if (StringUtils.isNotEmpty(Args.PARAMETER.witnessAddress)) { - witnessAddress = Commons.decodeFromBase58Check(Args.PARAMETER.witnessAddress); + this.localWitnesses = new LocalWitnesses(parameter.privateKey); + if (StringUtils.isNotEmpty(parameter.witnessAddress)) { + witnessAddress = Commons.decodeFromBase58Check(parameter.witnessAddress); if (witnessAddress == null) { throw new TronError("LocalWitnessAccountAddress format from cmd is incorrect", TronError.ErrCode.WITNESS_INIT); @@ -63,7 +65,7 @@ private boolean tryInitFromCommandLine() { } this.localWitnesses.initWitnessAccountAddress(witnessAddress, - Args.PARAMETER.isECKeyCryptoEngine()); + parameter.isECKeyCryptoEngine()); logger.debug("Got privateKey from cmd"); return true; } @@ -79,7 +81,7 @@ private boolean tryInitFromConfig() { logger.debug("Got privateKey from config.conf"); byte[] witnessAddress = getWitnessAddress(); this.localWitnesses.initWitnessAccountAddress(witnessAddress, - Args.PARAMETER.isECKeyCryptoEngine()); + Args.getInstance().isECKeyCryptoEngine()); return true; } @@ -96,15 +98,16 @@ private void tryInitFromKeystore() { + "others will be ignored."); } + CommonParameter parameter = Args.getInstance(); List privateKeys = new ArrayList<>(); String fileName = System.getProperty("user.dir") + "/" + localWitness.get(0); String password; - if (StringUtils.isEmpty(Args.PARAMETER.password)) { + if (StringUtils.isEmpty(parameter.password)) { System.out.println("Please input your password."); password = WalletUtils.inputPassword(); } else { - password = Args.PARAMETER.password; - Args.PARAMETER.password = null; + password = parameter.password; + parameter.password = null; } try { @@ -121,7 +124,7 @@ private void tryInitFromKeystore() { this.localWitnesses.setPrivateKeys(privateKeys); byte[] witnessAddress = getWitnessAddress(); this.localWitnesses.initWitnessAccountAddress(witnessAddress, - Args.PARAMETER.isECKeyCryptoEngine()); + parameter.isECKeyCryptoEngine()); logger.debug("Got privateKey from keystore"); } diff --git a/framework/src/test/java/org/tron/common/config/args/ArgsTest.java b/framework/src/test/java/org/tron/common/config/args/ArgsTest.java index 9a7283d18dc..6081021c74f 100644 --- a/framework/src/test/java/org/tron/common/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/common/config/args/ArgsTest.java @@ -13,6 +13,7 @@ import org.tron.common.TestConstants; import org.tron.common.parameter.RateLimiterInitialization; import org.tron.core.config.args.Args; +import org.tron.core.config.args.CLIParameter; public class ArgsTest { @@ -53,7 +54,7 @@ public void testConfig() { @Test public void testHelpMessage() { - JCommander jCommander = JCommander.newBuilder().addObject(Args.PARAMETER).build(); + JCommander jCommander = JCommander.newBuilder().addObject(new CLIParameter()).build(); Method method; try { method = Args.class.getDeclaredMethod("printVersion"); diff --git a/framework/src/test/java/org/tron/core/WalletMockTest.java b/framework/src/test/java/org/tron/core/WalletMockTest.java index ab7ad7ba10c..efcf0da8d0d 100644 --- a/framework/src/test/java/org/tron/core/WalletMockTest.java +++ b/framework/src/test/java/org/tron/core/WalletMockTest.java @@ -87,7 +87,7 @@ public class WalletMockTest { @Before public void init() { - CommonParameter.PARAMETER.setMinEffectiveConnection(0); + CommonParameter.getInstance().setMinEffectiveConnection(0); } @After diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index bdca1f02af5..7e60e0de507 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -71,7 +71,6 @@ public void get() { address = ByteArray.toHexString(Args.getLocalWitnesses() .getWitnessAccountAddress()); Assert.assertEquals("41", DecodeUtil.addressPreFixString); - // configFilePath should be set to shellConfFileName when -c is specified Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); Assert.assertEquals(0, parameter.getBackupPriority()); @@ -139,7 +138,6 @@ public void testIpFromLibP2p() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Args.setParam(new String[] {}, TestConstants.TEST_CONF); CommonParameter parameter = Args.getInstance(); - // configFilePath should fall back to confFileName when -c is not specified Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); String configuredExternalIp = parameter.getNodeExternalIp(); diff --git a/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java b/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java index 43fa59a17a0..e78e4b5fd90 100644 --- a/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java @@ -40,13 +40,11 @@ public void destroy() { @Test public void start() { CommonParameter parameter = Args.getInstance(); - // configFilePath should be resolved from confFileName at startup Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); Assert.assertTrue(parameter.isDynamicConfigEnable()); Assert.assertEquals(600, parameter.getDynamicConfigCheckInterval()); dynamicArgs.init(); - // configFile should be initialized from configFilePath during init() File configFile = (File) ReflectUtils.getFieldObject(dynamicArgs, "configFile"); Assert.assertNotNull(configFile); Assert.assertEquals(TestConstants.TEST_CONF, configFile.getName()); diff --git a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java index b38286ca84d..d23027285a8 100644 --- a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java +++ b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java @@ -62,13 +62,13 @@ public void clear() { @Test public void testInitLocalWitnessesEmpty() { - Args.PARAMETER.setWitness(false); + Args.getInstance().setWitness(false); LocalWitnesses result = witnessInitializer.initLocalWitnesses(); assertNotNull(result); assertTrue(result.getPrivateKeys().isEmpty()); - Args.PARAMETER.setWitness(true); + Args.getInstance().setWitness(true); LocalWitnesses localWitnesses = witnessInitializer.initLocalWitnesses(); assertTrue(localWitnesses.getPrivateKeys().isEmpty()); @@ -191,7 +191,7 @@ public void testTryInitFromKeystore() @Test public void testTryInitFromKeyStore2() throws NoSuchFieldException, IllegalAccessException { - Args.PARAMETER.setWitness(true); + Args.getInstance().setWitness(true); Config mockConfig = mock(Config.class); when(mockConfig.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(false); witnessInitializer = new WitnessInitializer(mockConfig); diff --git a/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java b/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java index e4b6b190b0b..8e1b295a4ca 100644 --- a/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java +++ b/framework/src/test/java/org/tron/core/db/TransactionExpireTest.java @@ -45,7 +45,7 @@ public class TransactionExpireTest { public void init() throws IOException { Args.setParam(new String[] {"--output-directory", temporaryFolder.newFolder().toString()}, TestConstants.TEST_CONF); - CommonParameter.PARAMETER.setMinEffectiveConnection(0); + CommonParameter.getInstance().setMinEffectiveConnection(0); CommonParameter.getInstance().setP2pDisable(true); context = new TronApplicationContext(DefaultConfig.class); From b12924660ccf248d5ae7a14bc6f46fcd1ae929ea Mon Sep 17 00:00:00 2001 From: vividcoder Date: Wed, 4 Mar 2026 02:45:27 +0800 Subject: [PATCH 2/8] refactor(config): restructure Args init flow and WitnessInitializer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Restructure Args.setParam into 4-step flow: parse CLI, apply config, apply CLI overrides, init witnesses - Rename setParam(Config) to applyConfigParams, setCLIParameter to applyCLIParams for clarity - Extract WitnessInitializer into 3 static methods (initFromCLIPrivateKey, initFromCFGPrivateKey, initFromKeystore) with routing in Args - Remove password/privateKey/witnessAddress/help/version/configFilePath from CommonParameter — pass as method params instead of global state - Move JDK version check from Args to FullNode entry point - Extract Configuration.getByFileName for single-param config loading --- .../common/parameter/CommonParameter.java | 23 +- .../org/tron/core/config/Configuration.java | 19 +- .../java/org/tron/core/config/args/Args.java | 348 ++++++++++-------- .../org/tron/core/config/args/ConfigKey.java | 2 +- .../tron/core/config/args/DynamicArgs.java | 4 +- .../core/config/args/WitnessInitializer.java | 182 +++++---- .../main/java/org/tron/program/FullNode.java | 12 + .../java/org/tron/common/ParameterTest.java | 1 - .../tron/core/config/ConfigurationTest.java | 10 +- .../org/tron/core/config/args/ArgsTest.java | 18 +- .../core/config/args/DynamicArgsTest.java | 4 +- .../config/args/WitnessInitializerTest.java | 339 +++++++---------- .../tron/core/exception/TronErrorTest.java | 13 +- .../test/java/org/tron/core/net/NodeTest.java | 2 +- 14 files changed, 456 insertions(+), 521 deletions(-) diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index bbf44900d63..86e98530dc3 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -23,26 +23,20 @@ public class CommonParameter { - public static final String IGNORE_WRONG_WITNESS_ADDRESS_FORMAT = - "The localWitnessAccountAddress format is incorrect," - + " ignored"; - protected static CommonParameter PARAMETER = new CommonParameter(); + // Runtime chain state: set by VMConfig.initVmHardFork() + // when the energy-limit governance proposal is activated. + // Legacy: should belong to VMConfig, not here. @Setter public static boolean ENERGY_LIMIT_HARD_FORK = false; - // ── Config / path ──────────────────────────────── - @Getter - public String configFilePath = ""; + // ── Startup parameters ───────────────────────── @Getter public String outputDirectory = "output-directory"; @Getter public String logbackPath = ""; - - // ── CLI-only flags ─────────────────────────────── - @Getter - public boolean help = false; + // ── Flags (CLI + Config) ───────────────────────── @Getter @Setter public boolean witness = false; @@ -81,9 +75,6 @@ public class CommonParameter { public int maxHttpConnectNumber = 50; @Getter public List seedNodes = new ArrayList<>(); - public String privateKey = ""; - public String witnessAddress = ""; - public String password; public String storageDbDirectory = ""; public String storageDbEngine = ""; public String storageDbSynchronous = ""; @@ -93,7 +84,6 @@ public class CommonParameter { public String storageTransactionHistorySwitch = ""; @Getter public boolean fastForward = false; - // ── Network / P2P ─────────────────────────────── @Getter @Setter @@ -362,7 +352,8 @@ public class CommonParameter { @Getter @Setter public long trxExpirationTimeInMilliseconds; - public boolean version; + + // ── Shielded / ZK ──────────────────────────────── @Getter @Setter public String zenTokenId; // clearParam: "000000" diff --git a/common/src/main/java/org/tron/core/config/Configuration.java b/common/src/main/java/org/tron/core/config/Configuration.java index 59e6bf11d4a..d75fc8430f8 100644 --- a/common/src/main/java/org/tron/core/config/Configuration.java +++ b/common/src/main/java/org/tron/core/config/Configuration.java @@ -19,7 +19,6 @@ package org.tron.core.config; import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.apache.commons.lang3.StringUtils.isNoneBlank; import com.typesafe.config.ConfigFactory; import java.io.File; @@ -36,21 +35,15 @@ public class Configuration { * @param confFileName path to configuration file * @return loaded configuration */ - public static com.typesafe.config.Config getByFileName(final String shellConfFileName, + public static com.typesafe.config.Config getByFileName( final String confFileName) { - if (isNoneBlank(shellConfFileName)) { - File shellConfFile = new File(shellConfFileName); - resolveConfigFile(shellConfFileName, shellConfFile); - return config; - } - if (isBlank(confFileName)) { - throw new IllegalArgumentException("Configuration path is required!"); - } else { - File confFile = new File(confFileName); - resolveConfigFile(confFileName, confFile); - return config; + throw new IllegalArgumentException( + "Configuration path is required!"); } + File confFile = new File(confFileName); + resolveConfigFile(confFileName, confFile); + return config; } private static void resolveConfigFile(String fileName, File confFile) { diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 4359cf91c0c..a19c431f266 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -1,7 +1,6 @@ package org.tron.core.config.args; import static java.lang.System.exit; -import static org.fusesource.jansi.Ansi.ansi; import static org.tron.common.math.Maths.max; import static org.tron.common.math.Maths.min; import static org.tron.core.Constant.ADD_PRE_FIX_BYTE_MAINNET; @@ -45,9 +44,7 @@ import lombok.NoArgsConstructor; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.fusesource.jansi.AnsiConsole; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.tron.common.arch.Arch; @@ -84,6 +81,9 @@ @Component public class Args extends CommonParameter { + @Getter + private static String configFilePath = ""; + @Getter @Setter private static LocalWitnesses localWitnesses = new LocalWitnesses(); @@ -99,142 +99,11 @@ public class Args extends CommonParameter { solidityContractEventTriggerMap = new ConcurrentHashMap<>(); - public static void clearParam() { - CommonParameter.reset(); - localWitnesses = null; - } - - /** - * print Version. - */ - private static void printVersion() { - Properties properties = new Properties(); - boolean noGitProperties = true; - try { - InputStream in = Thread.currentThread() - .getContextClassLoader().getResourceAsStream("git.properties"); - if (in != null) { - noGitProperties = false; - properties.load(in); - } - } catch (IOException e) { - logger.error(e.getMessage()); - } - JCommander jCommander = new JCommander(); - jCommander.getConsole().println("OS : " + System.getProperty("os.name")); - jCommander.getConsole().println("JVM : " + System.getProperty("java.vendor") + " " - + System.getProperty("java.version") + " " + System.getProperty("os.arch")); - if (!noGitProperties) { - jCommander.getConsole().println("Git : " + properties.getProperty("git.commit.id")); - } - jCommander.getConsole().println("Version : " + Version.getVersion()); - jCommander.getConsole().println("Code : " + Version.VERSION_CODE); - } - - public static void printHelp(JCommander jCommander) { - List parameterDescriptionList = jCommander.getParameters(); - Map stringParameterDescriptionMap = new HashMap<>(); - for (ParameterDescription parameterDescription : parameterDescriptionList) { - String parameterName = parameterDescription.getParameterized().getName(); - stringParameterDescriptionMap.put(parameterName, parameterDescription); - } - - StringBuilder helpStr = new StringBuilder(); - helpStr.append("Name:\n\tFullNode - the java-tron command line interface\n"); - String programName = Strings.isNullOrEmpty(jCommander.getProgramName()) ? "FullNode.jar" : - jCommander.getProgramName(); - helpStr.append(String.format("%nUsage: java -jar %s [options] [seedNode ...]%n", - programName)); - helpStr.append(String.format("%nVERSION: %n%s-%s%n", Version.getVersion(), - getCommitIdAbbrev())); - - Map groupOptionListMap = Args.getOptionGroup(); - for (Map.Entry entry : groupOptionListMap.entrySet()) { - String group = entry.getKey(); - helpStr.append(String.format("%n%s OPTIONS:%n", group.toUpperCase())); - int optionMaxLength = Arrays.stream(entry.getValue()).mapToInt(p -> { - ParameterDescription tmpParameterDescription = stringParameterDescriptionMap.get(p); - if (tmpParameterDescription == null) { - return 1; - } - return tmpParameterDescription.getNames().length(); - }).max().orElse(1); - - for (String option : groupOptionListMap.get(group)) { - ParameterDescription parameterDescription = stringParameterDescriptionMap.get(option); - if (parameterDescription == null) { - logger.warn("Miss option:{}", option); - continue; - } - String tmpOptionDesc = String.format("%s\t\t\t%s%n", - Strings.padEnd(parameterDescription.getNames(), optionMaxLength, ' '), - upperFirst(parameterDescription.getDescription())); - helpStr.append(tmpOptionDesc); - } - } - jCommander.getConsole().println(helpStr.toString()); - } - - public static String upperFirst(String name) { - if (name.length() <= 1) { - return name; - } - name = name.substring(0, 1).toUpperCase() + name.substring(1); - return name; - } - - private static String getCommitIdAbbrev() { - Properties properties = new Properties(); - try { - InputStream in = Thread.currentThread() - .getContextClassLoader().getResourceAsStream("git.properties"); - properties.load(in); - } catch (IOException e) { - logger.warn("Load resource failed,git.properties {}", e.getMessage()); - } - return properties.getProperty("git.commit.id.abbrev"); - } - - private static Map getOptionGroup() { - String[] tronOption = new String[] {"version", "help", "shellConfFileName", "logbackPath", - "eventSubscribe", "solidityNode", "keystoreFactory"}; - String[] dbOption = new String[] {"outputDirectory"}; - String[] witnessOption = new String[] {"witness", "privateKey"}; - String[] vmOption = new String[] {"debug"}; - - Map optionGroupMap = new LinkedHashMap<>(); - optionGroupMap.put("tron", tronOption); - optionGroupMap.put("db", dbOption); - optionGroupMap.put("witness", witnessOption); - optionGroupMap.put("virtual machine", vmOption); - - for (String[] optionList : optionGroupMap.values()) { - for (String option : optionList) { - try { - CLIParameter.class.getField(option); - } catch (NoSuchFieldException e) { - logger.warn("NoSuchFieldException:{},{}", option, e.getMessage()); - } - } - } - return optionGroupMap; - } - /** * set parameters. */ public static void setParam(final String[] args, final String confFileName) { - try { - Arch.throwIfUnsupportedJavaVersion(); - } catch (UnsupportedOperationException e) { - AnsiConsole.systemInstall(); - System.out.println( - ansi().fgRed().a(e.getMessage()).reset()); - AnsiConsole.systemUninstall(); - throw new TronError(e, TronError.ErrCode.JDK_VERSION); - } - // 1. Parse CLI args into a separate object CLIParameter cmd = new CLIParameter(); JCommander jc = @@ -251,26 +120,25 @@ public static void setParam(final String[] args, } // Resolve config file path - PARAMETER.configFilePath = - StringUtils.isNoneBlank(cmd.shellConfFileName) - ? cmd.shellConfFileName : confFileName; - Config config = Configuration.getByFileName( - cmd.shellConfFileName, confFileName); + configFilePath = StringUtils.isNoneBlank(cmd.shellConfFileName) + ? cmd.shellConfFileName : confFileName; + Config config = Configuration.getByFileName(configFilePath); // 2. Config overrides defaults - setParam(config); + applyConfigParams(config); // 3. CLI overrides Config (highest priority) - setCommandParam(cmd, jc); + applyCLIParams(cmd, jc); // 4. Init witness (depends on CLI witness flag) - initLocalWitnesses(config); + initLocalWitnesses(config, cmd); } /** - * set parameters. + * Apply parameters from config file. */ - public static void setParam(final Config config) { + public static void applyConfigParams( + final Config config) { Wallet.setAddressPreFixByte(ADD_PRE_FIX_BYTE_MAINNET); Wallet.setAddressPreFixString(Constant.ADD_PRE_FIX_STRING_MAINNET); @@ -1146,7 +1014,7 @@ public static void setParam(final Config config) { * Apply CLI parameters that were explicitly passed. * Only assigned parameters override Config values. */ - private static void setCommandParam(CLIParameter cmd, + private static void applyCLIParams(CLIParameter cmd, JCommander jc) { Map assigned = jc.getParameters().stream() @@ -1270,28 +1138,67 @@ private static void setCommandParam(CLIParameter cmd, if (assigned.containsKey("--log-config")) { PARAMETER.logbackPath = cmd.logbackPath; } - if (assigned.containsKey("--private-key")) { - PARAMETER.privateKey = cmd.privateKey; - } - if (assigned.containsKey("--witness-address")) { - PARAMETER.witnessAddress = cmd.witnessAddress; + } + + private static void initLocalWitnesses( + Config config, CLIParameter cmd) { + // not a witness node, skip + if (!PARAMETER.isWitness()) { + localWitnesses = new LocalWitnesses(); + return; + } + + // path 1: CLI --private-key + if (StringUtils.isNotBlank(cmd.privateKey)) { + localWitnesses = + WitnessInitializer.initFromCLIPrivateKey( + cmd.privateKey, cmd.witnessAddress); + return; + } + + String witnessAddr = config.hasPath( + ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) + ? config.getString( + ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) + : null; + + // path 2: config localwitness (private key list) + if (config.hasPath(ConfigKey.LOCAL_WITNESS)) { + List keys = config.getStringList( + ConfigKey.LOCAL_WITNESS); + if (!keys.isEmpty()) { + localWitnesses = + WitnessInitializer.initFromCFGPrivateKey( + keys, witnessAddr); + return; + } } - if (assigned.containsKey("--password")) { - PARAMETER.password = cmd.password; + + // path 3: config localwitnesskeystore + password + if (config.hasPath( + ConfigKey.LOCAL_WITNESS_KEYSTORE)) { + List keystores = config.getStringList( + ConfigKey.LOCAL_WITNESS_KEYSTORE); + if (!keystores.isEmpty()) { + localWitnesses = + WitnessInitializer.initFromKeystore( + keystores, cmd.password, + witnessAddr); + return; + } } + + // no private key source configured + throw new TronError( + "This is a witness node, " + + "but localWitnesses is null", + TronError.ErrCode.WITNESS_INIT); } - private static void initLocalWitnesses(Config config) { - localWitnesses = - new WitnessInitializer(config).initLocalWitnesses(); - if (PARAMETER.isWitness() - && CollectionUtils.isEmpty( - localWitnesses.getPrivateKeys())) { - throw new TronError( - "This is a witness node, " - + "but localWitnesses is null", - TronError.ErrCode.WITNESS_INIT); - } + public static void clearParam() { + CommonParameter.reset(); + configFilePath = ""; + localWitnesses = null; } private static long getProposalExpirationTime(final Config config) { @@ -1795,5 +1702,120 @@ public String getOutputDirectory() { } return this.outputDirectory; } + + // ── CLI help / version utilities ───────────────── + + private static void printVersion() { + Properties properties = new Properties(); + boolean noGitProperties = true; + try { + InputStream in = Thread.currentThread() + .getContextClassLoader().getResourceAsStream("git.properties"); + if (in != null) { + noGitProperties = false; + properties.load(in); + } + } catch (IOException e) { + logger.error(e.getMessage()); + } + JCommander jCommander = new JCommander(); + jCommander.getConsole().println("OS : " + System.getProperty("os.name")); + jCommander.getConsole().println("JVM : " + System.getProperty("java.vendor") + " " + + System.getProperty("java.version") + " " + System.getProperty("os.arch")); + if (!noGitProperties) { + jCommander.getConsole().println("Git : " + properties.getProperty("git.commit.id")); + } + jCommander.getConsole().println("Version : " + Version.getVersion()); + jCommander.getConsole().println("Code : " + Version.VERSION_CODE); + } + + public static void printHelp(JCommander jCommander) { + List parameterDescriptionList = jCommander.getParameters(); + Map stringParameterDescriptionMap = new HashMap<>(); + for (ParameterDescription parameterDescription : parameterDescriptionList) { + String parameterName = parameterDescription.getParameterized().getName(); + stringParameterDescriptionMap.put(parameterName, parameterDescription); + } + + StringBuilder helpStr = new StringBuilder(); + helpStr.append("Name:\n\tFullNode - the java-tron command line interface\n"); + String programName = Strings.isNullOrEmpty(jCommander.getProgramName()) ? "FullNode.jar" : + jCommander.getProgramName(); + helpStr.append(String.format("%nUsage: java -jar %s [options] [seedNode ...]%n", + programName)); + helpStr.append(String.format("%nVERSION: %n%s-%s%n", Version.getVersion(), + getCommitIdAbbrev())); + + Map groupOptionListMap = Args.getOptionGroup(); + for (Map.Entry entry : groupOptionListMap.entrySet()) { + String group = entry.getKey(); + helpStr.append(String.format("%n%s OPTIONS:%n", group.toUpperCase())); + int optionMaxLength = Arrays.stream(entry.getValue()).mapToInt(p -> { + ParameterDescription tmpParameterDescription = stringParameterDescriptionMap.get(p); + if (tmpParameterDescription == null) { + return 1; + } + return tmpParameterDescription.getNames().length(); + }).max().orElse(1); + + for (String option : groupOptionListMap.get(group)) { + ParameterDescription parameterDescription = stringParameterDescriptionMap.get(option); + if (parameterDescription == null) { + logger.warn("Miss option:{}", option); + continue; + } + String tmpOptionDesc = String.format("%s\t\t\t%s%n", + Strings.padEnd(parameterDescription.getNames(), optionMaxLength, ' '), + upperFirst(parameterDescription.getDescription())); + helpStr.append(tmpOptionDesc); + } + } + jCommander.getConsole().println(helpStr.toString()); + } + + public static String upperFirst(String name) { + if (name.length() <= 1) { + return name; + } + name = name.substring(0, 1).toUpperCase() + name.substring(1); + return name; + } + + private static String getCommitIdAbbrev() { + Properties properties = new Properties(); + try { + InputStream in = Thread.currentThread() + .getContextClassLoader().getResourceAsStream("git.properties"); + properties.load(in); + } catch (IOException e) { + logger.warn("Load resource failed,git.properties {}", e.getMessage()); + } + return properties.getProperty("git.commit.id.abbrev"); + } + + private static Map getOptionGroup() { + String[] tronOption = new String[] {"version", "help", "shellConfFileName", "logbackPath", + "eventSubscribe", "solidityNode", "keystoreFactory"}; + String[] dbOption = new String[] {"outputDirectory"}; + String[] witnessOption = new String[] {"witness", "privateKey"}; + String[] vmOption = new String[] {"debug"}; + + Map optionGroupMap = new LinkedHashMap<>(); + optionGroupMap.put("tron", tronOption); + optionGroupMap.put("db", dbOption); + optionGroupMap.put("witness", witnessOption); + optionGroupMap.put("virtual machine", vmOption); + + for (String[] optionList : optionGroupMap.values()) { + for (String option : optionList) { + try { + CLIParameter.class.getField(option); + } catch (NoSuchFieldException e) { + logger.warn("NoSuchFieldException:{},{}", option, e.getMessage()); + } + } + } + return optionGroupMap; + } } diff --git a/framework/src/main/java/org/tron/core/config/args/ConfigKey.java b/framework/src/main/java/org/tron/core/config/args/ConfigKey.java index e160eb7a346..0cce5867d8b 100644 --- a/framework/src/main/java/org/tron/core/config/args/ConfigKey.java +++ b/framework/src/main/java/org/tron/core/config/args/ConfigKey.java @@ -10,7 +10,7 @@ private ConfigKey() { } // local witness - public static final String LOCAL_WITNESS = "localwitness"; + public static final String LOCAL_WITNESS = "localwitness"; //private key public static final String LOCAL_WITNESS_ACCOUNT_ADDRESS = "localWitnessAccountAddress"; public static final String LOCAL_WITNESS_KEYSTORE = "localwitnesskeystore"; diff --git a/framework/src/main/java/org/tron/core/config/args/DynamicArgs.java b/framework/src/main/java/org/tron/core/config/args/DynamicArgs.java index 9963ac1f419..04ba1b306eb 100644 --- a/framework/src/main/java/org/tron/core/config/args/DynamicArgs.java +++ b/framework/src/main/java/org/tron/core/config/args/DynamicArgs.java @@ -34,7 +34,7 @@ public void init() { reloadExecutor = ExecutorServiceManager.newSingleThreadScheduledExecutor(esName); logger.info("Start the dynamic loading configuration service"); long checkInterval = parameter.getDynamicConfigCheckInterval(); - configFile = new File(parameter.getConfigFilePath()); + configFile = new File(Args.getConfigFilePath()); if (!configFile.exists()) { logger.warn("Configuration path is required! No such file {}", configFile); return; @@ -60,7 +60,7 @@ public void run() { public void reload() { logger.debug("Reloading ... "); - Config config = Configuration.getByFileName(parameter.getConfigFilePath(), null); + Config config = Configuration.getByFileName(Args.getConfigFilePath()); updateActiveNodes(config); diff --git a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java index be5817407f5..50087c8502d 100644 --- a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java +++ b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java @@ -1,6 +1,5 @@ package org.tron.core.config.args; -import com.typesafe.config.Config; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -8,7 +7,6 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.tron.common.crypto.SignInterface; -import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.Commons; import org.tron.common.utils.LocalWitnesses; @@ -20,132 +18,128 @@ @Slf4j public class WitnessInitializer { - private final Config config; - - private LocalWitnesses localWitnesses; - - public WitnessInitializer(Config config) { - this.config = config; - this.localWitnesses = new LocalWitnesses(); - } - - public LocalWitnesses initLocalWitnesses() { - if (!Args.getInstance().isWitness()) { - return localWitnesses; - } - - if (tryInitFromCommandLine()) { - return localWitnesses; - } - - if (tryInitFromConfig()) { - return localWitnesses; - } - - tryInitFromKeystore(); - - return localWitnesses; - } - - private boolean tryInitFromCommandLine() { - CommonParameter parameter = Args.getInstance(); - if (StringUtils.isBlank(parameter.privateKey)) { - return false; - } - - byte[] witnessAddress = null; - this.localWitnesses = new LocalWitnesses(parameter.privateKey); - if (StringUtils.isNotEmpty(parameter.witnessAddress)) { - witnessAddress = Commons.decodeFromBase58Check(parameter.witnessAddress); - if (witnessAddress == null) { - throw new TronError("LocalWitnessAccountAddress format from cmd is incorrect", + /** + * Init from a single private key (and optional + * witness address). + */ + public static LocalWitnesses initFromCLIPrivateKey( + String privateKey, String witnessAddress) { + LocalWitnesses witnesses = + new LocalWitnesses(privateKey); + + byte[] address = null; + if (StringUtils.isNotEmpty(witnessAddress)) { + address = Commons.decodeFromBase58Check( + witnessAddress); + if (address == null) { + throw new TronError( + "LocalWitnessAccountAddress format" + + " from cmd is incorrect", TronError.ErrCode.WITNESS_INIT); } - logger.debug("Got localWitnessAccountAddress from cmd"); + logger.debug( + "Got localWitnessAccountAddress from cmd"); } - this.localWitnesses.initWitnessAccountAddress(witnessAddress, - parameter.isECKeyCryptoEngine()); + witnesses.initWitnessAccountAddress(address, + Args.getInstance().isECKeyCryptoEngine()); logger.debug("Got privateKey from cmd"); - return true; + return witnesses; } - private boolean tryInitFromConfig() { - if (!config.hasPath(ConfigKey.LOCAL_WITNESS) || config.getStringList(ConfigKey.LOCAL_WITNESS) - .isEmpty()) { - return false; - } - - List localWitness = config.getStringList(ConfigKey.LOCAL_WITNESS); - this.localWitnesses.setPrivateKeys(localWitness); + /** + * Init from a list of private keys. + */ + public static LocalWitnesses initFromCFGPrivateKey( + List privateKeys, + String witnessAccountAddress) { + LocalWitnesses witnesses = new LocalWitnesses(); + witnesses.setPrivateKeys(privateKeys); logger.debug("Got privateKey from config.conf"); - byte[] witnessAddress = getWitnessAddress(); - this.localWitnesses.initWitnessAccountAddress(witnessAddress, + + byte[] address = resolveWitnessAddress( + witnesses, witnessAccountAddress); + witnesses.initWitnessAccountAddress(address, Args.getInstance().isECKeyCryptoEngine()); - return true; + return witnesses; } - private void tryInitFromKeystore() { - if (!config.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE) - || config.getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE).isEmpty()) { - return; + /** + * Init from keystore files with password. + */ + public static LocalWitnesses initFromKeystore( + List keystoreFiles, String password, + String witnessAccountAddress) { + if (keystoreFiles.size() > 1) { + logger.warn("Multiple keystores detected." + + " Only the first keystore will be used" + + " as witness, all others will be" + + " ignored."); } - List localWitness = config.getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE); - if (localWitness.size() > 1) { - logger.warn( - "Multiple keystores detected. Only the first keystore will be used as witness, all " - + "others will be ignored."); - } - - CommonParameter parameter = Args.getInstance(); - List privateKeys = new ArrayList<>(); - String fileName = System.getProperty("user.dir") + "/" + localWitness.get(0); - String password; - if (StringUtils.isEmpty(parameter.password)) { - System.out.println("Please input your password."); - password = WalletUtils.inputPassword(); + String fileName = + System.getProperty("user.dir") + "/" + + keystoreFiles.get(0); + String pwd; + if (StringUtils.isEmpty(password)) { + System.out.println( + "Please input your password."); + pwd = WalletUtils.inputPassword(); } else { - password = parameter.password; - parameter.password = null; + pwd = password; } + List privateKeys = new ArrayList<>(); try { Credentials credentials = WalletUtils - .loadCredentials(password, new File(fileName)); - SignInterface sign = credentials.getSignInterface(); - String prikey = ByteArray.toHexString(sign.getPrivateKey()); + .loadCredentials(pwd, new File(fileName)); + SignInterface sign = + credentials.getSignInterface(); + String prikey = + ByteArray.toHexString(sign.getPrivateKey()); privateKeys.add(prikey); } catch (IOException | CipherException e) { logger.error("Witness node start failed!"); - throw new TronError(e, TronError.ErrCode.WITNESS_KEYSTORE_LOAD); + throw new TronError(e, + TronError.ErrCode.WITNESS_KEYSTORE_LOAD); } - this.localWitnesses.setPrivateKeys(privateKeys); - byte[] witnessAddress = getWitnessAddress(); - this.localWitnesses.initWitnessAccountAddress(witnessAddress, - parameter.isECKeyCryptoEngine()); + LocalWitnesses witnesses = new LocalWitnesses(); + witnesses.setPrivateKeys(privateKeys); + byte[] address = resolveWitnessAddress( + witnesses, witnessAccountAddress); + witnesses.initWitnessAccountAddress(address, + Args.getInstance().isECKeyCryptoEngine()); logger.debug("Got privateKey from keystore"); + return witnesses; } - private byte[] getWitnessAddress() { - if (!config.hasPath(ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS)) { + static byte[] resolveWitnessAddress( + LocalWitnesses witnesses, + String witnessAccountAddress) { + if (StringUtils.isEmpty(witnessAccountAddress)) { return null; } - if (localWitnesses.getPrivateKeys().size() != 1) { + if (witnesses.getPrivateKeys().size() != 1) { throw new TronError( - "LocalWitnessAccountAddress can only be set when there is only one private key", + "LocalWitnessAccountAddress can only be" + + " set when there is only one" + + " private key", TronError.ErrCode.WITNESS_INIT); } - byte[] witnessAddress = Commons - .decodeFromBase58Check(config.getString(ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS)); - if (witnessAddress != null) { - logger.debug("Got localWitnessAccountAddress from config.conf"); + byte[] address = Commons + .decodeFromBase58Check(witnessAccountAddress); + if (address != null) { + logger.debug( + "Got localWitnessAccountAddress" + + " from config.conf"); } else { - throw new TronError("LocalWitnessAccountAddress format from config is incorrect", + throw new TronError( + "LocalWitnessAccountAddress format" + + " from config is incorrect", TronError.ErrCode.WITNESS_INIT); } - return witnessAddress; + return address; } } diff --git a/framework/src/main/java/org/tron/program/FullNode.java b/framework/src/main/java/org/tron/program/FullNode.java index b93a4d79b82..95257d77f8e 100644 --- a/framework/src/main/java/org/tron/program/FullNode.java +++ b/framework/src/main/java/org/tron/program/FullNode.java @@ -5,12 +5,14 @@ import org.tron.common.application.Application; import org.tron.common.application.ApplicationFactory; import org.tron.common.application.TronApplicationContext; +import org.tron.common.arch.Arch; import org.tron.common.exit.ExitManager; import org.tron.common.log.LogService; import org.tron.common.parameter.CommonParameter; import org.tron.common.prometheus.Metrics; import org.tron.core.config.DefaultConfig; import org.tron.core.config.args.Args; +import org.tron.core.exception.TronError; @Slf4j(topic = "app") public class FullNode { @@ -20,6 +22,7 @@ public class FullNode { */ public static void main(String[] args) { ExitManager.initExceptionHandler(); + checkJdkVersion(); Args.setParam(args, "config.conf"); CommonParameter parameter = Args.getInstance(); @@ -54,4 +57,13 @@ public static void main(String[] args) { appT.startup(); appT.blockUntilShutdown(); } + + private static void checkJdkVersion() { + try { + Arch.throwIfUnsupportedJavaVersion(); + } catch (UnsupportedOperationException e) { + System.err.println(e.getMessage()); + throw new TronError(e, TronError.ErrCode.JDK_VERSION); + } + } } diff --git a/framework/src/test/java/org/tron/common/ParameterTest.java b/framework/src/test/java/org/tron/common/ParameterTest.java index 2f65189ac1c..d5dbced87fe 100644 --- a/framework/src/test/java/org/tron/common/ParameterTest.java +++ b/framework/src/test/java/org/tron/common/ParameterTest.java @@ -63,7 +63,6 @@ public void testCommonParameter() { assertEquals(1000000L, parameter.getMaxEnergyLimitForConstant()); assertEquals(5, parameter.getLruCacheSize()); assertEquals(60, parameter.getLongRunningTime()); - assertFalse(parameter.isHelp()); assertFalse(parameter.isSaveFeaturedInternalTx()); assertFalse(parameter.isSaveInternalTx()); CollectionUtils.isEmpty(parameter.getSeedNodes()); diff --git a/framework/src/test/java/org/tron/core/config/ConfigurationTest.java b/framework/src/test/java/org/tron/core/config/ConfigurationTest.java index 11ceb88bfcc..b066bc1e6be 100644 --- a/framework/src/test/java/org/tron/core/config/ConfigurationTest.java +++ b/framework/src/test/java/org/tron/core/config/ConfigurationTest.java @@ -58,17 +58,17 @@ public void testGetEcKey() { @Test(expected = IllegalArgumentException.class) public void whenNullPathGetShouldThrowIllegalArgumentException() { - Configuration.getByFileName(null, null); + Configuration.getByFileName(null); } @Test(expected = IllegalArgumentException.class) public void whenEmptyPathGetShouldThrowIllegalArgumentException() { - Configuration.getByFileName(StringUtils.EMPTY, StringUtils.EMPTY); + Configuration.getByFileName(StringUtils.EMPTY); } @Test(expected = IllegalArgumentException.class) public void getShouldNotFindConfiguration() { - Config config = Configuration.getByFileName("notExistingPath", "notExistingPath"); + Config config = Configuration.getByFileName("notExistingPath"); assertFalse(config.hasPath("storage")); assertFalse(config.hasPath("overlay")); assertFalse(config.hasPath("seed.node")); @@ -77,7 +77,7 @@ public void getShouldNotFindConfiguration() { @Test public void getShouldReturnConfiguration() { - Config config = Configuration.getByFileName(TestConstants.TEST_CONF, TestConstants.TEST_CONF); + Config config = Configuration.getByFileName(TestConstants.TEST_CONF); assertTrue(config.hasPath("storage")); assertTrue(config.hasPath("seed.node")); assertTrue(config.hasPath("genesis.block")); @@ -86,7 +86,7 @@ public void getShouldReturnConfiguration() { @Test public void getConfigurationWhenOnlyConfFileName() { URL res = getClass().getClassLoader().getResource(TestConstants.TEST_CONF); - Config config = Configuration.getByFileName("", res.getPath()); + Config config = Configuration.getByFileName(res.getPath()); assertTrue(config.hasPath("storage")); assertTrue(config.hasPath("seed.node")); assertTrue(config.hasPath("genesis.block")); diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 7e60e0de507..373b258b903 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -71,7 +71,7 @@ public void get() { address = ByteArray.toHexString(Args.getLocalWitnesses() .getWitnessAccountAddress()); Assert.assertEquals("41", DecodeUtil.addressPreFixString); - Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); + Assert.assertEquals(TestConstants.TEST_CONF, Args.getConfigFilePath()); Assert.assertEquals(0, parameter.getBackupPriority()); Assert.assertEquals(3000, parameter.getKeepAliveInterval()); @@ -138,12 +138,12 @@ public void testIpFromLibP2p() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Args.setParam(new String[] {}, TestConstants.TEST_CONF); CommonParameter parameter = Args.getInstance(); - Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); + Assert.assertEquals(TestConstants.TEST_CONF, Args.getConfigFilePath()); String configuredExternalIp = parameter.getNodeExternalIp(); Assert.assertEquals("46.168.1.1", configuredExternalIp); - Config config = Configuration.getByFileName(null, TestConstants.TEST_CONF); + Config config = Configuration.getByFileName(TestConstants.TEST_CONF); Config config3 = config.withoutPath(ConfigKey.NODE_DISCOVERY_EXTERNAL_IP); CommonParameter.getInstance().setNodeExternalIp(null); @@ -168,7 +168,7 @@ public void testInitService() { storage.put("storage.db.directory", "database"); Config config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // test default value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertTrue(Args.getInstance().isRpcEnable()); Assert.assertTrue(Args.getInstance().isRpcSolidityEnable()); Assert.assertTrue(Args.getInstance().isRpcPBFTEnable()); @@ -195,7 +195,7 @@ public void testInitService() { storage.put("node.jsonrpc.maxSubTopics", "20"); config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // test value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertTrue(Args.getInstance().isRpcEnable()); Assert.assertTrue(Args.getInstance().isRpcSolidityEnable()); Assert.assertTrue(Args.getInstance().isRpcPBFTEnable()); @@ -222,7 +222,7 @@ public void testInitService() { storage.put("node.jsonrpc.maxSubTopics", "1000"); config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // test value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertFalse(Args.getInstance().isRpcEnable()); Assert.assertFalse(Args.getInstance().isRpcSolidityEnable()); Assert.assertFalse(Args.getInstance().isRpcPBFTEnable()); @@ -249,7 +249,7 @@ public void testInitService() { storage.put("node.jsonrpc.maxSubTopics", "40"); config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // test value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertFalse(Args.getInstance().isRpcEnable()); Assert.assertFalse(Args.getInstance().isRpcSolidityEnable()); Assert.assertTrue(Args.getInstance().isRpcPBFTEnable()); @@ -267,7 +267,7 @@ public void testInitService() { storage.put("node.jsonrpc.maxSubTopics", "0"); config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // check value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertEquals(0, Args.getInstance().getJsonRpcMaxBlockRange()); Assert.assertEquals(0, Args.getInstance().getJsonRpcMaxSubTopics()); @@ -276,7 +276,7 @@ public void testInitService() { storage.put("node.jsonrpc.maxSubTopics", "-4"); config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage)); // check value - Args.setParam(config); + Args.applyConfigParams(config); Assert.assertEquals(-2, Args.getInstance().getJsonRpcMaxBlockRange()); Assert.assertEquals(-4, Args.getInstance().getJsonRpcMaxSubTopics()); diff --git a/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java b/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java index e78e4b5fd90..99469f9ce59 100644 --- a/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/DynamicArgsTest.java @@ -40,7 +40,7 @@ public void destroy() { @Test public void start() { CommonParameter parameter = Args.getInstance(); - Assert.assertEquals(TestConstants.TEST_CONF, parameter.getConfigFilePath()); + Assert.assertEquals(TestConstants.TEST_CONF, Args.getConfigFilePath()); Assert.assertTrue(parameter.isDynamicConfigEnable()); Assert.assertEquals(600, parameter.getDynamicConfigCheckInterval()); @@ -52,7 +52,7 @@ public void start() { TronNetService tronNetService = context.getBean(TronNetService.class); ReflectUtils.setFieldValue(tronNetService, "p2pConfig", new P2pConfig()); - File config = new File(parameter.getConfigFilePath()); + File config = new File(Args.getConfigFilePath()); if (!config.exists()) { try { config.createNewFile(); diff --git a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java index d23027285a8..189158820e9 100644 --- a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java +++ b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java @@ -5,31 +5,22 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThrows; -import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockStatic; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import com.typesafe.config.Config; -import com.typesafe.config.ConfigFactory; import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.bouncycastle.util.encoders.Hex; import org.junit.After; -import org.junit.Before; import org.junit.Test; import org.mockito.MockedStatic; import org.tron.common.crypto.SignInterface; -import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; @@ -41,19 +32,14 @@ public class WitnessInitializerTest { - private Config config; - private WitnessInitializer witnessInitializer; - - private static final String privateKey = PublicMethod.getRandomPrivateKey(); - private static final String address = Base58.encode58Check( - ByteArray.fromHexString(PublicMethod.getHexAddressByPrivateKey(privateKey))); - private static final String invalidAddress = "RJCzdnv88Hvqa2jB1C9dMmMYHr5DFdF2R3"; - - @Before - public void setUp() { - config = ConfigFactory.empty(); - witnessInitializer = new WitnessInitializer(config); - } + private static final String privateKey = + PublicMethod.getRandomPrivateKey(); + private static final String address = + Base58.encode58Check(ByteArray.fromHexString( + PublicMethod.getHexAddressByPrivateKey( + privateKey))); + private static final String invalidAddress = + "RJCzdnv88Hvqa2jB1C9dMmMYHr5DFdF2R3"; @After public void clear() { @@ -61,207 +47,144 @@ public void clear() { } @Test - public void testInitLocalWitnessesEmpty() { - Args.getInstance().setWitness(false); - - LocalWitnesses result = witnessInitializer.initLocalWitnesses(); + public void testInitFromCLI() { + // privateKey only + LocalWitnesses result = + WitnessInitializer.initFromCLIPrivateKey( + privateKey, null); assertNotNull(result); - assertTrue(result.getPrivateKeys().isEmpty()); - - Args.getInstance().setWitness(true); - LocalWitnesses localWitnesses = witnessInitializer.initLocalWitnesses(); - assertTrue(localWitnesses.getPrivateKeys().isEmpty()); - - String configString = "localwitness = [] \n localwitnesskeystore = []"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - localWitnesses = witnessInitializer.initLocalWitnesses(); - assertTrue(localWitnesses.getPrivateKeys().isEmpty()); - } - - @Test - public void testTryInitFromCommandLine() - throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, - InvocationTargetException { - Field privateKeyField = CommonParameter.class.getDeclaredField("privateKey"); - privateKeyField.setAccessible(true); - privateKeyField.set(Args.getInstance(), ""); - - witnessInitializer = new WitnessInitializer(config); - Method method = WitnessInitializer.class.getDeclaredMethod( - "tryInitFromCommandLine"); - method.setAccessible(true); - boolean result = (boolean) method.invoke(witnessInitializer); - assertFalse(result); - - privateKeyField.set(Args.getInstance(), privateKey); - method.invoke(witnessInitializer); - result = (boolean) method.invoke(witnessInitializer); - assertTrue(result); - - Field witnessAddress = CommonParameter.class.getDeclaredField("witnessAddress"); - witnessAddress.setAccessible(true); - witnessAddress.set(Args.getInstance(), address); - result = (boolean) method.invoke(witnessInitializer); - assertTrue(result); - - witnessAddress.set(Args.getInstance(), invalidAddress); - InvocationTargetException thrown = assertThrows(InvocationTargetException.class, - () -> method.invoke(witnessInitializer)); - TronError targetException = (TronError) thrown.getTargetException(); - assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); - } - - @Test - public void testTryInitFromConfig() - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { - witnessInitializer = new WitnessInitializer(config); - Method method = WitnessInitializer.class.getDeclaredMethod( - "tryInitFromConfig"); - method.setAccessible(true); - boolean result = (boolean) method.invoke(witnessInitializer); - assertFalse(result); - - String configString = "localwitness = []"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - result = (boolean) method.invoke(witnessInitializer); - assertFalse(result); - - configString = "localwitness = [" + privateKey + "]"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - result = (boolean) method.invoke(witnessInitializer); - assertTrue(result); - - configString = "localWitnessAccountAddress = " + address + "\n" - + "localwitness = [\n" + privateKey + "]"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - result = (boolean) method.invoke(witnessInitializer); - assertTrue(result); + assertFalse(result.getPrivateKeys().isEmpty()); + assertEquals(privateKey, + result.getPrivateKeys().get(0)); - configString = "localwitness = [\n" + privateKey + "\n" + privateKey + "]"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - result = (boolean) method.invoke(witnessInitializer); - assertTrue(result); - - configString = "localWitnessAccountAddress = " + invalidAddress + "\n" - + "localwitness = [\n" + privateKey + "]"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - InvocationTargetException thrown = assertThrows(InvocationTargetException.class, - () -> method.invoke(witnessInitializer)); - TronError targetException = (TronError) thrown.getTargetException(); - assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); - - configString = "localWitnessAccountAddress = " + address + "\n" - + "localwitness = [\n" + privateKey + "\n" + privateKey + "]"; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - thrown = assertThrows(InvocationTargetException.class, - () -> method.invoke(witnessInitializer)); - targetException = (TronError) thrown.getTargetException(); - assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + // with valid witnessAddress + result = WitnessInitializer.initFromCLIPrivateKey( + privateKey, address); + assertNotNull(result); + assertFalse(result.getPrivateKeys().isEmpty()); + + // with invalid witnessAddress + TronError err = assertThrows(TronError.class, + () -> WitnessInitializer.initFromCLIPrivateKey( + privateKey, invalidAddress)); + assertEquals(ErrCode.WITNESS_INIT, + err.getErrCode()); } @Test - public void testTryInitFromKeystore() - throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, - NoSuchFieldException { - witnessInitializer = new WitnessInitializer(config); - Method method = WitnessInitializer.class.getDeclaredMethod( - "tryInitFromKeystore"); - method.setAccessible(true); - method.invoke(witnessInitializer); - Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); - localWitnessField.setAccessible(true); - LocalWitnesses localWitnesses = (LocalWitnesses) localWitnessField.get(witnessInitializer); - assertTrue(localWitnesses.getPrivateKeys().isEmpty()); - - String configString = "localwitnesskeystore = []"; - Config emptyListConfig = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(emptyListConfig); - method.invoke(witnessInitializer); - localWitnesses = (LocalWitnesses) localWitnessField.get(witnessInitializer); - assertTrue(localWitnesses.getPrivateKeys().isEmpty()); + public void testInitFromConfig() { + // single private key, no address + LocalWitnesses result = + WitnessInitializer.initFromCFGPrivateKey( + Collections.singletonList(privateKey), + null); + assertFalse(result.getPrivateKeys().isEmpty()); + + // single key + valid address + result = WitnessInitializer.initFromCFGPrivateKey( + Collections.singletonList(privateKey), + address); + assertFalse(result.getPrivateKeys().isEmpty()); + + // multiple keys, no address + result = WitnessInitializer.initFromCFGPrivateKey( + Arrays.asList(privateKey, privateKey), null); + assertFalse(result.getPrivateKeys().isEmpty()); + + // single key + invalid address + TronError err = assertThrows(TronError.class, + () -> WitnessInitializer.initFromCFGPrivateKey( + Collections.singletonList(privateKey), + invalidAddress)); + assertEquals(ErrCode.WITNESS_INIT, + err.getErrCode()); + + // multiple keys + address = error + err = assertThrows(TronError.class, + () -> WitnessInitializer.initFromCFGPrivateKey( + Arrays.asList(privateKey, privateKey), + address)); + assertEquals(ErrCode.WITNESS_INIT, + err.getErrCode()); } @Test - public void testTryInitFromKeyStore2() - throws NoSuchFieldException, IllegalAccessException { - Args.getInstance().setWitness(true); - Config mockConfig = mock(Config.class); - when(mockConfig.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(false); - witnessInitializer = new WitnessInitializer(mockConfig); - witnessInitializer.initLocalWitnesses(); - verify(mockConfig, never()).getStringList(anyString()); - - when(mockConfig.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(true); - when(mockConfig.getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(new ArrayList<>()); - witnessInitializer = new WitnessInitializer(mockConfig); - witnessInitializer.initLocalWitnesses(); - verify(mockConfig, times(1)).getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE); - - List keystores = new ArrayList<>(); - keystores.add("keystore1.json"); - keystores.add("keystore2.json"); - when(mockConfig.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(true); - when(mockConfig.getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE)).thenReturn(keystores); - - Field password = CommonParameter.class.getDeclaredField("password"); - password.setAccessible(true); - password.set(Args.getInstance(), "password"); - - try (MockedStatic mockedWalletUtils = mockStatic(WalletUtils.class); - MockedStatic mockedByteArray = mockStatic(ByteArray.class)) { - // Mock WalletUtils.loadCredentials - Credentials credentials = mock(Credentials.class); - SignInterface signInterface = mock(SignInterface.class); - when(credentials.getSignInterface()).thenReturn(signInterface); + public void testInitFromKeystore() { + List keystores = + Arrays.asList("keystore1.json", + "keystore2.json"); + + try (MockedStatic mockedWallet = + mockStatic(WalletUtils.class); + MockedStatic mockedByteArray = + mockStatic(ByteArray.class)) { + + Credentials credentials = + mock(Credentials.class); + SignInterface signInterface = + mock(SignInterface.class); + when(credentials.getSignInterface()) + .thenReturn(signInterface); byte[] keyBytes = Hex.decode(privateKey); - when(signInterface.getPrivateKey()).thenReturn(keyBytes); - mockedWalletUtils.when(() -> WalletUtils.loadCredentials(anyString(), any(File.class))) + when(signInterface.getPrivateKey()) + .thenReturn(keyBytes); + mockedWallet.when(() -> + WalletUtils.loadCredentials( + anyString(), any(File.class))) .thenReturn(credentials); - mockedByteArray.when(() -> ByteArray.toHexString(any())).thenReturn(privateKey); - mockedByteArray.when(() -> ByteArray.fromHexString(anyString())).thenReturn(keyBytes); - - witnessInitializer = new WitnessInitializer(mockConfig); - Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); - localWitnessField.setAccessible(true); - localWitnessField.set(witnessInitializer, new LocalWitnesses(privateKey)); - LocalWitnesses localWitnesses = witnessInitializer.initLocalWitnesses(); - assertFalse(localWitnesses.getPrivateKeys().isEmpty()); + mockedByteArray.when(() -> + ByteArray.toHexString(any())) + .thenReturn(privateKey); + mockedByteArray.when(() -> + ByteArray.fromHexString(anyString())) + .thenReturn(keyBytes); + + LocalWitnesses result = + WitnessInitializer.initFromKeystore( + keystores, "password", null); + assertFalse( + result.getPrivateKeys().isEmpty()); } } @Test - public void testGetWitnessAddress() - throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, - NoSuchFieldException { - witnessInitializer = new WitnessInitializer(config); - Method method = WitnessInitializer.class.getDeclaredMethod( - "getWitnessAddress"); - method.setAccessible(true); - byte[] result = (byte[]) method.invoke(witnessInitializer); + public void testResolveWitnessAddress() { + // null address -> null + LocalWitnesses witnesses = + new LocalWitnesses(privateKey); + byte[] result = + WitnessInitializer.resolveWitnessAddress( + witnesses, null); + assertNull(result); + + // empty address -> null + result = WitnessInitializer.resolveWitnessAddress( + witnesses, ""); assertNull(result); - String configString = "localWitnessAccountAddress = " + address; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - Field localWitnessField = WitnessInitializer.class.getDeclaredField("localWitnesses"); - localWitnessField.setAccessible(true); - localWitnessField.set(witnessInitializer, new LocalWitnesses(privateKey)); - result = (byte[]) method.invoke(witnessInitializer); + // valid address with single key + result = WitnessInitializer.resolveWitnessAddress( + witnesses, address); assertNotNull(result); - configString = "localWitnessAccountAddress = " + invalidAddress; - config = ConfigFactory.parseString(configString); - witnessInitializer = new WitnessInitializer(config); - InvocationTargetException thrown = assertThrows(InvocationTargetException.class, - () -> method.invoke(witnessInitializer)); - TronError targetException = (TronError) thrown.getTargetException(); - assertEquals(ErrCode.WITNESS_INIT, targetException.getErrCode()); + // invalid address + TronError err = assertThrows(TronError.class, + () -> WitnessInitializer.resolveWitnessAddress( + new LocalWitnesses(privateKey), + invalidAddress)); + assertEquals(ErrCode.WITNESS_INIT, + err.getErrCode()); + + // multiple keys + address = error + LocalWitnesses multiKey = new LocalWitnesses(); + List keys = new ArrayList<>(); + keys.add(privateKey); + keys.add(privateKey); + multiKey.setPrivateKeys(keys); + err = assertThrows(TronError.class, + () -> WitnessInitializer.resolveWitnessAddress( + multiKey, address)); + assertEquals(ErrCode.WITNESS_INIT, + err.getErrCode()); } } diff --git a/framework/src/test/java/org/tron/core/exception/TronErrorTest.java b/framework/src/test/java/org/tron/core/exception/TronErrorTest.java index 3b238f50edc..e965ae3fd60 100644 --- a/framework/src/test/java/org/tron/core/exception/TronErrorTest.java +++ b/framework/src/test/java/org/tron/core/exception/TronErrorTest.java @@ -141,7 +141,7 @@ public void shutdownBlockTimeInitTest() { params.put("storage.db.directory", "database"); Config config = ConfigFactory.defaultOverrides().withFallback( ConfigFactory.parseMap(params)); - TronError thrown = assertThrows(TronError.class, () -> Args.setParam(config)); + TronError thrown = assertThrows(TronError.class, () -> Args.applyConfigParams(config)); assertEquals(TronError.ErrCode.AUTO_STOP_PARAMS, thrown.getErrCode()); } @@ -177,15 +177,16 @@ private void runArchTest(String osArch, String javaVersion, boolean expectThrow) mocked.when(Arch::throwIfUnsupportedJavaVersion).thenCallRealMethod(); if (expectThrow) { - TronError err = assertThrows( - TronError.class, () -> Args.setParam(new String[]{}, TestConstants.TEST_CONF)); + UnsupportedOperationException err = assertThrows( + UnsupportedOperationException.class, + Arch::throwIfUnsupportedJavaVersion); String expectedJavaVersion = isX86 ? "1.8" : "17"; String expectedMessage = String.format( - "Java %s is required for %s architecture. Detected version %s", + "Java %s is required for %s architecture." + + " Detected version %s", expectedJavaVersion, osArch, javaVersion); - assertEquals(expectedMessage, err.getCause().getMessage()); - assertEquals(TronError.ErrCode.JDK_VERSION, err.getErrCode()); + assertEquals(expectedMessage, err.getMessage()); mocked.verify(Arch::withAll, times(1)); } else { try { diff --git a/framework/src/test/java/org/tron/core/net/NodeTest.java b/framework/src/test/java/org/tron/core/net/NodeTest.java index 69bb8aae312..cbf545af646 100644 --- a/framework/src/test/java/org/tron/core/net/NodeTest.java +++ b/framework/src/test/java/org/tron/core/net/NodeTest.java @@ -79,7 +79,7 @@ public void testEndpointFromNode() { @Test public void testPublishConfig() { - Config config = Configuration.getByFileName(TestConstants.TEST_CONF, TestConstants.TEST_CONF); + Config config = Configuration.getByFileName(TestConstants.TEST_CONF); PublishConfig publishConfig = new PublishConfig(); Assert.assertFalse(publishConfig.isDnsPublishEnable()); From 0163c6f090d89dcdeb6aed9b811aa9f26b63aaac Mon Sep 17 00:00:00 2001 From: vividcoder Date: Wed, 4 Mar 2026 13:04:25 +0800 Subject: [PATCH 3/8] fix: add @Getter @Setter to 7 storage fields for SonarCloud S1104 --- .../org/tron/common/parameter/CommonParameter.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index 86e98530dc3..a50103e323d 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -75,12 +75,26 @@ public class CommonParameter { public int maxHttpConnectNumber = 50; @Getter public List seedNodes = new ArrayList<>(); + @Getter + @Setter public String storageDbDirectory = ""; + @Getter + @Setter public String storageDbEngine = ""; + @Getter + @Setter public String storageDbSynchronous = ""; + @Getter + @Setter public String contractParseEnable = ""; + @Getter + @Setter public String storageIndexDirectory = ""; + @Getter + @Setter public String storageIndexSwitch = ""; + @Getter + @Setter public String storageTransactionHistorySwitch = ""; @Getter public boolean fastForward = false; From 8cdda548e497f5a0c61b3a14a3a772b98948ef2a Mon Sep 17 00:00:00 2001 From: vividcoder Date: Wed, 4 Mar 2026 15:45:28 +0800 Subject: [PATCH 4/8] style: fix code style to match codebase conventions --- .../common/parameter/CommonParameter.java | 20 +-- .../java/org/tron/core/config/args/Args.java | 122 ++++++---------- .../tron/core/config/args/CLIParameter.java | 132 +++++++----------- .../core/config/args/WitnessInitializer.java | 79 ++++------- .../config/args/WitnessInitializerTest.java | 116 ++++++--------- 5 files changed, 164 insertions(+), 305 deletions(-) diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index a50103e323d..675fea359db 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -31,12 +31,12 @@ public class CommonParameter { @Setter public static boolean ENERGY_LIMIT_HARD_FORK = false; - // ── Startup parameters ───────────────────────── + // ── Startup parameters ──────────────────────── @Getter public String outputDirectory = "output-directory"; @Getter public String logbackPath = ""; - // ── Flags (CLI + Config) ───────────────────────── + // ── Flags (CLI + Config) ────────────────────── @Getter @Setter public boolean witness = false; @@ -98,7 +98,7 @@ public class CommonParameter { public String storageTransactionHistorySwitch = ""; @Getter public boolean fastForward = false; - // ── Network / P2P ─────────────────────────────── + // ── Network / P2P ───────────────────────────── @Getter @Setter public String chainId; @@ -180,7 +180,7 @@ public class CommonParameter { @Setter public boolean keystoreFactory = false; - // ── RPC / HTTP ────────────────────────────────── + // ── RPC / HTTP ──────────────────────────────── @Getter @Setter public int rpcPort; @@ -254,7 +254,7 @@ public class CommonParameter { @Setter public int checkFrozenTime; // clearParam: 1 - // ── Committee parameters ──────────────────────── + // ── Committee parameters ────────────────────── @Getter @Setter public long allowCreationOfContracts; @@ -280,7 +280,7 @@ public class CommonParameter { @Setter public long forbidTransferToContract; - // ── Netty ─────────────────────────────────────── + // ── Netty ───────────────────────────────────── @Getter @Setter public int tcpNettyWorkThreadNum; @@ -367,7 +367,7 @@ public class CommonParameter { @Setter public long trxExpirationTimeInMilliseconds; - // ── Shielded / ZK ──────────────────────────────── + // ── Shielded / ZK ───────────────────────────── @Getter @Setter public String zenTokenId; // clearParam: "000000" @@ -420,10 +420,12 @@ public class CommonParameter { public boolean p2pDisable = false; @Getter @Setter - public List activeNodes = new ArrayList<>(); // from clearParam(), consistent with mainnet.conf + // from clearParam(), consistent with mainnet.conf + public List activeNodes = new ArrayList<>(); @Getter @Setter - public List passiveNodes = new ArrayList<>(); // from clearParam(), consistent with mainnet.conf + // from clearParam(), consistent with mainnet.conf + public List passiveNodes = new ArrayList<>(); @Getter public List fastForwardNodes; // clearParam: new ArrayList<>() @Getter diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index a19c431f266..c2356994a09 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -102,12 +102,10 @@ public class Args extends CommonParameter { /** * set parameters. */ - public static void setParam(final String[] args, - final String confFileName) { + 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(); + JCommander jc = JCommander.newBuilder().addObject(cmd).build(); jc.parse(args); if (cmd.version) { @@ -1014,14 +1012,10 @@ 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) { - Map assigned = - jc.getParameters().stream() - .filter(ParameterDescription::isAssigned) - .collect(Collectors.toMap( - ParameterDescription::getLongestName, - p -> p)); + private static void applyCLIParams(CLIParameter cmd, JCommander jc) { + Map assigned = jc.getParameters().stream() + .filter(ParameterDescription::isAssigned) + .collect(Collectors.toMap(ParameterDescription::getLongestName, p -> p)); if (assigned.containsKey("--output-directory")) { PARAMETER.outputDirectory = cmd.outputDirectory; @@ -1032,10 +1026,8 @@ private static void applyCLIParams(CLIParameter cmd, if (assigned.containsKey("--support-constant")) { PARAMETER.supportConstant = cmd.supportConstant; } - if (assigned.containsKey( - "--max-energy-limit-for-constant")) { - PARAMETER.maxEnergyLimitForConstant = - cmd.maxEnergyLimitForConstant; + if (assigned.containsKey("--max-energy-limit-for-constant")) { + PARAMETER.maxEnergyLimitForConstant = cmd.maxEnergyLimitForConstant; } if (assigned.containsKey("--lru-cache-size")) { PARAMETER.lruCacheSize = cmd.lruCacheSize; @@ -1052,54 +1044,38 @@ private static void applyCLIParams(CLIParameter cmd, if (assigned.containsKey("--save-internaltx")) { PARAMETER.saveInternalTx = cmd.saveInternalTx; } - if (assigned.containsKey( - "--save-featured-internaltx")) { - PARAMETER.saveFeaturedInternalTx = - cmd.saveFeaturedInternalTx; + if (assigned.containsKey("--save-featured-internaltx")) { + PARAMETER.saveFeaturedInternalTx = cmd.saveFeaturedInternalTx; } - if (assigned.containsKey( - "--save-cancel-all-unfreeze-v2-details")) { - PARAMETER.saveCancelAllUnfreezeV2Details = - cmd.saveCancelAllUnfreezeV2Details; + if (assigned.containsKey("--save-cancel-all-unfreeze-v2-details")) { + PARAMETER.saveCancelAllUnfreezeV2Details = cmd.saveCancelAllUnfreezeV2Details; } if (assigned.containsKey("--long-running-time")) { PARAMETER.longRunningTime = cmd.longRunningTime; } if (assigned.containsKey("--max-connect-number")) { - PARAMETER.maxHttpConnectNumber = - cmd.maxHttpConnectNumber; + PARAMETER.maxHttpConnectNumber = cmd.maxHttpConnectNumber; } if (assigned.containsKey("--storage-db-directory")) { - PARAMETER.storageDbDirectory = - cmd.storageDbDirectory; + PARAMETER.storageDbDirectory = cmd.storageDbDirectory; } if (assigned.containsKey("--storage-db-engine")) { PARAMETER.storageDbEngine = cmd.storageDbEngine; } - if (assigned.containsKey( - "--storage-db-synchronous")) { - PARAMETER.storageDbSynchronous = - cmd.storageDbSynchronous; + if (assigned.containsKey("--storage-db-synchronous")) { + PARAMETER.storageDbSynchronous = cmd.storageDbSynchronous; } - if (assigned.containsKey( - "--contract-parse-enable")) { - PARAMETER.contractParseEnable = - cmd.contractParseEnable; + if (assigned.containsKey("--contract-parse-enable")) { + PARAMETER.contractParseEnable = cmd.contractParseEnable; } - if (assigned.containsKey( - "--storage-index-directory")) { - PARAMETER.storageIndexDirectory = - cmd.storageIndexDirectory; + if (assigned.containsKey("--storage-index-directory")) { + PARAMETER.storageIndexDirectory = cmd.storageIndexDirectory; } - if (assigned.containsKey( - "--storage-index-switch")) { - PARAMETER.storageIndexSwitch = - cmd.storageIndexSwitch; + if (assigned.containsKey("--storage-index-switch")) { + PARAMETER.storageIndexSwitch = cmd.storageIndexSwitch; } - if (assigned.containsKey( - "--storage-transactionHistory-switch")) { - PARAMETER.storageTransactionHistorySwitch = - cmd.storageTransactionHistorySwitch; + if (assigned.containsKey("--storage-transactionHistory-switch")) { + PARAMETER.storageTransactionHistorySwitch = cmd.storageTransactionHistorySwitch; } if (assigned.containsKey("--fast-forward")) { PARAMETER.fastForward = cmd.fastForward; @@ -1116,10 +1092,8 @@ private static void applyCLIParams(CLIParameter cmd, if (assigned.containsKey("--solidity-thread")) { PARAMETER.solidityThreads = cmd.solidityThreads; } - if (assigned.containsKey( - "--validate-sign-thread")) { - PARAMETER.validateSignThreadNum = - cmd.validateSignThreadNum; + if (assigned.containsKey("--validate-sign-thread")) { + PARAMETER.validateSignThreadNum = cmd.validateSignThreadNum; } if (assigned.containsKey("--trust-node")) { PARAMETER.trustNodeAddr = cmd.trustNodeAddr; @@ -1130,18 +1104,15 @@ private static void applyCLIParams(CLIParameter cmd, if (assigned.containsKey("--p2p-disable")) { PARAMETER.p2pDisable = cmd.p2pDisable; } - if (assigned.containsKey( - "--history-balance-lookup")) { - PARAMETER.historyBalanceLookup = - cmd.historyBalanceLookup; + if (assigned.containsKey("--history-balance-lookup")) { + PARAMETER.historyBalanceLookup = cmd.historyBalanceLookup; } if (assigned.containsKey("--log-config")) { PARAMETER.logbackPath = cmd.logbackPath; } } - private static void initLocalWitnesses( - Config config, CLIParameter cmd) { + private static void initLocalWitnesses(Config config, CLIParameter cmd) { // not a witness node, skip if (!PARAMETER.isWitness()) { localWitnesses = new LocalWitnesses(); @@ -1150,48 +1121,35 @@ private static void initLocalWitnesses( // path 1: CLI --private-key if (StringUtils.isNotBlank(cmd.privateKey)) { - localWitnesses = - WitnessInitializer.initFromCLIPrivateKey( - cmd.privateKey, cmd.witnessAddress); + localWitnesses = WitnessInitializer.initFromCLIPrivateKey( + cmd.privateKey, cmd.witnessAddress); return; } - String witnessAddr = config.hasPath( - ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) - ? config.getString( - ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) - : null; + String witnessAddr = config.hasPath(ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) + ? config.getString(ConfigKey.LOCAL_WITNESS_ACCOUNT_ADDRESS) : null; // path 2: config localwitness (private key list) if (config.hasPath(ConfigKey.LOCAL_WITNESS)) { - List keys = config.getStringList( - ConfigKey.LOCAL_WITNESS); + List keys = config.getStringList(ConfigKey.LOCAL_WITNESS); if (!keys.isEmpty()) { - localWitnesses = - WitnessInitializer.initFromCFGPrivateKey( - keys, witnessAddr); + localWitnesses = WitnessInitializer.initFromCFGPrivateKey(keys, witnessAddr); return; } } // path 3: config localwitnesskeystore + password - if (config.hasPath( - ConfigKey.LOCAL_WITNESS_KEYSTORE)) { - List keystores = config.getStringList( - ConfigKey.LOCAL_WITNESS_KEYSTORE); + if (config.hasPath(ConfigKey.LOCAL_WITNESS_KEYSTORE)) { + List keystores = config.getStringList(ConfigKey.LOCAL_WITNESS_KEYSTORE); if (!keystores.isEmpty()) { - localWitnesses = - WitnessInitializer.initFromKeystore( - keystores, cmd.password, - witnessAddr); + localWitnesses = WitnessInitializer.initFromKeystore( + keystores, cmd.password, witnessAddr); return; } } // no private key source configured - throw new TronError( - "This is a witness node, " - + "but localWitnesses is null", + throw new TronError("This is a witness node, but localWitnesses is null", TronError.ErrCode.WITNESS_INIT); } diff --git a/framework/src/main/java/org/tron/core/config/args/CLIParameter.java b/framework/src/main/java/org/tron/core/config/args/CLIParameter.java index 2dfec98e942..f65ed7063eb 100644 --- a/framework/src/main/java/org/tron/core/config/args/CLIParameter.java +++ b/framework/src/main/java/org/tron/core/config/args/CLIParameter.java @@ -16,61 +16,48 @@ public class CLIParameter { // ── Startup parameters ────────────────────────── - @Parameter(names = {"-c", "--config"}, - description = "Config file (default:config.conf)") + @Parameter(names = {"-c", "--config"}, description = "Config file (default:config.conf)") public String shellConfFileName; - @Parameter(names = {"-d", "--output-directory"}, - description = "Data directory for the databases" - + " (default:output-directory)") + @Parameter(names = {"-d", "--output-directory"}, description = "Data directory for the " + + "databases (default:output-directory)") public String outputDirectory; - @Parameter(names = {"--log-config"}, - description = "Logback config file") + @Parameter(names = {"--log-config"}, description = "Logback config file") public String logbackPath; - @Parameter(names = {"-h", "--help"}, help = true, - description = "Show help message") + @Parameter(names = {"-h", "--help"}, help = true, description = "Show help message") public boolean help; - @Parameter(names = {"-v", "--version"}, - description = "Output code version", help = true) + @Parameter(names = {"-v", "--version"}, description = "Output code version", help = true) public boolean version; - @Parameter(names = {"-w", "--witness"}, - description = "Is witness node") + @Parameter(names = {"-w", "--witness"}, description = "Is witness node") public boolean witness; - @Parameter(names = {"-p", "--private-key"}, - description = "Witness private key") + @Parameter(names = {"-p", "--private-key"}, description = "Witness private key") public String privateKey; - @Parameter(names = {"--witness-address"}, - description = "witness-address") + @Parameter(names = {"--witness-address"}, description = "witness-address") public String witnessAddress; - @Parameter(names = {"--password"}, - description = "password") + @Parameter(names = {"--password"}, description = "password") public String password; - @Parameter(names = {"--solidity"}, - description = "running a solidity node for java tron") + @Parameter(names = {"--solidity"}, description = "running a solidity node for java tron") public boolean solidityNode; - @Parameter(names = {"--keystore-factory"}, - description = "running KeystoreFactory") + @Parameter(names = {"--keystore-factory"}, description = "running KeystoreFactory") public boolean keystoreFactory; @Parameter(names = {"--fast-forward"}) public boolean fastForward; - @Parameter(names = {"--es"}, - description = "Start event subscribe server") + @Parameter(names = {"--es"}, description = "Start event subscribe server") public boolean eventSubscribe; - @Parameter(names = {"--p2p-disable"}, - description = "Switch for p2p module initialization." - + " (defalut: false)", arity = 1) + @Parameter(names = {"--p2p-disable"}, description = "Switch for p2p module initialization. " + + "(defalut: false)", arity = 1) public boolean p2pDisable; @Parameter(description = "--seed-nodes") @@ -78,22 +65,18 @@ public class CLIParameter { // ── Storage parameters ────────────────────────── - @Parameter(names = {"--storage-db-directory"}, - description = "Storage db directory") + @Parameter(names = {"--storage-db-directory"}, description = "Storage db directory") public String storageDbDirectory; @Parameter(names = {"--storage-db-engine"}, - description = "Storage db engine." - + "(leveldb or rocksdb)") + description = "Storage db engine.(leveldb or rocksdb)") public String storageDbEngine; @Parameter(names = {"--storage-db-synchronous"}, - description = "Storage db is synchronous or not." - + "(true or false)") + description = "Storage db is synchronous or not.(true or false)") public String storageDbSynchronous; - @Parameter(names = {"--storage-index-directory"}, - description = "Storage index directory") + @Parameter(names = {"--storage-index-directory"}, description = "Storage index directory") public String storageIndexDirectory; @Parameter(names = {"--storage-index-switch"}, @@ -101,92 +84,71 @@ public class CLIParameter { public String storageIndexSwitch; @Parameter(names = {"--storage-transactionHistory-switch"}, - description = "Storage transaction history switch." - + "(on or off)") + description = "Storage transaction history switch.(on or off)") public String storageTransactionHistorySwitch; - @Parameter(names = {"--contract-parse-enable"}, - description = "Switch for contract parses in" - + " java-tron. (default: true)") + @Parameter(names = {"--contract-parse-enable"}, description = "Switch for contract parses in " + + "java-tron. (default: true)") public String contractParseEnable; // ── Runtime parameters ────────────────────────── - @Parameter(names = {"--support-constant"}, - description = "Support constant calling for TVM." - + " (defalut: false)") + @Parameter(names = {"--support-constant"}, description = "Support constant calling for TVM. " + + "(defalut: false)") public boolean supportConstant; @Parameter(names = {"--max-energy-limit-for-constant"}, - description = "Max energy limit for constant calling." - + " (default: 100,000,000)") + description = "Max energy limit for constant calling. (default: 100,000,000)") public long maxEnergyLimitForConstant; - @Parameter(names = {"--lru-cache-size"}, - description = "Max LRU size for caching bytecode and" - + " result of JUMPDEST analysis. (default: 500)") + @Parameter(names = {"--lru-cache-size"}, description = "Max LRU size for caching bytecode and " + + "result of JUMPDEST analysis. (default: 500)") public int lruCacheSize; - @Parameter(names = {"--debug"}, - description = "Switch for TVM debug mode. In debug" - + " model, TVM will not check for timeout." - + " (default: false)") + @Parameter(names = {"--debug"}, description = "Switch for TVM debug mode. In debug model, TVM " + + "will not check for timeout. (default: false)") public boolean debug; - @Parameter(names = {"--min-time-ratio"}, - description = "Minimum CPU tolerance when executing" - + " timeout transactions while synchronizing" - + " blocks. (default: 0.0)") + @Parameter(names = {"--min-time-ratio"}, description = "Minimum CPU tolerance when executing " + + "timeout transactions while synchronizing blocks. (default: 0.0)") public double minTimeRatio; - @Parameter(names = {"--max-time-ratio"}, - description = "Maximum CPU tolerance when executing" - + " non-timeout transactions while synchronizing" - + " blocks. (default: 5.0)") + @Parameter(names = {"--max-time-ratio"}, description = "Maximum CPU tolerance when executing " + + "non-timeout transactions while synchronizing blocks. (default: 5.0)") public double maxTimeRatio; - @Parameter(names = {"--save-internaltx"}, - description = "Save internal transactions generated" - + " during TVM execution, such as create, call" - + " and suicide. (default: false)") + @Parameter(names = {"--save-internaltx"}, description = "Save internal transactions generated " + + "during TVM execution, such as create, call and suicide. (default: false)") public boolean saveInternalTx; - @Parameter(names = {"--save-featured-internaltx"}, - description = "Save featured internal transactions" - + " generated during TVM execution, such as" - + " freeze, vote and so on. (default: false)") + @Parameter(names = {"--save-featured-internaltx"}, description = "Save featured internal " + + "transactions generated during TVM execution, such as freeze, vote and so on. " + + "(default: false)") public boolean saveFeaturedInternalTx; @Parameter(names = {"--save-cancel-all-unfreeze-v2-details"}, - description = "Record the details of the internal" - + " transactions generated by the" - + " CANCELALLUNFREEZEV2 opcode, such as" - + " bandwidth/energy/tronpower cancel amount." - + " (default: false)") + description = "Record the details of the internal transactions generated by the " + + "CANCELALLUNFREEZEV2 opcode, such as bandwidth/energy/tronpower cancel amount. " + + "(default: false)") public boolean saveCancelAllUnfreezeV2Details; @Parameter(names = {"--long-running-time"}) public int longRunningTime; - @Parameter(names = {"--max-connect-number"}, - description = "Http server max connect number" - + " (default:50)") + @Parameter(names = {"--max-connect-number"}, description = "Http server max connect number " + + "(default:50)") public int maxHttpConnectNumber; - @Parameter(names = {"--rpc-thread"}, - description = "Num of gRPC thread") + @Parameter(names = {"--rpc-thread"}, description = "Num of gRPC thread") public int rpcThreadNum; - @Parameter(names = {"--solidity-thread"}, - description = "Num of solidity thread") + @Parameter(names = {"--solidity-thread"}, description = "Num of solidity thread") public int solidityThreads; - @Parameter(names = {"--validate-sign-thread"}, - description = "Num of validate thread") + @Parameter(names = {"--validate-sign-thread"}, description = "Num of validate thread") public int validateSignThreadNum; - @Parameter(names = {"--trust-node"}, - description = "Trust node addr") + @Parameter(names = {"--trust-node"}, description = "Trust node addr") public String trustNodeAddr; @Parameter(names = {"--history-balance-lookup"}) diff --git a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java index 50087c8502d..30711eb6190 100644 --- a/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java +++ b/framework/src/main/java/org/tron/core/config/args/WitnessInitializer.java @@ -19,30 +19,25 @@ public class WitnessInitializer { /** - * Init from a single private key (and optional - * witness address). + * Init from a single private key (and optional witness address). */ public static LocalWitnesses initFromCLIPrivateKey( String privateKey, String witnessAddress) { - LocalWitnesses witnesses = - new LocalWitnesses(privateKey); + LocalWitnesses witnesses = new LocalWitnesses(privateKey); byte[] address = null; if (StringUtils.isNotEmpty(witnessAddress)) { - address = Commons.decodeFromBase58Check( - witnessAddress); + address = Commons.decodeFromBase58Check(witnessAddress); if (address == null) { throw new TronError( - "LocalWitnessAccountAddress format" - + " from cmd is incorrect", + "LocalWitnessAccountAddress format from cmd is incorrect", TronError.ErrCode.WITNESS_INIT); } - logger.debug( - "Got localWitnessAccountAddress from cmd"); + logger.debug("Got localWitnessAccountAddress from cmd"); } - witnesses.initWitnessAccountAddress(address, - Args.getInstance().isECKeyCryptoEngine()); + witnesses.initWitnessAccountAddress( + address, Args.getInstance().isECKeyCryptoEngine()); logger.debug("Got privateKey from cmd"); return witnesses; } @@ -51,16 +46,14 @@ public static LocalWitnesses initFromCLIPrivateKey( * Init from a list of private keys. */ public static LocalWitnesses initFromCFGPrivateKey( - List privateKeys, - String witnessAccountAddress) { + List privateKeys, String witnessAccountAddress) { LocalWitnesses witnesses = new LocalWitnesses(); witnesses.setPrivateKeys(privateKeys); logger.debug("Got privateKey from config.conf"); - byte[] address = resolveWitnessAddress( - witnesses, witnessAccountAddress); - witnesses.initWitnessAccountAddress(address, - Args.getInstance().isECKeyCryptoEngine()); + byte[] address = resolveWitnessAddress(witnesses, witnessAccountAddress); + witnesses.initWitnessAccountAddress( + address, Args.getInstance().isECKeyCryptoEngine()); return witnesses; } @@ -71,19 +64,14 @@ public static LocalWitnesses initFromKeystore( List keystoreFiles, String password, String witnessAccountAddress) { if (keystoreFiles.size() > 1) { - logger.warn("Multiple keystores detected." - + " Only the first keystore will be used" - + " as witness, all others will be" - + " ignored."); + logger.warn("Multiple keystores detected. Only the first keystore will be used" + + " as witness, all others will be ignored."); } - String fileName = - System.getProperty("user.dir") + "/" - + keystoreFiles.get(0); + String fileName = System.getProperty("user.dir") + "/" + keystoreFiles.get(0); String pwd; if (StringUtils.isEmpty(password)) { - System.out.println( - "Please input your password."); + System.out.println("Please input your password."); pwd = WalletUtils.inputPassword(); } else { pwd = password; @@ -91,53 +79,40 @@ public static LocalWitnesses initFromKeystore( List privateKeys = new ArrayList<>(); try { - Credentials credentials = WalletUtils - .loadCredentials(pwd, new File(fileName)); - SignInterface sign = - credentials.getSignInterface(); - String prikey = - ByteArray.toHexString(sign.getPrivateKey()); + Credentials credentials = WalletUtils.loadCredentials(pwd, new File(fileName)); + SignInterface sign = credentials.getSignInterface(); + String prikey = ByteArray.toHexString(sign.getPrivateKey()); privateKeys.add(prikey); } catch (IOException | CipherException e) { logger.error("Witness node start failed!"); - throw new TronError(e, - TronError.ErrCode.WITNESS_KEYSTORE_LOAD); + throw new TronError(e, TronError.ErrCode.WITNESS_KEYSTORE_LOAD); } LocalWitnesses witnesses = new LocalWitnesses(); witnesses.setPrivateKeys(privateKeys); - byte[] address = resolveWitnessAddress( - witnesses, witnessAccountAddress); - witnesses.initWitnessAccountAddress(address, - Args.getInstance().isECKeyCryptoEngine()); + byte[] address = resolveWitnessAddress(witnesses, witnessAccountAddress); + witnesses.initWitnessAccountAddress( + address, Args.getInstance().isECKeyCryptoEngine()); logger.debug("Got privateKey from keystore"); return witnesses; } static byte[] resolveWitnessAddress( - LocalWitnesses witnesses, - String witnessAccountAddress) { + LocalWitnesses witnesses, String witnessAccountAddress) { if (StringUtils.isEmpty(witnessAccountAddress)) { return null; } if (witnesses.getPrivateKeys().size() != 1) { throw new TronError( - "LocalWitnessAccountAddress can only be" - + " set when there is only one" - + " private key", + "LocalWitnessAccountAddress can only be set when there is only one private key", TronError.ErrCode.WITNESS_INIT); } - byte[] address = Commons - .decodeFromBase58Check(witnessAccountAddress); + byte[] address = Commons.decodeFromBase58Check(witnessAccountAddress); if (address != null) { - logger.debug( - "Got localWitnessAccountAddress" - + " from config.conf"); + logger.debug("Got localWitnessAccountAddress from config.conf"); } else { - throw new TronError( - "LocalWitnessAccountAddress format" - + " from config is incorrect", + throw new TronError("LocalWitnessAccountAddress format from config is incorrect", TronError.ErrCode.WITNESS_INIT); } return address; diff --git a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java index 189158820e9..3ecef5b10c9 100644 --- a/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java +++ b/framework/src/test/java/org/tron/core/config/args/WitnessInitializerTest.java @@ -32,14 +32,10 @@ public class WitnessInitializerTest { - private static final String privateKey = - PublicMethod.getRandomPrivateKey(); - private static final String address = - Base58.encode58Check(ByteArray.fromHexString( - PublicMethod.getHexAddressByPrivateKey( - privateKey))); - private static final String invalidAddress = - "RJCzdnv88Hvqa2jB1C9dMmMYHr5DFdF2R3"; + private static final String privateKey = PublicMethod.getRandomPrivateKey(); + private static final String address = Base58.encode58Check( + ByteArray.fromHexString(PublicMethod.getHexAddressByPrivateKey(privateKey))); + private static final String invalidAddress = "RJCzdnv88Hvqa2jB1C9dMmMYHr5DFdF2R3"; @After public void clear() { @@ -50,16 +46,13 @@ public void clear() { public void testInitFromCLI() { // privateKey only LocalWitnesses result = - WitnessInitializer.initFromCLIPrivateKey( - privateKey, null); + WitnessInitializer.initFromCLIPrivateKey(privateKey, null); assertNotNull(result); assertFalse(result.getPrivateKeys().isEmpty()); - assertEquals(privateKey, - result.getPrivateKeys().get(0)); + assertEquals(privateKey, result.getPrivateKeys().get(0)); // with valid witnessAddress - result = WitnessInitializer.initFromCLIPrivateKey( - privateKey, address); + result = WitnessInitializer.initFromCLIPrivateKey(privateKey, address); assertNotNull(result); assertFalse(result.getPrivateKeys().isEmpty()); @@ -67,23 +60,19 @@ public void testInitFromCLI() { TronError err = assertThrows(TronError.class, () -> WitnessInitializer.initFromCLIPrivateKey( privateKey, invalidAddress)); - assertEquals(ErrCode.WITNESS_INIT, - err.getErrCode()); + assertEquals(ErrCode.WITNESS_INIT, err.getErrCode()); } @Test public void testInitFromConfig() { // single private key, no address - LocalWitnesses result = - WitnessInitializer.initFromCFGPrivateKey( - Collections.singletonList(privateKey), - null); + LocalWitnesses result = WitnessInitializer.initFromCFGPrivateKey( + Collections.singletonList(privateKey), null); assertFalse(result.getPrivateKeys().isEmpty()); // single key + valid address result = WitnessInitializer.initFromCFGPrivateKey( - Collections.singletonList(privateKey), - address); + Collections.singletonList(privateKey), address); assertFalse(result.getPrivateKeys().isEmpty()); // multiple keys, no address @@ -94,86 +83,61 @@ public void testInitFromConfig() { // single key + invalid address TronError err = assertThrows(TronError.class, () -> WitnessInitializer.initFromCFGPrivateKey( - Collections.singletonList(privateKey), - invalidAddress)); - assertEquals(ErrCode.WITNESS_INIT, - err.getErrCode()); + Collections.singletonList(privateKey), invalidAddress)); + assertEquals(ErrCode.WITNESS_INIT, err.getErrCode()); // multiple keys + address = error err = assertThrows(TronError.class, () -> WitnessInitializer.initFromCFGPrivateKey( - Arrays.asList(privateKey, privateKey), - address)); - assertEquals(ErrCode.WITNESS_INIT, - err.getErrCode()); + Arrays.asList(privateKey, privateKey), address)); + assertEquals(ErrCode.WITNESS_INIT, err.getErrCode()); } @Test public void testInitFromKeystore() { - List keystores = - Arrays.asList("keystore1.json", - "keystore2.json"); - - try (MockedStatic mockedWallet = - mockStatic(WalletUtils.class); - MockedStatic mockedByteArray = - mockStatic(ByteArray.class)) { - - Credentials credentials = - mock(Credentials.class); - SignInterface signInterface = - mock(SignInterface.class); - when(credentials.getSignInterface()) - .thenReturn(signInterface); + List keystores = Arrays.asList("keystore1.json", "keystore2.json"); + + try (MockedStatic mockedWallet = mockStatic(WalletUtils.class); + MockedStatic mockedByteArray = mockStatic(ByteArray.class)) { + + Credentials credentials = mock(Credentials.class); + SignInterface signInterface = mock(SignInterface.class); + when(credentials.getSignInterface()).thenReturn(signInterface); byte[] keyBytes = Hex.decode(privateKey); - when(signInterface.getPrivateKey()) - .thenReturn(keyBytes); - mockedWallet.when(() -> - WalletUtils.loadCredentials( - anyString(), any(File.class))) - .thenReturn(credentials); - mockedByteArray.when(() -> - ByteArray.toHexString(any())) + when(signInterface.getPrivateKey()).thenReturn(keyBytes); + mockedWallet.when(() -> WalletUtils.loadCredentials( + anyString(), any(File.class))).thenReturn(credentials); + mockedByteArray.when(() -> ByteArray.toHexString(any())) .thenReturn(privateKey); - mockedByteArray.when(() -> - ByteArray.fromHexString(anyString())) + mockedByteArray.when(() -> ByteArray.fromHexString(anyString())) .thenReturn(keyBytes); - LocalWitnesses result = - WitnessInitializer.initFromKeystore( - keystores, "password", null); - assertFalse( - result.getPrivateKeys().isEmpty()); + LocalWitnesses result = WitnessInitializer.initFromKeystore( + keystores, "password", null); + assertFalse(result.getPrivateKeys().isEmpty()); } } @Test public void testResolveWitnessAddress() { // null address -> null - LocalWitnesses witnesses = - new LocalWitnesses(privateKey); - byte[] result = - WitnessInitializer.resolveWitnessAddress( - witnesses, null); + LocalWitnesses witnesses = new LocalWitnesses(privateKey); + byte[] result = WitnessInitializer.resolveWitnessAddress(witnesses, null); assertNull(result); // empty address -> null - result = WitnessInitializer.resolveWitnessAddress( - witnesses, ""); + result = WitnessInitializer.resolveWitnessAddress(witnesses, ""); assertNull(result); // valid address with single key - result = WitnessInitializer.resolveWitnessAddress( - witnesses, address); + result = WitnessInitializer.resolveWitnessAddress(witnesses, address); assertNotNull(result); // invalid address TronError err = assertThrows(TronError.class, () -> WitnessInitializer.resolveWitnessAddress( - new LocalWitnesses(privateKey), - invalidAddress)); - assertEquals(ErrCode.WITNESS_INIT, - err.getErrCode()); + new LocalWitnesses(privateKey), invalidAddress)); + assertEquals(ErrCode.WITNESS_INIT, err.getErrCode()); // multiple keys + address = error LocalWitnesses multiKey = new LocalWitnesses(); @@ -182,9 +146,7 @@ public void testResolveWitnessAddress() { keys.add(privateKey); multiKey.setPrivateKeys(keys); err = assertThrows(TronError.class, - () -> WitnessInitializer.resolveWitnessAddress( - multiKey, address)); - assertEquals(ErrCode.WITNESS_INIT, - err.getErrCode()); + () -> WitnessInitializer.resolveWitnessAddress(multiKey, address)); + assertEquals(ErrCode.WITNESS_INIT, err.getErrCode()); } } From c4cb0e15ad0bdcd728107fc21d9a2d8526907648 Mon Sep 17 00:00:00 2001 From: vividcoder Date: Thu, 5 Mar 2026 21:57:41 +0800 Subject: [PATCH 5/8] fix(config): write CLI storage params directly to Storage object applyCLIParams() wrote 7 storage-related values to intermediate fields on CommonParameter instead of the Storage object that is actually used at runtime. Since applyConfigParams() runs first, these CLI values were silently ignored. - Remove 7 intermediate fields from CommonParameter - Simplify applyConfigParams() to read directly from config - Fix applyCLIParams() to write directly to PARAMETER.storage - Add tests for CLI-overrides-config and config-defaults scenarios --- .../common/parameter/CommonParameter.java | 21 -------- .../java/org/tron/core/config/args/Args.java | 53 ++++++------------- .../org/tron/core/config/args/ArgsTest.java | 53 +++++++++++++++++++ 3 files changed, 68 insertions(+), 59 deletions(-) diff --git a/common/src/main/java/org/tron/common/parameter/CommonParameter.java b/common/src/main/java/org/tron/common/parameter/CommonParameter.java index 675fea359db..2bcc2e9c6f3 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -76,27 +76,6 @@ public class CommonParameter { @Getter public List seedNodes = new ArrayList<>(); @Getter - @Setter - public String storageDbDirectory = ""; - @Getter - @Setter - public String storageDbEngine = ""; - @Getter - @Setter - public String storageDbSynchronous = ""; - @Getter - @Setter - public String contractParseEnable = ""; - @Getter - @Setter - public String storageIndexDirectory = ""; - @Getter - @Setter - public String storageIndexSwitch = ""; - @Getter - @Setter - public String storageTransactionHistorySwitch = ""; - @Getter public boolean fastForward = false; // ── Network / P2P ───────────────────────────── @Getter diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index c2356994a09..3d5fc321cda 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -225,37 +225,14 @@ public static void applyConfigParams( PARAMETER.storage = new Storage(); - PARAMETER.storage.setDbEngine(Optional.ofNullable(PARAMETER.storageDbEngine) - .filter(StringUtils::isNotEmpty) - .orElse(Storage.getDbEngineFromConfig(config))); - - PARAMETER.storage.setDbSync(Optional.ofNullable(PARAMETER.storageDbSynchronous) - .filter(StringUtils::isNotEmpty) - .map(Boolean::valueOf) - .orElse(Storage.getDbVersionSyncFromConfig(config))); - - PARAMETER.storage.setContractParseSwitch(Optional.ofNullable(PARAMETER.contractParseEnable) - .filter(StringUtils::isNotEmpty) - .map(Boolean::valueOf) - .orElse(Storage.getContractParseSwitchFromConfig(config))); - - PARAMETER.storage.setDbDirectory(Optional.ofNullable(PARAMETER.storageDbDirectory) - .filter(StringUtils::isNotEmpty) - .orElse(Storage.getDbDirectoryFromConfig(config))); - - PARAMETER.storage.setIndexDirectory(Optional.ofNullable(PARAMETER.storageIndexDirectory) - .filter(StringUtils::isNotEmpty) - .orElse(Storage.getIndexDirectoryFromConfig(config))); - - PARAMETER.storage.setIndexSwitch(Optional.ofNullable(PARAMETER.storageIndexSwitch) - .filter(StringUtils::isNotEmpty) - .orElse(Storage.getIndexSwitchFromConfig(config))); - - PARAMETER.storage - .setTransactionHistorySwitch( - Optional.ofNullable(PARAMETER.storageTransactionHistorySwitch) - .filter(StringUtils::isNotEmpty) - .orElse(Storage.getTransactionHistorySwitchFromConfig(config))); + PARAMETER.storage.setDbEngine(Storage.getDbEngineFromConfig(config)); + PARAMETER.storage.setDbSync(Storage.getDbVersionSyncFromConfig(config)); + PARAMETER.storage.setContractParseSwitch(Storage.getContractParseSwitchFromConfig(config)); + PARAMETER.storage.setDbDirectory(Storage.getDbDirectoryFromConfig(config)); + PARAMETER.storage.setIndexDirectory(Storage.getIndexDirectoryFromConfig(config)); + PARAMETER.storage.setIndexSwitch(Storage.getIndexSwitchFromConfig(config)); + PARAMETER.storage.setTransactionHistorySwitch( + Storage.getTransactionHistorySwitchFromConfig(config)); PARAMETER.storage .setCheckpointVersion(Storage.getCheckpointVersionFromConfig(config)); @@ -1057,25 +1034,25 @@ private static void applyCLIParams(CLIParameter cmd, JCommander jc) { PARAMETER.maxHttpConnectNumber = cmd.maxHttpConnectNumber; } if (assigned.containsKey("--storage-db-directory")) { - PARAMETER.storageDbDirectory = cmd.storageDbDirectory; + PARAMETER.storage.setDbDirectory(cmd.storageDbDirectory); } if (assigned.containsKey("--storage-db-engine")) { - PARAMETER.storageDbEngine = cmd.storageDbEngine; + PARAMETER.storage.setDbEngine(cmd.storageDbEngine); } if (assigned.containsKey("--storage-db-synchronous")) { - PARAMETER.storageDbSynchronous = cmd.storageDbSynchronous; + PARAMETER.storage.setDbSync(Boolean.valueOf(cmd.storageDbSynchronous)); } if (assigned.containsKey("--contract-parse-enable")) { - PARAMETER.contractParseEnable = cmd.contractParseEnable; + PARAMETER.storage.setContractParseSwitch(Boolean.valueOf(cmd.contractParseEnable)); } if (assigned.containsKey("--storage-index-directory")) { - PARAMETER.storageIndexDirectory = cmd.storageIndexDirectory; + PARAMETER.storage.setIndexDirectory(cmd.storageIndexDirectory); } if (assigned.containsKey("--storage-index-switch")) { - PARAMETER.storageIndexSwitch = cmd.storageIndexSwitch; + PARAMETER.storage.setIndexSwitch(cmd.storageIndexSwitch); } if (assigned.containsKey("--storage-transactionHistory-switch")) { - PARAMETER.storageTransactionHistorySwitch = cmd.storageTransactionHistorySwitch; + PARAMETER.storage.setTransactionHistorySwitch(cmd.storageTransactionHistorySwitch); } if (assigned.containsKey("--fast-forward")) { PARAMETER.fastForward = cmd.fastForward; diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 373b258b903..d2f74850299 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -282,5 +282,58 @@ public void testInitService() { Args.clearParam(); } + + /** + * Verify that CLI storage parameters correctly override config file values. + * + *

config-test.conf defines: db.directory = "database", db.engine = "LEVELDB". + * When CLI passes different values (e.g. --storage-db-directory cli-db-dir), + * the Storage object should reflect the CLI values, not the config file values. + * + *

This ensures the three-layer override chain works: + * Storage defaults -> config file -> CLI arguments. + */ + @Test + public void testCliOverridesStorageConfig() { + Args.setParam(new String[] { + "--storage-db-directory", "cli-db-dir", + "--storage-db-engine", "ROCKSDB", + "--storage-db-synchronous", "true", + "--storage-index-directory", "cli-index-dir", + "--storage-index-switch", "cli-index-switch", + "--storage-transactionHistory-switch", "off", + "--contract-parse-enable", "false" + }, TestConstants.TEST_CONF); + + CommonParameter parameter = Args.getInstance(); + + Assert.assertEquals("cli-db-dir", parameter.getStorage().getDbDirectory()); + Assert.assertEquals("ROCKSDB", parameter.getStorage().getDbEngine()); + Assert.assertTrue(parameter.getStorage().isDbSync()); + Assert.assertEquals("cli-index-dir", parameter.getStorage().getIndexDirectory()); + Assert.assertEquals("cli-index-switch", parameter.getStorage().getIndexSwitch()); + Assert.assertEquals("off", parameter.getStorage().getTransactionHistorySwitch()); + Assert.assertFalse(parameter.getStorage().isContractParseSwitch()); + + Args.clearParam(); + } + + /** + * Verify that config file storage values are applied when no CLI override is present. + * + *

config-test.conf defines: db.directory = "database", db.engine = "LEVELDB". + * Without any CLI storage arguments, the Storage object should use these config values. + */ + @Test + public void testConfigStorageDefaults() { + Args.setParam(new String[] {}, TestConstants.TEST_CONF); + + CommonParameter parameter = Args.getInstance(); + + Assert.assertEquals("database", parameter.getStorage().getDbDirectory()); + Assert.assertEquals("LEVELDB", parameter.getStorage().getDbEngine()); + + Args.clearParam(); + } } From 56f2cec2ae07d37f86faa811ac160c949fad0e86 Mon Sep 17 00:00:00 2001 From: vividcoder Date: Thu, 5 Mar 2026 23:57:26 +0800 Subject: [PATCH 6/8] fix(config): fix ARM64 test failure by adding config validation The test failed on ARM64 because Storage.getDbEngineFromConfig() silently overrode the user's config to ROCKSDB, which is unreasonable as it hides incompatible configuration from the user. Replace the silent override with an explicit validateConfig() check in Args that fails fast with IllegalArgumentException when LevelDB is configured on ARM64. This makes the incompatibility visible instead of silently swallowed. --- .../java/org/tron/core/config/args/Storage.java | 7 ------- .../main/java/org/tron/core/config/args/Args.java | 14 ++++++++++++++ .../java/org/tron/core/config/args/ArgsTest.java | 15 +++++++++++---- 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/Storage.java b/common/src/main/java/org/tron/core/config/args/Storage.java index 655b6b779fe..116074c62ee 100644 --- a/common/src/main/java/org/tron/core/config/args/Storage.java +++ b/common/src/main/java/org/tron/core/config/args/Storage.java @@ -29,7 +29,6 @@ import org.apache.commons.lang3.StringUtils; import org.iq80.leveldb.CompressionType; import org.iq80.leveldb.Options; -import org.tron.common.arch.Arch; import org.tron.common.cache.CacheStrategies; import org.tron.common.cache.CacheType; import org.tron.common.utils.DbOptionalsUtils; @@ -90,7 +89,6 @@ public class Storage { * Default values of directory */ private static final String DEFAULT_DB_ENGINE = "LEVELDB"; - private static final String ROCKS_DB_ENGINE = "ROCKSDB"; private static final boolean DEFAULT_DB_SYNC = false; private static final boolean DEFAULT_EVENT_SUBSCRIBE_CONTRACT_PARSE = true; private static final String DEFAULT_DB_DIRECTORY = "database"; @@ -175,11 +173,6 @@ public class Storage { private final Map dbRoots = Maps.newConcurrentMap(); public static String getDbEngineFromConfig(final Config config) { - if (Arch.isArm64()) { - // if is arm64 but config is leveldb, should throw exception? - logger.warn("Arm64 architecture detected, using RocksDB as db engine, ignore config."); - return ROCKS_DB_ENGINE; - } return config.hasPath(DB_ENGINE_CONFIG_KEY) ? config.getString(DB_ENGINE_CONFIG_KEY) : DEFAULT_DB_ENGINE; } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index 3d5fc321cda..a820d21bea8 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -130,6 +130,20 @@ public static void setParam(final String[] args, final String confFileName) { // 4. Init witness (depends on CLI witness flag) initLocalWitnesses(config, cmd); + + // 5. Validate final configuration + validateConfig(); + } + + /** + * Validate the final configuration after all layers (defaults, config, CLI) are applied. + * Fails fast on incompatible configurations. + */ + private static void validateConfig() { + if (Arch.isArm64() && "LEVELDB".equalsIgnoreCase(PARAMETER.storage.getDbEngine())) { + throw new IllegalArgumentException( + "LevelDB is not supported on ARM64 architecture, please use ROCKSDB"); + } } /** diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index d2f74850299..3dcc755f520 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -38,6 +38,7 @@ import org.tron.common.utils.DecodeUtil; import org.tron.common.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; +import org.tron.common.arch.Arch; import org.tron.core.config.Configuration; @Slf4j @@ -323,15 +324,21 @@ public void testCliOverridesStorageConfig() { * *

config-test.conf defines: db.directory = "database", db.engine = "LEVELDB". * Without any CLI storage arguments, the Storage object should use these config values. + * On ARM64, LEVELDB is not supported and validateConfig() should throw. */ @Test public void testConfigStorageDefaults() { - Args.setParam(new String[] {}, TestConstants.TEST_CONF); + if (Arch.isArm64()) { + Assert.assertThrows(IllegalArgumentException.class, + () -> Args.setParam(new String[] {}, TestConstants.TEST_CONF)); + } else { + Args.setParam(new String[] {}, TestConstants.TEST_CONF); - CommonParameter parameter = Args.getInstance(); + CommonParameter parameter = Args.getInstance(); - Assert.assertEquals("database", parameter.getStorage().getDbDirectory()); - Assert.assertEquals("LEVELDB", parameter.getStorage().getDbEngine()); + Assert.assertEquals("database", parameter.getStorage().getDbDirectory()); + Assert.assertEquals("LEVELDB", parameter.getStorage().getDbEngine()); + } Args.clearParam(); } From d90b7e2bf397d612dcfde37d7d696d21c7d9844f Mon Sep 17 00:00:00 2001 From: vividcoder Date: Fri, 6 Mar 2026 01:23:08 +0800 Subject: [PATCH 7/8] fix(config): revert validateConfig, restore ARM64 silent db engine override The validateConfig() approach caused 1273 test failures on ARM64 because most tests use config files with db.engine="LEVELDB" and setParam() was throwing IllegalArgumentException before any test logic could run. Restore the original silent override in Storage.getDbEngineFromConfig() which automatically switches to ROCKSDB on ARM64. Update the testConfigStorageDefaults test to be architecture-aware. --- .../java/org/tron/core/config/args/Storage.java | 6 ++++++ .../main/java/org/tron/core/config/args/Args.java | 14 -------------- .../java/org/tron/core/config/args/ArgsTest.java | 15 +++++++-------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/Storage.java b/common/src/main/java/org/tron/core/config/args/Storage.java index 116074c62ee..7961bb9a9d5 100644 --- a/common/src/main/java/org/tron/core/config/args/Storage.java +++ b/common/src/main/java/org/tron/core/config/args/Storage.java @@ -29,6 +29,7 @@ import org.apache.commons.lang3.StringUtils; import org.iq80.leveldb.CompressionType; import org.iq80.leveldb.Options; +import org.tron.common.arch.Arch; import org.tron.common.cache.CacheStrategies; import org.tron.common.cache.CacheType; import org.tron.common.utils.DbOptionalsUtils; @@ -89,6 +90,7 @@ public class Storage { * Default values of directory */ private static final String DEFAULT_DB_ENGINE = "LEVELDB"; + private static final String ROCKS_DB_ENGINE = "ROCKSDB"; private static final boolean DEFAULT_DB_SYNC = false; private static final boolean DEFAULT_EVENT_SUBSCRIBE_CONTRACT_PARSE = true; private static final String DEFAULT_DB_DIRECTORY = "database"; @@ -173,6 +175,10 @@ public class Storage { private final Map dbRoots = Maps.newConcurrentMap(); public static String getDbEngineFromConfig(final Config config) { + if (Arch.isArm64()) { + logger.warn("Arm64 architecture detected, using RocksDB as db engine, ignore config."); + return ROCKS_DB_ENGINE; + } return config.hasPath(DB_ENGINE_CONFIG_KEY) ? config.getString(DB_ENGINE_CONFIG_KEY) : DEFAULT_DB_ENGINE; } diff --git a/framework/src/main/java/org/tron/core/config/args/Args.java b/framework/src/main/java/org/tron/core/config/args/Args.java index a820d21bea8..3d5fc321cda 100644 --- a/framework/src/main/java/org/tron/core/config/args/Args.java +++ b/framework/src/main/java/org/tron/core/config/args/Args.java @@ -130,20 +130,6 @@ public static void setParam(final String[] args, final String confFileName) { // 4. Init witness (depends on CLI witness flag) initLocalWitnesses(config, cmd); - - // 5. Validate final configuration - validateConfig(); - } - - /** - * Validate the final configuration after all layers (defaults, config, CLI) are applied. - * Fails fast on incompatible configurations. - */ - private static void validateConfig() { - if (Arch.isArm64() && "LEVELDB".equalsIgnoreCase(PARAMETER.storage.getDbEngine())) { - throw new IllegalArgumentException( - "LevelDB is not supported on ARM64 architecture, please use ROCKSDB"); - } } /** diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 3dcc755f520..09fac7b48df 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -324,19 +324,18 @@ public void testCliOverridesStorageConfig() { * *

config-test.conf defines: db.directory = "database", db.engine = "LEVELDB". * Without any CLI storage arguments, the Storage object should use these config values. - * On ARM64, LEVELDB is not supported and validateConfig() should throw. + * On ARM64, the silent override in Storage.getDbEngineFromConfig() forces ROCKSDB. */ @Test public void testConfigStorageDefaults() { - if (Arch.isArm64()) { - Assert.assertThrows(IllegalArgumentException.class, - () -> Args.setParam(new String[] {}, TestConstants.TEST_CONF)); - } else { - Args.setParam(new String[] {}, TestConstants.TEST_CONF); + Args.setParam(new String[] {}, TestConstants.TEST_CONF); - CommonParameter parameter = Args.getInstance(); + CommonParameter parameter = Args.getInstance(); - Assert.assertEquals("database", parameter.getStorage().getDbDirectory()); + Assert.assertEquals("database", parameter.getStorage().getDbDirectory()); + if (Arch.isArm64()) { + Assert.assertEquals("ROCKSDB", parameter.getStorage().getDbEngine()); + } else { Assert.assertEquals("LEVELDB", parameter.getStorage().getDbEngine()); } From 46b00bdf7b86865b4a2ce08cba97979beb252cb8 Mon Sep 17 00:00:00 2001 From: vividcoder Date: Fri, 6 Mar 2026 01:34:53 +0800 Subject: [PATCH 8/8] style: fix import order in ArgsTest for checkstyle compliance --- framework/src/test/java/org/tron/core/config/args/ArgsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java index 09fac7b48df..a4ce9a5030e 100644 --- a/framework/src/test/java/org/tron/core/config/args/ArgsTest.java +++ b/framework/src/test/java/org/tron/core/config/args/ArgsTest.java @@ -32,13 +32,13 @@ import org.junit.Test; import org.junit.rules.ExpectedException; import org.tron.common.TestConstants; +import org.tron.common.arch.Arch; import org.tron.common.args.GenesisBlock; import org.tron.common.parameter.CommonParameter; import org.tron.common.utils.ByteArray; import org.tron.common.utils.DecodeUtil; import org.tron.common.utils.LocalWitnesses; import org.tron.common.utils.PublicMethod; -import org.tron.common.arch.Arch; import org.tron.core.config.Configuration; @Slf4j