Skip to content

fix: JVM heap headroom, in-container HTTP port conflicts, and ssh probe tunneling - #218

Merged
kuny0707 merged 5 commits into
tronprotocol:developfrom
warku123:fix/tx167-high-bugs
Aug 20, 2026
Merged

fix: JVM heap headroom, in-container HTTP port conflicts, and ssh probe tunneling#218
kuny0707 merged 5 commits into
tronprotocol:developfrom
warku123:fix/tx167-high-bugs

Conversation

@warku123

Copy link
Copy Markdown

Summary

Found during end-to-end functional testing of trond (TX-167). Three high-severity fixes plus one CI chore:

  1. JVM heap headroom below 8GBresources.memory < 8GB produced -Xmx equal to the container limit (the tier table floors at 2g), and the image's ZGC with Xms=Xmx then crash-loops with Failed to commit memory. Heap is now capped at 50% of container memory below 8GB (2GB→1024m, 3GB→1536m; ≥8GB tiers unchanged), jvm.heap_max override still wins, and preflight warns on <8GB nodes referencing java-tron's ALLOW_MIN_MEMORY=8192 guidance.

  2. In-container HTTP port conflicts rejected early — a fullnode with ports.http: 8091 (as shipped in examples/private-network.yaml) collided in-container with the template's fixed solidityPort: 8091 (and PBFTPort), crash-looping the node. Render and config validate now refuse such intents with VALIDATION_ERROR/RENDER_ERROR and suggestions; the example moves the fullnode to host port 8095 with an explanatory comment.

  3. Probe ssh nodes through the ssh tunnel — HTTP/TCP probes for ssh targets either exec'd remote curl (rejected by the ssh allowlist) or dialed 127.0.0.1 from the operator machine, so verify/health/diagnose port_listening/MCP health failed against healthy remote nodes. Adds a Dialer capability to targets (ssh → direct-tcpip over the existing connection, local → net.Dialer) and routes every probe through a target-aware client; api_endpoints now report the real target host instead of hard-coded loopback.

  4. CI chore — pause tag-triggered releases (manual workflow_dispatch only) until the release-CI work tracked in TX-167 lands; PR snapshot workflow and .goreleaser.yaml untouched.

Test plan

  • go build ./... && go test ./... — all packages green (new table-driven tests: heap tiers, port-conflict validation, ssh/local dialers, HTTP client fallback)
  • End-to-end functional run: private 2-node network (create → sync → chaos partition/heal → destroy), java-tron source build with cache hit, Nile snapshot download → clone → shadow-fork, ssh-target node lifecycle on a firewalled remote host

The tiered heap table returned -Xmx2g for any resources.memory < 8GB,
which equals the container limit verbatim (compose.go) — with the image's
forced ZGC (Xms=Xmx) there is zero headroom and the JVM crash-loops with
'Failed to commit memory'. Below 8GB now cap -Xmx at floor(total/2) in MB
(2GB->1024m, 3GB->1536m, 4GB->2g). jvm.heap_max still bypasses verbatim.
Also fix the 1GB edge where -Xmn equaled -Xmx leaving zero old gen
(512m heap now gets 128m new). Found in TX-167 functional testing.
…BFT)

ports.http: 8091 rendered fullNodePort = solidityPort = 8091 because
solidityPort defaulted to 8091 independently of ports.http — the shipped
examples/private-network.yaml crash-looped its fullnode on bind conflict
(HttpApiOnSolidityService, then HttpApiOnPBFTService once that was moved).

RenderHOCON now bumps solidityPort/PBFTPort by +2 when they equal
fullNodePort, with a >65535 overflow guard. Explicitness is judged by
config_overrides only: ApplyDefaults pre-fills ports.solidity_http before
render, so checking the intent field made the avoidance dead code in the
real pipeline (caught in review, with an intent.Parse end-to-end
regression test to pin it). Bumps only de-conflict the three node.http
keys; cross-family clashes with grpc/p2p/jsonrpc/metrics are out of scope
(documented in the function comment).

The example also sets ports.solidity_http: 8093 explicitly. Found in
TX-167 functional testing.
…endpoints

verify/health/diagnose/wait and MCP health probed ssh nodes either via
t.Exec('curl') — rejected by the ssh command allowlist — or by dialing
127.0.0.1 from the trond host, bypassing ssh entirely. On a firewalled
target (22 only) every liveness/sync probe failed while the node was
healthy; status/apply/inspect also reported endpoints as 127.0.0.1.

internal/target now offers a target-aware transport: an optional Dialer
interface (SSHTarget.DialContext = direct-tcpip over the existing ssh
client, restricted to loopback addrs; LocalTarget = net.Dialer), plus
HTTPClient/Get/Post/DialContext helpers with an enforceable timeout
(preemptable even when the underlying dial ignores ctx). Probes migrated:
verify, health, diagnose sync/peers/version/ports, apply LiveStatus jar
branch, wait --port/--http, MCP health. Endpoint reporting (status, apply
created/updated/no_change, inspect, network add/create, MCP status/
endpoints/monitoring, healthTool display) now uses EndpointHost so ssh
rigs report the target host. preflight checkPorts now dials through the
target too — it previously checked the local machine for ssh targets.

Found in TX-167 functional testing.
@kuny0707
kuny0707 merged commit 67dd808 into tronprotocol:develop Aug 20, 2026
11 checks passed
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.

3 participants