From dc4c1bc1f2d90a07bb2404a9057552d5403a4e33 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 15:27:41 +0800 Subject: [PATCH 01/16] supplement comments in reference.conf; reduce comments and items in config.conf --- common/src/main/resources/reference.conf | 111 ++++-- framework/src/main/resources/config.conf | 418 ++--------------------- 2 files changed, 103 insertions(+), 426 deletions(-) diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 0864f4d512..29de4e7bca 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -72,19 +72,27 @@ storage { # } # setting can improve leveldb performance .... end, deprecated for arm - # Example per-database overrides: + # Per-database storage configuration overrides. Otherwise databases use global defaults and store + # data in "output-directory" or the directory specified by the "-d" / "--output-directory" option. + # Attention: name is a required field that must be set! + # The name and path properties take effect for both LevelDB and RocksDB storage engines, + # while additional properties (createIfMissing, paranoidChecks, compressionType, etc.) + # only take effect when using LevelDB. + # Example: + # properties = [ # { # name = "account", # path = "storage_directory_test", - # createIfMissing = true, + # createIfMissing = true, // deprecated for arm start # paranoidChecks = true, # verifyChecksums = true, # compressionType = 1, // compressed with snappy # blockSize = 4096, // 4 KB = 4 * 1024 B # writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B # cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - # maxOpenFiles = 100 + # maxOpenFiles = 100 // deprecated for arm end # } + # ] properties = [] needToUpdateAsset = true @@ -138,12 +146,11 @@ node.discovery = { # } node.backup { - port = 10001 - priority = 0 - keepAliveInterval = 3000 + port = 10001 # UDP listen port; each member should have the same configuration + priority = 0 # Node priority; each member should use a different priority + keepAliveInterval = 3000 # Keep-alive interval (ms); each member should have the same configuration members = [ - # "ip", - # "ip" + # "ip", # Peer IP list; must not contain this node's own IP ] } @@ -188,7 +195,12 @@ node { maxHttpConnectNumber = 50 minParticipationRate = 0 - # Whether to enable shielded transaction API + # WARNING: Some shielded transaction APIs require sending private keys as parameters. + # Calling these APIs on untrusted or remote nodes may leak your private keys. + # It is recommended to invoke them locally for development and testing. + # To opt in, set: allowShieldedTransactionApi = true + # Migration: the legacy key node.fullNodeAllowShieldedTransaction is still supported + # but deprecated; please migrate to node.allowShieldedTransactionApi. # allowShieldedTransactionApi = false # Whether to print config log at startup @@ -243,7 +255,10 @@ node { PBFTEnable = true PBFTPort = 8092 - # Maximum HTTP request body size, default 4MB. Independent from rpc.maxMessageSize. + # Maximum HTTP request body size (default 4MB). Supports human-readable sizes: 4m, 4MB, 4194304. + # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). + # Setting to 0 rejects all non-empty request bodies (not "unlimited"). + # Independent from rpc.maxMessageSize. maxMessageSize = 4M maxNestingDepth = 100 maxTokenCount = 100000 @@ -267,13 +282,15 @@ node { # HTTP/2 flow control window (bytes), default 1MB flowControlWindow = 1048576 - # Connection idle timeout (ms). No limit by default. - maxConnectionIdleInMillis = 9223372036854775807 + # Connection idle timeout (ms). Connections idle longer than this are gracefully terminated. + maxConnectionIdleInMillis = 60000 # Connection max age (ms). No limit by default. maxConnectionAgeInMillis = 9223372036854775807 - # Maximum message size (bytes), default 4MB + # Maximum gRPC message size (default 4MB). Supports human-readable sizes: 4m, 4MB, 4194304. + # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). + # Setting to 0 rejects all non-empty request bodies (not "unlimited"). maxMessageSize = 4194304 # Maximum header list size (bytes), default 8192 @@ -343,21 +360,36 @@ node { validContractProto.threads = 0 dns { + # DNS URLs to discover peers, format: tree://{pubkey}@{domain}. Default: empty. treeUrls = [ # "tree://AKMQMNAJJBL73LXWPXDI4I5ZWWIZ4AWO34DWQ636QOBBXNFXH3LQS@main.trondisco.net", ] + + # Enable or disable DNS publish. Default: false. publish = false + # DNS domain to publish nodes, required if publish is true. dnsDomain = "" + # DNS private key used to publish, required if publish is true, hex string of length 64. dnsPrivate = "" + # Known DNS URLs to publish if publish is true, format: tree://{pubkey}@{domain}. Default: empty. knownUrls = [] + # Static nodes to publish on DNS, "ip:port". staticNodes = [] + # Merge several nodes into a leaf of tree, should be 1~5. maxMergeSize = 0 + # Only update DNS data when node change percent exceeds this threshold. changeThreshold = 0.0 + # DNS server to publish, required if publish is true. Supported values: "aws", "aliyun". serverType = "" + # Access key ID of AWS or Aliyun API, required if publish is true. accessKeyId = "" + # Access key secret of AWS or Aliyun API, required if publish is true. accessKeySecret = "" + # Endpoint of Aliyun DNS server, required if serverType is "aliyun". aliyunDnsEndpoint = "" + # Region of AWS API (e.g. "us-east-1"), required if serverType is "aws". awsRegion = "" + # Host zone ID of AWS domain, required if serverType is "aws". awsHostZoneId = "" } @@ -365,6 +397,8 @@ node { openHistoryQueryWhenLiteFN = false jsonrpc { + # Note: Before release_4.8.1, if you turn on jsonrpc and run it for a while and then turn it off, + # you will not be able to get the data from eth_getLogs for that period of time. Default: false httpFullNodeEnable = false httpFullNodePort = 8545 httpSolidityEnable = false @@ -699,7 +733,16 @@ vm = { # Max retry time for executing transaction in estimating energy estimateEnergyMaxRetry = 3 - # Max TVM execution time (ms) for constant calls. 0 means no effect + # Max TVM execution time (ms) for constant calls — applies to + # triggerconstantcontract, triggersmartcontract dispatched to view/pure + # functions, estimateenergy, eth_call, eth_estimateGas, and any other RPC + # routed through the constant-call path. When set, must be a positive + # integer that fits VM deadline conversion and is used verbatim as the + # per-call deadline (no clamp against the network's maxCpuTimeOfOneTx). + # Omit the property entirely to keep the default behaviour of sharing the + # block-processing deadline. Migration note: if previously running --debug + # to extend constant calls, switch to this option (--debug also extends + # block-processing, which is unsafe; see issue #6266). Default: 0 (no effect). constantCallTimeoutMs = 0 } @@ -758,34 +801,38 @@ event.subscribe = { enable = false native = { - useNativeQueue = false - bindport = 5555 - sendqueuelength = 1000 + useNativeQueue = false // if true, use native message queue, else use event plugin. + bindport = 5555 // bind port + sendqueuelength = 1000 // max length of send queue } version = 0 + # Specify the starting block number to sync historical events. Only applicable when version = 1. + # After performing a full event sync, set this value to 0 or a negative number. startSyncBlockNum = 0 - path = "" - server = "" + path = "" // absolute path of plugin + server = "" // target server address to receive event triggers, "ip:port" + # dbname|username|password. To auto-create indexes on missing collections, append |2: + # dbname|username|password|2 (if collection exists, indexes must be created manually). dbconfig = "" contractParse = true topics = [ { - triggerName = "block" + triggerName = "block" // block trigger, the value can't be modified enable = false - topic = "block" - solidified = false + topic = "block" // plugin topic, the value could be modified + solidified = false // if set true, just need solidified block. Default: false }, { triggerName = "transaction" enable = false topic = "transaction" solidified = false - ethCompatible = false + ethCompatible = false // if set true, add transactionIndex, cumulativeEnergyUsed, preCumulativeLogCount, logList, energyUnitPrice. Default: false }, { - triggerName = "contractevent" + triggerName = "contractevent" // contractevent represents contractlog data decoded by the ABI. enable = false topic = "contractevent" }, @@ -793,11 +840,11 @@ event.subscribe = { triggerName = "contractlog" enable = false topic = "contractlog" - redundancy = false + redundancy = false // if set true, contractevent will also be regarded as contractlog }, { - triggerName = "solidity" - enable = true + triggerName = "solidity" // solidity block trigger (just block number and timestamp), the value can't be modified + enable = true // Default: true topic = "solidity" }, { @@ -809,18 +856,18 @@ event.subscribe = { triggerName = "soliditylog" enable = false topic = "soliditylog" - redundancy = false + redundancy = false // if set true, solidityevent will also be regarded as soliditylog } ] filter = { - fromblock = "" - toblock = "" + fromblock = "" // "", "earliest", or a specific block number as the beginning of the queried range + toblock = "" // "", "latest", or a specific block number as end of the queried range contractAddress = [ - "" + "" // contract address to subscribe; "" means any contract address ] contractTopic = [ - "" + "" // contract topic to subscribe; "" means any contract topic ] } } diff --git a/framework/src/main/resources/config.conf b/framework/src/main/resources/config.conf index 0686890f03..21bddd2037 100644 --- a/framework/src/main/resources/config.conf +++ b/framework/src/main/resources/config.conf @@ -4,7 +4,6 @@ net { } storage { - # Directory for storing persistent data db.engine = "LEVELDB", // deprecated for arm, because arm only support "ROCKSDB". db.sync = false, db.directory = "database", @@ -12,57 +11,17 @@ storage { # Whether to write transaction result in transactionRetStore transHistory.switch = "on", - # setting can improve leveldb performance .... start, deprecated for arm - # node: if this will increase process fds,you may be check your ulimit if 'too many open files' error occurs - # see https://github.com/tronprotocol/tips/blob/master/tip-343.md for detail - # if you find block sync has lower performance, you can try this settings - # default = { - # maxOpenFiles = 100 - # } - # defaultM = { - # maxOpenFiles = 500 - # } - # defaultL = { - # maxOpenFiles = 1000 - # } - # setting can improve leveldb performance .... end, deprecated for arm - - # You can customize the configuration for each database. Otherwise, the database settings will use - # their defaults, and data will be stored in the "output-directory" or in the directory specified - # by the "-d" or "--output-directory" option. Attention: name is a required field that must be set! - # In this configuration, the name and path properties take effect for both LevelDB and RocksDB storage engines, - # while the additional properties (such as createIfMissing, paranoidChecks, compressionType, etc.) only take effect when using LevelDB. + # Per-database storage path overrides (name is required; see reference.conf for full property list). properties = [ # { # name = "account", # path = "storage_directory_test", - # createIfMissing = true, // deprecated for arm start - # paranoidChecks = true, - # verifyChecksums = true, - # compressionType = 1, // compressed with snappy - # blockSize = 4096, // 4 KB = 4 * 1024 B - # writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - # cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - # maxOpenFiles = 100 // deprecated for arm end - # }, - # { - # name = "account-index", - # path = "storage_directory_test", - # createIfMissing = true, - # paranoidChecks = true, - # verifyChecksums = true, - # compressionType = 1, // compressed with snappy - # blockSize = 4096, // 4 KB = 4 * 1024 B - # writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - # cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B - # maxOpenFiles = 100 # }, ] needToUpdateAsset = true - # dbsettings is needed when using rocksdb as the storage implement (db.engine="ROCKSDB"). - # we'd strongly recommend that do not modify it unless you know every item's meaning clearly. + # RocksDB settings (only used when db.engine = "ROCKSDB"). See reference.conf for details. dbSettings = { levelNumber = 7 # compactThreads = 32 @@ -77,24 +36,8 @@ storage { balance.history.lookup = false - # checkpoint.version = 2 - # checkpoint.sync = true - - # the estimated number of block transactions (default 1000, min 100, max 10000). - # so the total number of cached transactions is 65536 * txCache.estimatedTransactions - # txCache.estimatedTransactions = 1000 - - # if true, transaction cache initialization will be faster. Default: false + # If true, transaction cache initialization will be faster. Default: false txCache.initOptimization = true - - # The number of blocks flushed to db in each batch during node syncing. Default: 1 - # snapshot.maxFlushCount = 1 - - # data root setting, for check data, currently, only reward-vi is used. - # merkleRoot = { - # reward-vi = 9debcb9924055500aaae98cdee10501c5c39d4daa75800a996f4bdda73dbccd8 // main-net, Sha256Hash, hexString - # } - } node.discovery = { @@ -102,24 +45,17 @@ node.discovery = { persist = true } -# custom stop condition -#node.shutdown = { -# BlockTime = "54 59 08 * * ?" # if block header time in persistent db matched. -# BlockHeight = 33350800 # if block header height in persistent db matched. -# BlockCount = 12 # block sync count after node start. -#} +# Custom stop condition +# node.shutdown = { +# BlockTime = "54 59 08 * * ?" # if block header time in persistent db matched. +# BlockHeight = 33350800 # if block header height in persistent db matched. +# BlockCount = 12 # block sync count after node start. +# } node.backup { - # udp listen port, each member should have the same configuration port = 10001 - - # my priority, each member should use different priority priority = 8 - - # time interval to send keepAlive message, each member should have the same configuration keepAliveInterval = 3000 - - # peer's ip list, can't contain mine members = [ # "ip", # "ip" @@ -132,17 +68,13 @@ crypto { } node.metrics = { - # prometheus metrics prometheus { enable = false port = 9527 } - } node { - # trust node for solidity node - # trustNode = "ip:port" trustNode = "127.0.0.1:50051" # expose extension api to public or not @@ -151,50 +83,14 @@ node { listen.port = 18888 fetchBlock.timeout = 200 - # syncFetchBatchNum = 2000 - - # Maximum number of blocks allowed in-flight (requested but not yet processed). - # Throttles block download to reduce memory pressure during sync. - # Range: [50, 2000], default: 500 - # maxPendingBlockSize = 500 - - # Maximum total number of cached transactions (handler queues + pending + rePush). - # When exceeded, the node stops accepting TRX INV messages from peers. - # maxTrxCacheSize = 50000 - - # Number of validate sign thread, default availableProcessors - # validateSignThreadNum = 16 maxConnections = 30 - minConnections = 8 - minActiveConnections = 3 - maxConnectionsWithSameIp = 2 - maxHttpConnectNumber = 50 - minParticipationRate = 15 - # WARNING: Some shielded transaction APIs require sending private keys as parameters. - # Calling these APIs on untrusted or remote nodes may leak your private keys. - # It is recommended to invoke them locally for development and testing. - # To opt in, set: allowShieldedTransactionApi = true - # Migration: the legacy key node.fullNodeAllowShieldedTransaction is still supported - # but deprecated; please migrate to node.allowShieldedTransactionApi. - # allowShieldedTransactionApi = false - - # openPrintLog = true - - # If set to true, SR packs transactions into a block in descending order of fee; otherwise, it packs - # them based on their receive timestamp. Default: false - # openTransactionSort = false - - # The threshold for the number of broadcast transactions received from each peer every second, - # transactions exceeding this threshold will be discarded - # maxTps = 1000 - isOpenFullTcpDisconnect = false inactiveThreshold = 600 //seconds @@ -204,14 +100,12 @@ node { active = [ # Active establish connection in any case - # Sample entries: # "ip:port", # "ip:port" ] passive = [ # Passive accept connection in any case - # Sample entries: # "ip:port", # "ip:port" ] @@ -228,12 +122,6 @@ node { solidityPort = 8091 PBFTEnable = true PBFTPort = 8092 - - # The maximum request body size for HTTP API, default 4M (4194304 bytes). - # Supports human-readable sizes: 4m, 4MB, 4194304. - # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). - # Setting to 0 rejects all non-empty request bodies (not "unlimited"). - # maxMessageSize = 4m } rpc { @@ -244,223 +132,51 @@ node { PBFTEnable = true PBFTPort = 50071 - # Number of gRPC thread, default availableProcessors / 2 - # thread = 16 - - # The maximum number of concurrent calls permitted for each incoming connection - # maxConcurrentCallsPerConnection = - - # The HTTP/2 flow control window, default 1MB - # flowControlWindow = - - # Connection being idle for longer than which will be gracefully terminated maxConnectionIdleInMillis = 60000 - - # Connection lasting longer than which will be gracefully terminated - # maxConnectionAgeInMillis = - - # The maximum message size allowed to be received on the server, default 4M (4194304 bytes). - # Supports human-readable sizes: 4m, 4MB, 4194304. - # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). - # Setting to 0 rejects all non-empty request bodies (not "unlimited"). - # maxMessageSize = 4m - - # The maximum size of header list allowed to be received, default 8192 - # maxHeaderListSize = - - # The number of RST_STREAM frames allowed to be sent per connection per period for grpc, by default there is no limit. - # maxRstStream = - - # The number of seconds per period for grpc - # secondsPerWindow = - - # Transactions can only be broadcast if the number of effective connections is reached. minEffectiveConnection = 1 - # The switch of the reflection service, effective for all gRPC services, used for grpcurl tool. Default: false + # The switch of the reflection service for grpcurl tool. Default: false reflectionService = false } - # number of solidity thread in the FullNode. - # If accessing solidity rpc and http interface timeout, could increase the number of threads, - # The default value is the number of cpu cores of the machine. - # solidity.threads = 8 - - # Limits the maximum percentage (default 75%) of producing block interval - # to provide sufficient time to perform other operations e.g. broadcast block - # blockProducedTimeOut = 75 - - # Limits the maximum number (default 700) of transaction from network layer - # netMaxTrxPerSecond = 700 - - # Whether to enable the node detection function. Default: false - # nodeDetectEnable = false - - # use your ipv6 address for node discovery and tcp connection. Default: false - # enableIpv6 = false - - # if your node's highest block num is below than all your pees', try to acquire new connection. Default: false - # effectiveCheckEnable = false - - # Dynamic loading configuration function, disabled by default dynamicConfig = { # enable = false - # checkInterval = 600 // Check interval of Configuration file's change, default is 600 seconds + # checkInterval = 600 } - # Whether to continue broadcast transactions after at least maxUnsolidifiedBlocks are not solidified. Default: false - # unsolidifiedBlockCheck = false - # maxUnsolidifiedBlocks = 54 - dns { - # dns urls to get nodes, url format tree://{pubkey}@{domain}, default empty treeUrls = [ #"tree://AKMQMNAJJBL73LXWPXDI4I5ZWWIZ4AWO34DWQ636QOBBXNFXH3LQS@main.trondisco.net", ] - - # enable or disable dns publish. Default: false - # publish = false - - # dns domain to publish nodes, required if publish is true - # dnsDomain = "nodes1.example.org" - - # dns private key used to publish, required if publish is true, hex string of length 64 - # dnsPrivate = "b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291" - - # known dns urls to publish if publish is true, url format tree://{pubkey}@{domain}, default empty - # knownUrls = [ - #"tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes2.example.org", - # ] - - # staticNodes = [ - # static nodes to published on dns - # Sample entries: - # "ip:port", - # "ip:port" - # ] - - # merge several nodes into a leaf of tree, should be 1~5 - # maxMergeSize = 5 - - # only nodes change percent is bigger then the threshold, we update data on dns - # changeThreshold = 0.1 - - # dns server to publish, required if publish is true, only aws or aliyun is support - # serverType = "aws" - - # access key id of aws or aliyun api, required if publish is true, string - # accessKeyId = "your-key-id" - - # access key secret of aws or aliyun api, required if publish is true, string - # accessKeySecret = "your-key-secret" - - # if publish is true and serverType is aliyun, it's endpoint of aws dns server, string - # aliyunDnsEndpoint = "alidns.aliyuncs.com" - - # if publish is true and serverType is aws, it's region of aws api, such as "eu-south-1", string - # awsRegion = "us-east-1" - - # if publish is true and server-type is aws, it's host zone id of aws's domain, string - # awsHostZoneId = "your-host-zone-id" } - # open the history query APIs(http&GRPC) when node is a lite FullNode, - # like {getBlockByNum, getBlockByID, getTransactionByID...}. Default: false. - # note: above APIs may return null even if blocks and transactions actually are on the blockchain - # when opening on a lite FullNode. only open it if the consequences being clearly known - # openHistoryQueryWhenLiteFN = false - jsonrpc { - # The maximum request body size for JSON-RPC API, default 4M (4194304 bytes). - # Supports human-readable sizes: 4m, 4MB, 4194304. - # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). - # Setting to 0 rejects all non-empty request bodies (not "unlimited"). - # maxMessageSize = 4m - - # Note: Before release_4.8.1, if you turn on jsonrpc and run it for a while and then turn it off, - # you will not be able to get the data from eth_getLogs for that period of time. Default: false - # httpFullNodeEnable = false - # httpFullNodePort = 8545 - # httpSolidityEnable = false - # httpSolidityPort = 8555 - # httpPBFTEnable = false - # httpPBFTPort = 8565 - - # The maximum blocks range to retrieve logs for eth_getLogs, default: 5000, <=0 means no limit + httpFullNodeEnable = false + httpFullNodePort = 8545 + maxBlockRange = 5000 - # Allowed max address count in filter request, default: 1000, <=0 means no limit maxAddressSize = 1000 - # The maximum number of allowed topics within a topic criteria, default: 1000, <=0 means no limit maxSubTopics = 1000 - # Allowed maximum number for blockFilter, default: 50000, <=0 means no limit maxBlockFilterNum = 50000 - # Allowed batch size, default: 100, <=0 means no limit maxBatchSize = 100 - # Allowed max response byte size, default: 26214400 (25 MB), <=0 means no limit maxResponseSize = 26214400 - # Allowed maximum number for newFilter, <=0 means no limit maxLogFilterNum = 20000 - # Maximum JSON-RPC request body size, default 4MB. Independent from rpc.maxMessageSize. maxMessageSize = 4M } - # Disabled api list, it will work for http, rpc and pbft, both FullNode and SolidityNode, - # but not jsonrpc. The setting is case insensitive, GetNowBlock2 is equal to getnowblock2 disabledApi = [ # "getaccount", # "getnowblock2" ] - } ## rate limiter config rate.limiter = { - # Every api could only set a specific rate limit strategy. Three strategy are supported: - # GlobalPreemptibleAdapter: The number of preemptible resource or maximum concurrent requests globally. - # QpsRateLimiterAdapter: qps is the average request count in one second supported by the server, it could be a Double or a Integer. - # IPQPSRateLimiterAdapter: similar to the QpsRateLimiterAdapter, qps could be a Double or a Integer. - # If not set, QpsRateLimiterAdapter with qps=1000 is the default strategy. - # - # Sample entries: - # + # See reference.conf for available strategies (GlobalPreemptibleAdapter, QpsRateLimiterAdapter, IPQPSRateLimiterAdapter). http = [ - # { - # component = "GetNowBlockServlet", - # strategy = "GlobalPreemptibleAdapter", - # paramString = "permit=1" - # }, - - # { - # component = "GetAccountServlet", - # strategy = "IPQPSRateLimiterAdapter", - # paramString = "qps=1" - # }, - - # { - # component = "ListWitnessesServlet", - # strategy = "QpsRateLimiterAdapter", - # paramString = "qps=1" - # } ], rpc = [ - # { - # component = "protocol.Wallet/GetBlockByLatestNum2", - # strategy = "GlobalPreemptibleAdapter", - # paramString = "permit=1" - # }, - - # { - # component = "protocol.Wallet/GetAccount", - # strategy = "IPQPSRateLimiterAdapter", - # paramString = "qps=1" - # }, - - # { - # component = "protocol.Wallet/ListWitnesses", - # strategy = "QpsRateLimiterAdapter", - # paramString = "qps=1" - # }, ] p2p = { @@ -473,8 +189,7 @@ rate.limiter = { global.qps = 50000 # IP-based global qps, default 10000 global.ip.qps = 10000 - # If true, API rate limiters reject immediately on overload (non-blocking). - # If false (default), callers wait for a permit (blocking, the legacy behaviour). + # If true, API rate limiters reject immediately on overload (non-blocking). Default: false apiNonBlocking = false } @@ -483,11 +198,6 @@ rate.limiter = { seed.node = { # List of the seed nodes # Seed nodes are stable full nodes - # example: - # ip.list = [ - # "ip:port", - # "ip:port" - # ] ip.list = [ "3.225.171.164:18888", "52.8.46.215:18888", @@ -690,10 +400,10 @@ genesis.block = { parentHash = "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f" } -# Optional. The default is empty. It is used when the witness account has set the witnessPermission. -# When it is not empty, the localWitnessAccountAddress represents the address of the witness account, -# and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account. -# When it is empty,the localwitness is configured with the private key of the witness account. +# Optional. Used when the witness account has set witnessPermission. +# localWitnessAccountAddress is the witness account address; +# localwitness is configured with the private key of the witnessPermissionAddress. +# When empty, localwitness is the private key of the witness account itself. # localWitnessAccountAddress = localwitness = [ @@ -707,100 +417,24 @@ block = { needSyncCheck = true maintenanceTimeInterval = 21600000 // 6 hours: 21600000(ms) proposalExpireTime = 259200000 // default value: 3 days: 259200000(ms), Note: this value is controlled by committee proposal - # checkFrozenTime = 1 // for test only } # Transaction reference block, default is "solid", configure to "head" may cause TaPos error trx.reference.block = "solid" // "head" or "solid" -# This property sets the number of milliseconds after the creation of the transaction that is expired, default value is 60000. -# trx.expiration.timeInMilliseconds = 60000 - vm = { supportConstant = false maxEnergyLimitForConstant = 100000000 minTimeRatio = 0.0 maxTimeRatio = 5.0 saveInternalTx = false - # lruCacheSize = 500 - # vmTrace = false - - # Indicates whether the node stores featured internal transactions, such as freeze, vote and so on. Default: false. - # saveFeaturedInternalTx = false - - # Indicates whether the node stores the details of the internal transactions generated by the CANCELALLUNFREEZEV2 opcode, - # such as bandwidth/energy/tronpower cancel amount. Default: false. - # saveCancelAllUnfreezeV2Details = false - - # In rare cases, transactions that will be within the specified maximum execution time (default 10(ms)) are re-executed and packaged - # longRunningTime = 10 - - # Indicates whether the node support estimate energy API. Default: false. - # estimateEnergy = false - - # Indicates the max retry time for executing transaction in estimating energy. Default 3. - # estimateEnergyMaxRetry = 3 - - # Max TVM execution time (ms) for constant calls — applies to - # triggerconstantcontract, triggersmartcontract dispatched to view/pure - # functions, estimateenergy, eth_call, eth_estimateGas, and any other RPC - # routed through the constant-call path. When set, must be a positive - # integer that fits VM deadline conversion and is used verbatim as the - # per-call deadline (no clamp against the network's maxCpuTimeOfOneTx). - # Omit the property entirely to keep the default behaviour of sharing the - # block-processing deadline. Migration note: if previously running --debug - # to extend constant calls, switch to this option (--debug also extends - # block-processing, which is unsafe; see issue #6266). Default: 0. - # constantCallTimeoutMs = 100 } # These parameters are designed for private chain testing only and cannot be freely switched on or off in production systems. +# In production, they are controlled by on-chain committee proposals. committee = { allowCreationOfContracts = 0 //mainnet:0 (reset by committee),test:1 allowAdaptiveEnergy = 0 //mainnet:0 (reset by committee),test:1 - # allowCreationOfContracts = 0 - # allowMultiSign = 0 - # allowAdaptiveEnergy = 0 - # allowDelegateResource = 0 - # allowSameTokenName = 0 - # allowTvmTransferTrc10 = 0 - # allowTvmConstantinople = 0 - # allowTvmSolidity059 = 0 - # forbidTransferToContract = 0 - # allowShieldedTRC20Transaction = 0 - # allowTvmIstanbul = 0 - # allowMarketTransaction = 0 - # allowProtoFilterNum = 0 - # allowAccountStateRoot = 0 - # changedDelegation = 0 - # allowPBFT = 0 - # pBFTExpireNum = 0 - # allowTransactionFeePool = 0 - # allowBlackHoleOptimization = 0 - # allowNewResourceModel = 0 - # allowReceiptsMerkleRoot = 0 - # allowTvmFreeze = 0 - # allowTvmVote = 0 - # unfreezeDelayDays = 0 - # allowTvmLondon = 0 - # allowTvmCompatibleEvm = 0 - # allowNewRewardAlgorithm = 0 - # allowAccountAssetOptimization = 0 - # allowAssetOptimization = 0 - # allowNewReward = 0 - # memoFee = 0 - # allowDelegateOptimization = 0 - # allowDynamicEnergy = 0 - # dynamicEnergyThreshold = 0 - # dynamicEnergyMaxFactor = 0 - # allowTvmShangHai = 0 - # allowOldRewardOpt = 0 - # allowEnergyAdjustment = 0 - # allowStrictMath = 0 - # allowTvmCancun = 0 - # allowTvmBlob = 0 - # consensusLogicOptimization = 0 - # allowOptimizedReturnValueOfChainId = 0 } event.subscribe = { @@ -811,17 +445,13 @@ event.subscribe = { sendqueuelength = 1000 //max length of send queue } version = 0 - # Specify the starting block number to sync historical events. This is only applicable when version = 1. + # Specify the starting block number to sync historical events. Only applicable when version = 1. # After performing a full event sync, set this value to 0 or a negative number. # startSyncBlockNum = 1 path = "" // absolute path of plugin - server = "" // target server address to receive event triggers - # dbname|username|password, if you want to create indexes for collections when the collections - # are not exist, you can add version and set it to 2, as dbname|username|password|version - # if you use version 2 and one collection not exists, it will create index automaticaly; - # if you use version 2 and one collection exists, it will not create index, you must create index manually; - dbconfig = "" + server = "" // target server address to receive event triggers, "ip:port" + dbconfig = "" // dbname|username|password (append |2 to auto-create indexes on missing collections) contractParse = true topics = [ { From 31948e7d02bc969fe0302829dd9bc0df6beb717d Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 16:40:03 +0800 Subject: [PATCH 02/16] change default value of dns.maxMergeSize and changeThreshold --- .../main/java/org/tron/core/config/args/NodeConfig.java | 7 +++++-- common/src/main/resources/reference.conf | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 82619726b7..d20328c0b3 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -269,6 +269,9 @@ public static class DynamicConfigSection { private long checkInterval = 600; } + /** + * All default parameters come from PublishConfig + */ @Getter @Setter public static class DnsConfig { @@ -279,8 +282,8 @@ public static class DnsConfig { private String dnsPrivate = ""; private List knownUrls = new ArrayList<>(); private List staticNodes = new ArrayList<>(); - private int maxMergeSize = 0; - private double changeThreshold = 0.0; + private int maxMergeSize = 5; + private double changeThreshold = 0.1; private String serverType = ""; private String accessKeyId = ""; private String accessKeySecret = ""; diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 29de4e7bca..5639ee87cd 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -376,9 +376,9 @@ node { # Static nodes to publish on DNS, "ip:port". staticNodes = [] # Merge several nodes into a leaf of tree, should be 1~5. - maxMergeSize = 0 + maxMergeSize = 5 # Only update DNS data when node change percent exceeds this threshold. - changeThreshold = 0.0 + changeThreshold = 0.1 # DNS server to publish, required if publish is true. Supported values: "aws", "aliyun". serverType = "" # Access key ID of AWS or Aliyun API, required if publish is true. From 20494bc0a5b006bc8b44884b4937f85dc73be7a8 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 16:58:33 +0800 Subject: [PATCH 03/16] add comment --- common/src/main/resources/reference.conf | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 5639ee87cd..27241fc4e1 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -150,7 +150,7 @@ node.backup { priority = 0 # Node priority; each member should use a different priority keepAliveInterval = 3000 # Keep-alive interval (ms); each member should have the same configuration members = [ - # "ip", # Peer IP list; must not contain this node's own IP + # "ip", # Peer IP list, better to add at most one IP; must not contain this node's own IP ] } @@ -195,6 +195,11 @@ node { maxHttpConnectNumber = 50 minParticipationRate = 0 + # Deprecate, don't use + activeConnectFactor = 0.1 + # Deprecate, don't use + connectFactor = 0.6 + # WARNING: Some shielded transaction APIs require sending private keys as parameters. # Calling these APIs on untrusted or remote nodes may leak your private keys. # It is recommended to invoke them locally for development and testing. @@ -219,8 +224,7 @@ node { isOpenFullTcpDisconnect = false inactiveThreshold = 600 // seconds maxFastForwardNum = 4 - activeConnectFactor = 0.1 - connectFactor = 0.6 + # Legacy alias `maxActiveNodesWithSameIp` is still accepted from user config # (see NodeConfig alias-fallback) but is intentionally NOT defaulted here — # shipping it in reference.conf would always mask the modern `maxConnectionsWithSameIp`. From 609353efa81c573321dfb02ee8b255b9a9b16cce Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 17:14:29 +0800 Subject: [PATCH 04/16] change default value to 0 of maxConcurrentCallsPerConnection, maxConnectionIdleInMillis, maxConnectionAgeInMillis --- .../org/tron/core/config/args/NodeConfig.java | 16 +++++++++++++--- common/src/main/resources/reference.conf | 12 ++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index d20328c0b3..7c256147f3 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -217,10 +217,10 @@ public static class RpcConfig { private int pBFTPort = 50071; private int thread = 0; - private int maxConcurrentCallsPerConnection = 2147483647; + private int maxConcurrentCallsPerConnection = 0; private int flowControlWindow = 1048576; - private long maxConnectionIdleInMillis = Long.MAX_VALUE; - private long maxConnectionAgeInMillis = Long.MAX_VALUE; + private long maxConnectionIdleInMillis = 0; + private long maxConnectionAgeInMillis = 0; private int maxMessageSize = 4194304; private int maxHeaderListSize = 8192; private int maxRstStream = 0; @@ -356,6 +356,16 @@ private void postProcess() { rpc.thread = (Runtime.getRuntime().availableProcessors() + 1) / 2; } + if (rpc.maxConcurrentCallsPerConnection == 0) { + rpc.maxConcurrentCallsPerConnection = Integer.MAX_VALUE; + } + if (rpc.maxConnectionIdleInMillis == 0) { + rpc.maxConnectionIdleInMillis = Long.MAX_VALUE; + } + if (rpc.maxConnectionAgeInMillis == 0) { + rpc.maxConnectionAgeInMillis = Long.MAX_VALUE; + } + // validateSignThreadNum: 0 = auto-detect if (validateSignThreadNum == 0) { validateSignThreadNum = Runtime.getRuntime().availableProcessors(); diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 27241fc4e1..1619b817a4 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -280,17 +280,17 @@ node { thread = 0 # Maximum concurrent calls per incoming connection - # No limit on concurrent calls per connection - maxConcurrentCallsPerConnection = 2147483647 + # 0 means No limit on concurrent calls per connection + maxConcurrentCallsPerConnection = 0 # HTTP/2 flow control window (bytes), default 1MB flowControlWindow = 1048576 - # Connection idle timeout (ms). Connections idle longer than this are gracefully terminated. - maxConnectionIdleInMillis = 60000 + # Connection idle timeout (ms). Connections idle longer than this are gracefully terminated. 0 = no limit + maxConnectionIdleInMillis = 0 - # Connection max age (ms). No limit by default. - maxConnectionAgeInMillis = 9223372036854775807 + # Connection max age (ms). 0 = no limit + maxConnectionAgeInMillis = 0 # Maximum gRPC message size (default 4MB). Supports human-readable sizes: 4m, 4MB, 4194304. # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). From f7da4eb30e487be075adf470a2c410886fed25d3 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 17:23:40 +0800 Subject: [PATCH 05/16] add configuration.md to tell use how to use config.conf --- docs/configuration.md | 255 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) create mode 100644 docs/configuration.md diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 0000000000..43ab867600 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,255 @@ +# Node Configuration Guide + +This guide explains the two-layer configuration system used by java-tron and walks through the most common customizations a node operator needs. + +## How the Two Config Files Work Together + +java-tron uses [Typesafe Config](https://github.com/lightbend/config) and applies two layers of configuration at startup: + +| File | Location | Purpose | +|------|----------|---------| +| `reference.conf` | Bundled inside the jar (`common` module) | Declares every parameter with its default value | +| `config.conf` | External, supplied by the operator via `-c` | Overrides only the values that differ from defaults | + +**Loading priority:** values in `config.conf` always win. Any parameter that your `config.conf` omits is automatically filled in from `reference.conf`. You never need to copy the entire `reference.conf` into your own file — only include the parameters you actually want to change. + +``` +startup resolution order (highest wins): + 1. config.conf (your file, passed with -c) + 2. reference.conf (bundled in jar, fallback for everything) +``` + +`reference.conf` is the authoritative source of truth for every parameter name and its default. When in doubt, consult that file to see what a parameter does and what value the node will use if you leave it out. + +## Starting a Node with a Config File + +```bash +# Using the distribution script +java-tron-1.0.0/bin/FullNode -c /path/to/config.conf + +# Using the jar directly +java -jar FullNode.jar -c /path/to/config.conf + +# SR (Super Representative) mode +java-tron-1.0.0/bin/FullNode -c /path/to/config.conf -w +``` + +If `-c` is omitted, the node uses only the defaults from `reference.conf`. For anything beyond a quick local test, always provide an explicit config file. + +## Minimal config.conf + +A `config.conf` only needs to contain what you want to change. The following is sufficient for a mainnet full node: + +```hocon +node.discovery = { + enable = true + persist = true +} + +node { + listen.port = 18888 + minParticipationRate = 15 + p2p.version = 11111 # mainnet +} + +seed.node.ip.list = [ + "3.225.171.164:18888", + "52.8.46.215:18888", + # ... (see reference.conf for the full seed list) +] +``` + +## Common Configuration Sections + +### Network and P2P (`node`, `node.discovery`, `seed.node`) + +```hocon +node.discovery = { + enable = true # join the peer-discovery network + persist = true # save discovered peers across restarts +} + +node { + listen.port = 18888 # TCP port for peer connections + maxConnections = 30 # maximum peer connections + minConnections = 8 # minimum peer connections to maintain + minParticipationRate = 15 # minimum % of active witnesses before producing blocks + + p2p { + version = 11111 # Mainnet:11111 Nile:201910292 Shasta:1 + } +} + +seed.node.ip.list = [ + "3.225.171.164:18888", + # add more entries as needed +] +``` + +### HTTP and gRPC APIs (`node.http`, `node.rpc`) + +```hocon +node { + http { + fullNodeEnable = true + fullNodePort = 8090 + solidityEnable = true + solidityPort = 8091 + } + + rpc { + enable = true + port = 50051 + solidityEnable = true + solidityPort = 50061 + # Maximum concurrent calls per connection. 0 = no limit. + maxConcurrentCallsPerConnection = 0 + # Idle connection timeout (ms). 0 = no limit. + maxConnectionIdleInMillis = 0 + # Minimum active connections required before broadcasting transactions. + minEffectiveConnection = 1 + } +} +``` + +To disable an API endpoint that you do not want to expose publicly, set its `Enable` flag to `false` or add endpoints to `node.disabledApi`: + +```hocon +node.disabledApi = [ + "getaccount", + "getnowblock2" +] +``` + +### Storage Engine (`storage`) + +```hocon +storage { + db.engine = "LEVELDB" # "LEVELDB" or "ROCKSDB"; ARM64 requires "ROCKSDB" + db.sync = false # set true for maximum durability (slower writes) + db.directory = "database" +} +``` + +To override the storage path for individual databases: + +```hocon +storage.properties = [ + { + name = "account", + path = "/data/tron/account-db" + } +] +``` + +### Block Production (Super Representatives) + +```hocon +# Plain private key (use localwitnesskeystore for production) +localwitness = [ + "your-private-key-hex" +] + +# Recommended: keystore file +# localwitnesskeystore = [ +# "/path/to/localwitnesskeystore.json" +# ] + +# Required when the witness account has delegated block-signing to a separate key +# localWitnessAccountAddress = "T..." +``` + +### JSON-RPC (Ethereum-compatible, `node.jsonrpc`) + +```hocon +node.jsonrpc { + httpFullNodeEnable = true + httpFullNodePort = 8545 + maxBlockRange = 5000 # max block range for eth_getLogs + maxResponseSize = 26214400 # 25 MB +} +``` + +### Event Subscription (`event.subscribe`) + +```hocon +event.subscribe = { + enable = true + native { + useNativeQueue = true + bindport = 5555 + sendqueuelength = 1000 + } + topics = [ + { triggerName = "block", enable = true, topic = "block" }, + { triggerName = "transaction", enable = true, topic = "transaction" }, + { triggerName = "solidity", enable = true, topic = "solidity" } + ] +} +``` + +### Rate Limiting (`rate.limiter`) + +```hocon +rate.limiter = { + # Available strategies: + # GlobalPreemptibleAdapter — semaphore-based, paramString = "permit=N" + # QpsRateLimiterAdapter — node-wide QPS cap, paramString = "qps=N" + # IPQPSRateLimiterAdapter — per-IP QPS cap, paramString = "qps=N" + + http = [ + { + component = "GetAccountServlet", + strategy = "IPQPSRateLimiterAdapter", + paramString = "qps=10" + } + ] + + global.qps = 50000 + global.ip.qps = 10000 +} +``` + +### Dynamic Config Reload (`node.dynamicConfig`) + +When enabled, the node re-reads `config.conf` periodically without restarting: + +```hocon +node.dynamicConfig = { + enable = true + checkInterval = 600 # seconds between checks +} +``` + +Not all parameters support hot-reload. Parameters that affect node identity, genesis block, or database layout require a full restart. + +## Parameters You Should Not Change + +| Parameter | Reason | +|-----------|--------| +| `crypto.engine` | Changing the key-derivation algorithm will fork the node | +| `genesis.block.*` | Must be identical on every node in the network | +| `committee.*` | Controlled by on-chain governance proposals; manual overrides are for private chains only | +| `node.p2p.version` | Must match the network (11111 for mainnet) | +| `enery.limit.block.num` | Intentional typo preserved for backward compatibility; do not rename | + +## Applying a Config Change + +1. Edit your `config.conf` — only add or change the keys you need. +2. If `node.dynamicConfig.enable = true`, wait up to `checkInterval` seconds; the node picks up the change automatically. +3. Otherwise, restart the node: `kill ` then relaunch with the same `-c` flag. +4. Check startup logs for a `[config]` line confirming the file was loaded and watch for any `ERROR` lines about unknown or invalid keys. + +## Viewing Effective Configuration + +At startup, the node logs the resolved configuration (merged result of `config.conf` + `reference.conf`) when `node.openPrintLog = true` (the default). Look for lines prefixed with the section name in the startup output to confirm your overrides took effect. + +## Full Reference + +Every parameter with its default value and an inline comment is documented in: + +``` +common/src/main/resources/reference.conf +``` + +When you need the authoritative default for a parameter or want to understand what a key does, consult that file directly. \ No newline at end of file From 90e15a69758ed73ca9250cc1adbce070c9b0a7c9 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 20 May 2026 17:36:27 +0800 Subject: [PATCH 06/16] add document of how to add config item --- docs/configuration-conventions.md | 195 ++++++++++++++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 docs/configuration-conventions.md diff --git a/docs/configuration-conventions.md b/docs/configuration-conventions.md new file mode 100644 index 0000000000..c03a7f2e72 --- /dev/null +++ b/docs/configuration-conventions.md @@ -0,0 +1,195 @@ +# HOCON Configuration Conventions for Developers + +This document covers the rules and patterns that developers must follow when adding or modifying configuration parameters in java-tron. Violations cause silent misreads, startup failures, or hard-to-diagnose defaults being applied instead of user-supplied values. + +## How Config Keys Bind to Java Fields + +java-tron uses [Typesafe Config](https://github.com/lightbend/config)'s `ConfigBeanFactory` to map a HOCON section to a Java bean automatically. The mapping algorithm is: + +1. For each field `fooBar` in the bean, `ConfigBeanFactory` looks for a HOCON key named `fooBar`. +2. The bean class must expose a public setter (`setFooBar`) — in practice this is provided by Lombok `@Setter`. +3. If the key is absent from the config, the field keeps its Java default value (the one assigned in the field declaration). +4. If the key is present but the type does not match, binding fails with a `ConfigException` at startup. + +The binding entry point for each top-level section looks like: + +```java +// "node" section → NodeConfig bean +Config section = config.getConfig("node"); +NodeConfig nc = ConfigBeanFactory.create(section, NodeConfig.class); +``` + +## Key Naming: Use camelCase + +**All keys in `reference.conf` and `config.conf` must use standard camelCase.** + +`ConfigBeanFactory` derives the expected key name from the Java setter via the JavaBean Introspector: `setFooBar` → property name `fooBar` → expected HOCON key `fooBar`. If the key in the config file uses a different casing, the binding silently skips it and the field keeps its Java default. + +```hocon +# Correct +node { + maxConnections = 30 + syncFetchBatchNum = 2000 +} + +# Wrong — ConfigBeanFactory cannot find these +node { + MaxConnections = 30 # PascalCase → ignored + sync_fetch_batch_num = 2000 # snake_case → ignored + max-connections = 30 # kebab-case → ignored +} +``` + +### The PBFT Exception + +Two legacy keys under `committee` (`allowPBFT`, `pBFTExpireNum`) and the HTTP/RPC fields (`PBFTEnable`, `PBFTPort`) were introduced with non-standard casing before this rule was established. They are retained as-is in the config files for backward compatibility. **Do not model new keys after them.** + +For `allowPBFT` and `pBFTExpireNum`, `CommitteeConfig.normalizeNonStandardKeys()` renames them to proper camelCase (`allowPbft`, `pbftExpireNum`) before handing the section to `ConfigBeanFactory`. If you ever need to accept a non-standard key from users while binding to a standard field, follow this same pattern. + +### The `is` Prefix Exception + +A HOCON key named `isOpenFullTcpDisconnect` produces the setter `setIsOpenFullTcpDisconnect`, but the JavaBean Introspector derives the property name as `openFullTcpDisconnect` (stripping `is`), so `ConfigBeanFactory` looks for key `openFullTcpDisconnect`. `NodeConfig.normalizeNonStandardKeys()` renames the key at read time for backward compatibility. **Do not add new keys with an `is` prefix.** + +## Nesting Depth + +Keep nesting to **at most 3 levels** from the top-level section. Deeper nesting creates long key paths that are hard to override in `config.conf` and require more boilerplate inner bean classes. + +``` +level 1: node { ... } +level 2: node { rpc { ... } } +level 3: node { rpc { flowControl { ... } } } ← maximum +level 4+: node { rpc { flowControl { window { ... } } } } ← avoid +``` + +Each level of nesting requires a corresponding inner static bean class. If you find yourself going 4 levels deep, consider flattening by moving the leaf keys up one level or using a longer camelCase key at level 2. + +## Adding a New Parameter: Checklist + +When adding a configuration parameter, all four steps are required in the same commit. + +### Step 1 — Add the key to `reference.conf` with its default value + +`reference.conf` (in `common/src/main/resources/`) must contain every key the code reads. This is the single source of truth for defaults. Add a brief inline comment explaining the key's purpose and valid range. + +```hocon +node { + # Maximum number of transaction verifier threads. 0 = auto (availableProcessors). + myNewOption = 0 +} +``` + +### Step 2 — Add the field to the corresponding bean class + +Add a field whose name **exactly matches** the HOCON key, with the same default value as `reference.conf`. If the field is in a sub-bean, ensure the sub-bean is mapped correctly. + +```java +// NodeConfig.java +private int myNewOption = 0; // 0 = auto +``` + +Lombok `@Getter` and `@Setter` on the class provide the accessor methods that `ConfigBeanFactory` needs. Do not write them by hand. + +### Step 3 — Add clamping / validation in `postProcess()` if needed + +Every bean's `postProcess()` (called from `fromConfig()` after binding) is where out-of-range values are clamped and cross-field invariants are enforced. Do not add defensive checks scattered through the rest of the codebase. + +```java +// in NodeConfig.postProcess() +if (myNewOption == 0) { + myNewOption = Runtime.getRuntime().availableProcessors(); +} +if (myNewOption > 64) { + myNewOption = 64; +} +``` + +### Step 4 — Add the key to `config.conf` only if the default is intentionally different + +`config.conf` (in `framework/src/main/resources/`) is the sample user config shipped with the distribution. Only add your new key there if the value users should start with differs from the `reference.conf` default, or if the key needs a visible comment for users. + +## Field Types and HOCON Value Types + +| Java field type | HOCON value | Notes | +|-------------------|-------------|-------| +| `boolean` | `true` / `false` | | +| `int` / `long` | numeric | Use `getMemorySize` path if human-readable sizes should be supported (see below) | +| `double` | numeric | | +| `String` | `"value"` | Null HOCON values must be normalized to `""` before binding (see `normalizeNonStandardKeys`) | +| `List` | `["a", "b"]` | Must be read manually; `ConfigBeanFactory` does not handle `List` | +| Inner bean | `{ key = val }` | The Java field type must be the inner static class | + +### Human-Readable Size Values (`4m`, `128MB`) + +For byte-size parameters, users can write `4m` or `128MB` in HOCON. `ConfigBeanFactory` cannot parse these into `int`/`long` directly. Pre-normalize them before calling `ConfigBeanFactory`: + +```java +// normalize before binding +long bytes = config.getMemorySize("node.rpc.maxMessageSize").toBytes(); +if (bytes < 0 || bytes > Integer.MAX_VALUE) { + throw new TronError("node.rpc.maxMessageSize must be non-negative and <= " + + Integer.MAX_VALUE + ", got: " + bytes, PARAMETER_INIT); +} +config = config.withValue("node.rpc.maxMessageSize", ConfigValueFactory.fromAnyRef(bytes)); +``` + +This pattern is already centralized in `NodeConfig.normalizeMaxMessageSizes()`. Add new size keys to the paths array there rather than duplicating the logic. + +### List Fields + +`ConfigBeanFactory` handles `List` but not `List`. Read string-list fields manually after `ConfigBeanFactory.create()`: + +```java +NodeConfig nc = ConfigBeanFactory.create(section, NodeConfig.class); +nc.active = section.getStringList("active"); +``` + +## Backward Compatibility and Legacy Keys + +When renaming a key, keep reading the old key as a fallback for at least one major release: + +```java +// fromConfig() — after ConfigBeanFactory binding +if (section.hasPath("oldKeyName")) { + nc.newFieldName = section.getInt("oldKeyName"); + logger.warn("Config key [section.oldKeyName] is deprecated; use [section.newKeyName]."); +} +``` + +Never remove the old key from this fallback read without a deprecation period and a release note. + +## Optional Keys (Not in `reference.conf`) + +Most keys should be in `reference.conf`. Use optional keys (absent from `reference.conf`, only read if present) sparingly — only for parameters where the presence/absence itself carries meaning. Read them with `hasPath()` guards and annotate the Java field with `@Setter(lombok.AccessLevel.NONE)` to prevent `ConfigBeanFactory` from requiring the key: + +```java +@Setter(lombok.AccessLevel.NONE) +private String shutdownBlockTime = ""; // "" = not set + +// in fromConfig(), after ConfigBeanFactory.create(): +nc.shutdownBlockTime = section.hasPath("shutdown.BlockTime") + ? section.getString("shutdown.BlockTime") : ""; +``` + +## Key Naming Conventions Summary + +| Rule | Good | Bad | +|------|------|-----| +| Standard camelCase | `maxConnections` | `MaxConnections`, `max_connections`, `max-connections` | +| No `is` prefix | `openFullTcpDisconnect` | `isOpenFullTcpDisconnect` | +| No all-caps acronym prefix | `pbftExpireNum`, `pBFTPort`* | `PBFTExpireNum` | +| Nesting ≤ 3 levels | `node.rpc.maxMessageSize` | `node.rpc.limits.size.max` | +| Java field name matches HOCON key exactly | field `maxConnections` ↔ key `maxConnections` | field `maxConns` ↔ key `maxConnections` | + +\* `PBFTEnable` / `PBFTPort` are legacy exceptions; do not model new keys after them. + +## Where to Find Existing Patterns + +| Pattern | Reference location | +|---------|-------------------| +| Standard flat scalar binding | `VmConfig.java`, `BlockConfig.java` | +| Sub-bean nesting | `NodeConfig.HttpConfig`, `NodeConfig.RpcConfig` | +| Legacy key fallback | `NodeConfig.fromConfig()` (`maxActiveNodes`, `maxActiveNodesWithSameIp`) | +| Non-standard key normalization | `CommitteeConfig.normalizeNonStandardKeys()`, `NodeConfig.normalizeNonStandardKeys()` | +| Human-readable size normalization | `NodeConfig.normalizeMaxMessageSizes()` | +| Optional PascalCase keys | `NodeConfig.fromConfig()` (`shutdown.BlockTime/Height/Count`) | +| `postProcess()` clamping | `NodeConfig.postProcess()`, `CommitteeConfig.postProcess()` | From 33a0f878ccfb8b07b9f532bfec243795e96bc373 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 21 May 2026 00:20:21 +0800 Subject: [PATCH 07/16] simply fetchBlockTimeout and openHistoryQueryWhenLiteFN --- .../java/org/tron/core/config/args/NodeConfig.java | 8 ++++++++ .../src/main/java/org/tron/core/config/args/Args.java | 11 ++--------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 7c256147f3..1915d9ce69 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -389,6 +389,14 @@ private void postProcess() { syncFetchBatchNum = 100; } + // fetchBlock.timeout : clamp to [100, 1000] + if (fetchBlock.timeout > 1000) { + fetchBlock.timeout = 1000; + } + if (fetchBlock.timeout < 100) { + fetchBlock.timeout = 100; + } + // maxPendingBlockSize: clamp to [50, 2000] if (maxPendingBlockSize > 2000) { maxPendingBlockSize = 2000; 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 8d8e2500c9..3dfc922af9 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 @@ -583,14 +583,7 @@ private static void applyNodeConfig(NodeConfig nc) { // ---- Flat scalar fields ---- PARAMETER.nodeEffectiveCheckEnable = nc.isEffectiveCheckEnable(); - // fetchBlock.timeout — range check [100, 1000], default 500 - int fetchTimeout = nc.getFetchBlockTimeout(); - if (fetchTimeout > 1000) { - fetchTimeout = 1000; - } else if (fetchTimeout < 100) { - fetchTimeout = 100; - } - PARAMETER.fetchBlockTimeout = fetchTimeout; + PARAMETER.fetchBlockTimeout = nc.getFetchBlockTimeout(); PARAMETER.maxConnections = nc.getMaxConnections(); PARAMETER.minConnections = nc.getMinConnections(); @@ -630,7 +623,7 @@ private static void applyNodeConfig(NodeConfig nc) { PARAMETER.shieldedTransInPendingMaxCounts = nc.getShieldedTransInPendingMaxCounts(); PARAMETER.agreeNodeCount = nc.getAgreeNodeCount(); - PARAMETER.setOpenHistoryQueryWhenLiteFN(nc.isOpenHistoryQueryWhenLiteFN()); + PARAMETER.openHistoryQueryWhenLiteFN = nc.isOpenHistoryQueryWhenLiteFN(); PARAMETER.nodeMetricsEnable = nc.isMetricsEnable(); PARAMETER.openPrintLog = nc.isOpenPrintLog(); PARAMETER.openTransactionSort = nc.isOpenTransactionSort(); From 67c223ede8b8f60e4d078fac22f86735181f8b4f Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 21 May 2026 00:38:40 +0800 Subject: [PATCH 08/16] add some warning message for deprecated item in NodeConfig --- .../java/org/tron/core/config/args/NodeConfig.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 1915d9ce69..4640058bb7 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -309,20 +309,28 @@ public static NodeConfig fromConfig(Config config) { // --- Legacy key fallbacks (backward compatibility) --- // node.maxActiveNodes (old) -> maxConnections (new) if (section.hasPath("maxActiveNodes")) { + logger.warn("Configuring [node.maxActiveNodes] is deprecated and will be removed in a future " + + "release. Please use [node.maxConnections] instead."); nc.maxConnections = section.getInt("maxActiveNodes"); if (section.hasPath("connectFactor")) { + logger.warn("Configuring [node.connectFactor] is deprecated and will be removed in a future " + + "release."); nc.minConnections = (int) (nc.maxConnections * section.getDouble("connectFactor")); } if (section.hasPath("activeConnectFactor")) { + logger.warn("Configuring [node.activeConnectFactor] is deprecated and will be removed in a " + + "future release."); nc.minActiveConnections = (int) (nc.maxConnections * section.getDouble("activeConnectFactor")); } } if (section.hasPath("maxActiveNodesWithSameIp")) { + logger.warn("Configuring [node.maxActiveNodesWithSameIp] is deprecated and will be removed " + + "in a future release. Please use [node.maxConnectionsWithSameIp] instead."); nc.maxConnectionsWithSameIp = section.getInt("maxActiveNodesWithSameIp"); } - // Legacy key fallback: node.fullNodeAllowShieldedTransaction -> allowShieldedTransactionApi. + // Legacy key fallback: node.allowShieldedTransactionApi wins fullNodeAllowShieldedTransaction if (section.hasPath("allowShieldedTransactionApi")) { nc.allowShieldedTransactionApi = section.getBoolean("allowShieldedTransactionApi"); From 3b788e2183f11d4d7055f1b822f5e58b94cae136 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 21 May 2026 11:37:09 +0800 Subject: [PATCH 09/16] delete unused config item receiveTcpMinDataLength --- .../main/java/org/tron/common/parameter/CommonParameter.java | 3 --- common/src/main/java/org/tron/core/config/args/NodeConfig.java | 1 - common/src/main/resources/reference.conf | 1 - framework/src/main/java/org/tron/core/config/args/Args.java | 1 - framework/src/test/java/org/tron/common/ParameterTest.java | 2 -- 5 files changed, 8 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 7c8c16ed42..4bd06c1108 100644 --- a/common/src/main/java/org/tron/common/parameter/CommonParameter.java +++ b/common/src/main/java/org/tron/common/parameter/CommonParameter.java @@ -316,9 +316,6 @@ public class CommonParameter { public List backupMembers; @Getter @Setter - public long receiveTcpMinDataLength; // clearParam: 2048 - @Getter - @Setter public boolean isOpenFullTcpDisconnect; @Getter @Setter diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 4640058bb7..879055c8a7 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -77,7 +77,6 @@ public String getDiscoveryExternalIp() { private ValidContractProtoConfig validContractProto = new ValidContractProtoConfig(); private int shieldedTransInPendingMaxCounts = 10; private long blockCacheTimeout = 60; - private long receiveTcpMinDataLength = 2048; private int maxTransactionPendingSize = 2000; private long pendingTransactionTimeout = 60000; private int maxTrxCacheSize = 50_000; diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index 1619b817a4..a2af815f25 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -347,7 +347,6 @@ node { blockCacheTimeout = 60 # TCP and transaction limits - receiveTcpMinDataLength = 2048 maxTransactionPendingSize = 2000 pendingTransactionTimeout = 60000 # total cached trx across handler queues + pending + rePush 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 3dfc922af9..9f1c6afe35 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 @@ -607,7 +607,6 @@ private static void applyNodeConfig(NodeConfig nc) { PARAMETER.validateSignThreadNum = nc.getValidateSignThreadNum(); PARAMETER.walletExtensionApi = nc.isWalletExtensionApi(); - PARAMETER.receiveTcpMinDataLength = nc.getReceiveTcpMinDataLength(); PARAMETER.isOpenFullTcpDisconnect = nc.isOpenFullTcpDisconnect(); PARAMETER.nodeDetectEnable = nc.isNodeDetectEnable(); diff --git a/framework/src/test/java/org/tron/common/ParameterTest.java b/framework/src/test/java/org/tron/common/ParameterTest.java index 91bb580a3b..0b66c96462 100644 --- a/framework/src/test/java/org/tron/common/ParameterTest.java +++ b/framework/src/test/java/org/tron/common/ParameterTest.java @@ -176,8 +176,6 @@ public void testCommonParameter() { assertEquals(2, parameter.getEstimateEnergyMaxRetry()); parameter.setKeepAliveInterval(1000); assertEquals(1000, parameter.getKeepAliveInterval()); - parameter.setReceiveTcpMinDataLength(10); - assertEquals(10, parameter.getReceiveTcpMinDataLength()); parameter.setOpenFullTcpDisconnect(false); assertFalse(parameter.isOpenFullTcpDisconnect()); parameter.setNodeDetectEnable(false); From 9ff5cd21bf6c00d17e0a5b08bf77e8136a5c06b6 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 21 May 2026 11:50:09 +0800 Subject: [PATCH 10/16] add instruction when it should add config item or not --- docs/configuration-conventions.md | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/docs/configuration-conventions.md b/docs/configuration-conventions.md index c03a7f2e72..c9b322c68a 100644 --- a/docs/configuration-conventions.md +++ b/docs/configuration-conventions.md @@ -2,6 +2,35 @@ This document covers the rules and patterns that developers must follow when adding or modifying configuration parameters in java-tron. Violations cause silent misreads, startup failures, or hard-to-diagnose defaults being applied instead of user-supplied values. +## Configuration Parameter vs. Constant: Which One to Use? + +Before writing any code, decide whether the value belongs in a config file or in source code as a constant. Getting this wrong creates dead configuration surface (parameters that exist but are never tuned) or inflexibility (values that should be adjustable but aren't). + +### Use a configuration parameter when + +- **Different deployments legitimately need different values.** Port numbers, peer lists, storage paths, block-production timeouts, and rate limits vary by environment (mainnet / testnet / private chain) or by hardware capacity. +- **Operators may need to tune the value without rebuilding.** Examples: thread pool sizes, connection limits, QPS caps. +- **The value is an on/off feature flag with production-safe semantics.** The flag must be safe to flip while the rest of the system is unchanged (e.g. `node.rpc.reflectionService`, `vm.estimateEnergy`). +- **The default differs across deployment scenarios.** If the mainnet default and the private-chain default are different, it belongs in config so each can override. + +### Use a constant when + +- **No operator would ever need to change it.** Protocol-level numbers (address prefix bytes, transaction size ceilings, energy unit ratios) are part of the chain specification — changing them causes a fork. +- **The value is a technical limit determined by the implementation, not the deployment.** Jackson `StreamReadConstraints` (`MAX_NESTING_DEPTH`, `MAX_TOKEN_COUNT`) guard against malformed input; no legitimate request comes close to the limit and no operator tunes it. +- **The "configurability" is an illusion.** If the value is captured in a `static final` field at class-load time (before config is applied), a config key is misleading — it appears tunable but changes are silently ignored. Convert to a constant and document why. +- **The value is derived from other constants or from the Java runtime.** Use `Runtime.getRuntime().availableProcessors()` or arithmetic on existing constants; don't push the formula into a config file. +- **No code path reads the value after assignment.** A parameter that exists in `reference.conf` and propagates through `NodeConfig → Args → CommonParameter` but is never consumed by business logic is dead weight. Delete it entirely (see `receiveTcpMinDataLength` as a past example). + +### The warning signs of a misplaced parameter + +| Symptom | Likely problem | +|---------|---------------| +| Parameter exists in `reference.conf` but `grep` finds no call site beyond the binding chain | Dead parameter — delete it | +| Value is read from a `static final` field initialized before `Args.setParam()` | Config change is silently ignored — convert to constant | +| Operator sets the value and nothing changes | Same as above, or value is clamped away in `postProcess()` | +| Parameter controls something that would cause a network fork if mismatched across nodes | Must be a constant, not configurable | +| Parameter has been at its default value in every known deployment for over a year | Candidate for removal or promotion to constant | + ## How Config Keys Bind to Java Fields java-tron uses [Typesafe Config](https://github.com/lightbend/config)'s `ConfigBeanFactory` to map a HOCON section to a Java bean automatically. The mapping algorithm is: From ebb32e047d1bb0380f49998a3fa40480de3d1008 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Thu, 21 May 2026 18:25:20 +0800 Subject: [PATCH 11/16] don't support human readable size --- .../org/tron/core/config/args/NodeConfig.java | 37 +---- common/src/main/resources/reference.conf | 16 +- docs/configuration.md | 6 +- .../org/tron/core/config/args/ArgsTest.java | 150 +----------------- 4 files changed, 14 insertions(+), 195 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 879055c8a7..292d6fdc8f 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -1,7 +1,6 @@ package org.tron.core.config.args; import static org.tron.core.config.Parameter.ChainConstant.MAX_ACTIVE_WITNESS_NUM; -import static org.tron.core.exception.TronError.ErrCode.PARAMETER_INIT; import com.typesafe.config.Config; import com.typesafe.config.ConfigBeanFactory; @@ -11,7 +10,6 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; -import org.tron.core.exception.TronError; // Node configuration bean for the "node" section of config.conf. // ConfigBeanFactory auto-binds all fields including sub-beans, dot-notation keys, @@ -298,8 +296,7 @@ public static class DnsConfig { * since ConfigBeanFactory expects typed bean lists, not string lists. */ public static NodeConfig fromConfig(Config config) { - Config section = normalizeNonStandardKeys( - normalizeMaxMessageSizes(config).getConfig("node")); + Config section = normalizeNonStandardKeys(config.getConfig("node")); // Auto-bind all fields and sub-beans. ConfigBeanFactory fails fast with a // descriptive path on any `= null` value @@ -495,36 +492,4 @@ private static Config normalizeNonStandardKeys(Config section) { return section; } - /** - * Pre-normalize size paths so ConfigBeanFactory's primitive int/long binding succeeds - * for human-readable values like "4m" / "128MB". For each maxMessageSize key, parse - * via getMemorySize, validate non-negative and <= Integer.MAX_VALUE, and write the - * numeric byte value back into the Config tree. Validation errors propagate before - * bean creation so the failure points at the user-facing config path. - */ - private static Config normalizeMaxMessageSizes(Config config) { - String[] paths = { - "node.rpc.maxMessageSize", - "node.http.maxMessageSize", - "node.jsonrpc.maxMessageSize" - }; - Config result = config; - for (String path : paths) { - if (config.hasPath(path)) { - long bytes = parseMaxMessageSize(config, path); - result = result.withValue(path, ConfigValueFactory.fromAnyRef(bytes)); - } - } - return result; - } - - private static long parseMaxMessageSize(Config config, String key) { - long value = config.getMemorySize(key).toBytes(); - if (value < 0 || value > Integer.MAX_VALUE) { - throw new TronError(key + " must be non-negative and <= " - + Integer.MAX_VALUE + ", got: " + value, PARAMETER_INIT); - } - return value; - } - } diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index a2af815f25..ad3b9a3a20 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -259,11 +259,10 @@ node { PBFTEnable = true PBFTPort = 8092 - # Maximum HTTP request body size (default 4MB). Supports human-readable sizes: 4m, 4MB, 4194304. - # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). - # Setting to 0 rejects all non-empty request bodies (not "unlimited"). + # Maximum HTTP request body size in bytes (default 4194304, ~4MB). + # Must be a non-negative integer. Setting to 0 rejects all non-empty request bodies. # Independent from rpc.maxMessageSize. - maxMessageSize = 4M + maxMessageSize = 4194304 maxNestingDepth = 100 maxTokenCount = 100000 } @@ -292,9 +291,8 @@ node { # Connection max age (ms). 0 = no limit maxConnectionAgeInMillis = 0 - # Maximum gRPC message size (default 4MB). Supports human-readable sizes: 4m, 4MB, 4194304. - # Must be non-negative and <= 2147483647 (Integer.MAX_VALUE, ~2 GiB). - # Setting to 0 rejects all non-empty request bodies (not "unlimited"). + # Maximum gRPC message size in bytes (default 4194304, ~4MB). + # Must be a non-negative integer. Setting to 0 rejects all non-empty messages. maxMessageSize = 4194304 # Maximum header list size (bytes), default 8192 @@ -423,8 +421,8 @@ node { maxResponseSize = 26214400 # Allowed maximum number for newFilter, <=0 means no limit maxLogFilterNum = 20000 - # Maximum JSON-RPC request body size, default 4MB. Independent from rpc.maxMessageSize. - maxMessageSize = 4M + # Maximum JSON-RPC request body size in bytes (default 4194304, ~4MB). Independent from rpc.maxMessageSize. + maxMessageSize = 4194304 } # Disabled API list (works for http, rpc and pbft, not jsonrpc). Case insensitive. diff --git a/docs/configuration.md b/docs/configuration.md index 43ab867600..f243e8ccff 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,7 +34,7 @@ java -jar FullNode.jar -c /path/to/config.conf java-tron-1.0.0/bin/FullNode -c /path/to/config.conf -w ``` -If `-c` is omitted, the node uses only the defaults from `reference.conf`. For anything beyond a quick local test, always provide an explicit config file. +If `-c` is omitted, the node loads the `config.conf` bundled inside the jar (the same file shipped with the distribution) merged with `reference.conf` as fallback. The bundled file already enables discovery/persist for mainnet operation. For production, copy it out, edit, and pass the edited copy via `-c` to make your configuration visible to operators. ## Minimal config.conf @@ -242,7 +242,9 @@ Not all parameters support hot-reload. Parameters that affect node identity, gen ## Viewing Effective Configuration -At startup, the node logs the resolved configuration (merged result of `config.conf` + `reference.conf`) when `node.openPrintLog = true` (the default). Look for lines prefixed with the section name in the startup output to confirm your overrides took effect. +At startup, the node unconditionally logs a summary of key parameters under `Net config`, `Backup config`, `Code version`, `DB config`, and `shutDown config` headers (see `Args.logConfig()`` for the exact fields). For parameters not in this summary, you must inspect runtime behavior or consult `reference.conf` directly — the full merged configuration is never dumped. + +Note: `node.openPrintLog` is a separate flag that controls runtime verbosity of P2P/inventory/pending-tx logs, not startup config logging. ## Full Reference 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 3ae5677fbd..c34db47ac5 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 @@ -17,7 +17,6 @@ import com.google.common.collect.Lists; import com.typesafe.config.Config; -import com.typesafe.config.ConfigException; import com.typesafe.config.ConfigFactory; import io.grpc.internal.GrpcUtil; import io.grpc.netty.NettyServerBuilder; @@ -515,79 +514,14 @@ public void testAllowShieldedTransactionApiDefault() { } @Test - public void testMaxMessageSizeHumanReadable() { + public void testMaxMessageSizePureNumber() { Map configMap = new HashMap<>(); configMap.put("storage.db.directory", "database"); - // --- KB tier: binary (k/K/Ki/KiB = 1024) vs SI (kB = 1000) --- - configMap.put("node.rpc.maxMessageSize", "512k"); - configMap.put("node.http.maxMessageSize", "512K"); - configMap.put("node.jsonrpc.maxMessageSize", "512kB"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - Args.applyConfigParams(config); - Assert.assertEquals(512 * 1024, Args.getInstance().getMaxMessageSize()); - Assert.assertEquals(512 * 1024, Args.getInstance().getHttpMaxMessageSize()); - Assert.assertEquals(512 * 1000, Args.getInstance().getJsonRpcMaxMessageSize()); - Args.clearParam(); - - configMap.put("node.rpc.maxMessageSize", "256Ki"); - configMap.put("node.http.maxMessageSize", "256KiB"); - configMap.put("node.jsonrpc.maxMessageSize", "256kB"); - config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - Args.applyConfigParams(config); - Assert.assertEquals(256 * 1024, Args.getInstance().getMaxMessageSize()); - Assert.assertEquals(256 * 1024, Args.getInstance().getHttpMaxMessageSize()); - Assert.assertEquals(256 * 1000, Args.getInstance().getJsonRpcMaxMessageSize()); - Args.clearParam(); - - // --- MB tier: binary (m/M/Mi/MiB = 1024*1024) vs SI (MB = 1000*1000) --- - configMap.put("node.rpc.maxMessageSize", "4m"); - configMap.put("node.http.maxMessageSize", "8M"); - configMap.put("node.jsonrpc.maxMessageSize", "2MB"); - config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - Args.applyConfigParams(config); - Assert.assertEquals(4 * 1024 * 1024, Args.getInstance().getMaxMessageSize()); - Assert.assertEquals(8 * 1024 * 1024, Args.getInstance().getHttpMaxMessageSize()); - Assert.assertEquals(2 * 1000 * 1000, Args.getInstance().getJsonRpcMaxMessageSize()); - Args.clearParam(); - - configMap.put("node.rpc.maxMessageSize", "4Mi"); - configMap.put("node.http.maxMessageSize", "4MiB"); - configMap.put("node.jsonrpc.maxMessageSize", "4MB"); - config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - Args.applyConfigParams(config); - Assert.assertEquals(4 * 1024 * 1024, Args.getInstance().getMaxMessageSize()); - Assert.assertEquals(4 * 1024 * 1024, Args.getInstance().getHttpMaxMessageSize()); - Assert.assertEquals(4 * 1000 * 1000, Args.getInstance().getJsonRpcMaxMessageSize()); - Args.clearParam(); - - // --- GB tier: binary (g/G/Gi/GiB) vs SI (GB) --- - // All three paths are int-bounded; values up to Integer.MAX_VALUE are accepted. - configMap.put("node.rpc.maxMessageSize", "4m"); - configMap.put("node.http.maxMessageSize", "1g"); - configMap.put("node.jsonrpc.maxMessageSize", "1GB"); - config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - Args.applyConfigParams(config); - Assert.assertEquals(4 * 1024 * 1024, Args.getInstance().getMaxMessageSize()); - Assert.assertEquals(1024L * 1024 * 1024, Args.getInstance().getHttpMaxMessageSize()); - Assert.assertEquals(1000L * 1000 * 1000, Args.getInstance().getJsonRpcMaxMessageSize()); - Args.clearParam(); - - // --- raw integer (backward compatible): treated as bytes --- configMap.put("node.rpc.maxMessageSize", "4194304"); configMap.put("node.http.maxMessageSize", "4194304"); configMap.put("node.jsonrpc.maxMessageSize", "4194304"); - config = ConfigFactory.defaultOverrides() + Config config = ConfigFactory.defaultOverrides() .withFallback(ConfigFactory.parseMap(configMap)) .withFallback(ConfigFactory.defaultReference()); Args.applyConfigParams(config); @@ -596,7 +530,6 @@ public void testMaxMessageSizeHumanReadable() { Assert.assertEquals(4 * 1024 * 1024, Args.getInstance().getJsonRpcMaxMessageSize()); Args.clearParam(); - // --- zero is allowed --- configMap.put("node.rpc.maxMessageSize", "0"); configMap.put("node.http.maxMessageSize", "0"); configMap.put("node.jsonrpc.maxMessageSize", "0"); @@ -610,85 +543,6 @@ public void testMaxMessageSizeHumanReadable() { Args.clearParam(); } - @Test - public void testRpcMaxMessageSizeExceedsIntMax() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.rpc.maxMessageSize", "3g"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - TronError e = Assert.assertThrows(TronError.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue(e.getMessage().contains("node.rpc.maxMessageSize must be non-negative")); - } - - @Test - public void testHttpMaxMessageSizeExceedsIntMax() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.http.maxMessageSize", "2Gi"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - TronError e = Assert.assertThrows(TronError.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue(e.getMessage().contains("node.http.maxMessageSize must be non-negative")); - } - - @Test - public void testJsonRpcMaxMessageSizeExceedsIntMax() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.jsonrpc.maxMessageSize", "2Gi"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - TronError e = Assert.assertThrows(TronError.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue( - e.getMessage().contains("node.jsonrpc.maxMessageSize must be non-negative")); - } - - @Test - public void testMaxMessageSizeNegativeValue() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.rpc.maxMessageSize", "-4m"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - IllegalArgumentException e = Assert.assertThrows(IllegalArgumentException.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue(e.getMessage().contains("negative")); - } - - @Test - public void testMaxMessageSizeInvalidUnit() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.rpc.maxMessageSize", "4x"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - ConfigException.BadValue e = Assert.assertThrows(ConfigException.BadValue.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue(e.getMessage().contains("Could not parse size-in-bytes unit")); - } - - @Test - public void testMaxMessageSizeNonNumeric() { - Map configMap = new HashMap<>(); - configMap.put("storage.db.directory", "database"); - configMap.put("node.http.maxMessageSize", "abc"); - Config config = ConfigFactory.defaultOverrides() - .withFallback(ConfigFactory.parseMap(configMap)) - .withFallback(ConfigFactory.defaultReference()); - ConfigException.BadValue e = Assert.assertThrows(ConfigException.BadValue.class, - () -> Args.applyConfigParams(config)); - Assert.assertTrue(e.getMessage().contains("No number in size-in-bytes value")); - } - // ===== checkBackupMembers() tests ===== @Test From 0cac2a59cebc4ef0df02fd741ec1954256848673 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 22 May 2026 00:04:38 +0800 Subject: [PATCH 12/16] fix maxMessageSize in config.conf --- framework/src/main/resources/config.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/main/resources/config.conf b/framework/src/main/resources/config.conf index 21bddd2037..13a31f52c0 100644 --- a/framework/src/main/resources/config.conf +++ b/framework/src/main/resources/config.conf @@ -161,7 +161,7 @@ node { maxBatchSize = 100 maxResponseSize = 26214400 maxLogFilterNum = 20000 - maxMessageSize = 4M + maxMessageSize = 4194304 } disabledApi = [ From 40a68b70baae4eeb321f927ab6c9ab665170f457 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 22 May 2026 00:32:44 +0800 Subject: [PATCH 13/16] update comment and configuration-conventions.md --- .../org/tron/core/config/args/NodeConfig.java | 1 + docs/configuration-conventions.md | 19 +------------------ .../org/tron/core/config/args/ArgsTest.java | 7 ++----- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 292d6fdc8f..5e0d1b4c0d 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -15,6 +15,7 @@ // ConfigBeanFactory auto-binds all fields including sub-beans, dot-notation keys, // PBFT fields, and list fields. Only legacy key fallbacks and PascalCase shutdown // keys are read manually. +// Always construct via {@link #fromConfig} — direct construction skips postProcess() clamping. @Slf4j @Getter @Setter diff --git a/docs/configuration-conventions.md b/docs/configuration-conventions.md index c9b322c68a..41d43f3d08 100644 --- a/docs/configuration-conventions.md +++ b/docs/configuration-conventions.md @@ -141,28 +141,12 @@ if (myNewOption > 64) { | Java field type | HOCON value | Notes | |-------------------|-------------|-------| | `boolean` | `true` / `false` | | -| `int` / `long` | numeric | Use `getMemorySize` path if human-readable sizes should be supported (see below) | +| `int` / `long` | numeric | Must be a plain integer; human-readable sizes (`4m`, `128MB`) are not supported | | `double` | numeric | | | `String` | `"value"` | Null HOCON values must be normalized to `""` before binding (see `normalizeNonStandardKeys`) | | `List` | `["a", "b"]` | Must be read manually; `ConfigBeanFactory` does not handle `List` | | Inner bean | `{ key = val }` | The Java field type must be the inner static class | -### Human-Readable Size Values (`4m`, `128MB`) - -For byte-size parameters, users can write `4m` or `128MB` in HOCON. `ConfigBeanFactory` cannot parse these into `int`/`long` directly. Pre-normalize them before calling `ConfigBeanFactory`: - -```java -// normalize before binding -long bytes = config.getMemorySize("node.rpc.maxMessageSize").toBytes(); -if (bytes < 0 || bytes > Integer.MAX_VALUE) { - throw new TronError("node.rpc.maxMessageSize must be non-negative and <= " - + Integer.MAX_VALUE + ", got: " + bytes, PARAMETER_INIT); -} -config = config.withValue("node.rpc.maxMessageSize", ConfigValueFactory.fromAnyRef(bytes)); -``` - -This pattern is already centralized in `NodeConfig.normalizeMaxMessageSizes()`. Add new size keys to the paths array there rather than duplicating the logic. - ### List Fields `ConfigBeanFactory` handles `List` but not `List`. Read string-list fields manually after `ConfigBeanFactory.create()`: @@ -219,6 +203,5 @@ nc.shutdownBlockTime = section.hasPath("shutdown.BlockTime") | Sub-bean nesting | `NodeConfig.HttpConfig`, `NodeConfig.RpcConfig` | | Legacy key fallback | `NodeConfig.fromConfig()` (`maxActiveNodes`, `maxActiveNodesWithSameIp`) | | Non-standard key normalization | `CommitteeConfig.normalizeNonStandardKeys()`, `NodeConfig.normalizeNonStandardKeys()` | -| Human-readable size normalization | `NodeConfig.normalizeMaxMessageSizes()` | | Optional PascalCase keys | `NodeConfig.fromConfig()` (`shutdown.BlockTime/Height/Count`) | | `postProcess()` clamping | `NodeConfig.postProcess()`, `CommitteeConfig.postProcess()` | 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 c34db47ac5..274e9291e5 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 @@ -380,12 +380,9 @@ public void testConfigStorageDefaults() { } // =========================================================================== - // Boundary tests for clamps applied in Args.java bridge code (not in - // bean postProcess()). + // Boundary tests for node.fetchBlock.timeout clamping. // - // fetchBlockTimeout is read from NodeConfig but clamped in Args.applyNodeConfig - // to range [100, 1000]. Pin this clamp here so any future refactor that moves - // it (e.g. into NodeConfig.postProcess()) preserves the behavior. + // The clamp to [100, 1000] is applied in NodeConfig.postProcess(). // =========================================================================== @Test From fb8815937fe654bb41dd1a4c10555858df7025e0 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 22 May 2026 00:45:29 +0800 Subject: [PATCH 14/16] fix the description of config.conf's purpose --- docs/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index f243e8ccff..c9909fb257 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -9,7 +9,7 @@ java-tron uses [Typesafe Config](https://github.com/lightbend/config) and applie | File | Location | Purpose | |------|----------|---------| | `reference.conf` | Bundled inside the jar (`common` module) | Declares every parameter with its default value | -| `config.conf` | External, supplied by the operator via `-c` | Overrides only the values that differ from defaults | +| `config.conf` | bundled template and optionally edited & passed via -c | Overrides only the values that differ from defaults | **Loading priority:** values in `config.conf` always win. Any parameter that your `config.conf` omits is automatically filled in from `reference.conf`. You never need to copy the entire `reference.conf` into your own file — only include the parameters you actually want to change. From 970b47a07415cc26f94f104cd9f64b1695374adf Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 22 May 2026 16:48:19 +0800 Subject: [PATCH 15/16] fix(config): address review findings in docs and reference.conf - Remove incorrect DnsConfig Javadoc referencing nonexistent PublishConfig - Move deprecated activeConnectFactor/connectFactor to end of node block in reference.conf with clearer deprecation comment - Fix double backtick typo in configuration.md (Args.logConfig()) - Fix capitalisation inconsistency in configuration.md table - Add missing trailing newline to configuration.md - Clarify nesting depth in configuration-conventions.md: CI gate hard ceiling is 5 (historical max); new keys must stay within 3 levels Co-Authored-By: Claude Sonnet 4.6 --- .../java/org/tron/core/config/args/NodeConfig.java | 3 --- common/src/main/resources/reference.conf | 10 +++++----- docs/configuration-conventions.md | 11 ++++++----- docs/configuration.md | 6 +++--- 4 files changed, 14 insertions(+), 16 deletions(-) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index 5e0d1b4c0d..e58d842d17 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -267,9 +267,6 @@ public static class DynamicConfigSection { private long checkInterval = 600; } - /** - * All default parameters come from PublishConfig - */ @Getter @Setter public static class DnsConfig { diff --git a/common/src/main/resources/reference.conf b/common/src/main/resources/reference.conf index ad3b9a3a20..b016ef7ba6 100644 --- a/common/src/main/resources/reference.conf +++ b/common/src/main/resources/reference.conf @@ -195,11 +195,6 @@ node { maxHttpConnectNumber = 50 minParticipationRate = 0 - # Deprecate, don't use - activeConnectFactor = 0.1 - # Deprecate, don't use - connectFactor = 0.6 - # WARNING: Some shielded transaction APIs require sending private keys as parameters. # Calling these APIs on untrusted or remote nodes may leak your private keys. # It is recommended to invoke them locally for development and testing. @@ -397,6 +392,11 @@ node { # Open history query APIs on lite FullNode (may return null for some queries) openHistoryQueryWhenLiteFN = false + # Deprecated: these fields were used by the old connection-factor algorithm. + # They are still accepted from user config for backward compatibility but have no effect. + activeConnectFactor = 0.1 + connectFactor = 0.6 + jsonrpc { # Note: Before release_4.8.1, if you turn on jsonrpc and run it for a while and then turn it off, # you will not be able to get the data from eth_getLogs for that period of time. Default: false diff --git a/docs/configuration-conventions.md b/docs/configuration-conventions.md index 41d43f3d08..6d456c1ba0 100644 --- a/docs/configuration-conventions.md +++ b/docs/configuration-conventions.md @@ -81,16 +81,17 @@ A HOCON key named `isOpenFullTcpDisconnect` produces the setter `setIsOpenFullTc ## Nesting Depth -Keep nesting to **at most 3 levels** from the top-level section. Deeper nesting creates long key paths that are hard to override in `config.conf` and require more boilerplate inner bean classes. +The CI gate enforces a hard ceiling of **5 levels** (the historical maximum in `reference.conf`). New parameters must stay within **3 levels** from the top-level section. The gap between 3 and 5 is reserved for legacy paths that already exist — it is not a license to add new deep keys. ``` level 1: node { ... } level 2: node { rpc { ... } } -level 3: node { rpc { flowControl { ... } } } ← maximum -level 4+: node { rpc { flowControl { window { ... } } } } ← avoid +level 3: node { rpc { flowControl { ... } } } ← limit for new keys +level 4+: node { rpc { flowControl { window { ... } } } } ← legacy only; do not add new keys here +level 6+: rejected by CI gate unconditionally ``` -Each level of nesting requires a corresponding inner static bean class. If you find yourself going 4 levels deep, consider flattening by moving the leaf keys up one level or using a longer camelCase key at level 2. +Each level of nesting requires a corresponding inner static bean class. If you find yourself going beyond 3 levels deep, consider flattening by moving the leaf keys up one level or using a longer camelCase key at level 2. ## Adding a New Parameter: Checklist @@ -190,7 +191,7 @@ nc.shutdownBlockTime = section.hasPath("shutdown.BlockTime") | Standard camelCase | `maxConnections` | `MaxConnections`, `max_connections`, `max-connections` | | No `is` prefix | `openFullTcpDisconnect` | `isOpenFullTcpDisconnect` | | No all-caps acronym prefix | `pbftExpireNum`, `pBFTPort`* | `PBFTExpireNum` | -| Nesting ≤ 3 levels | `node.rpc.maxMessageSize` | `node.rpc.limits.size.max` | +| New keys: nesting ≤ 3 levels | `node.rpc.maxMessageSize` | `node.rpc.limits.size.max` | | Java field name matches HOCON key exactly | field `maxConnections` ↔ key `maxConnections` | field `maxConns` ↔ key `maxConnections` | \* `PBFTEnable` / `PBFTPort` are legacy exceptions; do not model new keys after them. diff --git a/docs/configuration.md b/docs/configuration.md index c9909fb257..42dc1ea377 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -9,7 +9,7 @@ java-tron uses [Typesafe Config](https://github.com/lightbend/config) and applie | File | Location | Purpose | |------|----------|---------| | `reference.conf` | Bundled inside the jar (`common` module) | Declares every parameter with its default value | -| `config.conf` | bundled template and optionally edited & passed via -c | Overrides only the values that differ from defaults | +| `config.conf` | Bundled template, optionally edited & passed via -c | Overrides only the values that differ from defaults | **Loading priority:** values in `config.conf` always win. Any parameter that your `config.conf` omits is automatically filled in from `reference.conf`. You never need to copy the entire `reference.conf` into your own file — only include the parameters you actually want to change. @@ -242,7 +242,7 @@ Not all parameters support hot-reload. Parameters that affect node identity, gen ## Viewing Effective Configuration -At startup, the node unconditionally logs a summary of key parameters under `Net config`, `Backup config`, `Code version`, `DB config`, and `shutDown config` headers (see `Args.logConfig()`` for the exact fields). For parameters not in this summary, you must inspect runtime behavior or consult `reference.conf` directly — the full merged configuration is never dumped. +At startup, the node unconditionally logs a summary of key parameters under `Net config`, `Backup config`, `Code version`, `DB config`, and `shutDown config` headers (see `Args.logConfig()` for the exact fields). For parameters not in this summary, you must inspect runtime behavior or consult `reference.conf` directly — the full merged configuration is never dumped. Note: `node.openPrintLog` is a separate flag that controls runtime verbosity of P2P/inventory/pending-tx logs, not startup config logging. @@ -254,4 +254,4 @@ Every parameter with its default value and an inline comment is documented in: common/src/main/resources/reference.conf ``` -When you need the authoritative default for a parameter or want to understand what a key does, consult that file directly. \ No newline at end of file +When you need the authoritative default for a parameter or want to understand what a key does, consult that file directly. From a93ec155b801f663795179b6f5ad5ee9e2a0e30b Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Fri, 22 May 2026 17:13:41 +0800 Subject: [PATCH 16/16] check if maxMessageSize is negative --- .../org/tron/core/config/args/NodeConfig.java | 16 ++++++++ .../org/tron/core/config/args/ArgsTest.java | 40 +++++++++++++++++++ 2 files changed, 56 insertions(+) diff --git a/common/src/main/java/org/tron/core/config/args/NodeConfig.java b/common/src/main/java/org/tron/core/config/args/NodeConfig.java index e58d842d17..527bea948d 100644 --- a/common/src/main/java/org/tron/core/config/args/NodeConfig.java +++ b/common/src/main/java/org/tron/core/config/args/NodeConfig.java @@ -1,6 +1,7 @@ package org.tron.core.config.args; import static org.tron.core.config.Parameter.ChainConstant.MAX_ACTIVE_WITNESS_NUM; +import static org.tron.core.exception.TronError.ErrCode.PARAMETER_INIT; import com.typesafe.config.Config; import com.typesafe.config.ConfigBeanFactory; @@ -10,6 +11,7 @@ import lombok.Getter; import lombok.Setter; import lombok.extern.slf4j.Slf4j; +import org.tron.core.exception.TronError; // Node configuration bean for the "node" section of config.conf. // ConfigBeanFactory auto-binds all fields including sub-beans, dot-notation keys, @@ -450,6 +452,20 @@ private void postProcess() { if (maxTrxCacheSize < 2000) { maxTrxCacheSize = 2000; } + + // maxMessageSize: reject negative values + if (rpc.maxMessageSize < 0) { + throw new TronError("node.rpc.maxMessageSize must be non-negative, got: " + + rpc.maxMessageSize, PARAMETER_INIT); + } + if (http.maxMessageSize < 0) { + throw new TronError("node.http.maxMessageSize must be non-negative, got: " + + http.maxMessageSize, PARAMETER_INIT); + } + if (jsonrpc.maxMessageSize < 0) { + throw new TronError("node.jsonrpc.maxMessageSize must be non-negative, got: " + + jsonrpc.maxMessageSize, PARAMETER_INIT); + } } // =========================================================================== 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 274e9291e5..a62b1418d5 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 @@ -540,6 +540,46 @@ public void testMaxMessageSizePureNumber() { Args.clearParam(); } + @Test + public void testMaxMessageSizeNegativeValueRejected() { + // Negative maxMessageSize must be rejected at startup which threw TronError(PARAMETER_INIT) + // for negative values). + for (String key : new String[]{ + "node.rpc.maxMessageSize", "node.http.maxMessageSize", "node.jsonrpc.maxMessageSize"}) { + Map configMap = new HashMap<>(); + configMap.put("storage.db.directory", "database"); + configMap.put(key, "-1"); + Config config = ConfigFactory.defaultOverrides() + .withFallback(ConfigFactory.parseMap(configMap)) + .withFallback(ConfigFactory.defaultReference()); + try { + Args.applyConfigParams(config); + Assert.fail("Expected TronError for negative " + key); + } catch (TronError e) { + Assert.assertEquals(TronError.ErrCode.PARAMETER_INIT, e.getErrCode()); + } + Args.clearParam(); + } + } + + @Test + public void testRpcMaxMessageSizeExceedsIntMax() { + // HOCON's Config.getInt() throws when a numeric value exceeds int range. + // This documents the failure mode for node.rpc.maxMessageSize (int field). + Map configMap = new HashMap<>(); + configMap.put("storage.db.directory", "database"); + configMap.put("node.rpc.maxMessageSize", (long) Integer.MAX_VALUE + 1); + Config config = ConfigFactory.defaultOverrides() + .withFallback(ConfigFactory.parseMap(configMap)) + .withFallback(ConfigFactory.defaultReference()); + try { + Args.applyConfigParams(config); + Assert.fail("Expected RuntimeException for maxMessageSize > Integer.MAX_VALUE"); + } catch (RuntimeException e) { + // ConfigBeanFactory/HOCON throws when binding a long out of int range + } + } + // ===== checkBackupMembers() tests ===== @Test