Node operations issues

Diagnostic flows for the operational issues node operators hit most often — slow or stopped sync, faster startup, conditional shutdown at a block height, JVM and TCP-traffic tuning, the different resultCode sync error, and the --debug 80 ms bypass.

📘

Prerequisites

This page covers operational issues you encounter when running a TRON full node — slow or stuck block sync, JVM and OS-level tuning, conditional shutdown, the sync-stopping different resultCode error, and the debug-mode bypass for the 80 ms execution time limit.

For deployment basics (hardware, JDK choice, starting and stopping a node), see Deploy a node. For database utilities (Lite Fullnode pruning, engine conversion, LevelDB startup pre-warm), see Node maintenance toolkit.


Slow or stopped block sync

A running node falls behind Mainnet or stops applying new blocks. Three things to check in order:

1. Hardware

Recommended: 16-core CPU, 32 GB RAM, 1 TB SSD. Below that, the node may stop syncing when the chain hits a complex contract call. Verify your physical core count:

$ cat /proc/cpuinfo | grep -e "cpu cores" -e "siblings" | sort | uniq
cpu cores : 8
siblings  : 16

Both cpu cores and siblings should be ≥ 16 on production. See Deploy a node — hardware requirements for the full table.

2. Verification time tolerance

If hardware is borderline, raise the transaction-verification time tolerance in config.conf:

vm = {
  supportConstant = false
  minTimeRatio = 0.0
  maxTimeRatio = 20.0            # raise to 50 on very slow hardware
  saveInternalTx = false
}

maxTimeRatio multiplies the 80 ms execution budget at the verification stage — a higher value lets slow nodes accept blocks containing heavy contract calls that would otherwise time out locally.

3. JVM heap and GC

Make sure GC and heap are sized correctly:

# JDK 8
java -Xmx24g -XX:+UseConcMarkSweepGC -jar FullNode.jar -c config.conf

# JDK 17+ — CMS was removed in JDK 14, use G1GC instead
java -Xmx24g -XX:+UseG1GC -jar FullNode.jar -c config.conf
  • -Xmx70 % of physical RAM, never exceeding it. A 16 GB host uses -Xmx12g, not -Xmx24g.
  • GC option must come before -jar.

See Deploy a node — JVM flags for the full set of recommended flags.


Speed up node startup

For nodes using LevelDB, the LevelDB Startup Optimization Tool (shipped with the Toolkit JAR) pre-warms the manifest file and LevelDB metadata to reduce startup time and initial memory usage.

See the Node maintenance toolkit for the full toolkit utility list, and the Toolkit User Guide — LevelDB Startup Optimization Tool for the exact CLI invocation.

This optimization is most useful when:

  • You restart the node frequently (development / staging deployments)
  • Startup time is dominated by LevelDB compaction or recovery passes

Stop the node at a specific block height

For data backup or query-only operations, configure automatic shutdown in config.conf:

node {
  shutdown {
    # Stop at a specific time (Quartz expression)
    BlockTime  = "54 59 08 * * ?"

    # Stop at a specific block height
    BlockHeight = 33350800

    # Stop after syncing N blocks since startup
    BlockCount = 12
  }
}

Only one of the three options can be set at a time. Setting multiple causes the node to fail to start with an error.

Once the node stops, you can back up output-directory or restart the node in query-only mode.

Query-only mode after shutdown

After the conditional shutdown, restart with --p2p-disable true to serve queries without rejoining P2P:

java -jar FullNode.jar -c config.conf --p2p-disable true

In this mode the node does not participate in peer discovery or block sync, but the HTTP and gRPC API surface continues to work — so you can query the snapshot state without it advancing. See Deploy a node — read-only query node.


Network stability and resource usage control

For nodes that face abnormal traffic or run on memory-constrained hardware, two operational levers help control resource consumption.

Cap JVM direct memory

Set the MaxDirectMemorySize JVM parameter to bound off-heap (direct) memory. A common rule of thumb: one-quarter of physical RAM.

# 16 GB host → 4 GB direct memory cap
java -XX:MaxDirectMemorySize=4g -jar FullNode.jar -c config.conf

Without this cap, direct memory can grow until the OS kills the process, producing hard-to-diagnose crashes.

Throttle TCP traffic with iptables

Use the kernel hashlimit module to bound inbound and outbound TCP rates. Two example rules — adjust the numeric thresholds to your bandwidth budget:

Outbound — limit per-destination-IP rate:

iptables -A OUTPUT -p tcp -m hashlimit \
  --hashlimit-name out_limit \
  --hashlimit-mode dstip \
  --hashlimit-above 15mb/sec \
  --hashlimit-burst 30mb \
  -j DROP

This caps outbound traffic to each destination IP at 15 MB/s steady-state with a 30 MB burst window.

Inbound — limit per-source-IP rate on the P2P port:

iptables -A INPUT -p tcp --dport 18888 -m hashlimit \
  --hashlimit-name in_limit \
  --hashlimit-mode srcip,dstport \
  --hashlimit-above 300/sec \
  --hashlimit-burst 600 \
  -j DROP

This caps incoming TCP packets to port 18888 (default P2P listen port) from any single source IP at 300 packets/sec with a 600-packet burst window.

hashlimit parameters:

ParameterMeaning
--hashlimit-nameInternal label so you can identify the rule
--hashlimit-modeBucket dimension: srcip, dstip, or combinations like srcip,dstport
--hashlimit-aboveSteady-state rate above which packets match
--hashlimit-burstBurst tolerance above the steady-state rate
-jAction to take when matched (commonly DROP)

different resultCode — sync stops mid-block

When tron.log contains different resultCode, the local node executed a transaction and produced a result different from what the block records. The node refuses to accept the block, halting sync.

The message is emitted from TransactionTrace.java:345. Older java-tron versions logged it from Manager.java, so existing logs may show different file:line locations — the message format (and the diagnosis) is stable. Three common patterns:

Expected: SUCCESS; Actual: OUT_OF_TIME

ERROR [sync-handle-block] different resultCode
  txId: ae53f8a6394d7adcc2337e0e71724f520818161cbb1f6f5d556f873b08e17c99,
  expect: SUCCESS, actual: OUT_OF_TIME

Cause: the local node took longer than the 80 ms budget to execute the transaction. The producing SR did not — typically because the local hardware is slower.

Fix: meet the hardware recommendation (16 cores minimum). On borderline hardware, raise the verification time tolerance:

vm.maxTimeRatio = 50

Restart the node to apply.

Expected: OUT_OF_ENERGY; Actual: SUCCESS

ERROR [pool-48-thread-1] different resultCode
  txId: fbe7109a993b52243dc4de4087967cebc74be739d725dc27e96eb757496bd359,
  expect: OUT_OF_ENERGY, actual: SUCCESS

Cause: local databases are inconsistent — transactions that should have failed are marked as successful. Typically caused by an unclean shutdown, hardware fault, or other database corruption.

Fix: download the latest database snapshot, wipe output-directory, restore from the snapshot, and restart. Doing this re-grounds every database against a known-consistent baseline.

Expected: OUT_OF_TIME; Actual: SUCCESS

ERROR [sync-handle-block] different resultCode
  txId: 4ccf1feb7da348cef4190bc5d84d09d3c37160bfbdd21a0b5fd0b1d5005ead09,
  expect: OUT_OF_TIME, actual: SUCCESS

Cause: the node was started with the --debug flag, which bypasses the 80 ms execution-time check. Transactions that should have timed out are instead executed successfully locally — diverging from the block record.

Fix: remove --debug from the start-up command and restart. The node will resume normal sync.


Bypass 80 ms execution time limit for testing

The 80 ms per-transaction execution budget is enforced by default (chain parameter #13, getMaxCpuTimeOfOneTx). For certain testing scenarios — heavy-computation view/pure queries, profiling experiments — you may want to bypass the check temporarily.

Start the node with the --debug flag:

java -jar FullNode.jar -c config.conf --debug

The node skips the 80 ms timeout check when processing transactions, with no execution-time restriction. You can then use /wallet/triggerconstantcontract for queries that would otherwise time out.

🚧

Do not run --debug on a Mainnet-syncing node.

Any block containing a transaction whose expected result is OUT_OF_TIME will execute locally with a different outcome (SUCCESS), causing a different resultCode error and stopping sync. See the previous section for the symptom.

For testing complex contracts or long-running transactions, set up a private chain instead — see TRON private chain.


Related resources