feat(tvm,api,config,ci)Release v4.8.2#16
Conversation
Signed-off-by: imalasong <imalasong@qq.com>
…,version code:18636 (tronprotocol#6542)
* fix readme typo and format
Removed 4 config files from framework/src/main/resources that were not referenced anywhere in the codebase: - config-backup.conf: no references - config-beta.conf: no references - config-test-net.conf: no references - config-localtest.conf: only used in tests, shadowed by src/test/resources/config-localtest.conf on the test classpath
…ronprotocol#6586) * test: add dual DB engine (LevelDB + RocksDB) test coverage
# Conflicts: # common/src/main/java/org/tron/core/Constant.java # framework/src/main/java/org/tron/core/config/args/Args.java
1. Change ALLOW_TVM_OSAKA proposal id from 95 to 96 2. DynamicPropertiesStore.getAllowTvmOsaka() defaults to CommonParameter 3. ModExp returns Pair.of(false, EMPTY_BYTE_ARRAY) instead of throwing PrecompiledContractException when inputs exceed 1024 bytes, matching geth/besu behavior where only the CALL fails (not the whole tx) 4. Update test to verify return value instead of catching exception
docs: fix shieldedTransaction typos in comments
- baseLen == 1024 boundary value should succeed - baseLen == 1025 just over limit should fail - oversized expLen only should fail - oversized modLen only should fail - all limits exceeded with osaka disabled should succeed
…onprotocol#6816) MerkleTree was a shared volatile singleton holding per-build mutable state (leaves/hashList/root). When merkle validation runs concurrently (e.g. pre-broadcast validation on the P2P handler threads alongside the apply path), concurrent calls mutated the shared leaves list and threw ArrayIndexOutOfBoundsException (surfaced on an ARM SR due to its weaker memory model), which escaped the BadBlockException catch and dropped peers. - MerkleTree: replace the getInstance() singleton with a static build() factory returning a thread-confined instance; drop the now-inaccurate @NotThreadSafe. - BlockCapsule.calcMerkleRoot: use MerkleTree.build(ids); keeps the config-driven hash engine, so no consensus behavior change. - MerkleTreeTest: switch call sites to build(); un-ignore testConcurrent and turn it into a regression test asserting 1000 concurrent builds succeed.
* feat(*): disable exchange transaction (tronprotocol#6507) * update a new version. version name:GreatVoyage-v4.8.0-1-g45e3bf88ca,version code:18634 (tronprotocol#6508) * Merge release_v4.8.1 to master (tronprotocol#6541) * update a new version. version name:GreatVoyage-v4.8.0.1-1-g44a4bc8263,version code:18636 (tronprotocol#6542) * feat(vm): optimize the check for create2 * feat(vm): optimize the check for ModExp * test(vm): add tests for create2/modExp checks * feat(version): update version to 4.8.1.1 * feat(ci): add PR pipeline and system-test workflows New workflows: - pr-build.yml: multi-OS build matrix (macOS, Ubuntu, RockyLinux, Debian11) and changed-line/overall coverage gate - pr-check.yml: PR title/body lint + Checkstyle - pr-reviewer.yml: scope-based reviewer auto-assignment - pr-cancel.yml: cancel in-progress runs when PR is closed unmerged - system-test.yml: spin up FullNode and run the system-test suite Existing workflows: - codeql.yml: bump to v4/v5 actions, switch to manual build-mode with JDK 8, add paths-ignore for docs-only changes - math-check.yml: bump checkout/upload-artifact/github-script versions * feat(config): fix git.properties NPE * update a new version. version name:GreatVoyage-v4.8.1-6-g52d7d9d23e,version code:18643 --------- Co-authored-by: YAaron <4241080+kuny0707@users.noreply.github.com> Co-authored-by: zz <aaa@bb.cc>
* feat(vm): check CREATE2 max depth under Osaka * feat(vm): clear residual logs on exception escape paths under Osaka Mirror the in-try failure path: failed txs must not leak event logs into TransactionInfo/Bloom. Gated on Osaka to preserve replay.
… triggers (tronprotocol#6833) On a chain reorg, BlockLogTrigger/TransactionLogTrigger subscribers previously never learned that an orphaned block's events were rolled back. Add the same "removed" semantics already used by ContractTrigger. - add a `removed` field to BlockLogTrigger/TransactionLogTrigger and the matching setRemoved() on their capsules - Manager (event version 0): refactor postBlockTrigger to emit a single real-time block (with removed), move the solidified-mode batch into postSolidityTrigger, add reOrgBlockTrigger to re-emit erased blocks with removed=true, rename reApplyLogsFilter to reApplyBlockEvents and re-emit the re-applied fork branch's block/tx triggers (forward), thread removed through processTransactionTrigger/postTransactionTrigger - RealtimeEventService (event version 1): post block/tx triggers synchronously to the plugin with the removed flag instead of the async triggerCapsuleQueue, avoiding overwrite of the shared cached capsule; drop the unused manager field - tests: capsule removed passthrough, version-0 emit (testReOrgBlockTriggerRemoved), rewritten RealtimeEventServiceTest, updated ManagerTest stub
Improve the hand-rolled JsonFormat parser used by HTTP wallet APIs so field-heavy and deeply nested JSON no longer overflows the request thread stack. mergeField now consumes one field per call and leaves comma iteration to the caller. JsonFormat also enforces Constant.MAX_NESTING_DEPTH for object/array descent and returns ParseException instead of allowing StackOverflowError to escape. Compatibility notes: direct JsonFormat.merge callers now reject nesting beyond 100 levels; trailing commas on known-field parse paths (top-level fields, known message fields, and known repeated fields) may be accepted, while trailing commas inside unknown nested object/array fields remain rejected; malicious deep-nesting requests now surface as parse errors instead of container-level HTTP 500s.
…l#6842) * fix(jsonrpc): enforce maxBlockRange on eth_getFilterLogs * style(jsonrpc): fix styles and comments
…tronprotocol#6851) Validate the inventory type at the inbound entry points and reject any value other than TRX or BLOCK with P2pException(BAD_MESSAGE), before the type is used for cache insertion or outbound fetch construction: - P2pEventHandlerImpl.checkInvRateLimit: add else branch for unknown type - InventoryMsgHandler.check: add type allowlist check - FetchInvDataMsgHandler.check: validate raw getInventoryType() instead of getInvMessageType() (which mapped non-BLOCK types to TRX) Use getTypeValue() when building the error message to avoid calling getNumber() on an UNRECOGNIZED enum value. Add regression tests for all three entry points. Co-authored-by: wb <wb@wbdeMacBook-Air.local>
tronprotocol#6857) * fix(vm): self-dispatch vote-witness cost by proposal flag getVoteWitnessCost3 falls back to cost2 when Osaka is off, and cost2 to the legacy cost when energy adjustment is off. The energy then stays correct even if a stale cost function lingers in the shared jump table after a reorg, or is read by a constant call whose view has the proposal off. * fix(vm): isolate constant-call config view to prevent global pollution Constant calls bound to a lagging solidity/PBFT snapshot loaded their flags into the process-global VMConfig, racing block processing during a proposal's activation-to-solidification window and risking a fork. Route a constant call's config into a thread-local snapshot; the block/broadcast path keeps writing (and reading) the global.
1. Treat known protobuf fields with literal null as absent so HTTP APIs recover the 4.8.1 fastjson-compatible behavior for null object fields. 2. This relaxes JSON-RPC buildTransaction ABI handling because that path now accepts null ABI fields instead of returning invalid abi. 3. TRON's JsonFormat now aligns more closely with protobuf Java JsonFormat: field-level null is treated as absent, while null elements inside repeated arrays remain invalid.
…tocol#6864) The switchFork new-branch apply loop only re-validated each block's witness signature; the transactions inside were applied through the isVerified cache. That flag caches a signature-verification result computed against a specific account-permission state, but a fork switch re-applies blocks on a rewound, diverged chain state where those permissions may have changed. Trusting the stale flag lets a transaction skip verification and be accepted with a signature no longer valid under the fork-chain state. - Manager.switchFork: clear isVerified on every transaction of each block on the branch being switched to, before applyBlock, forcing full signature re-validation against the fork-chain state. The switch-back path (original main branch) is left untouched: it reproduces the exact original state, so its cached verifications stay valid and resetting them would only cost perf. - ManagerTest: add switchForkShouldResetTransactionSignVerifiedOnNewBranch, which drives a real reorg and asserts the new branch's transaction gets its cached verification flag cleared (fails without the fix).
…_merge_master chore(release): record master merge into release_v4.8.2
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
| byte[] s = Arrays.copyOfRange(sign, 32, 64); | ||
| byte v = sign[64]; | ||
| if (v < 27) { | ||
| v += 27; //revId -> v |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 851575de48
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| batchResult.add(buildErrorNode(JsonRpcError.RESPONSE_TOO_LARGE, | ||
| "Response exceeds the limit of " + maxResponseSize + " bytes", | ||
| subRequest.get("id"))); |
There was a problem hiding this comment.
Keep overflow batch errors within the response cap
When node.jsonrpc.maxResponseSize is configured below the size of the accumulated batch plus the generated errors, this overflow path appends a -32003 object for every remaining request with an id without updating or rechecking accumulatedSize. A batch with many ids can therefore return a body much larger than the configured maximum, defeating the new response-size protection in the exact large-batch/overflow case.
Useful? React with 👍 / 👎.
What does this PR do?
GreatVoyage-v4.8.2 (Pyrrho) introduces several important optimizations and updates, centered on the theme of “protocol hardening, EVM compatibility, and improved API and operational experience”:
More robust core protocol: historical block hashes are provided from state via TIP-2935 (EIP-2935), improving friendliness toward stateless clients and L2.
TVM continues to align with Ethereum Osaka: adds the secp256r1 signature verification precompile (TIP-7951), the CLZ leading-zero count instruction (TIP-7939), sets an input upper bound for the MODEXP precompile (TIP-7823) and reprices it (TIP-7883), and standardizes the inputs of signature-verification precompiles (TIP-854).
More efficient, secure, and controllable APIs: rate limiting can optionally be non-blocking, HTTP and JSON-RPC parameter validation is enhanced, and API output is optimized.
Improved networking and operational experience: seed/active/passive and others support configuring domain names, InfluxDB is removed in favor of unifying on Prometheus, a configuration auto-binding mechanism is added, Toolkit subcommands are enriched, and more.
Upgrade type: Mandatory upgrade
Adapt to Ethereum Upgrade
GreatVoyage-v4.8.2 introduces at the TVM layer a set of execution capabilities aligned with Ethereum Osaka and Pectra. The related changes are all controlled by on-chain governance parameters; upgrading the node software itself does not automatically activate the new TVM semantics.
Osaka
TIP-7939: Add the CLZ (Count Leading Zeros) instruction
TVM adds the CLZ instruction (opcode 0x1e), which pops a 256-bit integer from the stack and returns the number of its leading zero bits; when the input is 0 it returns 256. The instruction has a fixed cost of 5 energy, in the same tier as MUL.
Compared with a simulated implementation in Solidity that costs roughly 184 gas and 110–160 bytes of bytecode, the native CLZ requires only a 1-byte instruction, reducing computation and ZK proof costs in scenarios such as fixed-point math, bitmap scanning, calldata compression, and post-quantum signatures. CTZ can be computed by first isolating the least significant bit via x & -x and then applying CLZ.
Ethereum EIP: EIP-7939: Count leading zeros (CLZ) opcode
TIP: TIP-7939: Count leading zeros (CLZ) opcode · Issue #838 · tronprotocol/tips
Source Code: tronprotocol#6656
The MODEXP precompile (address 0x…05) previously allowed its three length fields to take arbitrary values; unbounded inputs enlarged the test space of consensus implementations and have historically been a source of multiple consensus bugs. After Osaka activation, length_of_BASE, length_of_EXPONENT, and length_of_MODULUS must not exceed 8192 bit, i.e. 1024 bytes. If any length exceeds the limit, the precompile immediately returns an execution failure and consumes all energy allocated to the current precompile call frame; the caller receives a failure status, which the outer contract can continue to handle. This upper bound still covers RSA 8192-bit keys and elliptic-curve use cases that are typically smaller than 384 bits. Historical call analyses of both TRON and Ethereum show that no successful call had any single length field exceeding 513 bytes.
Ethereum EIP: https://eips.ethereum.org/EIPS/eip-7823
TIP: tronprotocol/tips#826
Source Code: tronprotocol#6611
Before Osaka, TVM followed the legacy pricing path based on EIP-198: it used a piecewise multiplication complexity and divided by GQUAD_DIVISOR = 20; this implementation was not EIP-2565 pricing and had no fixed minimum energy floor.
After Osaka activation, MODEXP switches to the TIP/EIP-7883 formula:
Minimum energy: 500.
Multiplication complexity: let maxLen = max(baseLen, modLen). When maxLen ≤ 32, multiplication_complexity = 16; otherwise, multiplication_complexity = 2 × ceil(maxLen / 8)².
Iteration count: when the exponent length exceeds 32 bytes, the multiplier is changed from 8 to 16.
Final pricing: energy = max(500, multiplication_complexity × iteration_count).
TIP-7883 directly replaces TVM’s legacy pricing formula, so the change relative to the old implementation depends on the specific input, and not all calls increase in price monotonically; for example, some test vectors drop from 665 to 512, while the energy of high-load edge inputs rises significantly. The input interface and modular exponentiation algorithm of MODEXP remain unchanged.
Ethereum EIP: https://eips.ethereum.org/EIPS/eip-7883
TIP: tronprotocol/tips#837
Source Code: tronprotocol#6654
To be compatible with EIP-7951 and to support modern secure hardware such as Apple Secure Enclave, Android Keystore, and FIDO2/WebAuthn, this release adds a secp256r1 signature verification precompile to the TVM, enabling scenarios such as account abstraction and device-native signing. According to TIP-7951’s estimate for a Solidity implementation, signature verification cost can be reduced by roughly 50–73×.
Press enter or click to view image in full size
On failure it does not revert and consumes the same energy as on success. It remains interface-compatible with the RIP-7212 deployment on L2 (same address, same input/output format).
Ethereum EIP: https://eips.ethereum.org/EIPS/eip-7951
TIP: tronprotocol/tips#785
Source Code: tronprotocol#6720
Previously, TVM’s BLOCKHASH could only serve the most recent 256 blocks and implicitly assumed that the client held recent block hashes, which was not friendly enough for stateless clients / Rollups.
This release deploys the block hash history contract at HISTORY_STORAGE_ADDRESS (0x0000F90827F1C53a10cb7A02335B175320002935, consistent with Ethereum) and uses a ring buffer with a capacity of 8191 to store parent block hashes. The parent hash of block N is written to slot (N-1) % 8191, and querying block K reads K % 8191. The query parameter must be 32 bytes, and K must lie within [block.number-8191, block.number-1]; querying a future block or a block outside the window causes the call to revert. The BLOCKHASH instruction still retains its original semantics and cost for the most recent 256 blocks.
This feature is activated by Proposal 95 ALLOW_TVM_PRAGUE and requires ALLOW_TVM_SHANGHAI to be enabled, because the history contract bytecode uses PUSH0. The contract is deployed by directly writing to CodeStore, ContractStore, and AccountStore, and by directly writing to StorageRowStore at the protocol layer, without executing a system call or consuming block energy; when users query via STATICCALL, they are still billed as an ordinary TVM call.
Activation does not backfill the previous 8191 blocks of hashes; the buffer takes about 8191 blocks (roughly 7 hours on TRON) to fill completely. During startup, slots that are still within the valid range but not yet written return bytes32(0). Because TRON’s proposal activation occurs during the maintenance processing phase, the parent hash of the activation block is not written, leaving a one-block coverage gap.
Ethereum EIP: https://eips.ethereum.org/EIPS/eip-2935
Ethereum Pectra Meta EIP: https://eips.ethereum.org/EIPS/eip-7600
TIP: tronprotocol/tips#719
Source Code:
tronprotocol#6686
tronprotocol#6800
3. Core
In previous versions, ResourceProcessor completed part of the intermediate results in its resource window calculation logic — such as increase, increaseV2, unDelegateIncreaseV2, getNewWindowSize, and getUsage — using consecutive multiplication with the long type.
Based on the actual range of on-chain parameters, these calculations will not overflow during normal network operation, and there is no realistically triggerable resource calculation risk. However, from a code implementation perspective, the safety of these calculations relies on the implicit boundary constraints of on-chain parameters, making the logic less explicit and robust in its expression.
This optimization unifies the handling of intermediate products in resource window calculations by using BigInteger, and applies strict validation via longValueExact() when writing the final result back as a long. If a future combination of parameters exceeds the range representable by long, an ArithmeticException will be thrown directly, avoiding silent overflow or implicit truncation.
NOTE: This feature is enabled through the on-chain governance proposal parameter 97.
TIP: tronprotocol/tips#833
PR: tronprotocol#6721
Previously, the VOTEWITNESS opcode used DataWord to calculate the memory bounds required for a dynamic array. DataWord arithmetic operates modulo 256 bits, and extreme combinations of length and offset could wrap around, thereby underestimating the memory expansion cost. This update adds getVoteWitnessCost3, which changes the calculation of array length, offset, and memory bounds to BigInteger, avoiding 256-bit modular wraparound, and adds tests for extreme inputs. The new path takes effect after proposal 96 ALLOW_TVM_OSAKA is activated; this PR uses the existing Osaka gate and does not add a separate governance proposal.
Source Code: tronprotocol#6613
The two signature verification precompiles (batchValidateSign at address 0x…09, validateMultiSign at address 0x…0a) assume in their billing that the input is a “fixed-length header + an integer number of equal-length elements,” but execute did not enforce the same shape before decoding. This meant the set of acceptable byte strings exceeded the shape covered by pricing (non-word-aligned trailing bytes were silently discarded, overly short inputs were zero-padded, and so on), which was unfavorable for auditing and formalization.
This update adds a total length check at the execution entry point of both precompiles. Let the word length be W=32: validateMultiSign uses H=5, I=5; batchValidateSign uses H=5, I=6. Only inputs satisfying data.length = H×W + N×I×W with N ≥ 1 pass. When data == null, length % W != 0, length ≤ H×W, or (length-H×W) % (I×W) != 0, the precompile returns execution failure and empty output; the current call frame consumes its pre-allocated energy, the call stack receives 0, and the outer transaction can still continue. The billing formula itself is unchanged.
NOTE: This check only regulates the total length shape of the calldata and does not verify dynamic offset, array length, element offset, or the full Solidity ABI canonical encoding. The functionality is controlled by proposal 96 ALLOW_TVM_OSAKA.
TIP: tronprotocol/tips#854
Source Code: tronprotocol#6715
Previously, the MODEXP precompile returned an empty byte string (length 0) when the modulus was 0. To align with EIP semantics and ensure a predictable output length, this update normalizes the zero-modulus return value under Osaka to “an all-zero string of the same length as the modulus”: when the modulus length is modLen, it returns modLen zero bytes. This change only affects inputs where modLen > 0 and the modulus bytes are all 0; when modLen == 0, both the old and new outputs are empty. Neither energy pricing nor the non-zero-modulus path is affected.
NOTE: Compatible with Osaka; gated by allowTvmOsaka, proposal 96 ALLOW_TVM_OSAKA.
TIP: tronprotocol/tips#871
Source Code: tronprotocol#6780
Constant calls such as /wallet/triggerconstantcontract/eth_call are subject to the TVM execution time limit (mainnet default of 80ms), and complex contracts will hit out_of_time; meanwhile, using –debug to remove the timeout also affects block processing, causing OUT_OF_TIME divergence and sync stalls, which is unsafe in production. This update adds a node-level configuration vm.constantCallTimeoutMs that only applies to the constant call path (default 0, meaning it is disabled and the original constant call time limit is used; setting a positive millisecond value overrides that limit), without affecting the block processing/broadcast path. When the configuration is loaded, only the validity of the value is checked (non-negative and ≤ Long.MAX_VALUE/1000, to ensure it can be safely converted to a microsecond deadline).
Usage tip: Use vm.constantCallTimeoutMs to extend the constant call time limit instead of –debug; public nodes are advised to combine it with rate limiting.
Source Code: https://github.com/tronprotocol/java-tron/pull/6719 (issue #6681)
The configuration items seed.node.ip.list, node.active, node.passive, node.fastForward, and node.backup.members are now allowed to be configured with domain names in addition to IP addresses. When the node starts, domain names are resolved into IP addresses; for node.backup.members, if the IP address returned by DNS changes, the system automatically refreshes the backup node’s IP every 60 seconds.
Source Code: tronprotocol#6727
Previously, when connections were full, java-tron would randomly evict a peer to free up a connection slot, but the candidate range was too broad, potentially disconnecting a peer that was normally relaying blocks; meanwhile, an attacker could use stale block inventory to refresh the active time and evade eviction.
This optimization includes three points:
Adding blockRcvTime, which records the time a peer most recently delivered a valid block.
Correcting the lastInteractiveTime update logic, so that only block inventory higher than the current head block is considered valid activity.
Adjusting the random eviction strategy to select only from the half of peers with the oldest blockRcvTime, reducing the probability of mistakenly killing peers that have recently relayed valid blocks.
Source Code: tronprotocol#6704
Previously, java-tron’s rate limiting for inbound inventory had two vulnerabilities: the TRX inventory check only compared “the existing 10s window count” against the limit (count > maxCountIn10s), without counting the number of hashes carried by the current InventoryMessage. An attacker could stuff tens of thousands of hashes into a single message, and as long as the window count had not yet reached the cap, the entire message would pass through, effectively bypassing rate limiting via batch packing; meanwhile, BLOCK inventory had no rate limiting at all, and a malicious peer could flood block-inv hashes without restraint, each requiring the receiver to perform a lookup, wastefully consuming I/O and CPU. This update tightens things along the rate-limiting theme: (1) the TRX check is changed to count + currentSize > maxCountIn10s, comparing the projected window size rather than the current window against the limit, blocking the batch bypass; (2) adding per-peer BLOCK inv rate limiting, where the hash count limit within 10s is controlled by the new configuration node.maxBlockInvPerSecond (default 10, minimum 1); (3) on the same inbound path, completing type validation as well: the three entry points checkInvRateLimit, InventoryMsgHandler.check, and FetchInvDataMsgHandler.check apply a whitelist to inventory types, and any unknown type other than TRX/BLOCK is rejected with P2pException(BAD_MESSAGE) and disconnected, preventing unknown types from being used for cache writes or constructing outbound fetches outside of rate limiting.
Source Code:
tronprotocol#6731, tronprotocol#6851 (issue #6659)
Previously, java-tron lacked duplicate-data and length validation for some P2P inbound messages, and a malicious node could construct messages containing a large number of duplicate hashes, duplicate transactions, or overly long block lists to amplify the node’s processing overhead and affect network stability. This update adds duplicate-data and length validation for messages such as Inventory, FetchInvData, Transactions, and SyncBlockChain, uniformly deeming messages that contain duplicate data or exceed limits as illegal and disconnecting, effectively reducing the resource consumption caused by malicious messages and improving the security and robustness of the P2P network.
Source Code: tronprotocol#6712 (issue #6667)
Previously, during catch-up synchronization, java-tron would immediately deserialize received blocks and cache them for a long time, which in multi-peer concurrent synchronization scenarios could easily cause continuous heap memory growth and increase GC pressure. This optimization introduces the lightweight UnparsedBlock, which only caches the block ID and raw data, deferring deserialization to the actual processing stage; it also adds a global in-flight block count limit node.maxPendingBlockSize (default value 500) to uniformly control the synchronization cache size, preventing memory from spiraling out of control due to concurrent block pulling. After the optimization, memory usage during synchronization is predictable, significantly reducing memory pressure and OOM risk in large-scale synchronization scenarios.
Source Code: tronprotocol#6717 (issue #6685)
Previously, when java-tron judged whether a node was busy, it only counted part of the transaction queue and did not include the overall caches of pushTransactionQueue, pendingTransactions, and rePushTransactions in the calculation, which meant that new transaction Inventory continued to be received even when transactions were backlogged, easily causing the transaction cache to keep growing and increasing memory pressure. In addition, the busy threshold was hardcoded and could not be flexibly adjusted. This update uniformly counts the transaction cache size and refines the backpressure judgment logic, promptly stopping the reception of new transaction Inventory when the transaction pipeline is overall busy; it also adds a configurable item node.maxTrxCacheSize to replace the hardcoded threshold, making the transaction cache capacity more controllable and effectively reducing memory pressure in high-load scenarios.
Usage tip: The transaction cache capacity and the backpressure trigger threshold can be adjusted via node.maxTrxCacheSize.
Source Code: https://github.com/tronprotocol/java-tron/pull/6714(issue #6684)
Previously, some network/broadcast entry points only detected abnormal signature lengths during subsequent signature recovery or consensus validation, and inbound transactions, batch TransactionsMessage, and fast-forward HelloMessage could all carry overly short or overly long signatures into deeper processing paths, bringing invalid computation and log noise.
This update adds SignUtils.isValidLength, and the entry layer only accepts signatures of 65–68 bytes: broadcastTransaction returns SIGERROR before entering the pool; TransactionsMsgHandler rejects with BAD_TRX during the batch transaction check stage; RelayService.checkHelloMessage rejects abnormal lengths before signature verification. The consensus path TransactionCapsule.checkWeight still retains the historical compatibility rule of “size < 65,” not pushing the entry rate-limiting rule down into block replay, avoiding impact on historical on-chain transactions.
Source Code: tronprotocol#6782
Previously, when an API triggered rate limiting, java-tron used Guava’s RateLimiter.acquire() to block and queue the calling thread. Under high concurrency, request latency grew without bound and could even exhaust the Netty/Jetty worker thread pool, leaving normal traffic unable to be served as well. This release adds support for non-blocking rate limiting: the core path now uses the non-blocking tryAcquire(), which rejects immediately and informs the client that it has been rate limited when no tokens are available; and the rate.limiter.apiNonBlocking switch toggles between blocking and non-blocking modes (off by default = blocking, backward compatible; on = non-blocking peak shaving), letting nodes choose as needed. Two related issues were also fixed: the rate limiting check now evaluates the endpoint first and then the global limit, avoiding a situation where an already-limited endpoint still consumes global quota; and a leak was fixed where per-endpoint semaphores were not released on the global-rejection / exception paths (otherwise, once the accumulated count reached zero, gRPC calls would block permanently).
Usage tip: After enabling non-blocking mode, clients should expect to be rejected immediately rather than receiving a delayed response, and must implement retry / backoff; the default blocking mode behaves the same as before.
Affected interfaces: All HTTP/gRPC/PBFT API entry points with the API rate limiter enabled; the exact coverage is determined by the rate.limiter configuration. This change primarily alters the return timing when rate limiting is hit (blocking wait vs. immediate rejection), and does not add or remove any specific business interfaces.
Source Code:
tronprotocol#6733
tronprotocol#6761
Issue: (issue #6363)
TRON JSON-RPC previously only declared the data field in the call parameter object. Ethereum’s execution-apis use input to represent calldata; go-ethereum’s ethclient and gethclient, since #28078 (ethclient: use 'input', not 'data' as field for transaction input ethereum/go-ethereum#28078), also send input rather than data when calldata is non-empty. Because java-tron did not previously declare input, jsonrpc4j/Jackson treated it as an unknown field during parameter deserialization, causing the request to be rejected before the method executed. This release adds input to CallArguments and BuildArguments, and uses it uniformly for calldata parsing in eth_call, eth_estimateGas, and the java-tron extension interface buildTransaction. In eth_call and eth_estimateGas, input takes precedence over data; in buildTransaction, if both are present and their decoded bytes differ, a -32602 Invalid params error is returned.
Usage tip: Legacy clients that continue to use data are unaffected; new integrations are advised to use input. A non-empty input must carry the 0x prefix and contain an even number of hexadecimal characters; for empty calldata, using 0x is recommended. Submitting both input and data at the same time should be avoided, and all submitted fields must be valid hexadecimal.
Affected interfaces: eth_call, eth_estimateGas, buildTransaction.
Source Code: tronprotocol#6722
TRON JSON-RPC’s TransactionResult.nonce is a compatibility placeholder field fixed at 0. Previously this field returned 0x0000000000000000, a fixed 8-byte DATA-style encoding that does not conform to the QUANTITY constraint ^0x(0|[1–9a-f][0–9a-f]*)$ that Ethereum’s execution-apis impose on the transaction nonce. This release normalizes it to 0x0. This change affects eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, as well as the transaction nonce included when eth_getBlockByHash and eth_getBlockByNumber return full transaction objects with the second parameter set to true. The block object’s own BlockResult.nonce is unaffected and still returns 0x0000000000000000 per the Ethereum bytes8 type. This change only corrects the JSON-RPC encoding of the transaction nonce; it does not change its numeric value, nor does it introduce Ethereum-style nonce semantics for TRON transactions.
Compatibility tip: Clients that parse it as a QUANTITY numeric value are generally unaffected; clients that compare against string literals or fixed lengths need to adapt.
Affected interfaces: eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getBlockByHash , eth_getBlockByNumber.
Source Code: tronprotocol#6709
The gRPC proto still carried google.api.http REST mappings (such as post:/wallet/getaccount) that existed for the deprecated grpc-gateway, while these endpoints have long had independent HTTP implementations in FullNodeHttpApiService, making the mappings redundant. This release removes the google.api.http option blocks from 56 gRPC interface definitions and deletes 8 empty proto files under protocol/src/main/protos/core/tron.
Usage tip: Access via the default HTTP endpoints (such as IP:8090/wallet/xxxx) or directly via gRPC (Trident SDK), without relying on grpc-gateway REST translation.
Affected interfaces: The Wallet/ WalletSolidity / WalletExtension / Monitor gRPC methods in api.proto that were originally annotated with google.api.http (56 mapping blocks in total); java-tron’s own HTTP Servlet paths are unaffected and still use /wallet*/*.
Source Code: tronprotocol#6726 (issue #6548)
tronprotocol#6874
Previously the HTTP layer had no unified “before-entry” request body size limit; validation was performed after reading the full request body, posing a memory amplification risk, and the validation logic was scattered. This release inserts a Jetty SizeLimitHandler at the top of the processing chain for streaming validation; it introduces node.http.maxMessageSize and node.jsonrpc.maxMessageSize (node.rpc.maxMessageSize is still used only for gRPC), defaulting to roughly 4MB. Exceeding Content-Length returns HTTP 413; exceeding it in chunked mode returns 200 + an error JSON, or 200 + an empty body (jsonrpc).
Usage tip: Adjust node.http.maxMessageSize / node.jsonrpc.maxMessageSize as needed; over-limit requests need to be split.
Affected interfaces: HTTP REST /wallet*/* use node.http.maxMessageSize; JSON-RPC /jsonrpc uses node.jsonrpc.maxMessageSize; gRPC is unaffected by this item and is still controlled by node.rpc.maxMessageSize.
Source Code:
tronprotocol#6658
tronprotocol#6843
6. Optimize JSON serialization for block interfaces
Previously the block-related HTTP interfaces took a redundant path — first fully serializing to a JSON string, then deserializing back to an object, then overwriting fields — causing repeated “protobuf→JSON→object” conversions, extra CPU usage, and elevated GC pressure. This release changes the approach to build the JSON field by field on demand in Util.java: printBlockList directly populates the block array, while printBlockToJSON serializes only the block_header and manually populates blockID and transactions. The returned fields are unchanged and fully backward compatible; the goal is to reduce CPU/GC.
Usage tip: Affects GetBlockByLimitNext, GetBlockByLatestNum, GetBlock, GetNowBlock, GetBlockByNum, GetBlockById; callers need no changes.
Affected interfaces: /wallet/getblockbylimitnext, /wallet/getblockbylatestnum, /wallet/getblock, /wallet/getnowblock, /wallet/getblockbynum, /wallet/getblockbyid, and the corresponding /wallet*/* block query paths.
Source Code: tronprotocol#6693
Previously the JSON-RPC log object did not include the block timestamp, so for sorting/indexing clients had to make an additional eth_getBlockByHash/eth_getBlockByNumber call for each log, which was also inconsistent with Ethereum’s execution-apis. This release adds blockTimestamp (a hexadecimal string) to the log object, in the same format as the JSON-RPC block timestamp: a 0x-prefixed Unix second value (not TRON’s internal milliseconds). It is purely additive and non-breaking.
Usage tip: Affects eth_getLogs, eth_getFilterLogs, eth_getFilterChanges (log/event filters only), eth_getTransactionReceipt, eth_getBlockReceipts; clients read blockTimestamp directly, eliminating the second block query.
Affected interfaces: eth_getLogs, eth_getFilterLogs, eth_getFilterChanges (log/event filters), eth_getTransactionReceipt, eth_getBlockReceipts.
Source Code: tronprotocol#6671
Previously JSON-RPC had no limits on batch array size, response body size, or the number of address filters, posing OOM and resource-exhaustion risks in public/high-concurrency scenarios. This release adds: node.jsonrpc.maxBatchSize (default 100), node.jsonrpc.maxAddressSize (default 1000, validated before eth_getLogs queries), and node.jsonrpc.maxResponseSize (default 25MB, counted incrementally during serialization). Error codes: address over limit −32602, batch over limit −32005, response too large −32003.
Affected interfaces: node.jsonrpc.maxBatchSize, node.jsonrpc.maxResponseSize apply to all /jsonrpc requests; node.jsonrpc.maxAddressSize applies to the address array of eth_getLogs, eth_newFilter; node.jsonrpc.maxLogFilterNum applies to the number of log filters in eth_newFilter; the existing node.jsonrpc.maxSubTopics applies to a single topic OR array of eth_getLogs, eth_newFilter.
Source Code:
tronprotocol#6728
tronprotocol#6763
9. Add an optional parameter: serialize 64-bit integers in HTTP GET responses as JSON strings
Previously, protobuf 64-bit integer fields in the TRON HTTP API were typically output as JSON numbers. After JavaScript clients parse them with JSON.parse, these values are converted to Number; when an integer exceeds Number’s safe integer range [-(2⁵³-1), 2⁵³-1], silent precision loss can occur.
This release adds the optional parameter int64_as_string. When int64_as_string=true is set in the URL query of an HTTP GET request, the signed and unsigned 64-bit integer protobuf fields serialized via TRON’s JsonFormat are returned as JSON strings, including the relevant fields in nested objects and maps. Additionally, the four hand-written JSON fields burnTrxAmount, pendingSize, reward, and count have been individually adapted.
When the parameter is not set or is set to false, the response format remains unchanged. This capability applies to HTTP GET paths in FullNode, Solidity, and PBFT that ultimately generate responses via JsonFormat, or via Util methods that internally call JsonFormat. Interfaces using other serialization approaches are outside the scope of this change. JSON-RPC, gRPC, and all POST requests are unaffected.
Usage example: GET /wallet/getnowblock?int64_as_string=true
Usage tip: This parameter is only accepted in the GET URL query. For POST requests, setting it in either the URL query or the body has no effect. Once enabled, the JSON type of the relevant fields changes from number to string, and clients should handle them as strings, BigInt, or a big-integer library.
Typical interfaces include:
/wallet/getnowblock and the corresponding /wallet*/getnowblock
/wallet/getblock, /wallet/getblockbynum, /wallet/getblockbyid, /wallet/getblockbylimitnext, /wallet/getblockbylatestnum and the registered Solidity counterpart paths
/wallet/getburntrx, /wallet/getReward, /wallet/gettransactioncountbyblocknum and the corresponding /Solidity paths
/wallet/getpendingsize, provided only by FullNode
Source Code: tronprotocol#6699
The JSON-RPC / HTTP API parameter-parsing paths previously lacked validation of input length and format, posing two kinds of risk — first, algorithmic-complexity DoS (Base58.decode/BigInteger parsing, where overly long inputs can saturate threads with a very small request body); and second, various malformed/out-of-bounds inputs that would break through directly to unexpected exceptions (NPE, DecoderException, StackOverflowError, etc.), caught by jsonrpc4j as a fallback returning a default error message. This release adds unified up-front length and format validation across a series of parameter entry points — addresses (Base58/hex length caps), block number/hash/storage key/transaction index/log topic and address/ABI depth/gas-value overflow, and more — converging these exceptional cases into a well-formed -32602 invalid params error response.
Get TRON Core Devs’s stories in your inbox
Join Medium for free to get updates from this writer.
Enter your email
Subscribe
Remember me for faster sign in
Affected interfaces: JSON-RPC methods that parse addresses, hashes, topics, block selectors, transaction indexes, gas/value, and ABI/revert data (typically including eth_getBalance, eth_getStorageAt, eth_getCode, eth_call, eth_estimateGas, buildTransaction, eth_getTransactionByHash, eth_getTransactionReceipt, eth_getBlockByHash, eth_getBlockByNumber, eth_getLogs, eth_newFilter, eth_getFilterLogs); HTTP REST paths that parse address/contract parameters (typically including /wallet/getaccount, /wallet/triggerconstantcontract, /wallet/triggersmartcontract, /wallet/deploycontract, /wallet/getcontract, /wallet/estimateenergy).
Source Code: tronprotocol#6828
The parsing logic for the JSON-RPC block selector (latest/earliest/pending/safe/hexadecimal block number) was scattered and duplicated across three places — Wallet, JsonRpcApiUtil, and TronJsonRpcImpl — each with slightly different responsibilities and control flow, resulting in duplicated and inconsistent parsing logic that was costly to maintain. This change consolidates the relevant logic into JsonRpcApiUtil, giving the code a more reasonable structure and clearer logic, and lowering maintenance cost.
Affected interfaces: All interfaces that accept a JSON-RPC block tag / block number parameter, typically including eth_getBalance, eth_getStorageAt, eth_getCode, eth_call, eth_getTransactionCount, eth_getBlockByNumber, eth_getBlockReceipts, eth_getBlockTransactionCountByNumber, eth_getTransactionByBlockNumberAndIndex, eth_getUncleByBlockNumberAndIndex, eth_getUncleCountByBlockNumber, eth_getLogs, eth_newFilter.
Source Code: tronprotocol#6668
Source Code: tronprotocol#6711
Tightened the multi-signature query logic to prevent overly long signatures from amplifying responses or bypassing validation. Changes:
Both query entry points now first limit the signature count according to the on-chain totalSignNum, returning too many signatures immediately when the limit is exceeded.
Signatures longer than 65 bytes are uniformly truncated to the standard 65 bytes before participating in weight and approvedList calculations, and the transaction in the response also uses the truncated signatures.
getApprovedList now reuses TransactionCapsule.checkWeight and adds validation of permissionId, permission type, and operation.
getApprovedList behaves more strictly: cases such as too many signatures, signatures not belonging to the current permission, and duplicate signers all fail as a whole, and it no longer returns a partial approvedList.
Early-exit errors return only result, and the HTTP JSON may not contain a transaction field.
The weight == 0 error message no longer echoes the overly long signature hex, but instead uses the fixed-length tx hash, avoiding amplification of the error response.
Compatibility tip: Wallets, multi-signature services, and SDKs should no longer treat getApprovedList as an “arbitrary signature recovery” or “partial authorization probe” interface. Before calling, they should limit the signature count, filter out irrelevant signatures and duplicate signers themselves, judge failure by result.code / result.message, and also handle the case where the response is missing the transaction field.
Affected interfaces: HTTP /wallet/getsignweight, /wallet/getapprovedlist; gRPC Wallet.GetTransactionSignWeight, Wallet.GetTransactionApprovedList.
Source Code: tronprotocol#6820
Previously, java-tron internally used two different JSON processing libraries at the same time: modules such as JSON-RPC, the event plugin, keystore, and TVM trace mainly used jackson, while the HTTP API layer relied on fastjson.
To reduce the impact of this change on business code, we did not directly rewrite every call site to the native Jackson API. Instead, we added lightweight compatibility wrappers such as org.tron.json.JSON, JSONObject, and JSONArray, implemented on top of Jackson. This allows most scenarios to be migrated simply by “replacing the import,” reducing the cost of large-scale refactoring and keeping the JSON parsing and output behavior of the existing HTTP API layer as stable as possible.
From an external compatibility standpoint, this change is an internal dependency replacement and security hardening. It does not involve any changes to API paths, request parameters, response structures, configuration items, or protocol formats. External callers that normally use the HTTP API, JSON-RPC, and gRPC, as well as those consuming event data, generally do not need to adapt. Callers that conform to the interface contract and use standard JSON requests are largely compatible; callers that rely on fastjson’s lenient syntax, field ordering, or special null behavior should take note, and scenarios where downstream code directly depends on com.alibaba.fastjson.* types also require special attention.
Therefore, the core goal of this change is: to unify the JSON technology stack, remove legacy security burdens, and reduce subsequent maintenance and audit costs, while keeping external behavior as unchanged as possible.
Source Code:
tronprotocol#6701
tronprotocol#6844
tronprotocol#6845
tronprotocol#6863
2. Dependency upgrades
Bump libp2p from 2.2.7 to 2.2.8
Bump bcprov-jdk18on from 1.79 to 1.84 to address CVE-2026–5598
Bump jetty from 9.4.57 to 9.4.58 to address CVE-2025–5115
Bump pf4j from 3.10.0 to 3.14.1 to address CVE-2025–70952
Bump grpc-java from 1.75 to 1.81 to address CVE-2026–33871
Source Code:
tronprotocol#6747
tronprotocol#6859
8. Configuration
This round of refactoring upgraded the java-tron configuration system from “hand-written parsing” to “typed automatic binding.” In the past, a large number of configuration items were centralized in Args and read one by one via hasPath/getXxx, with default values scattered across code, comments, and configuration samples. Adding a new parameter required modifying multiple places at once, which easily led to default-value drift and compatibility issues. The new approach is based on Typesafe Config’s ConfigBeanFactory, splitting configuration such as node, storage, vm, committee, event, and rate.limiter into domain Beans, with reference.conf uniformly carrying default values and parameter descriptions.
Subsequent optimizations focused on three areas: first, calibrating behavioral differences after automatic binding, preserving compatibility with old configuration keys, default-value semantics, and boundary validation; second, cleaning up unused or misleading configuration items to reduce the historical baggage of CommonParameter and the configuration files; and third, establishing normalization or manual-parsing strategies for scenarios such as non-standard naming, optional lists, and nested structures, to avoid strict binding breaking existing configurations. Ultimately, reference.conf became the authoritative configuration reference, config.conf was streamlined into a user-override sample, and documentation on configuration usage and development conventions was added. Overall, this improved the type safety, maintainability, and auditability of the configuration system, and laid the groundwork for later removing the CommonParameter intermediate layer.
Source Code:
tronprotocol#6615
tronprotocol#6735
tronprotocol#6755
tronprotocol#6757
tronprotocol#6759
tronprotocol#6762
tronprotocol#6790
tronprotocol#6794
tronprotocol#6806
tronprotocol#6834
tronprotocol#6795
tronprotocol#6555
2. Fixed 13 CLI parameters being silently overridden by the configuration file
The standard priority should be CLI > configuration file > default value. Previously this was implemented correctly for 9 parameters, but Args.setParam(Config) unconditionally overrode the CLI values of another 13 parameters with configuration-file values, causing these CLI flags to be silently ignored. This refactoring introduces a Default → Config → CLI three-layer override model; the affected flags include –rpc-thread, –solidity-thread, –validate-sign-thread, –max-connect-number, –lru-cache-size, –long-running-time, –max-energy-limit-for-constant, –min-time-ratio, –max-time-ratio, –support-constant, –save-internaltx, –save-featured-internaltx, and –history-balance-lookup, and it also corrects the –seed-nodes flag.
Usage tip: For example, java -jar FullNode.jar –rpc-thread 16 will now correctly override config.conf; please check your startup scripts before upgrading.
Source Code: tronprotocol#6569
This change extracts about 232 HOCON configuration key constants (such as “node.rpc.port”) from Constant.java into the newly created ConfigKey.java, leaving only about 32 business constants in Constant.java. It also removes the outdated testnet configuration and the 0xa0 address format, unifying on the mainnet address format (T- Base58 / 41 hexadecimal). In addition, a unit test for rocksdb was added for the x86 environment.
Source Code:
tronprotocol#6565
tronprotocol#6580
4. Removing the actuator.whitelist configuration to prevent forks
actuator.whitelist (an early testing feature) allowed a node to register only the actuator types in the whitelist; on the public chain, if a block contained a non-whitelisted transaction type, getActuator() would return null, causing execution to diverge from the rest of the network and leading to state forks and node isolation. This change fully removes the configuration and its related logic; all nodes unconditionally register/execute all valid actuators, and the enabling of transaction types is entirely governed by on-chain proposals.
NOTE: Breaking change. Please remove actuator.whitelist from your configuration before upgrading.
Source Code: tronprotocol#6723
storage.backup periodically copies the database (every frequency blocks), originally intended to guard against disk failures, power outages, or kill-9 corruption. However, the mainnet state database is now about 3TB, and a single copy may take hours and block block synchronization during that window, which is a fatal stability risk; testing also confirmed that kill -9 does not corrupt the database. This change removes the entire storage.backup configuration block and the copy logic in pushBlock(), and recommends switching to a primary-standby dual-FullNode solution using node.backup { port, priority, members } or RAID instead.
NOTE: Breaking change, incompatible with 4.8.1 and earlier; before upgrading, remove storage.backup and migrate to a dual-node disaster-recovery setup or RAID.
Source Code: https://github.com/tronprotocol/java-tron/pull/6724 (issue #6595)
Prometheus metrics lacked visibility into the number of transactions per block (and whether an empty block was produced) and into changes to the super representative (SR) set during the maintenance period.
This change adds statistics for SR set changes and for the number of transactions within a block.
SR set changes are tracked with a counter, tron:sr_set_change_total (add/remove); the number of transactions within a block is recorded with a histogram, tron:block_transaction_count, with the custom transaction-count buckets {0, 20, 50, 80, 100, 120, 140, 160, 180, 200, 230, 260, 300, 500, 2000, 5000, 10000}, so as to derive the approximate distribution of transaction counts per block. Empty blocks are captured by the le=“0” bucket, and the ratio is computed in Grafana using PromQL.
Usage tip: After Prometheus scraping, compute the empty-block ratio using the le=“0” bucket or PromQL.
Source Code:
tronprotocol#6624
tronprotocol#6730
Issue: tronprotocol#6590
Up to and including v4.8.1, two monitoring stacks coexisted: Prometheus (/metrics) and the legacy dropwizard MetricsUtil + InfluxDB (monitor/getstatsinfo), which led to fragmented metrics and unmaintained dependencies. This change removes the InfluxDB reporter from MetricsUtil and deletes its configuration block (storageEnable, influxdb { ip=xx, port=8086, database=xx, metricsReportInterval=10 }), consolidating everything on Prometheus.
NOTE: Breaking change; before upgrading, please remove the influxdb configuration and migrate to Prometheus + Grafana (tron-docker).
Source Code: https://github.com/tronprotocol/java-tron/pull/6725(issue #6665)
Previously, some of java-tron’s runtime logs had shortcomings in observability and operational troubleshooting: for example, the gRPC layer used the JUL logging framework, and some diagnostic information could bypass Logback and be written directly to stderr; during the node startup phase, DB statistics were output at INFO level in large volumes, easily drowning out key initialization logs; during abnormal shutdown, some logs might not be fully flushed in time; in addition, issues such as long signature-verification times, LevelDB open stalls (on long-running nodes), and invalid log configurations lacked sufficiently clear log prompts.
This change enhances the logging system with a focus on operations, mainly including the following aspects:
Unified ingestion of gRPC logs into Logback
Introduced org.slf4j:jul-to-slf4j:1.7.36 and installed SLF4JBridgeHandler early during node startup, bridging logs that grpc-java originally emitted through JUL into Logback in a unified manner. After the upgrade, io.grpc logs are managed at INFO level by default and output to a dedicated ./logs/grpc/grpc.log. This means that gRPC diagnostic information such as TLS handshake failures, abnormal connection resets, and NettyServerTransport’s “Transport failed” will go into managed log files rather than being scattered across stderr.
Reduced DB statistics log noise during startup
The log level of DbStat.statProperty() was changed from INFO to DEBUG, avoiding a flood of DB statistics being emitted during node startup. This makes important logs such as key initialization, configuration loading, and network startup clearer, reducing interference during startup troubleshooting.
Improved shutdown log completeness
TronLogShutdownHook was refactored, with related constants named more clearly, and the maximum wait time was increased from 60 seconds to 180 seconds, reserving more time for the node executor thread pool to be released, tasks to wrap up, and logs to be flushed to disk, reducing the likelihood of log loss during abnormal exit or normal shutdown.
Slow signature verification made observable
Added slow signature-verification logging. When a single signature verification takes more than 50 ms, TransactionCapsule.logSlowSigVerify(…) outputs an INFO log, making it easier for operators to identify abnormally slow signature verification, increased CPU pressure, or performance bottlenecks triggered by specific transactions.
LevelDB open stalls no longer silent
LevelDbDataSourceImpl adds a watchdog mechanism for factory.open(…), which may block at the JNI layer. If opening LevelDB takes more than 60 seconds, a WARN log is output with troubleshooting and remediation hints, pointing to related tools such as Toolkit.jar db archive, making it easier for operators to handle overly long LevelDB open times.
Invalid –log-config configuration fails fast
If the log configuration file specified via –log-config is not readable, LogService.load(…) will directly throw TronError(ErrCode.LOG_LOAD), and the node fails fast instead of continuing to start with the default log configuration. This exposes deployment configuration problems earlier, avoiding the situation where a missing expected log output is only discovered after the node is running.
After the upgrade, log output will be clearer and more controllable:
gRPC-related diagnostic information will go into ./logs/grpc/grpc.log;
the main log tron.log will no longer be flooded by DB statistics INFO logs during startup;
operations-relevant events such as slow signature verification and LevelDB open stalls will be retained in the main log;
in CI scenarios, the test root logger was changed from DEBUG to INFO to reduce the volume of test logs.
Usage tip: To adjust the verbosity of gRPC logs, you can configure the io.grpc logger in logback.xml.
This change only involves the logging system and operational observability, and does not involve changes to the API, RPC, network protocol, consensus logic, or database format. Normal business calls require no adaptation, but node operators can use this to update log collection paths, alerting rules, and troubleshooting runbooks.
Source Code: tronprotocol#6700
Issue: #6583
This upgrade adds a minimum version check for the Event Plugin: when a node enables event subscription and loads an external Event Plugin, the plugin version must be no lower than 3.0.0; otherwise, the node will fail outright during the startup phase.
This change is primarily intended to align with the adjustment of java-tron’s internal JSON technology stack. v4.8.2 has removed the fastjson dependency and switched uniformly to Jackson, whereas the old Event Plugin still relies on fastjson. Continuing to use the old plugin may cause issues such as missing classes, plugin loading exceptions, or event processing failures in the new version of java-tron. Compared with allowing a node to silently drop events during operation after startup, this change adopts a fail-fast approach during the startup phase, which exposes plugin compatibility issues earlier and prevents the event subscription service from being left in an unreliable state.
The nodes affected are those that have enabled an external Event Plugin, for example deployment scenarios that use the Kafka or MongoDB event plugin. A node will be affected only if it meets all of the following conditions:
Uses the –es command-line option or event.subscribe.enable = true
Uses an external Event Plugin rather than the native queue
event.subscribe.path points to an old-version plugin package
The Plugin-Version in the plugin package is lower than 3.0.0, or the version information is missing
If a node has not enabled event subscription, or uses the native queue, it is not affected by this version check.
When upgrading, node operators need to rebuild or replace the Kafka / MongoDB Event Plugin package, and point event.subscribe.path to the new plugin zip, for example plugin-kafka-3.0.0.zip or plugin-mongodb-3.0.0.zip. It is also recommended to check the Plugin-Version in the plugin package’s META-INF/MANIFEST.MF to ensure the version number is no lower than 3.0.0.
This change is an operations-side compatibility requirement and does not affect on-chain consensus, the API protocol, or the event data model itself. However, for data services, indexing services, and Kafka/MongoDB consumption pipelines that depend on event subscription, the Event Plugin must be upgraded in sync before upgrading java-tron; otherwise the node may be unable to start the event subscription normally.
For detailed upgrade instructions and plugin package information, please refer to the Event Plugin v3.0.0 Release Notes: https://github.com/tronprotocol/event-plugin/releases/tag/v3.0.0
Source Code: tronprotocol#6760
2.Add chain reorganization rollback (removed) semantics for block and transaction events
Previously, java-tron only provided chain reorganization rollback (removed) semantics for contract events. Block and transaction events did not notify subscribers to roll back when a chain reorganization occurred, which meant subscribers might retain events that had become invalid, and might miss the corresponding block and transaction events when reapplying the new fork branch. This update adds a removed flag to BlockLogTrigger and TransactionLogTrigger, sending rollback events to subscribers during a chain reorganization and resending the corresponding events when the new fork branch is reapplied, ensuring that the event stream can fully reflect chain state changes.
Compatibility tip: After the upgrade, BlockLogTrigger and TransactionLogTrigger will add a removed field and send a removed=true rollback event during a chain reorganization. Event subscribers need to correctly handle the chain reorganization scenario based on this field, undoing the local state corresponding to rolled-back blocks or transactions. In addition, since the event JSON structure adds a field, clients that use strict JSON Schema validation or that disallow unknown fields need to update their parsing logic accordingly to avoid compatibility issues.
Source Code:
tronprotocol#6833
tronprotocol#6718
3. Fix the issue where the eth_getFilterChanges interface could not obtain new main-chain blocks/logs after a chain reorganization
This fixes a long-standing issue: when a chain reorg occurs, switchFork() was only responsible for withdrawing the logs of the discarded branch (reOrgLogsFilter, marked removed=true), but returned directly after switching to the new main chain. This resulted in “only withdrawing the old, never resending the new,” violating the semantics that a reorg should follow — “first withdraw the old branch, then resend the new branch” — causing dApps polling with eth_newFilter to completely lose the logs of all blocks on the new main chain after the reorg.
Source Code: tronprotocol#6819
Previously, TransactionRegister would scan and register actuators via reflection during the startup phase. Because the scanned package scope was large, the startup process incurred some additional overhead; at the same time, if an exception occurred during actuator registration, there was no fast-fail, which could increase the cost of problem diagnosis.
This update optimizes the actuator registration process, mainly in three aspects:
Add a registration status check
Uses a registration status check to avoid duplicate initialization, preventing the same batch of actuators from being scanned and registered repeatedly, reducing unnecessary overhead.
Adopt fail-fast error handling
If an exception occurs during registration, it will fail fast via TronError, preventing the node from continuing to start when actuator registration is incomplete or the state is uncertain. This allows deployment or code issues to be exposed as early as possible during the startup phase, making it easier for operations and development personnel to quickly locate them.
Narrow the reflection scanning scope
Narrows the actuator scanning scope from the larger org.tron package to org.tron.core.actuator, reducing the scanning of irrelevant classes and lowering the cost of reflection initialization. According to test results, the first registration time was reduced from about 375 ms to about 188 ms, and the repeat registration scenario from about 165 ms to about 24 ms.
Overall, this optimization does not change transaction execution logic, API behavior, or external protocols; it mainly improves the registration efficiency and error observability during the node startup phase. Ordinary node users do not need additional adaptation; if a custom actuator exists, you need to confirm that its class is located under the org.tron.core.actuator package path, otherwise it may not be scanned and registered.
Source Code: tronprotocol#6447
KeystoreFactory (previously invoked via FullNode.jar –keystore-factory) was located in the framework module, with unclear module boundaries. This update migrates it to plugins as a Toolkit subcommand (java -jar Toolkit.jar keystore) and switches to picocli; for compatibility, –keystore-factory is retained for a deprecation period (with a deprecation notice).
Usage tip: The new invocation method is java -jar Toolkit.jar keystore; the old method remains available during the deprecation period.
Source Code: tronprotocol#6637
SolidityNode (which syncs about 30%+ faster than FullNode and does not verify signatures) previously lacked conditional automatic shutdown, which is useful when verifying the global state of a target height across architectures (x86 vs ARM). This update introduces the existing node.shutdown automatic stop conditions into SolidityNode: BlockTime (cron), BlockHeight, BlockCount (only one may be set, otherwise fail-fast).
Source Code:
tronprotocol#6734
tronprotocol#6801
tronprotocol#6804
tronprotocol#6655
4. CI / Workflow optimization
Improve the 4.8.2 release quality assurance system.
On the CI side, added multi-platform builds, Checkstyle, and single-node/multi-node integration tests, and placed the build after the PR lint to reduce wasted resource consumption;
The coverage process was adjusted from the Codecov approach to a base vs PR comparison based on JaCoCo and diff-cover, focusing on verifying the coverage of changed lines and any regression in overall coverage.
In terms of configuration governance, added key naming, hierarchy depth, port uniqueness, and comment coverage checks for reference.conf, reducing the risk of configuration items that cannot be bound or lack descriptions.
At the protocol layer, added protoLint, enforcing the use of the UNKNOWN_ prefix for enum 0 values, ensuring API evolution compatibility.
Also introduced CODEOWNERS / automatic reviewer assignment and fixed the fork PR permission issue, upgraded actions/cache to v5, and improved GitHub Actions compatibility and stability.
Source Code:
tronprotocol#6574
tronprotocol#6706
tronprotocol#6795
tronprotocol#6789
tronprotocol#6582
tronprotocol#6605
tronprotocol#6635
tronprotocol#6663
tronprotocol#6636
tronprotocol#6559
tronprotocol#6808
tronprotocol#6810
tronprotocol#6631
Why are these changes required?
This PR has been tested by:
Follow up
Extra details