Skip to content

ci(config): enforce lowerCamelCase and max depth in reference.conf#29

Open
bladehan1 wants to merge 7 commits into
developfrom
feat/ci_conf
Open

ci(config): enforce lowerCamelCase and max depth in reference.conf#29
bladehan1 wants to merge 7 commits into
developfrom
feat/ci_conf

Conversation

@bladehan1
Copy link
Copy Markdown
Owner

@bladehan1 bladehan1 commented May 19, 2026

What does this PR do?

Adds a CI gate that scans common/src/main/resources/reference.conf and fails the build on:

  1. Any key whose dot-separated segment does not match ^[a-z][a-zA-Z0-9]*$ (lowerCamelCase).
  2. Any key whose hierarchy depth exceeds 5.

The check runs as a new step (Validate reference.conf key names and depth) inside the existing checkstyle job of .github/workflows/pr-check.yml, so it reuses the existing checkout and adds no new runner.

Why are these changes required?

reference.conf keys must auto-bind to XxxConfig.java bean fields via ConfigBeanFactory, which requires lowerCamelCase. Without an automated gate the file has drifted (4 legacy PBFT* keys with leading uppercase, grandfathered via an in-script allowlist), and deeply nested hierarchies can creep in unnoticed (current max depth is 4; the gate allows up to 5 for headroom).

This PR has been tested by:

  • Manual Testing — ran the validator locally against the current reference.conf (exit 0, 266 keys, max depth 4 ≤ 5) and against synthetic bad inputs (1 format + 1 depth violation → exit 1, single consolidated ::error annotation emitted).

Follow up

This PR is for fork-internal smoke-test of the gate itself, not for upstream. It validates that the new step runs on GHA against an unmodified reference.conf and exits clean.

Extra details

  • 4 PBFT keys allowlisted in the script: node.http.PBFTEnable, node.http.PBFTPort, node.rpc.PBFTEnable, node.rpc.PBFTPort. Renaming them would break user config.conf files and is tracked separately.
  • The Python script is dependency-free and uses the python3 already on ubuntu-24.04-arm runners — no setup-python action.

Summary by cubic

Adds a CI gate to validate reference.conf keys (lowerCamelCase, depth ≤5) and introduces a switchable blocking mode for API rate limiting; also enforces a minimum event‑plugin version and improves JSON‑RPC compliance.

  • New Features

    • CI: adds .github/scripts/check_reference_conf.py and runs it in the checkstyle job to enforce per-segment ^[a-z][a-zA-Z0-9]*$, max depth 5; four legacy keys are allowlisted (node.http.PBFTEnable, node.http.PBFTPort, node.rpc.PBFTEnable, node.rpc.PBFTPort). Emits one ::error with all offenders and fails on violations.
    • Rate limiting: adds rate.limiter.apiNonBlocking (default false). Servlet and gRPC paths use a new acquirePermit that chooses blocking or non‑blocking per this switch; per-endpoint checks still run before global limits.
    • Events: rejects event-plugin versions below 3.0.0 at startup with a clear upgrade hint.
  • Bug Fixes

    • CLI --es now reliably starts event subscription by applying CLI before event config; useNativeQueue default restored to false.
    • JSON‑RPC: responses use application/json-rpc, input limits are applied via a single binding path, and redundant config keys were removed; parser constraints now respect node settings.

Written for commit 2e2f3e0. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

Release Notes

  • New Features

    • Added rate limiter non-blocking mode for API endpoints that rejects requests on overload instead of blocking
    • Added VM constant call execution timeout configuration option
    • Enhanced event plugin version validation with minimum version requirement
  • Configuration Updates

    • Event queue default behavior changed from enabled to disabled
    • Improved JSON-RPC response handling with proper content-type headers
    • Configuration keys normalized for consistency
  • Bug Fixes

    • Fixed potential null pointer exception in peer relay node handling
    • Enhanced JSON-RPC error responses for invalid input

Review Change Stack

317787106 and others added 7 commits May 10, 2026 16:09
* fix(config): remove redundant JSON-RPC config fields and consolidate parameter binding

Remove maxBlockFilterNum, maxAddressSize, and maxRequestTimeout from NodeConfig/CommonParameter
since they were superseded by the jsonRpcMaxBatchSize/jsonRpcMaxResponseSize parameters.
Consolidate the config binding path so all JSON-RPC size limits flow through a single
reference.conf entry, and clean up stale test-config fixtures.

* fix bug of NodeConfigTest

* remove allowShieldedTransactionApi from reference.conf

* add testcase of external.ip is null

* change comment

* fix the bug of --es and 7 failed testcases
…onprotocol#6760)

Pre-3.0.0(The previous event-plugin public release is 2.2.0)
event-plugin builds still link against com.alibaba.fastjson, which
was removed from java-tron in tronprotocol#6701. When such a plugin is loaded, the
NoClassDefFoundError surfaces inside the plugin's own worker thread and is
swallowed by its catch(Throwable) handler. The node keeps running while
silently dropping every trigger, leaving operators with no signal that the
event subscription is broken.

Enforce a minimum Plugin-Version at startup in EventPluginLoader.startPlugin
using pf4j's VersionManager (semver). When the descriptor version is below
3.0.0, log a clear upgrade hint and return false; the existing call chain in
Manager.startEventSubscribing wraps that into TronError(EVENT_SUBSCRIBE_INIT)
and aborts node startup instead of silently degrading.
…rs (tronprotocol#6761)

- Add `rate.limiter.apiNonBlocking` switch (default false). When off, callers wait for a permit; when on, they reject immediately and shed load.
- Wire the switch through `RateLimiterConfig` → `Args` → `CommonParameter`; update `reference.conf` / `config.conf`.
- Add blocking `acquire()` paths on `IRateLimiter`, `GlobalRateLimiter`, and `QpsStrategy` / `IPQpsStrategy` / `GlobalPreemptibleStrategy`. Only the semaphore-based strategy is bounded (2s); the QPS-based paths use unbounded Guava `RateLimiter.acquire()`.
- Introduce `acquirePermit()` dispatcher (default method on `IRateLimiter`; static on `GlobalRateLimiter`) that picks blocking vs non-blocking based on the switch.
- Swap `tryAcquire` → `acquirePermit` at the `RateLimiterServlet` and `RateLimiterInterceptor` call sites; preserve per-endpoint-before-global ordering to avoid consuming global quota on per-endpoint rejection.
- Extract `loadIpLimiter()` in `GlobalRateLimiter` and `loadLimiter()` in `IPQpsStrategy` to share cache+exception handling between `tryAcquire` and `acquire`.
- Add unit tests covering dispatcher routing (both directions), acquire IP-before-global ordering, and IP-loader-failure fail-closed behaviour.
Add a CI gate that scans common/src/main/resources/reference.conf and
fails the build when any new key violates lowerCamelCase
(^[a-z][a-zA-Z0-9]*$ per dot-separated segment) or exceeds the maximum
hierarchy depth of 5.

Runs as a new step in the existing checkstyle job of pr-check.yml (no
extra runner spin-up). Four legacy PBFT* keys are grandfathered via an
in-script allowlist so the gate fails only on new violations. The
script emits a consolidated GHA error annotation listing every
offending key/line, and uses sys.exit(1) to drive step failure.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 19, 2026

📝 Walkthrough

Walkthrough

This PR refactors configuration binding and rate-limiter acquisition semantics, adds runtime validation for event plugin versions, and hardens JSON-RPC request processing. Configuration classes normalize non-standard keys before auto-binding instead of manual field assignment. Rate-limiters now dispatch acquire requests through a conditional acquirePermit API based on a new apiNonBlocking flag. JSON-RPC servlet validates request structure and enforces streaming constraints.

Changes

Configuration validation, rate-limiter routing, and JSON-RPC hardening

Layer / File(s) Summary
Configuration validation infrastructure and reference defaults
.github/scripts/check_reference_conf.py, .github/workflows/pr-check.yml, common/src/main/resources/reference.conf, codecov.yml
New CI script validates reference.conf key naming (lowerCamelCase with allowlist) and max-depth constraints. Integrated into checkstyle job. Reference defaults updated: rate-limiter apiNonBlocking=false, VM constantCallTimeoutMs=0, event useNativeQueue=false.
Configuration normalization and binding refactoring
common/src/main/java/org/tron/core/config/args/*.java, common/src/main/java/org/tron/common/parameter/CommonParameter.java
CommitteeConfig, NodeConfig, EventConfig, VmConfig refactored to normalize non-standard keys before ConfigBeanFactory binding. Removes custom getter/setter overrides in favor of Lombok generation. Deletes Overlay class; adds rateLimiterApiNonBlocking and apiNonBlocking flags.
Rate-limiter permit acquisition dispatch and adapter implementations
framework/src/main/java/org/tron/core/services/ratelimiter/adapter/IRateLimiter.java, framework/src/main/java/org/tron/core/services/ratelimiter/strategy/*.java, framework/src/main/java/org/tron/core/services/ratelimiter/adapter/*.java, framework/src/main/java/org/tron/core/services/ratelimiter/GlobalRateLimiter.java
IRateLimiter interface adds acquirePermit default method routing to tryAcquire (non-blocking) or acquire (blocking) based on configuration flag. Strategy and adapter classes implement acquire() methods. GlobalRateLimiter centralizes per-IP limiter loading and implements acquirePermit dispatch.
Rate-limiter integration in servlets and interceptors
framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java, framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java, framework/src/main/java/org/tron/core/config/args/Args.java, framework/src/main/java/org/tron/program/FullNode.java
Servlets and interceptors updated to call acquirePermit(...) instead of tryAcquire(...). Args maps new rateLimiterApiNonBlocking config during startup. FullNode switches to StringUtils for emptiness check.
Event subscription configuration and plugin version checking
common/src/main/java/org/tron/core/config/args/EventConfig.java, framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java, framework/src/main/java/org/tron/core/config/args/Args.java
EventConfig refactored to use ConfigBeanFactory with topic defaults fallback; useNativeQueue default changed to false. EventPluginLoader enforces minimum version (3.0.0). Args applies eventConfig after CLI overrides, preserving CLI-set eventSubscribe.
JSON-RPC request validation and streaming constraints
framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java
JsonRpcServlet applies Jackson StreamReadConstraints from CommonParameter. Rejects invalid JSON parse errors and non-object/array roots as Invalid Request. Batch handling distinguishes invalid (non-object) from valid sub-requests with proper size accounting. Content-Type set to application/json-rpc (no charset) for all responses.
Tests for configuration normalization and event config
common/src/test/java/org/tron/core/config/args/*.java, framework/src/test/java/org/tron/core/config/args/ArgsTest.java
Updated test assertions for renamed getters (allowPbft/pbftExpireNum). Added test for empty topics list. Removed OverlayTest. Event config tests explicitly call applyEventConfig(). Added regression test for CLI --es flag.
Tests for rate-limiter dispatch and JSON-RPC validation
framework/src/test/java/org/tron/core/services/http/RateLimiterServletTest.java, framework/src/test/java/org/tron/core/services/ratelimiter/*.java, framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java
Added comprehensive acquirePermit dispatch tests (non-blocking vs blocking behavior). Updated servlet/interceptor test mocks. GlobalRateLimiter tests verify acquire order and failure scenarios. 12 new JsonRpcServletTest cases validate content-type, primitive roots, batch handling, and StreamReadConstraints.
Tests for event plugin versioning and miscellaneous updates
framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java, framework/src/test/java/org/tron/core/net/messagehandler/ChainInventoryMsgHandlerTest.java, framework/src/test/java/org/tron/common/ParameterTest.java, framework/src/main/java/org/tron/core/net/peer/PeerConnection.java
EventLoaderTest adds plugin version support coverage with mocked descriptors. ChainInventoryMsgHandlerTest adds JUnit lifecycle hooks for Args setup/cleanup. ParameterTest updated to assert event config instead of overlay. PeerConnection adds null-check for relayNodes.
Configuration and framework documentation updates
framework/src/main/resources/config.conf
Documented rate.limiter apiNonBlocking flag behavior (immediate rejection vs blocking). Updated VM timeout default documentation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A rabbit hops through config trees,

Where keys now nest with camelCase ease,

The rate-limiter learns to pause or rush,

JSON-RPC guards against the crush,

Version gates keep plugins in their place! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 36.92% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ci(config): enforce lowerCamelCase and max depth in reference.conf' accurately and concisely summarizes the main change: a CI validation gate that enforces lowerCamelCase naming and maximum depth constraints on configuration keys.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/ci_conf

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 559 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="common/build.gradle">

<violation number="1" location="common/build.gradle:24">
P2: Avoid using a SNAPSHOT dependency in `api`; it makes builds non-reproducible and can introduce unexpected changes without code updates.</violation>
</file>

<file name="chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java">

<violation number="1" location="chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java:233">
P1: `validateMerkleRoot()` memoizes success but never invalidates it when the block is mutated, so later merkle-root mismatches can be skipped.</violation>
</file>

Note: This PR contains a large number of files. cubic only reviews up to 100 files per PR, so some files may not have been reviewed. cubic prioritizes the most important files to review.
On a pro plan you can use ultrareview for larger PRs.

Re-trigger cubic

}

public void validateMerkleRoot() throws BadBlockException {
if (merkleValidated) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: validateMerkleRoot() memoizes success but never invalidates it when the block is mutated, so later merkle-root mismatches can be skipped.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At chainbase/src/main/java/org/tron/core/capsule/BlockCapsule.java, line 233:

<comment>`validateMerkleRoot()` memoizes success but never invalidates it when the block is mutated, so later merkle-root mismatches can be skipped.</comment>

<file context>
@@ -225,6 +229,19 @@ public Sha256Hash calcMerkleRoot() {
   }
 
+  public void validateMerkleRoot() throws BadBlockException {
+    if (merkleValidated) {
+      return;
+    }
</file context>

Comment thread common/build.gradle
api 'org.aspectj:aspectjweaver:1.9.8'
api 'org.aspectj:aspectjtools:1.9.8'
api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{
api group: 'com.github.tronprotocol', name: 'libp2p', version: 'release-v2.2.8-SNAPSHOT',{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Avoid using a SNAPSHOT dependency in api; it makes builds non-reproducible and can introduce unexpected changes without code updates.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At common/build.gradle, line 24:

<comment>Avoid using a SNAPSHOT dependency in `api`; it makes builds non-reproducible and can introduce unexpected changes without code updates.</comment>

<file context>
@@ -21,7 +21,8 @@ dependencies {
     api 'org.aspectj:aspectjweaver:1.9.8'
     api 'org.aspectj:aspectjtools:1.9.8'
-    api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{
+    api group: 'com.github.tronprotocol', name: 'libp2p', version: 'release-v2.2.8-SNAPSHOT',{
+    //api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{
         exclude group: 'io.grpc', module: 'grpc-context'
</file context>
Suggested change
api group: 'com.github.tronprotocol', name: 'libp2p', version: 'release-v2.2.8-SNAPSHOT',{
api group: 'io.github.tronprotocol', name: 'libp2p', version: '2.2.7',{

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java (1)

22-27: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use an ephemeral port in launchNativeQueue test to remove CI flakiness.

Line 25 hardcodes 5555, and the current pipeline already fails with Errno 48: Address already in use. Pick a free ephemeral port at runtime instead.

Suggested fix
+import java.io.IOException;
+import java.net.ServerSocket;
...
   `@Test`
   public void launchNativeQueue() {
     EventPluginConfig config = new EventPluginConfig();
     config.setSendQueueLength(1000);
-    config.setBindPort(5555);
+    config.setBindPort(findFreePort());
     config.setUseNativeQueue(true);
...
   }
+
+  private static int findFreePort() {
+    try (ServerSocket socket = new ServerSocket(0)) {
+      return socket.getLocalPort();
+    } catch (IOException e) {
+      throw new AssertionError("Unable to allocate a free test port", e);
+    }
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java`
around lines 22 - 27, The test launchNativeQueue hardcodes port 5555 via
EventPluginConfig.setBindPort(5555), causing CI flakiness; change it to pick an
ephemeral free port at runtime by opening a ServerSocket on port 0 to obtain the
assigned port (socket.getLocalPort()), close the socket and then call
config.setBindPort(foundPort) so the test uses a free ephemeral port; update
launchNativeQueue to use this dynamic port acquisition before starting the
native queue.
framework/src/main/resources/config.conf (1)

744-754: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align constantCallTimeoutMs docs with zero-allowed behavior.

Line 747 says the value must be positive, but Line 753 sets default to 0 and current validation accepts 0. Please make this wording consistent to avoid operator confusion.

Suggested doc fix
-  # routed through the constant-call path. When set, must be a positive
-  # integer that fits VM deadline conversion and is used verbatim as the
+  # routed through the constant-call path. When set, must be a non-negative
+  # integer that fits VM deadline conversion and is used verbatim as the
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@framework/src/main/resources/config.conf` around lines 744 - 754, The docs
for the config property constantCallTimeoutMs are inconsistent: the text
currently says "must be a positive integer" but the default and validation allow
0; update the wording to state it accepts zero (e.g., "must be a non-negative
integer (0 disables sharing and uses a per-call deadline)") or "must be an
integer ≥ 0" and mention the default is 0 so operators aren't confused; ensure
the change is applied to the constantCallTimeoutMs description in config.conf.
🧹 Nitpick comments (1)
common/src/main/java/org/tron/core/config/args/NodeConfig.java (1)

452-468: 💤 Low value

Potential exception if discovery.external.ip path is missing.

getIsNull(externalIpPath) on line 463 will throw ConfigException.Missing if the path doesn't exist in the config. While reference.conf guarantees this path exists, a defensive hasPath check would prevent failures from malformed user configs.

Suggested defensive check
 private static Config normalizeNonStandardKeys(Config section) {
     if (section.hasPath("isOpenFullTcpDisconnect")) {
         section = section.withValue("openFullTcpDisconnect",
             section.getValue("isOpenFullTcpDisconnect"));
     }
     String externalIpPath = "discovery.external.ip";
-    if (section.getIsNull(externalIpPath)
+    if (!section.hasPath(externalIpPath)
+        || section.getIsNull(externalIpPath)
         || "null".equalsIgnoreCase(section.getString(externalIpPath))) {
         section = section.withValue(externalIpPath, ConfigValueFactory.fromAnyRef(""));
     }
     return section;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@common/src/main/java/org/tron/core/config/args/NodeConfig.java` around lines
452 - 468, normalizeNonStandardKeys can throw ConfigException.Missing when
"discovery.external.ip" is absent; guard the null/string check with a hasPath
check. Modify normalizeNonStandardKeys to first check
section.hasPath("discovery.external.ip") before calling section.getIsNull(...)
or section.getString(...), and only call withValue(...) to replace the value
when the path exists and is null or equals "null" (case-insensitive); keep the
existing handling for "isOpenFullTcpDisconnect" unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@framework/src/main/java/org/tron/core/services/ratelimiter/strategy/IPQpsStrategy.java`:
- Around line 29-35: The current IPQpsStrategy.acquire method calls
limiter.acquire() which can block indefinitely; change it to use a bounded call
limiter.tryAcquire(timeout, unit) and return false on timeout so threads don't
starve. Inside IPQpsStrategy.acquire, after obtaining the RateLimiter from
loadLimiter(ip), replace the blocking limiter.acquire() with
limiter.tryAcquire(<configuredTimeout>, <TimeUnit>) (use an existing
timeout/config property or add a private field like rateLimiterTimeout and
TimeUnit.MILLISECONDS) and if tryAcquire returns false then return false;
otherwise proceed and return true. Ensure behavior respects the
isRateLimiterApiNonBlocking flag (when non-blocking is required, use a short
timeout and fail fast) and reference the methods loadLimiter and acquire in your
change.

In
`@framework/src/main/java/org/tron/core/services/ratelimiter/strategy/QpsStrategy.java`:
- Around line 33-35: Replace the indefinite blocking call in
QpsStrategy.acquire() with a bounded wait: use rateLimiter.tryAcquire(timeout,
unit) (following the same timeout/unit used by GlobalPreemptibleStrategy) and
return false when tryAcquire times out; ensure the method returns true only on
successful acquisition and mirrors the non-blocking behavior when apiNonBlocking
is false by respecting the same timeout policy as GlobalPreemptibleStrategy.

---

Outside diff comments:
In `@framework/src/main/resources/config.conf`:
- Around line 744-754: The docs for the config property constantCallTimeoutMs
are inconsistent: the text currently says "must be a positive integer" but the
default and validation allow 0; update the wording to state it accepts zero
(e.g., "must be a non-negative integer (0 disables sharing and uses a per-call
deadline)") or "must be an integer ≥ 0" and mention the default is 0 so
operators aren't confused; ensure the change is applied to the
constantCallTimeoutMs description in config.conf.

In `@framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java`:
- Around line 22-27: The test launchNativeQueue hardcodes port 5555 via
EventPluginConfig.setBindPort(5555), causing CI flakiness; change it to pick an
ephemeral free port at runtime by opening a ServerSocket on port 0 to obtain the
assigned port (socket.getLocalPort()), close the socket and then call
config.setBindPort(foundPort) so the test uses a free ephemeral port; update
launchNativeQueue to use this dynamic port acquisition before starting the
native queue.

---

Nitpick comments:
In `@common/src/main/java/org/tron/core/config/args/NodeConfig.java`:
- Around line 452-468: normalizeNonStandardKeys can throw
ConfigException.Missing when "discovery.external.ip" is absent; guard the
null/string check with a hasPath check. Modify normalizeNonStandardKeys to first
check section.hasPath("discovery.external.ip") before calling
section.getIsNull(...) or section.getString(...), and only call withValue(...)
to replace the value when the path exists and is null or equals "null"
(case-insensitive); keep the existing handling for "isOpenFullTcpDisconnect"
unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7e7decea-1803-4ee3-a394-a842f0902d1d

📥 Commits

Reviewing files that changed from the base of the PR and between 6b57a43 and 2e2f3e0.

📒 Files selected for processing (46)
  • .github/scripts/check_reference_conf.py
  • .github/workflows/pr-check.yml
  • codecov.yml
  • common/src/main/java/org/tron/common/parameter/CommonParameter.java
  • common/src/main/java/org/tron/core/config/args/CommitteeConfig.java
  • common/src/main/java/org/tron/core/config/args/EventConfig.java
  • common/src/main/java/org/tron/core/config/args/NodeConfig.java
  • common/src/main/java/org/tron/core/config/args/Overlay.java
  • common/src/main/java/org/tron/core/config/args/RateLimiterConfig.java
  • common/src/main/java/org/tron/core/config/args/Storage.java
  • common/src/main/java/org/tron/core/config/args/StorageConfig.java
  • common/src/main/java/org/tron/core/config/args/VmConfig.java
  • common/src/main/resources/reference.conf
  • common/src/test/java/org/tron/core/config/args/CommitteeConfigTest.java
  • common/src/test/java/org/tron/core/config/args/EventConfigTest.java
  • common/src/test/java/org/tron/core/config/args/NodeConfigTest.java
  • common/src/test/java/org/tron/core/config/args/RateLimiterConfigTest.java
  • common/src/test/java/org/tron/core/config/args/VmConfigTest.java
  • framework/src/main/java/org/tron/common/logsfilter/EventPluginLoader.java
  • framework/src/main/java/org/tron/core/config/args/Args.java
  • framework/src/main/java/org/tron/core/net/peer/PeerConnection.java
  • framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java
  • framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/GlobalRateLimiter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/RateLimiterInterceptor.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/adapter/DefaultBaseQqsAdapter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/adapter/GlobalPreemptibleAdapter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/adapter/IPQPSRateLimiterAdapter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/adapter/IRateLimiter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/adapter/QpsRateLimiterAdapter.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/strategy/GlobalPreemptibleStrategy.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/strategy/IPQpsStrategy.java
  • framework/src/main/java/org/tron/core/services/ratelimiter/strategy/QpsStrategy.java
  • framework/src/main/java/org/tron/program/FullNode.java
  • framework/src/main/resources/config.conf
  • framework/src/test/java/org/tron/common/ParameterTest.java
  • framework/src/test/java/org/tron/common/logsfilter/EventLoaderTest.java
  • framework/src/test/java/org/tron/core/config/args/ArgsTest.java
  • framework/src/test/java/org/tron/core/config/args/OverlayTest.java
  • framework/src/test/java/org/tron/core/net/messagehandler/ChainInventoryMsgHandlerTest.java
  • framework/src/test/java/org/tron/core/services/http/RateLimiterServletTest.java
  • framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java
  • framework/src/test/java/org/tron/core/services/ratelimiter/GlobalRateLimiterTest.java
  • framework/src/test/java/org/tron/core/services/ratelimiter/RateLimiterInterceptorTest.java
  • framework/src/test/java/org/tron/core/services/ratelimiter/adaptor/AdaptorTest.java
  • protocol/src/main/protos/api/api.proto
💤 Files with no reviewable changes (7)
  • protocol/src/main/protos/api/api.proto
  • common/src/main/java/org/tron/core/config/args/Overlay.java
  • framework/src/test/java/org/tron/core/config/args/OverlayTest.java
  • common/src/main/java/org/tron/core/config/args/Storage.java
  • codecov.yml
  • common/src/test/java/org/tron/core/config/args/NodeConfigTest.java
  • framework/src/test/java/org/tron/common/ParameterTest.java

Comment on lines +29 to +35
public boolean acquire(String ip) {
RateLimiter limiter = loadLimiter(ip);
if (limiter == null) {
return false;
}
limiter.acquire();
return true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -name "IPQpsStrategy.java" -type f

Repository: bladehan1/java-tron

Length of output: 152


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/strategy/IPQpsStrategy.java

Repository: bladehan1/java-tron

Length of output: 2365


🏁 Script executed:

rg "\.acquire\(" --type java -B2 -A2 | head -100

Repository: bladehan1/java-tron

Length of output: 9431


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/GlobalRateLimiter.java

Repository: bladehan1/java-tron

Length of output: 2558


🏁 Script executed:

rg "acquirePermit\|\.acquire\(" --type java -l | head -20

Repository: bladehan1/java-tron

Length of output: 45


🏁 Script executed:

rg "acquirePermit" --type java -B2 -A2 | head -80

Repository: bladehan1/java-tron

Length of output: 8920


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/http/RateLimiterServlet.java

Repository: bladehan1/java-tron

Length of output: 7551


🏁 Script executed:

find . -name "IRateLimiter.java" -type f

Repository: bladehan1/java-tron

Length of output: 150


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/adapter/IRateLimiter.java

Repository: bladehan1/java-tron

Length of output: 612


🏁 Script executed:

rg "isRateLimiterApiNonBlocking" --type java -B2 -A2 | head -40

Repository: bladehan1/java-tron

Length of output: 1258


🏁 Script executed:

rg "RateLimiter" --type java | grep -i "import\|timeout\|tryacquire" | head -20

Repository: bladehan1/java-tron

Length of output: 2955


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/adapter/IPQPSRateLimiterAdapter.java

Repository: bladehan1/java-tron

Length of output: 845


🌐 Web query:

Guava RateLimiter tryAcquire timeout semantics API documentation

💡 Result:

The Guava RateLimiter tryAcquire method with timeout parameters is designed to attempt to acquire a specified number of permits within a defined time limit [1][2][3]. Its semantics are as follows: 1. Acquisition Attempt: The method attempts to acquire the requested number of permits from the RateLimiter [1][2][3]. 2. Timeout Behavior: If the permits can be obtained without exceeding the specified timeout, the method acquires them and returns true [1][2][3]. If the permits cannot be granted before the timeout expires, the method returns false immediately without waiting further [1][2][3]. 3. Negative Timeouts: Any negative timeout values provided to the method are treated as zero, meaning the method will return false immediately if the permits are not available at that exact moment [1][2][3]. 4. Overloads: - tryAcquire(long timeout, TimeUnit unit): Attempts to acquire a single permit within the specified timeout [1][2][3]. - tryAcquire(int permits, long timeout, TimeUnit unit): Attempts to acquire the specified number of permits within the specified timeout [1][2][3]. - tryAcquire(Duration timeout): A more modern alternative (available since Guava 28.0) that accepts a java.time.Duration object [1][3]. The method is non-blocking in the sense that it will not wait longer than the specified duration, providing a mechanism to avoid indefinite blocking when permits are unavailable [1][2][3].

Citations:


Replace unbounded RateLimiter.acquire() with bounded tryAcquire(timeout, unit) to prevent thread starvation.

Line 34 calls RateLimiter.acquire(), which blocks indefinitely. When blocking mode is enabled (via isRateLimiterApiNonBlocking=false), this exhausts servlet worker threads during sustained overload. Use tryAcquire(timeout, unit) to fail fast on timeout.

Suggested patch
 public class IPQpsStrategy extends Strategy {
+  public static final int DEFAULT_ACQUIRE_TIMEOUT_SECONDS = 2;
@@
   public boolean acquire(String ip) {
     RateLimiter limiter = loadLimiter(ip);
     if (limiter == null) {
       return false;
     }
-    limiter.acquire();
-    return true;
+    return limiter.tryAcquire(DEFAULT_ACQUIRE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@framework/src/main/java/org/tron/core/services/ratelimiter/strategy/IPQpsStrategy.java`
around lines 29 - 35, The current IPQpsStrategy.acquire method calls
limiter.acquire() which can block indefinitely; change it to use a bounded call
limiter.tryAcquire(timeout, unit) and return false on timeout so threads don't
starve. Inside IPQpsStrategy.acquire, after obtaining the RateLimiter from
loadLimiter(ip), replace the blocking limiter.acquire() with
limiter.tryAcquire(<configuredTimeout>, <TimeUnit>) (use an existing
timeout/config property or add a private field like rateLimiterTimeout and
TimeUnit.MILLISECONDS) and if tryAcquire returns false then return false;
otherwise proceed and return true. Ensure behavior respects the
isRateLimiterApiNonBlocking flag (when non-blocking is required, use a short
timeout and fail fast) and reference the methods loadLimiter and acquire in your
change.

Comment on lines +33 to +35
public boolean acquire() {
rateLimiter.acquire();
return true;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

find . -type f -name "QpsStrategy.java" | head -20

Repository: bladehan1/java-tron

Length of output: 150


🏁 Script executed:

find . -type f -name "GlobalPreemptibleStrategy.java" | head -20

Repository: bladehan1/java-tron

Length of output: 164


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/strategy/QpsStrategy.java

Repository: bladehan1/java-tron

Length of output: 1418


🏁 Script executed:

cat -n ./framework/src/main/java/org/tron/core/services/ratelimiter/strategy/GlobalPreemptibleStrategy.java

Repository: bladehan1/java-tron

Length of output: 2066


🏁 Script executed:

rg "\.acquire\(\)" --type java | grep -i qps

Repository: bladehan1/java-tron

Length of output: 410


🏁 Script executed:

rg "QpsStrategy" --type java -A 3 -B 3 | head -50

Repository: bladehan1/java-tron

Length of output: 5896


🌐 Web query:

Guava RateLimiter tryAcquire timeout TimeUnit API

💡 Result:

The Guava RateLimiter class provides the tryAcquire method with timeout support to allow threads to attempt to acquire permits without blocking indefinitely [1][2][3]. API Signatures The RateLimiter class offers two primary overloaded methods for acquiring permits with a timeout [1][2]: 1. boolean tryAcquire(long timeout, TimeUnit unit): Attempts to acquire a single permit within the specified timeout [1][4]. 2. boolean tryAcquire(int permits, long timeout, TimeUnit unit): Attempts to acquire the specified number of permits within the specified timeout [1][2]. Behavior - If the requested permit(s) can be acquired before the timeout expires, the method returns true [1][3]. - If the permit(s) cannot be acquired within the specified timeout, the method returns false immediately upon the expiration of that duration [1][2]. - Negative timeout values are treated as zero, meaning the method will return false immediately if no permits are currently available [1][2][4]. - The method is thread-safe [5]. Example Usage The following example demonstrates how to use tryAcquire to avoid indefinite blocking [3]: RateLimiter rateLimiter = RateLimiter.create(1.0); // 1 permit per second boolean acquired = rateLimiter.tryAcquire(1, 500, TimeUnit.MILLISECONDS); if (acquired) { // Proceed with the task } else { // Handle the case where the permit could not be acquired in time } Important Considerations When using tryAcquire, ensure that the timeout duration is appropriate for your application's latency requirements [6]. If the timeout is set too high, the thread may block for longer than expected, potentially leading to thread pool exhaustion or increased response times under high load [6][7]. Conversely, if the timeout is too short, you may experience a high rate of false returns even when the system is operating within its configured limits [6].

Citations:


Use bounded wait instead of indefinite RateLimiter.acquire().

The acquire() method blocks indefinitely, which can stall request-handling threads under sustained rate pressure when apiNonBlocking=false. Use bounded tryAcquire(timeout, unit) and return false on timeout, matching the pattern in GlobalPreemptibleStrategy.

Suggested patch
 import com.google.common.util.concurrent.RateLimiter;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.concurrent.TimeUnit;
@@
 public class QpsStrategy extends Strategy {
@@
+  public static final int DEFAULT_ACQUIRE_TIMEOUT_SECONDS = 2;
@@
   public boolean acquire() {
-    rateLimiter.acquire();
-    return true;
+    return rateLimiter.tryAcquire(DEFAULT_ACQUIRE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public boolean acquire() {
rateLimiter.acquire();
return true;
public boolean acquire() {
return rateLimiter.tryAcquire(DEFAULT_ACQUIRE_TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@framework/src/main/java/org/tron/core/services/ratelimiter/strategy/QpsStrategy.java`
around lines 33 - 35, Replace the indefinite blocking call in
QpsStrategy.acquire() with a bounded wait: use rateLimiter.tryAcquire(timeout,
unit) (following the same timeout/unit used by GlobalPreemptibleStrategy) and
return false when tryAcquire times out; ensure the method returns true only on
successful acquisition and mirrors the non-blocking behavior when apiNonBlocking
is false by respecting the same timeout policy as GlobalPreemptibleStrategy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants