<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by TRON Core Devs on Medium]]></title>
        <description><![CDATA[Stories by TRON Core Devs on Medium]]></description>
        <link>https://medium.com/@coredevs?source=rss-3dc4ed14a538------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*u3Mvm2xjPsxebXwyh9CQeA.png</url>
            <title>Stories by TRON Core Devs on Medium</title>
            <link>https://medium.com/@coredevs?source=rss-3dc4ed14a538------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 16 Jul 2026 10:13:53 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@coredevs/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Mainnet Pyrrho Announcement]]></title>
            <link>https://medium.com/tronnetwork/mainnet-pyrrho-announcement-ac8cccba2035?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/ac8cccba2035</guid>
            <category><![CDATA[announcements]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Thu, 16 Jul 2026 09:58:16 GMT</pubDate>
            <atom:updated>2026-07-16T09:58:40.846Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*8RD_8p-d0ThTczEvc9UubA.png" /></figure><h3>1. Summary</h3><p><strong>GreatVoyage-v4.8.2 (Pyrrho)</strong> introduces several important optimizations and updates, centered on the theme of “protocol hardening, EVM compatibility, and improved API and operational experience”:</p><ul><li>More robust core protocol: historical block hashes are provided from state via TIP-2935 (EIP-2935), improving friendliness toward stateless clients and L2.</li><li>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).</li><li>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.</li><li>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.</li></ul><blockquote><strong>Upgrade type: Mandatory upgrade</strong></blockquote><h3>2. Adapt to Ethereum Upgrade</h3><p>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.</p><h3>1. Osaka</h3><h4>1. TIP-7939: Add the CLZ (Count Leading Zeros) instruction</h4><p>TVM adds the <strong>CLZ</strong> instruction (<strong>opcode 0x1e</strong>), which pops a <strong>256-bit</strong> 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 <strong>5 energy</strong>, in the same tier as <strong>MUL</strong>.</p><p>Compared with a simulated implementation in Solidity that costs roughly <strong>184 gas</strong> and <strong>110–160 bytes</strong> of bytecode, the native <strong>CLZ</strong> requires only a 1-byte instruction, reducing computation and <strong>ZK</strong> proof costs in scenarios such as fixed-point math, bitmap scanning, <strong>calldata</strong> compression, and post-quantum signatures. <strong>CTZ</strong> can be computed by first isolating the least significant bit via <strong>x &amp; -x</strong> and then applying <strong>CLZ</strong>.</p><p>Ethereum EIP: <a href="https://eips.ethereum.org/EIPS/eip-7939">EIP-7939: Count leading zeros (CLZ) opcode</a></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/838">TIP-7939: Count leading zeros (CLZ) opcode · Issue #838 · tronprotocol/tips</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6656"><em>https://github.com/tronprotocol/java-tron/pull/6656</em></a></p><h4>2. TIP-7823: Set an input upper bound for the MODEXP precompile</h4><p>The <strong>MODEXP</strong> precompile (address <strong>0x…05</strong>) 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, <strong>length_of_BASE</strong>, <strong>length_of_EXPONENT</strong>, and <strong>length_of_MODULUS</strong> must not exceed <strong>8192 bit</strong>, i.e. <strong>1024 bytes</strong>. 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.</p><p>Ethereum EIP: <a href="https://eips.ethereum.org/EIPS/eip-7823">https://eips.ethereum.org/EIPS/eip-7823</a></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/826">https://github.com/tronprotocol/tips/issues/826</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6611">https://github.com/tronprotocol/java-tron/pull/6611</a></p><h4>3. TIP-7883: Increase the gas cost of the MODEXP precompile</h4><p>Before Osaka, TVM followed the legacy pricing path based on <strong>EIP-198</strong>: it used a piecewise multiplication complexity and divided by <strong>GQUAD_DIVISOR = 20</strong>; this implementation was not <strong>EIP-2565</strong> pricing and had no fixed minimum energy floor.</p><p>After Osaka activation, <strong>MODEXP</strong> switches to the <strong>TIP/EIP-7883</strong> formula:</p><ul><li><strong>Minimum energy</strong>: <strong>500</strong>.</li><li><strong>Multiplication complexity</strong>: let <strong>maxLen = max(baseLen, modLen)</strong>. When <strong>maxLen ≤ 32</strong>, <strong>multiplication_complexity = 16</strong>; otherwise, <strong>multiplication_complexity = 2 × ceil(maxLen / 8)²</strong>.</li><li><strong>Iteration count</strong>: when the exponent length exceeds <strong>32 bytes</strong>, the multiplier is changed from <strong>8</strong> to <strong>16</strong>.</li><li><strong>Final pricing</strong>: <strong>energy = max(500, multiplication_complexity × iteration_count)</strong>.</li></ul><p><strong>TIP-7883</strong> 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 <strong>665</strong> to <strong>512</strong>, while the energy of high-load edge inputs rises significantly. The input interface and modular exponentiation algorithm of <strong>MODEXP</strong> remain unchanged.</p><p>Ethereum EIP: <a href="https://eips.ethereum.org/EIPS/eip-7883">https://eips.ethereum.org/EIPS/eip-7883</a></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/837">https://github.com/tronprotocol/tips/issues/837</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6654"><em>https://github.com/tronprotocol/java-tron/pull/6654</em></a></p><h4>4. TIP-7951: Add the secp256r1 (P-256) curve signature verification precompile</h4><p>To be compatible with <strong>EIP-7951</strong> and to support modern secure hardware such as <strong>Apple Secure Enclave</strong>, <strong>Android Keystore</strong>, and <strong>FIDO2/WebAuthn</strong>, this release adds a <strong>secp256r1</strong> 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 <strong>50–73×</strong>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mQVYgivnbuz5TCTngRmPpw.png" /></figure><p>On failure it does not <strong>revert</strong> and consumes the same <strong>energy</strong> as on success. It remains interface-compatible with the <strong>RIP-7212</strong> deployment on L2 (same address, same input/output format).</p><p>Ethereum EIP: <a href="https://eips.ethereum.org/EIPS/eip-7951">https://eips.ethereum.org/EIPS/eip-7951</a></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/785">https://github.com/tronprotocol/tips/issues/785</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6720"><em>https://github.com/tronprotocol/java-tron/pull/6720</em></a></p><h3>2. <a href="https://eips.ethereum.org/EIPS/eip-7600">Pectra</a></h3><h4>1. TIP-2935: Provide historical block hashes from state</h4><p>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.</p><p>This release deploys the block hash history contract at <strong>HISTORY_STORAGE_ADDRESS</strong> (<strong>0x0000F90827F1C53a10cb7A02335B175320002935</strong>, 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 <strong>(N-1) % 8191</strong>, and querying block K reads <strong>K % 8191</strong>. The query parameter must be 32 bytes, and K must lie within <strong>[block.number-8191, block.number-1]</strong>; querying a future block or a block outside the window causes the call to <strong>revert</strong>. The <strong>BLOCKHASH</strong> instruction still retains its original semantics and cost for the most recent 256 blocks.</p><p>This feature is activated by <strong>Proposal 95 ALLOW_TVM_PRAGUE</strong> and requires <strong>ALLOW_TVM_SHANGHAI</strong> to be enabled, because the history contract bytecode uses <strong>PUSH0</strong>. The contract is deployed by directly writing to <strong>CodeStore</strong>, <strong>ContractStore</strong>, and <strong>AccountStore</strong>, and by directly writing to <strong>StorageRowStore</strong> at the protocol layer, without executing a system call or consuming block energy; when users query via <strong>STATICCALL</strong>, they are still billed as an ordinary <strong>TVM</strong> call.</p><p>Activation does not backfill the previous <strong>8191 blocks</strong> of hashes; the buffer takes about <strong>8191 blocks</strong> (roughly 7 hours on TRON) to fill completely. During startup, slots that are still within the valid range but not yet written return <strong>bytes32(0)</strong>. 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.</p><p>Ethereum EIP: <a href="https://eips.ethereum.org/EIPS/eip-2935">https://eips.ethereum.org/EIPS/eip-2935</a></p><p>Ethereum Pectra Meta EIP: <a href="https://eips.ethereum.org/EIPS/eip-7600">https://eips.ethereum.org/EIPS/eip-7600</a></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/719">https://github.com/tronprotocol/tips/issues/719</a></p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6686">https://github.com/tronprotocol/java-tron/pull/6686</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6800">https://github.com/tronprotocol/java-tron/pull/6800</a></li></ul><h3>3. Core</h3><h3>1. TIP-833: Hardening resource window calculation logic to eliminate potential overflow risks at the code level</h3><p>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.</p><p>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.</p><p>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.</p><p><strong>NOTE</strong>: This feature is enabled through the on-chain governance proposal parameter 97.</p><p><strong>TIP</strong>: <a href="https://github.com/tronprotocol/tips/issues/833">https://github.com/tronprotocol/tips/issues/833</a></p><p><strong>PR</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6721">https://github.com/tronprotocol/java-tron/pull/6721</a></p><h3>4. TVM</h3><h3>1. Optimizing the energy calculation for the VOTEWITNESS opcode</h3><p>Previously, the <strong>VOTEWITNESS</strong> opcode used <strong>DataWord</strong> to calculate the memory bounds required for a dynamic array. <strong>DataWord</strong> arithmetic operates modulo <strong>256 bits</strong>, and extreme combinations of length and offset could wrap around, thereby underestimating the memory expansion cost. This update adds <strong>getVoteWitnessCost3</strong>, which changes the calculation of array length, offset, and memory bounds to <strong>BigInteger</strong>, avoiding <strong>256-bit</strong> modular wraparound, and adds tests for extreme inputs. The new path takes effect after <strong>proposal 96 ALLOW_TVM_OSAKA</strong> is activated; this PR uses the existing <strong>Osaka gate</strong> and does not add a separate governance proposal.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6613">https://github.com/tronprotocol/java-tron/pull/6613</a></p><h3>2. TIP-854: Tightening the total calldata length shape for signature verification precompiles</h3><p>The two signature verification precompiles (<strong>batchValidateSign</strong> at address <strong>0x…09</strong>, <strong>validateMultiSign</strong> at address <strong>0x…0a</strong>) assume in their billing that the input is a “fixed-length header + an integer number of equal-length elements,” but <strong>execute</strong> 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.</p><p>This update adds a total length check at the execution entry point of both precompiles. Let the word length be <strong>W=32</strong>: <strong>validateMultiSign</strong> uses <strong>H=5</strong>, <strong>I=5</strong>; <strong>batchValidateSign</strong> uses <strong>H=5</strong>, <strong>I=6</strong>. Only inputs satisfying <strong>data.length = H×W + N×I×W</strong> with <strong>N ≥ 1</strong> pass. When <strong>data == null</strong>, <strong>length % W != 0</strong>, <strong>length ≤ H×W</strong>, or <strong>(length-H×W) % (I×W) != 0</strong>, the precompile returns execution failure and empty output; the current call frame consumes its pre-allocated <strong>energy</strong>, the call stack receives 0, and the outer transaction can still continue. The billing formula itself is unchanged.</p><p><em>NOTE: This check only regulates the total length shape of the</em> <strong><em>calldata</em></strong> <em>and does not verify dynamic</em> <strong><em>offset</em></strong><em>, array length, element</em> <strong><em>offset</em></strong><em>, or the full</em> <strong><em>Solidity ABI canonical encoding</em></strong><em>. The functionality is controlled by</em> <strong><em>proposal 96 ALLOW_TVM_OSAKA</em></strong><em>.</em></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/854">https://github.com/tronprotocol/tips/issues/854</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6715"><em>https://github.com/tronprotocol/java-tron/pull/6715</em></a></p><h3>3. TIP-871: Normalizing MODEXP zero-modulus output</h3><p>Previously, the <strong>MODEXP</strong> 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 <strong>modLen</strong>, it returns <strong>modLen</strong> zero bytes. This change only affects inputs where <strong>modLen &gt; 0</strong> and the modulus bytes are all 0; when <strong>modLen == 0</strong>, both the old and new outputs are empty. Neither <strong>energy</strong> pricing nor the non-zero-modulus path is affected.</p><p><em>NOTE: Compatible with Osaka; gated by</em> <strong><em>allowTvmOsaka</em></strong><em>,</em> <strong><em>proposal 96</em></strong> <strong><em>ALLOW_TVM_OSAKA</em></strong><em>.</em></p><p>TIP: <a href="https://github.com/tronprotocol/tips/issues/871">https://github.com/tronprotocol/tips/issues/871</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6780"><em>https://github.com/tronprotocol/java-tron/pull/6780</em></a></p><h3>4. Adding a node-level configuration to control the TVM execution time limit for constant calls</h3><p>Constant calls such as <strong>/wallet/triggerconstantcontract</strong>/<strong>eth_call</strong> are subject to the TVM execution time limit (mainnet default of <strong>80ms</strong>), and complex contracts will hit out_of_time; meanwhile, using <strong>–debug</strong> to remove the timeout also affects block processing, causing <strong>OUT_OF_TIME</strong> divergence and sync stalls, which is unsafe in production. This update adds a node-level configuration <strong>vm.constantCallTimeoutMs</strong> 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 ≤ <strong>Long.MAX_VALUE/1000</strong>, to ensure it can be safely converted to a microsecond deadline).</p><p><strong>Usage tip</strong>: Use <strong>vm.constantCallTimeoutMs</strong> to extend the constant call time limit instead of <strong>–debug</strong>; public nodes are advised to combine it with rate limiting.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/issues/6681"><em>https://github.com/tronprotocol/java-tron/pull/6719</em></a><em> (issue</em> <a href="https://github.com/tronprotocol/java-tron/issues/6681"><em>#6681</em></a><em>)</em></p><h3>5. Net</h3><h3>1. Node configuration supports domain name resolution</h3><p>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.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6727">https://github.com/tronprotocol/java-tron/pull/6727</a></p><h3>2. Optimizing the random disconnection strategy</h3><p>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.</p><p>This optimization includes three points:</p><ol><li>Adding blockRcvTime, which records the time a peer most recently delivered a valid block.</li><li>Correcting the lastInteractiveTime update logic, so that only block inventory higher than the current head block is considered valid activity.</li><li>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.</li></ol><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6704">https://github.com/tronprotocol/java-tron/pull/6704</a></p><h3>3. Tightening P2P inbound inventory rate limiting (fixing the TRX counting vulnerability, adding BLOCK rate limiting)</h3><p>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 &gt; 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 &gt; 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.</p><p>Source Code:</p><p><a href="https://github.com/tronprotocol/java-tron/pull/6731">https://github.com/tronprotocol/java-tron/pull/6731</a>, <a href="https://github.com/tronprotocol/java-tron/pull/6851">https://github.com/tronprotocol/java-tron/pull/6851</a> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6659">#6659</a>)</p><h3>4. Enhancing P2P inbound message validation</h3><p>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.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6712">https://github.com/tronprotocol/java-tron/pull/6712</a> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6667">#6667</a>)</p><h3>5. Reducing memory usage during block synchronization by deferring block deserialization and limiting the number of in-flight blocks.</h3><p>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.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6717">https://github.com/tronprotocol/java-tron/pull/6717</a> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6685">#6685</a>)</p><h3>6. Optimizing the transaction cache backpressure mechanism</h3><p>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.</p><p><strong>Usage tip</strong>: The transaction cache capacity and the backpressure trigger threshold can be adjusted via node.maxTrxCacheSize.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6714%EF%BC%88issue">https://github.com/tronprotocol/java-tron/pull/6714（issue</a> <a href="https://github.com/tronprotocol/java-tron/issues/6684">#6684</a>)</p><h3>7. Limiting the signature byte length of transactions and HelloMessage</h3><p>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.</p><p>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 &lt; 65,” not pushing the entry rate-limiting rule down into block replay, avoiding impact on historical on-chain transactions.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6782">https://github.com/tronprotocol/java-tron/pull/6782</a></p><h3>6. API</h3><h3>1. API rate limiting now supports a non-blocking mode with a configurable switch (resolving HTTP latency caused by rate limiting)</h3><p>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).</p><p><strong>Usage tip:</strong> 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.</p><p><strong>Affected interfaces:</strong> 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.</p><p>Source Code:</p><p><a href="https://github.com/tronprotocol/java-tron/pull/6733">https://github.com/tronprotocol/java-tron/pull/6733</a></p><p><a href="https://github.com/tronprotocol/java-tron/pull/6761">https://github.com/tronprotocol/java-tron/pull/6761</a></p><p><strong>Issue:</strong> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6363">#6363</a>)</p><h3>2. JSON-RPC call parameters now support input as the calldata field</h3><p>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 (https://github.com/ethereum/go-ethereum/pull/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.</p><p>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.</p><p><strong>Affected interfaces:</strong> eth_call, eth_estimateGas, buildTransaction.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6722">https://github.com/tronprotocol/java-tron/pull/6722</a></p><h3>3. Normalize the nonce returned in JSON-RPC transaction objects</h3><p>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.</p><p>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.</p><p><strong>Affected interfaces: </strong>eth_getTransactionByHash, eth_getTransactionByBlockHashAndIndex, eth_getTransactionByBlockNumberAndIndex, eth_getBlockByHash , eth_getBlockByNumber.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6709"><em>https://github.com/tronprotocol/java-tron/pull/6709</em></a></p><h3>4. Deprecate the HTTP REST mappings in the gRPC proto</h3><p>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.</p><p><strong>Usage tip:</strong> 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.</p><p><strong>Affected interfaces:</strong> 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*/*.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6726">https://github.com/tronprotocol/java-tron/pull/6726</a> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6548">#6548</a>)</p><p><a href="https://github.com/tronprotocol/java-tron/pull/6874">https://github.com/tronprotocol/java-tron/pull/6874</a></p><h3>5. Unify the HTTP request body size limit</h3><p>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).</p><p><strong>Usage tip:</strong> Adjust node.http.maxMessageSize / node.jsonrpc.maxMessageSize as needed; over-limit requests need to be split.</p><p><strong>Affected interfaces:</strong> 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.macMessageSize.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6658">https://github.com/tronprotocol/java-tron/pull/6658</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6843">https://github.com/tronprotocol/java-tron/pull/6843</a></li></ul><h3>6. Optimize JSON serialization for block interfaces</h3><p>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.</p><p><strong>Usage tip:</strong> Affects GetBlockByLimitNext, GetBlockByLatestNum, GetBlock, GetNowBlock, GetBlockByNum, GetBlockById; callers need no changes.</p><p>Affected interfaces: /wallet/getblockbylimitnext, /wallet/getblockbylatestnum, /wallet/getblock, /wallet/getnowblock, /wallet/getblockbynum, /wallet/getblockbyid, and the corresponding /wallet*/* block query paths.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6693">https://github.com/tronprotocol/java-tron/pull/6693</a></p><h3>7. Add a blockTimestamp field to JSON-RPC log objects</h3><p>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.</p><p><strong>Usage tip:</strong> Affects eth_getLogs, eth_getFilterLogs, eth_getFilterChanges (log/event filters only), eth_getTransactionReceipt, eth_getBlockReceipts; clients read blockTimestamp directly, eliminating the second block query.</p><p>Affected interfaces: eth_getLogs, eth_getFilterLogs, eth_getFilterChanges (log/event filters), eth_getTransactionReceipt, eth_getBlockReceipts.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6671">https://github.com/tronprotocol/java-tron/pull/6671</a></p><h3>8. Introduce resource limits for JSON-RPC (batch request count / response body / address count / request body size)</h3><p>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.</p><p>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.macLogFilterNum 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.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6728">https://github.com/tronprotocol/java-tron/pull/6728</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6763">https://github.com/tronprotocol/java-tron/pull/6763</a></li></ul><h3>9. Add an optional parameter: serialize 64-bit integers in HTTP GET responses as JSON strings</h3><p>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.</p><p>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.</p><p>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.</p><p>Usage example: GET /wallet/getnowblock?int64_as_string=true</p><p>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.</p><p>Typical interfaces include:</p><ul><li>/wallet/getnowblock and the corresponding /wallet*/getnowblock</li><li>/wallet/getblock, /wallet/getblockbynum, /wallet/getblockbyid, /wallet/getblockbylimitnext, /wallet/getblockbylatestnum and the registered Solidity counterpart paths</li><li>/wallet/getburntrx, /wallet/getReward, /wallet/gettransactioncountbyblocknum and the corresponding /Solidity paths</li><li>/wallet/getpendingsize, provided only by FullNode</li></ul><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6699">https://github.com/tronprotocol/java-tron/pull/6699</a></p><h3>10. Uniformly harden input validation on the JSON-RPC / HTTP API parameter-parsing paths</h3><p>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.</p><p>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).</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6828">https://github.com/tronprotocol/java-tron/pull/6828</a></p><h3>11. Refactor the parsing logic for the JSON-RPC block selector (block tag / block number)</h3><p>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.</p><p>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.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6668">https://github.com/tronprotocol/java-tron/pull/6668</a></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6711">https://github.com/tronprotocol/java-tron/pull/6711</a></p><h3>12. Add signature count and length protections to transaction signature query APIs</h3><p>Tightened the multi-signature query logic to prevent overly long signatures from amplifying responses or bypassing validation. Changes:</p><ol><li>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.</li><li>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.</li><li>getApprovedList now reuses TransactionCapsule.checkWeight and adds validation of permissionId, permission type, and operation.</li><li>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.</li><li>Early-exit errors return only result, and the HTTP JSON may not contain a transaction field.</li><li>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.</li></ol><p>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.</p><p>Affected interfaces: HTTP /wallet/getsignweight, /wallet/getapprovedlist; gRPC Wallet.GetTransactionSignWeight, Wallet.GetTransactionApprovedList.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6820">https://github.com/tronprotocol/java-tron/pull/6820</a></p><h3>7. Dependencies</h3><h3>1. Unifying the JSON technology stack on Jackson and reducing security risks from legacy dependencies</h3><p>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.</p><p>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.</p><p>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.</p><p>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.</p><p><strong>Source Code</strong>:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6701">https://github.com/tronprotocol/java-tron/pull/6701</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6844">https://github.com/tronprotocol/java-tron/pull/6844</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6845">https://github.com/tronprotocol/java-tron/pull/6845</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6863">https://github.com/tronprotocol/java-tron/pull/6863</a></li></ul><h3>2. Dependency upgrades</h3><ul><li>Bump libp2p from 2.2.7 to 2.2.8</li><li>Bump bcprov-jdk18on from 1.79 to 1.84 to address CVE-2026–5598</li><li>Bump jetty from 9.4.57 to 9.4.58 to address CVE-2025–5115</li><li>Bump pf4j from 3.10.0 to 3.14.1 to address CVE-2025–70952</li><li>Bump grpc-java from 1.75 to 1.81 to address CVE-2026–33871</li></ul><p><strong>Source Code</strong>:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6747">https://github.com/tronprotocol/java-tron/pull/6747</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6859">https://github.com/tronprotocol/java-tron/pull/6859</a></li></ul><h3>8. Configuration</h3><h3>1. Automatic binding mechanism for new configuration items</h3><p>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.</p><p>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.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6615">https://github.com/tronprotocol/java-tron/pull/6615</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6735">https://github.com/tronprotocol/java-tron/pull/6735</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6755">https://github.com/tronprotocol/java-tron/pull/6755</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6757">https://github.com/tronprotocol/java-tron/pull/6757</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6759">https://github.com/tronprotocol/java-tron/pull/6759</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6762">https://github.com/tronprotocol/java-tron/pull/6762</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6790">https://github.com/tronprotocol/java-tron/pull/6790</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6794">https://github.com/tronprotocol/java-tron/pull/6794</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6806">https://github.com/tronprotocol/java-tron/pull/6806</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6834">https://github.com/tronprotocol/java-tron/pull/6834</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6795">https://github.com/tronprotocol/java-tron/pull/6795</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6555">https://github.com/tronprotocol/java-tron/pull/6555</a></li></ul><h3>2. Fixed 13 CLI parameters being silently overridden by the configuration file</h3><p>The standard priority should be CLI &gt; configuration file &gt; 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.</p><p><strong>Usage tip:</strong> For example, java -jar FullNode.jar –rpc-thread 16 will now correctly override config.conf; please check your startup scripts before upgrading.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6569">https://github.com/tronprotocol/java-tron/pull/6569</a></p><h3>3. Extracting ConfigKey constants and deprecating the net.type configuration item</h3><p>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.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6565">https://github.com/tronprotocol/java-tron/pull/6565</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6580">https://github.com/tronprotocol/java-tron/pull/6580</a></li></ul><h3>4. Removing the actuator.whitelist configuration to prevent forks</h3><p>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.</p><p>NOTE: Breaking change. Please remove actuator.whitelist from your configuration before upgrading.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6723">https://github.com/tronprotocol/java-tron/pull/6723</a></p><h3>9. Database</h3><h3>1. Removing periodic RocksDB database backups</h3><p>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.</p><p><em>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.</em></p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6724%EF%BC%88issue">https://github.com/tronprotocol/java-tron/pull/6724</a> (issue <a href="https://github.com/tronprotocol/java-tron/issues/6595">#6595</a>）</p><h3>10. Metrics</h3><h3>1. New Prometheus metrics for empty blocks and SR set changes</h3><p>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.</p><p>This change adds statistics for SR set changes and for the number of transactions within a block.</p><p>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.</p><p><strong>Usage tip:</strong> After Prometheus scraping, compute the empty-block ratio using the le=“0” bucket or PromQL.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6624">https://github.com/tronprotocol/java-tron/pull/6624</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6730">https://github.com/tronprotocol/java-tron/pull/6730</a></li></ul><p>Issue: <a href="https://github.com/tronprotocol/java-tron/issues/6590">https://github.com/tronprotocol/java-tron/issues/6590</a></p><h3>2. Removal of InfluxDB metrics storage support</h3><p>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.</p><p>NOTE: Breaking change; before upgrading, please remove the influxdb configuration and migrate to Prometheus + Grafana (tron-docker).</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6725%EF%BC%88issue">https://github.com/tronprotocol/java-tron/pull/6725（issue</a> <a href="https://github.com/tronprotocol/java-tron/issues/6665">#6665</a>）</p><h3>11. Logging</h3><h3>1. Logging improvements: unify gRPC log ingestion, reduce startup noise, and enhance exception diagnostics</h3><p>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.</p><p>This change enhances the logging system with a focus on operations, mainly including the following aspects:</p><ol><li><strong>Unified ingestion of gRPC logs into Logback</strong><br>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.</li><li><strong>Reduced DB statistics log noise during startup</strong><br>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.</li><li><strong>Improved shutdown log completeness</strong><br>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.</li><li><strong>Slow signature verification made observable</strong><br>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.</li><li><strong>LevelDB open stalls no longer silent</strong><br>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.</li><li><strong>Invalid</strong> <strong>–log-config</strong> <strong>configuration fails fast</strong><br>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.</li></ol><p>After the upgrade, log output will be clearer and more controllable:</p><ul><li>gRPC-related diagnostic information will go into ./logs/grpc/grpc.log;</li><li>the main log tron.log will no longer be flooded by DB statistics INFO logs during startup;</li><li>operations-relevant events such as slow signature verification and LevelDB open stalls will be retained in the main log;</li><li>in CI scenarios, the test root logger was changed from DEBUG to INFO to reduce the volume of test logs.</li></ul><p><strong>Usage tip:</strong> To adjust the verbosity of gRPC logs, you can configure the io.grpc logger in logback.xml.</p><p>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.</p><p><strong>Source Code:</strong> <a href="https://github.com/tronprotocol/java-tron/pull/6700">https://github.com/tronprotocol/java-tron/pull/6700</a></p><p><strong>Issue:</strong> <a href="https://github.com/tronprotocol/java-tron/issues/6583">#6583</a></p><h3>12. Event Service</h3><h3>1. Event Plugin must be upgraded to version 3.0.0 or above</h3><p>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.</p><p>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.</p><p>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:</p><ul><li>Uses the –es command-line option or event.subscribe.enable = true</li><li>Uses an external Event Plugin rather than the native queue</li><li>event.subscribe.path points to an old-version plugin package</li><li>The Plugin-Version in the plugin package is lower than 3.0.0, or the version information is missing</li></ul><p>If a node has not enabled event subscription, or uses the native queue, it is not affected by this version check.</p><p>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.</p><p>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.</p><p>For detailed upgrade instructions and plugin package information, please refer to the Event Plugin v3.0.0 Release Notes: <a href="https://github.com/tronprotocol/event-plugin/releases/tag/v3.0.0">https://github.com/tronprotocol/event-plugin/releases/tag/v3.0.0</a></p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6760">https://github.com/tronprotocol/java-tron/pull/6760</a></p><h3>2.Add chain reorganization rollback (removed) semantics for block and transaction events</h3><p>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.</p><p><strong>Compatibility tip:</strong> 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.</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6833">https://github.com/tronprotocol/java-tron/pull/6833</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6718">https://github.com/tronprotocol/java-tron/pull/6718</a></li></ul><h3>3. Fix the issue where the eth_getFilterChanges interface could not obtain new main-chain blocks/logs after a chain reorganization</h3><p>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.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6819">https://github.com/tronprotocol/java-tron/pull/6819</a></p><h3>13. Tooling &amp; Others</h3><h3>1. Optimize the actuator registration process of TransactionRegister</h3><p>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.</p><p>This update optimizes the actuator registration process, mainly in three aspects:</p><ol><li><strong>Add a registration status check</strong><br>Uses a registration status check to avoid duplicate initialization, preventing the same batch of actuators from being scanned and registered repeatedly, reducing unnecessary overhead.</li><li><strong>Adopt fail-fast error handling</strong><br>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.</li><li><strong>Narrow the reflection scanning scope</strong><br>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.</li></ol><p>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.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6447">https://github.com/tronprotocol/java-tron/pull/6447</a></p><h3>2. Migrate keystore-factory to a Toolkit subcommand</h3><p>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).</p><p><strong>Usage tip:</strong> The new invocation method is java -jar Toolkit.jar keystore; the old method remains available during the deprecation period.</p><p>Source Code: <a href="https://github.com/tronprotocol/java-tron/pull/6637">https://github.com/tronprotocol/java-tron/pull/6637</a></p><h3>3. Solidity Node supports conditional shutdown</h3><p>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).</p><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6734">https://github.com/tronprotocol/java-tron/pull/6734</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6801">https://github.com/tronprotocol/java-tron/pull/6801</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6804">https://github.com/tronprotocol/java-tron/pull/6804</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6655">https://github.com/tronprotocol/java-tron/pull/6655</a></li></ul><h3>4. CI / Workflow optimization</h3><p>Improve the 4.8.2 release quality assurance system.</p><ol><li>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;</li><li>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.</li><li>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.</li><li>At the protocol layer, added protoLint, enforcing the use of the UNKNOWN_ prefix for enum 0 values, ensuring API evolution compatibility.</li><li>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.</li></ol><p>Source Code:</p><ul><li><a href="https://github.com/tronprotocol/java-tron/pull/6574">https://github.com/tronprotocol/java-tron/pull/6574</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6706">https://github.com/tronprotocol/java-tron/pull/6706</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6795">https://github.com/tronprotocol/java-tron/pull/6795</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6789">https://github.com/tronprotocol/java-tron/pull/6789</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6582">https://github.com/tronprotocol/java-tron/pull/6582</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6605">https://github.com/tronprotocol/java-tron/pull/6605</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6635">https://github.com/tronprotocol/java-tron/pull/6635</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6663">https://github.com/tronprotocol/java-tron/pull/6663</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6636">https://github.com/tronprotocol/java-tron/pull/6636</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6559">https://github.com/tronprotocol/java-tron/pull/6559</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6808">https://github.com/tronprotocol/java-tron/pull/6808</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6810">https://github.com/tronprotocol/java-tron/pull/6810</a></li><li><a href="https://github.com/tronprotocol/java-tron/pull/6631">https://github.com/tronprotocol/java-tron/pull/6631</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ac8cccba2035" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/mainnet-pyrrho-announcement-ac8cccba2035">Mainnet Pyrrho Announcement</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Inside the java-tron v4.8.2 Configuration System]]></title>
            <link>https://medium.com/tronnetwork/inside-the-java-tron-v4-8-2-configuration-system-ed92a2d24fb2?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/ed92a2d24fb2</guid>
            <category><![CDATA[java-tron-new-release]]></category>
            <category><![CDATA[java-tron]]></category>
            <category><![CDATA[tron]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Thu, 16 Jul 2026 08:42:30 GMT</pubDate>
            <atom:updated>2026-07-16T08:48:35.946Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7XsPKbJr64Ddwy7-5_nmnA.png" /></figure><h3>1. Overview</h3><p>In v4.8.2, the configuration loading process was optimized with reference to the config file formats of other mature projects in the industry; java-tron now uses HOCON with automatic parameter binding. The java-tron configuration system is composed of three layered sources, with priority from high to low:</p><pre>Command-line arguments (CLI)<br>↓ override<br>config.conf (a user-specified config file, or the built-in one)<br>↓ fallback<br>reference.conf (built-in default values in the jar)</pre><p>All values eventually converge into the CommonParameter.PARAMETER singleton, which the node reads from throughout its runtime. Args.setParam() coordinates the entire loading process; once it completes, CommonParameter.PARAMETER is the single source of configuration at runtime.</p><h3>2. Loading the configuration files</h3><p>HOCON (Human-Optimized Config Object Notation) is the configuration format defined by the Typesafe Config library, and it is a superset of JSON. It supports comments (# / //), unquoted strings, multi-line strings, variable substitution (${var}), and include statements. java-tron’s .conf files use exactly this HOCON format. reference.conf is the built-in default file name by Typesafe Config convention; when loading, the library automatically finds it on the classpath and uses it as the fallback.</p><h4>2.1 Locating the config file</h4><p>Configuration.java locates the config file in the following order of priority:</p><pre>getByFileName(configFilePath)<br>1. Look it up as a filesystem path (new File(configFilePath))<br>   ├─ Found → ConfigFactory.parseFile(file).withFallback(ConfigFactory.defaultReference())<br>   └─ Not found → load it from the classpath (ConfigFactory.load(name))</pre><p>configFilePath takes the path specified by the CLI flag -c / --config first; if none is specified, it defaults to “config.conf”.</p><p>How the HOCON merge works:</p><ul><li>ConfigFactory.parseFile(confFile) parses the user’s config.conf.</li><li>.withFallback(ConfigFactory.defaultReference()) uses reference.conf from the classpath to fill in, as defaults, every key not explicitly set.</li><li>Any key present in the user’s file completely overrides the same key in reference.conf; keys not present take their default values from reference.conf.</li></ul><h4>2.2 The role of config.conf</h4><p>Up to and including v4.8.1, config.conf contained almost every configuration item, along with detailed comments.</p><p>From v4.8.2 onward, it is a minimal set of commonly used configuration items recommended for users, with very few comments, reducing users’ cognitive load.</p><h4>2.3 The role of reference.conf</h4><p>The core role of reference.conf is to provide a complete default value for every configuration key, ensuring that the node can start in a reasonable state even when the user has not specified any parameters. It serves two purposes:</p><ol><li><strong>Baseline</strong>: the user’s custom config.conf only needs to contain the keys to override; all other keys are filled in from reference.conf. Typesafe Config’s withFallback mechanism guarantees that the merged config object is always complete, so ConfigBeanFactory binding never throws ValidationFailed due to a missing key.</li><li><strong>Contract</strong>: reference.conf is the configuration contract between the code and node operators — all tunable parameters, their default values, and their valid ranges are declared here. By reading this one file, operators can understand the node’s complete configuration space without reading Java code.</li></ol><p>Before v4.8.2, default values were scattered across ternary expressions throughout Args.java (config.hasPath(X) ? config.getInt(X) : 30), entirely opaque to operators. v4.8.2 introduced reference.conf precisely to make these implicit defaults explicit and centralized.</p><h4>2.4 Priority in three conflict scenarios</h4><h4>2.4.1 Starting a FullNode without specifying a config file via -c</h4><p><strong>① Finding the built-in </strong><strong>config.conf</strong></p><p>When a FullNode starts, the string &quot;config.conf&quot; is passed in by default:</p><pre>Args.setParam(args, &quot;config.conf&quot;)</pre><p>Configuration.getByFileName() searches in this order:</p><pre>1. Look for config.conf in the current working directory as a filesystem path<br>   └─ Found → parseFile() + withFallback(reference.conf)<br>2. Load a file of the same name from the classpath (ConfigFactory.load(&quot;config.conf&quot;))<br>   └─ Found → loaded (the framework jar contains an example config.conf, so this branch is matched)</pre><blockquote><strong>Note</strong>: the framework/src/main/resources/config.conf packaged inside the jar is only an example and may not match a production node’s configuration. For production deployments, specify a complete external config file via -c.</blockquote><p><strong>② If the built-in </strong><strong>config.conf and </strong><strong>reference.conf have different values</strong></p><p>config.conf takes precedence. The semantics of withFallback are: keys already present in the primary config (config.conf) are never overwritten by the fallback; only keys missing from the primary config are filled in from reference.conf.</p><h4>2.4.2 A config file specified via -c has values different from reference.conf</h4><p>In this case the built-in config.conf is ignored, and the user’s &lt;user_config.conf&gt; takes precedence. For any key absent from &lt;user_config.conf&gt;, the value from reference.conf is used.</p><h4>2.4.3 reference.conf has values different from a Config Bean field’s initial value in code</h4><p>reference.conf takes precedence. When ConfigBeanFactory.create() binds via reflection, it writes the values from the config object into the bean fields — and at that point the config object already contains every key from reference.conf, so the Java field initial values are always overwritten.</p><p>A bean field’s initial value is therefore never actually used; its role is to indicate the field’s default value to developers.</p><h4>2.5 Handling keys missing from reference.conf</h4><p>If a field exists in a Config Bean but the corresponding key is missing from reference.conf, the outcome depends on how that field is bound (source: ConfigBeanImpl.java, Typesafe Config 1.3.2):</p><p><strong>Case 1</strong>: the bean field has a setter but reference.conf lacks the key → startup throws an exception.</p><p>ConfigBeanFactory.create() performs a full validation before binding: it iterates over all setters, and if a setter’s key does not exist in the config object, it adds that key to a problems list, then throws a single ConfigException.ValidationFailed — the node fails to start.</p><p>No field in this project’s Config Beans uses the @com.typesafe.config.Optional annotation, so whenever a field has a setter and its key is missing, startup will always fail.</p><p><strong>Case 2</strong>: the bean field has no setter and reference.conf also lacks the key → it can be bound manually with a hasPath() check:</p><pre>// Safe: falls into the else branch when the key is missing, using a hard-coded default<br>mc.foo = config.hasPath(&quot;some.key&quot;) ? config.getLong(&quot;some.key&quot;) : defaultValue;</pre><p>When the key is missing, the code silently falls back to the hard-coded default in code, and startup is unaffected. The cost is that this default value is invisible to operators — it cannot be found in reference.conf.</p><h4>2.6 Location and contents of reference.conf (different from config.conf)</h4><p>common/src/main/resources/reference.conf — located in the common module and packaged into the jar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WVvbImjEsvFzA4QyHQwrSg.png" /></figure><h3>3. Parsing command-line arguments</h3><h4>3.1 Parsing approach</h4><p>Command-line parsing uses the JCommander library; the fields of the CLIParameter class carry @Parameter annotations.</p><pre>CLIParameter cmd = new CLIParameter();<br>JCommander jc = JCommander.newBuilder().addObject(cmd).build();<br>jc.parse(args);</pre><p>Code: framework/src/main/java/org/tron/core/config/args/CLIParameter.java and framework/src/main/java/org/tron/core/config/args/Args.java</p><p>CLIParameter fields have no default values; the default values are defined in CommonParameter. JCommander tracks which parameters were explicitly passed via ParameterDescription.isAssigned(), so parameters that were not passed do not override values from the config file.</p><h4>3.2 Common CLI parameters</h4><p>The available CLI parameters can be viewed with --help: java -jar FullNode.jar --help .</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gfo7A98J1dSKRDtbc8Zsuw.png" /></figure><h4>3.3 Deprecated CLI parameters and their config-key mappings</h4><p>Some legacy parameters are deprecated but still usable: using one prints a warning, and the value is mapped to the corresponding config key (the DEPRECATED_CLI_TO_CONFIG map in Args.java, lines 80–103). <strong>Deprecated parameters may be removed in future releases.</strong></p><ul><li><strong>Storage</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IZMhAB407PftTWvicZHbzg.png" /></figure><ul><li><strong>Virtual machine</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*a5D2fK4HS6abVqc92KsIqQ.png" /></figure><ul><li><strong>Node &amp; network</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/886/1*qTs1GY0mpcqfUPbfXKiTnw.png" /></figure><ul><li><strong>Events</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/946/1*uS2hoCAmiHqSnC_5SZqscQ.png" /></figure><p>In addition, passing seed node IPs as positional arguments is deprecated; at runtime the node prompts to use seed.node.ip.list in the config file instead.</p><h3>4. The full execution order of Args.setParam()</h3><p>The complete resolution order is:</p><pre>Args.setParam(args, defaultConfigFile)<br>├─ 1. JCommander parses the CLI flags → CLIParameter cmd<br>├─ 2. Determine the config file path: if cmd.shellConfFileName is non-empty, use it; otherwise use defaultConfigFile (&quot;config.conf&quot;)<br>├─ 3. Configuration.getByFileName() loads the HOCON config: config.conf ← withFallback ← reference.conf<br>├─ 4. applyConfigParams(config): runs fromConfig() → apply*Config() for VmConfig, NodeConfig, StorageConfig, GenesisConfig, BlockConfig, MiscConfig, CommitteeConfig, RateLimiterConfig, MetricsConfig, and NodeBackupConfig in turn<br>├─ 5. applyCLIParams(cmd, jc): only flags with isAssigned() == true override values in PARAMETER<br>├─ 6. applyEventConfig(eventConfig): the event config is applied after the CLI step so that --es takes effect<br>├─ 7. applyPlatformConstraints(): on ARM64, RocksDB is enforced (any dbEngine value in the config file is ignored)<br>└─ 8. initLocalWitnesses(config, cmd): SR private-key initialization (see Section 6)</pre><h3>5. The Config Bean binding mechanism</h3><p>Each configuration section maps to a Config Bean class under common/src/main/java/org/tron/core/config/args/:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_xrNwLYWhHlHm2Ov7H6a0w.png" /></figure><p>Keys covered by MiscConfig (scattered fields spanning multiple top-level sections, for which dedicated beans are not practical):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kYU0fldeOVH8zNBebw6RnA.png" /></figure><h4>Binding approach</h4><p>Standard fields are bound with Typesafe Config’s ConfigBeanFactory.create(section, BeanClass.class), which uses JavaBean naming conventions and reflection.</p><p>Manual binding is needed in these cases:</p><ol><li>The HOCON key collides with a Java reserved word (e.g. native, see EventConfig).</li><li>Non-standard camelCase names (e.g. pBFTExpireNum — the JavaBean rules would expect PBFTExpireNum; see CommitteeConfig). These are handled by renaming.</li><li>Keys whose value may be null in the config file, which the binder does not support — e.g. node.discovery.external.ip.</li></ol><p>All apply*Config() methods ultimately write the bean fields into CommonParameter.PARAMETER, the single source of configuration at runtime.</p><h3>6. Loading the <strong>Super Representative</strong> private key (special handling)</h3><p>Private-key sources, from highest to lowest priority:</p><pre>1. The CLI --private-key flag (plaintext private key)<br>2. The localwitness list in config.conf (a list of private keys)<br>3. The keystore file path(s) in localwitnesskeystore in config.conf, plus the CLI --password</pre><p>If the node is started in SR mode with -w but no private-key source is provided, the node fails to start and throws a TronError.</p><p>After Spring starts, any bean can obtain the configuration in either of the following ways:</p><pre>// Option 1: inject Args (which extends CommonParameter)<br>@Autowired private Args args;<br>// Option 2: access the singleton statically<br>CommonParameter.getInstance()</pre><p>The two are equivalent — Args.getInstance() returns the same PARAMETER object.</p><h3>7. Configuration changes from v4.8.1 to v4.8.2</h3><h4>7.1 New configuration parameters (13)</h4><ul><li>Event subscription (event.subscribe)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7dy2PnnaMQYiGpc-zwoogQ.png" /></figure><ul><li>Virtual machine (vm)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ENM37aLekO5TpyL5LMuJJw.png" /></figure><ul><li>Node (node)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Qqp0YoTxSWunAmjwhYmC0A.png" /></figure><ul><li>HTTP service (node.http)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4YJQimNxr0hW1GzOMdLzdA.png" /></figure><ul><li>JSON-RPC service (node.jsonrpc)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jC5O8aN6BVjR-tOUefNW1g.png" /></figure><ul><li>API rate limiting (rate.limiter)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*siuw9vj98obBIoyHqPZmFQ.png" /></figure><ul><li>On-chain governance (committee)</li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bwJHhKJau8waCNWW5GOz7w.png" /></figure><h4>7.2 Deprecated parameters (old names still accepted as aliases, 4)</h4><p>The following keys have been renamed. The old keys are still read in v4.8.2 for backward compatibility (with a deprecation warning), but reference.conf only lists the new names:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*3s9rODmztL-CQkgtX14bWw.png" /></figure><h4>7.3 Removed parameters (23)</h4><p>The following parameters are completely removed in v4.8.2. Writing them in a config file does not cause an error, but they no longer take effect.</p><ul><li><strong>Actuator whitelist (</strong><strong>actuator.whitelist)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*j_0v8y54W6W4YUVOFixtIA.png" /></figure><ul><li><strong>Database hot backup (</strong><strong>storage.backup, entire group)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Mch67L-YCRuzF0BCKOQKGQ.png" /></figure><p>node.backup (the primary/standby high-availability switchover for nodes) is a separate feature and is unaffected.</p><ul><li><strong>Low-level networking (</strong><strong>node.*)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*jtnjugXntetYDe2ejBc28g.png" /></figure><ul><li><strong>InfluxDB metrics (</strong><strong>node.metrics.influxdb, entire group)</strong></li></ul><p>v4.8.2 removes support for writing metrics to InfluxDB; the entire group of keys below no longer takes effect:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ICbXCuLivDYmUF6iUh_6ow.png" /></figure><p>Prometheus metrics (node.metrics.prometheus) are unaffected and continue to work.</p><ul><li><strong>Network typeNetwork type (</strong><strong>net.type)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*gm13iXpT_gYMOZknjRTmHw.png" /></figure><ul><li><strong>LevelDB storage settings (</strong><strong>storage.properties[].*)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*_w7N7HMICmKxErRaw4-i4A.png" /></figure><ul><li><strong>Database index settings (</strong><strong>storage.index.*)</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*TEF0XY0GmPLBwa2HWsIyow.png" /></figure><h3>8. Configuration file migration process</h3><p>The latest configuration template lives at common/src/main/resources/reference.conf.</p><p>You can migrate an old configuration to the new format in two ways. To standardize on the latest template, rebuild your configuration with the new reference.conf as the baseline. To preserve a large fleet of production nodes that each carry different environment settings or deployment-specific customizations, start from your existing configuration instead. Either way, finish with a complete diff against the latest reference.conf and confirm that every remaining difference is intentional.</p><h4>8.1 Option 1: rebuild using the new reference.conf as the baseline</h4><p>Suitable for scenarios where the goal is a unified configuration structure and standardized config files, or a first upgrade to the new configuration format.</p><p><strong>Migration steps:</strong></p><ol><li>Copy the new reference.conf as the base of the new configuration.</li></ol><p>2. Extract the deployment-specific settings you need to keep from the old configuration.</p><p>3. Migrate these settings into the corresponding places in the new template.</p><p>4. Migrate only settings confirmed to still be needed; avoid copying entire sections of the old configuration.</p><p>5. Map renamed keys to the new version, for example:</p><ul><li>node.maxActiveNodes → node.maxConnections</li><li>node.maxActiveNodesWithSameIp → node.maxConnectionsWithSameIp</li></ul><p>6. For newly added keys, use the template defaults directly, adjusting them to your deployment’s needs.</p><p>7. Review the following configuration modules with particular care: storage, node, node.metrics, event.subscribe, rate.limiter.</p><p>8. Finally, diff against the latest reference.conf and confirm that all remaining differences are intentional and deployment-specific configurations.</p><h4>8.2 Option 2: modify based on the old configuration</h4><p>Suitable for scenarios where a large number of production node configurations already exist, with considerable environment differences or deployment-specific customizations between nodes, and the migration should preserve the existing configurations as much as possible.</p><p><strong>Migration steps:</strong></p><ol><li>Keep the old configuration file as the base.</li></ol><p>2. Referring to the new documentation and the latest reference.conf, remove deprecated configuration items. <strong>Any configuration item not present in </strong><strong>reference.conf has no effect</strong> — for example:</p><ul><li>All factor keys are no longer in effect and should be removed.</li></ul><p>3. Replace renamed keys, for example:</p><ul><li>node.maxActiveNodes → node.maxConnections</li><li>node.maxActiveNodesWithSameIp → node.maxConnectionsWithSameIp</li></ul><p>4. Add the newly introduced keys, for example:</p><ul><li>node.minConnections = 8</li><li>node.minActiveConnections = 3</li></ul><p>5. Correct configuration structure and data types, for example:</p><ul><li>Move node.metricsEnable inside the node {} block.</li><li>Change node.metrics.prometheus.port = “9527” to port = 9527.</li></ul><p>6. Remove empty settings, invalid comments, and leftover legacy formatting.</p><p>7. Normalize the indentation, blank lines, and ordering of configuration items.</p><p>8. Finally, diff against the latest reference.conf and confirm that all remaining differences are intentional and deployment-specific configurations.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=ed92a2d24fb2" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/inside-the-java-tron-v4-8-2-configuration-system-ed92a2d24fb2">Inside the java-tron v4.8.2 Configuration System</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Technical Guide to the GreatVoyage v4.8.2(Pyrrho) API Upgrade: JSON, HTTP API, and JSON-RPC]]></title>
            <link>https://medium.com/tronnetwork/technical-guide-to-the-greatvoyage-v4-8-2-pyrrho-api-upgrade-json-http-api-and-json-rpc-c91813ca0956?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/c91813ca0956</guid>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Wed, 15 Jul 2026 09:46:26 GMT</pubDate>
            <atom:updated>2026-07-15T10:32:21.126Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SPTf2-q9vYXMMK_74dV55w.png" /></figure><h3>1. HTTP JSON Technology Stack Upgrade: fastjson → Jackson</h3><h3>Why Replace fastjson?</h3><p>Historically, java-tron maintained two JSON technology stacks simultaneously: <strong>fastjson</strong> and <strong>Jackson</strong>. The HTTP API primarily used fastjson, while modules like JSON-RPC and the Event Plugin relied more on Jackson. This dual-stack approach not only increased dependency maintenance costs but also easily led to inconsistencies in JSON serialization and parsing behaviors across different interfaces.</p><p>Therefore, GreatVoyage v4.8.2 unifies the underlying JSON framework of the HTTP API to <strong>Jackson</strong>. Rather than rewriting all HTTP Servlets at once, a compatibility layer has been added to org.tron.json.JSON, JSONObject, and JSONArray. The underlying implementation now uniformly uses <strong>Jackson</strong>, preserving the vast majority of existing call methods while avoiding massive modifications to business code.</p><p>This upgrade covers all /wallet*/* interfaces, as well as certain /net/* and /monitor/* interfaces that utilize the HTTP JSON parsing path. If third-party plugins rely on the fastjson provided by the java-tron runtime (such as older versions of the Event Plugin &lt; v3.0.0), they must also be updated accordingly.</p><h3>Impacts on the API</h3><p><strong>This upgrade primarily replaces the JSON Parser, not the HTTP API protocol itself.</strong></p><p>For the vast majority of HTTP interfaces, requests continue to follow a two-stage processing flow: <strong>Parser → JsonFormat.merge() → Protobuf</strong></p><p>Therefore, for standard JSON that conforms to the interface definition, the request processing logic remains unchanged. For invalid inputs such as repeated commas, illegal numbers, or type mismatches, many scenarios would naturally fail during the second parsing stage anyway. After upgrading to Jackson, such requests might return errors earlier, and the exception types or error messages may change, but the ultimate success or failure outcome of the interface generally remains consistent.</p><pre>4.8.1: Original Body → fastjson Pre-parsing → Same Original Body → TRON JsonFormat.merge → Protobuf<br>4.8.2: Original Body → Jackson  Pre-parsing → Same Original Body → TRON JsonFormat.merge → Protobuf</pre><p>For POST APIs on FullNode that utilize the <strong>Jackson-only</strong> path, requests bypass JsonFormat.merge() and are parsed entirely by the Jackson Parser, java-tron’s custom TypeUtils (which retains some historical fastjson conversion behaviors), and business validation logic. Post-upgrade, the handling of invalid JSON on these interfaces will align with the first category of interfaces, standardizing JSON validation standards and providing developers with a more consistent integration experience.</p><p>Affected Jackson-only APIs include:</p><ul><li><strong>Transactions, Accounts, and Proposals:</strong> /wallet/broadcasthex, /wallet/getaccountresource, /wallet/validateaddress, /wallet/gettransactionlistfrompending, /wallet/getproposalbyid</li><li><strong>Rewards and Brokerage:</strong> /wallet/getReward, /wallet/getBrokerage</li></ul><h3>Compatibility Notes</h3><p>For standard JSON requests that comply with interface definitions, this upgrade does not alter the protocol behavior of the HTTP API. The serialization of Protobuf and JSON remains controlled by java-tron’s self-maintained JsonFormat rather than defaulting directly to Jackson’s output. Thus, standard requests and responses remain compatible. <strong>Please note that the order of fields in JSON objects may change; however, field order is not part of the JSON protocol itself. Clients must parse based on field names and should never rely on fixed ordering or perform full-string comparisons of responses.</strong></p><p>While java-tron currently retains some of fastjson’s loose parsing behaviors (such as single quotes, unquoted field names, and trailing commas) to lower migration costs, these behaviors are solely for backward compatibility and are not part of the API contract. We strongly advise callers to <strong>strictly adhere to the </strong><a href="https://www.rfc-editor.org/rfc/rfc8259.html"><strong>RFC 8259</strong></a><strong> standard</strong> when constructing JSON requests, and <strong>do not rely on the loose parsing behaviors </strong>from either Jackson or fastjson, including single quotes, unquoted field names, trailing commas, leading plus signs, and leading zeros.</p><p><strong>We also highly recommend the following:</strong></p><ul><li>Parse JSON by field names; do not rely on the order of returned fields.</li><li>Do not rely on specific exception types or error texts.</li><li>Third-party plugins must explicitly declare their own JSON dependencies and no longer assume java-tron provides com.alibaba.fastjson.*.</li></ul><h3>2. JSON-RPC: Closer Alignment with Ethereum Client Conventions</h3><p>To further improve compatibility with Ethereum ecosystem tools and clients, GreatVoyage v4.8.2 optimizes several JSON-RPC interfaces, bringing their behaviors closer to the Ethereum JSON-RPC specifications while reducing adaptation costs for cross-chain tools.</p><h3>2.1 input as a Calldata Alias for data</h3><p>Previously, some Ethereum clients (such as go-ethereum) only sent the input field, which older versions of java-tron treated as an unknown field and subsequently rejected the request. GreatVoyage v4.8.2 (<a href="https://github.com/tronprotocol/java-tron/issues/6517">Issue #6517</a>, <a href="https://github.com/tronprotocol/java-tron/pull/6722">PR #6722</a>) adds support for the input field, making it a calldata alias for data.</p><p><strong>Affected Interfaces:</strong></p><ul><li>eth_call</li><li>eth_estimateGas</li><li>buildTransaction</li></ul><p><strong>Post-Upgrade Behavior:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YejzGAFLoJIsHAhAd3ynZQ.png" /></figure><p>We recommend that new clients uniformly use</p><pre>&quot;input&quot;: &quot;0x…&quot;</pre><p>and ensure the use of the 0x prefix with an even byte length. Although empty strings will also be parsed as empty bytes, using 0x to represent empty calldata is highly recommended to maintain cross-client compatibility.</p><h3>2.2 Transaction Object nonce Standardized to Ethereum QUANTITY Format</h3><p>To further align with Ethereum JSON-RPC, <a href="https://github.com/tronprotocol/java-tron/pull/6709">PR #6709</a> adjusts the return format of the nonce in transaction objects.</p><p>Previous Return Value:</p><pre>“nonce”: “0x0000000000000000”</pre><p>Adjusted Return Value:</p><pre>“nonce”: “0x0”</pre><p><strong>Affected Interfaces:</strong></p><ul><li>eth_getTransactionByHash</li><li>eth_getTransactionByBlockHashAndIndex</li><li>eth_getTransactionByBlockNumberAndIndex</li><li>eth_getBlockByHash</li><li>eth_getBlockByNumber (when fullTransactions=true)</li></ul><p>Please note that this adjustment only applies to the nonce encoding format within transaction objects; the numerical semantics remain unchanged. The nonce within block objects remains in bytes8 format (e.g., 0x0000000000000000) and is unaffected by this upgrade. Therefore, if clients rely on string snapshots, fixed-length validations, or literal value comparisons, they must adapt their code accordingly.</p><h3>2.3 blockTimestamp Added to Log Objects</h3><p>To lower the cost of fetching block timestamps for indexers, a blockTimestamp field has been added to Log objects. Callers no longer need to query the block separately to determine the time of the block containing the log.</p><p><strong>Affected Interfaces:</strong></p><ul><li>eth_getLogs</li><li>eth_getFilterLogs</li><li>eth_getFilterChanges (Log Filters)</li><li>eth_getTransactionReceipt (logs[])</li><li>eth_getBlockReceipts (logs[] of each Receipt)</li></ul><p>The new field uses a Unix timestamp (in seconds) prefixed with 0x, rather than the internal millisecond timestamp used by TRON. The top-level Receipt does not include a field of the same name.</p><p><strong>Recommendations for Callers:</strong></p><ul><li>Allow the new field when performing strict Schema validation.</li><li>Ensure compatibility during rolling upgrades when older nodes may not yet return this field.</li></ul><p><strong>JavaScript Example:</strong></p><p>JavaScript</p><pre>const timestampMs = Number(BigInt(log.blockTimestamp) * 1000n);</pre><h3>3. Proto Definitions</h3><p>To clean up legacy configurations, GreatVoyage v4.8.2 reorganizes the Proto files in the protocol repository, removing the deprecated google.api.http annotations. Specifically, <a href="https://github.com/tronprotocol/java-tron/issues/6548">Issue #6548</a> (<a href="https://github.com/tronprotocol/java-tron/pull/6726">PR #6726</a>, <a href="https://github.com/tronprotocol/java-tron/pull/6874">PR #6874</a>) removed the google.api.http mappings from api.proto, and subsequently, <a href="https://github.com/tronprotocol/java-tron/pull/6762">PR #6762</a> removed the residual google/api/annotations.proto dependency. As of v4.8.2, all related HTTP annotations have been completely removed.</p><p>These adjustments will not affect the HTTP API provided by the node, but they will impact developers who rely on automatically generated code based on Protos.</p><ul><li><strong>HTTP Annotation Removal:</strong> This affects methods previously annotated with google.api.http across four services: Wallet, WalletSolidity, WalletExtension, and Monitor. If your project relies on Proto annotations to automatically generate grpc-gateway REST routing, you will need to maintain the corresponding mappings yourself or continue retaining older versions of the Proto files.</li></ul><h3>4. Event Plugin Upgrade Requirements</h3><p>Alongside the <strong>fastjson → Jackson</strong> upgrade, the Event Plugin must also be adapted synchronously. This version introduces the following primary changes:</p><p><strong>New Plugin-Version Validation Mechanism:</strong> For nodes that enable Event Subscribe and load external Event Plugins (including the official Kafka/MongoDB plugins and custom PF4J plugins), the Plugin-Version will be checked upon startup.</p><ul><li><strong>Plugin-Version &gt;= 3.0.0:</strong> Allowed to load.</li><li><strong>Version &lt; 3.0.0 (or missing/unparseable):</strong> The plugin will fail to start, ultimately terminating node startup with EVENT_SUBSCRIBE_INIT.</li></ul><p><em>(Note: When </em><em>event.subscribe.native.useNativeQueue=true, the Native Queue is used, and external plugins are not loaded; thus, this check is not triggered.)</em></p><p>It is important to note that the Plugin-Version validation merely verifies the plugin version; it does not guarantee that Jackson adaptation is complete. For custom plugins, simply updating the version number to <strong>3.0.0</strong> or higher is insufficient. Developers must actively remove dependencies on the node runtime’s <strong>fastjson</strong> and implement the necessary code adaptations.</p><p><strong>Important Note for Developers:</strong> Due to the JSON stack upgrade, the parameter types for ContractEventParserJson.parseTopics and parseEventData have been changed from com.alibaba.fastjson.JSONObject to org.tron.json.JSONObject. If a custom plugin calls these interfaces directly, you must update the imports and parameter types, and recompile the plugin against v4.8.2. Failing to do so may still trigger a NoSuchMethodError due to method signature changes.</p><blockquote><strong>The Event Plugin v3.0.0 has been officially released and is available here:</strong></blockquote><blockquote><a href="https://github.com/tronprotocol/event-plugin/releases/tag/v3.0.0"><strong>https://github.com/tronprotocol/event-plugin/releases/tag/v3.0.0</strong></a></blockquote><p>This version is backward compatible with <strong>GreatVoyage v4.8.2</strong> and earlier versions. We highly recommend that developers using the Event Plugin complete their upgrades as soon as possible. After upgrading nodes to <strong>GreatVoyage v4.8.2</strong>, please pay special attention to verifying that the <strong>Plugin Manifest</strong>, node startup logs, and event message flows are operating normally.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c91813ca0956" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/technical-guide-to-the-greatvoyage-v4-8-2-pyrrho-api-upgrade-json-http-api-and-json-rpc-c91813ca0956">Technical Guide to the GreatVoyage v4.8.2(Pyrrho) API Upgrade: JSON, HTTP API, and JSON-RPC</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TVM Osaka Upgrade: Passkeys, Single-Instruction, and Rebuilt ModExp]]></title>
            <link>https://medium.com/tronnetwork/tvm-osaka-upgrade-passkeys-single-instruction-and-rebuilt-modexp-d52c6ef7d3d0?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/d52c6ef7d3d0</guid>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Mon, 13 Jul 2026 09:36:38 GMT</pubDate>
            <atom:updated>2026-07-14T03:48:16.422Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nwx-TtvfyBtSlJrcotMLgw.png" /></figure><blockquote>A Preview of Network Parameter ALLOW_TVM_OSAKA — Releasing with GreatVoyage-v4.8.2(Pyrrho)</blockquote><p>To bridge TRON with hardware-grade security standards and significantly reduce on-chain costs for complex cryptography, a new round of TRON Virtual Machine upgrades has been introduced in the release_v4.8.2 branch. It is controlled by an on-chain governance switch — network parameter AllOW_TVM_OSAKA, <strong>parameter number 96</strong>.</p><p>This upgrade introduces a new set of enhancements to the TRON Virtual Machine (TVM). This article highlights three key improvements that directly expand smart contract capabilities: native verification of signatures generated by secure hardware, a new opcode for more efficient bitwise operations, and an enhanced modular exponentiation precompiled contract with improved gas accounting and boundary handling.</p><p>Below is a breakdown of what they do, how much energy they consume, and what you should check in your contracts before the vote.</p><h3>Activation Mechanism</h3><p>First, let’s clarify a term, as it directly affects how you read this proposal on-chain: <strong>96 is the chain parameter number, not the proposal ID</strong>. A TRON proposal carries a map&lt;int64,int64&gt; mapping of “parameter → value” and has its own independent, incrementing proposal_id. The feature is activated through a governance proposal. Super Representatives vote on a proposal containing this parameter change, and once the proposal is approved, the feature becomes effective.</p><p>This switch has two prerequisites and is irreversible:</p><ul><li>The entire network must be upgraded to the VERSION_4_8_2 (block version 36).</li><li>Before it takes effect, none of the following behaviors exist: opcode 0x1e is unregistered, ModExp billing remains exactly as it is today, and there is no precompiled contract at 0x100.</li><li>The parameter can only be set to 1. There is no path to revert it to 0, and duplicate proposals for an already active parameter will be rejected.</li></ul><p>Upgrading a node to 4.8.2 <strong>does not activate</strong> any of these features. However, if you are a block-producing node, the upgrade will bring a visible change: the block headers you sign will include block version 36 — this is exactly the signaling mechanism for the hard fork itself, and it is how the network satisfies the VERSION_4_8_2 prerequisite. As for VM semantics, they will switch for everyone simultaneously at the maintenance block when the parameter takes effect.</p><h3>1. P256VERIFY: The Curve Your Phone Has Been Using All Along</h3><p>TVM has supported verifying secp256k1 signatures since day one. That is the curve chosen by Bitcoin and Ethereum. But <strong>it is not</strong> the curve chosen by the rest of the computing world.</p><p>Apple’s Secure Enclave, Android’s Keystore, WebAuthn, Passkeys, TPMs, smart cards, and almost all hardware security modules on the market speak <strong>secp256r1</strong> — also known as NIST P-256 or prime256v1. Previously, if a TRON contract wanted to verify such signatures, it had to run full curve operations in Solidity, at a cost that deterred the vast majority of applications.</p><p>Osaka introduces <strong>P256VERIFY</strong> as a native precompiled contract.</p><h3>Specifications</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*guBkF3TVCVWHmSLaBizRcw.png" /></figure><p>Note this address. TRON’s own precompiled contracts are located in an independent numbering range, but P256VERIFY deliberately reuses 0x100 — the exact same slot specified by Ethereum’s EIP-7951. Contracts and auditing tools already written for 0x100 can work on TRON without any modifications.</p><p>For reference, here is how the new precompile compares to the existing signature verification standard:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*4V0Cvmzto4NNt3z467dFow.png" /></figure><p><em>(Note: Both of these numbers are strictly the fees for the precompiled contracts themselves; the outer </em><em>CALL or </em><em>STATICCALL will also incur the basic opcode overhead and memory expansion costs.)</em></p><h3>Checks Performed During Execution</h3><p>Before any curve operations, the precompiled contract checks that 0&lt;r&lt;n, 0&lt;s&lt;n, 0≤qx&lt;p, and 0≤qy&lt;p; it rejects the point at infinity (0,0); and it verifies that (qx,qy) actually lies on the curve. (The cofactor of P-256 is 1, so finite points on the curve inevitably fall within the prime-order subgroup, meaning there are no additional cofactor checks to worry about.)</p><h3>Three Behaviors You Must Internalize</h3><ul><li><strong>It does not revert.</strong> As long as the forwarded energy is sufficient for its execution, all failure paths — invalid lengths, scalar out-of-bounds, points not on the curve, signature verification failures — return “success + empty data.” <strong>Your contract must check the return data, not the </strong><strong>CALL status</strong>. <strong>This is exactly in line with EIP-7951</strong>. (If the forwarded energy is less than 6900, you will get a standard out-of-energy result: 0 pushed to the stack, and the precompiled contract is not executed at all.)</li><li><strong>No low-s malleability check.</strong> Following the specification, s is only range-checked to [1,n-1]. Both s and n — s will simultaneously pass verification for the same message and the same public key. <strong>If your design treats the signature as a unique identifier, nonce, or replay protection, it is vulnerable.</strong> Please hash the message body and track that hash instead. This is the easiest trap to fall into with this precompile, and it’s not a TRON implementation flaw — that’s just how the standard is written.</li><li><strong>Feature detection must check return data.</strong> Before the parameter takes effect, 0x100 is not a registered precompiled contract — it’s just a regular address with no code. Therefore, calling it will <strong>succeed</strong> and return empty data, <strong>rather than</strong> pushing a 0 to the stack. Contracts probing for the availability of P256VERIFY must distinguish between “returned a 32-byte 1” and “returned nothing.” <strong>You must never treat a successful </strong><strong>CALL as proof that the precompiled contract exists.</strong></li></ul><h3>What It Unlocks, and What It Doesn’t</h3><p>This precompiled contract is the missing cryptographic primitive for scenarios like Passkey accounts, hardware-endorsed authorization, and enterprise HSM signatures. But it is not a WebAuthn implementation in itself.</p><p>P256VERIFY accepts an <strong>already-calculated</strong> 32-byte digest, plus the bare (r,s,qx,qy). It does not parse DER or COSE encoded public keys, does not hash WebAuthn’s clientDataJSON/authenticatorDatapayloads for you, and does not verify the challenge, origin, RP ID, authenticator flags, signature counters, or attestations. It also cannot tell you whether the private key behind the signature is truly secured by hardware or if it’s non-exportable. A production-grade Passkey wallet still needs to write these verification logics into the contract on top of the precompile. <strong>What changes is that the most expensive part — the curve operation — is no longer a bottleneck.</strong></p><h3>2. CLZ: Counting Leading Zeros in a Single Instruction</h3><p>Opcode 0x1e, mnemonic CLZ. One in, one out. Five energy — the LOW tier, on par with MUL.</p><p>It pops a 32-byte word, reads it in big-endian format, and pushes back the number of its leading zero bits, ranging from [0,256].</p><pre>CLZ(0x0000…0000) = 256<br>CLZ(0x0000…0001) = 255<br>CLZ(0x4000…0000) = 1<br>CLZ(0x8000…0000) = 0<br>CLZ(0xFFFF…FFFF) = 0</pre><p>The zero-value line is worth emphasizing separately: CLZ(0) returns 256 — neither 0 nor an error.</p><p>This is a small change, but it has a disproportionately large impact on a specific class of code. log2, integer square roots, fixed-point number normalization, Bancor and constant-product price curves, bitmap scanning, large integer libraries — currently, they all rely on hand-written binary search (typically seven to eight rounds of SHR plus comparisons) to locate the most significant bit. That loop now becomes a single opcode.</p><p>Before the parameter takes effect, 0x1e is not a registered opcode. Bytecode can <strong>contain</strong> it, but any execution path that actually hits it will trigger an invalid opcode exception halt, <strong>burning all remaining energy in the current call frame</strong>. This is different from REVERT — REVERT refunds unused energy to the caller. So: either add runtime switch protection or wait until the vote passes before deploying bytecode containing CLZ.</p><h3>3. ModExp: Constrained Inputs and Pricing Matched to True Overhead</h3><p>The modular exponentiation precompiled contract located at 0x05 is the workhorse behind RSA signature verification, VDFs, and various Zero-Knowledge constructions. Its pricing has not been re-evaluated for a long time. Osaka addresses this from three directions.</p><h3>Input Upper Bounds (EIP-7823)</h3><p>The upper limits for baseLen, expLen, and modLen are now individually capped at <strong>1024 bytes</strong>.</p><p>Exceeding the limit <strong>will not</strong> revert the entire transaction. The precompile returns a failure, CALL pushes 0 to the stack, RETURNDATASIZE is 0, and execution continues — this matches the behavior of geth and besu: only the subcall fails.</p><p>One detail is worth stating precisely: <strong>this boundary is checked during the execution phase, not within the billing function</strong>. The VM first calculates the cost, checks it against the energy you forwarded, executes the precompile, and then refunds no energy when it reports a failure. Therefore, an out-of-bounds call will cost you the entire energy budget forwarded to that subcall. Out-of-bounds inputs will be rejected, but the rejection is not free.</p><h3>Repricing (TIP-7883)</h3><p>Before getting to the formulas, here are two definitions. Let m = max(baseLen, modLen). Let highestBit be the <strong>zero-based index</strong> of the highest significant set bit in the first min(expLen, 32) bytes of the exponent; if these bytes are all zero, it evaluates to 0. All divisions below are integer truncating divisions.</p><p><strong>Simply put:</strong> Imagine writing the exponent in binary. highestBit is just counting how many bits are to the right of the leftmost 1. For example, 0x02 is 0000 0010 in binary. The leftmost 1 is at index 1 (counting from 0 from the right), so highestBit = 1. Likewise, 0x01001 yields 16.</p><p><strong>Current TVM Billing:</strong></p><pre>multComplexity(m):<br>    m ≤ 64     →  m²<br>    m ≤ 1024   →  m²/4 + 96m − 3072<br>    otherwise  →  m²/16 + 480m − 199680<br><br>adjExpLen:<br>    expLen ≤ 32  →  highestBit<br>    otherwise    →  8 × (expLen − 32) + highestBit<br><br>energy = multComplexity × max(adjExpLen, 1) / 20</pre><p><strong>After Osaka:</strong></p><pre>multComplexity(m):<br>    m ≤ 32     →  16<br>    otherwise  →  2 × ceil(m / 8)²<br><br>iterCount:<br>    expLen ≤ 32  →  highestBit<br>    otherwise    →  16 × (expLen − 32) + highestBit<br>    (minimum 1)<br><br>energy = max(multComplexity × iterCount, 500)</pre><p>Four changes: the complexity curve is replaced by a much flatter one; the multiplier for long exponents is doubled from 8 to 16; the /20 divisor is removed; and a floor of 500 is introduced.</p><p><strong>This is not an across-the-board price hike, and describing it as such is incorrect.</strong> Removing the /20 divisor, viewed in isolation, pushes prices up. However, the new complexity curve <strong>drastically lowers the cost of medium-sized operands</strong>, and under certain shapes, it will win out.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2mHtdO82ssVjm07JtLeETA.png" /></figure><blockquote><strong>Key Takeaway: The Net Result is Cheaper for Medium Operands.</strong></blockquote><blockquote>Please stare at the 128-byte row and walk through the math, because the intuition here is backward. The original complexity drops from 13,312 to 512 (a 26x reduction); losing the /20divisor pulls the price back up by 20x. <strong>The net result is a cost reduction: 665 → 512.</strong></blockquote><p>The floor raises the price of trivial calls, the doubled long exponent multiplier raises the price of genuinely expensive calls, and the middle ground could swing in either direction. If you have been budgeting under the assumption that “Osaka will uniformly make ModExp more expensive,” please re-measure using your actual operand sizes.</p><h3>Zero Modulus Normalization (TIP-871)</h3><p>For a successful, non-out-of-bounds call where modLen &gt; 0, when the modulus is numerically zero, ModExp previously returned an empty byte array. After Osaka, it returns an all-zero buffer with a length equal to modLen.</p><p>Mathematically, x mod 0 is undefined, so this return value has always been a convention rather than a computed result. The new convention is the more useful one: the caller can determine the size of the return buffer solely from the declared modLen, eliminating the need to write special-case branches for a zero modulus. Pay attention to those qualifiers — out-of-bounds calls still fail with empty return data, and calls where modLen ==0 return zero bytes both before and after the change.</p><h3>What to Do Before the Vote</h3><ul><li><strong>Contract Developers:</strong> If you call ModExp, please recalculate your costs with your actual operand sizes; do not assume the direction of the price change. If you rely on a zero modulus returning empty data, that behavior has changed. If you plan to adopt P256VERIFY, read the section on malleability twice — check the return data, never check the CALL status, and never treat signatures as unique identifiers. The same rule applies to feature detection: 0x100 will successfully respond today, it’s just that there’s nothing inside.</li><li><strong>Toolchain and Compiler Authors:</strong> CLZ at 0x1e requires disassembler and analyzer support. Emitting this instruction before the parameter takes effect will generate bytecode where, if the execution path actually reaches it, it will cause an exception halt and burn all remaining energy in that frame.</li><li><strong>Super Representatives:</strong> ALLOW_TVM_OSAKA (parameter 96) requires that the VERSION_4_8_2 hard fork has passed, only accepts a value of 1, and is irreversible. It can be voted on individually or bundled with other parameters into a single proposal.</li><li><strong>Node Operators:</strong> Upgrading to 4.8.2 itself does not activate anything. If you produce blocks, note that your block headers will carry block version 36 — this is the fork signal, which is exactly the intended effect.</li><li><strong>Test It Yourself:</strong> Developers are strongly encouraged to deploy and test these changes on the <strong>Nile</strong> testnet using the latest toolchains to audit their ModExp budgets and P256VERIFY integrations before the parameter officially takes effect on Mainnet.</li></ul><h3>Bonus: A Sneak Peek at Another VM Upgrade in 4.8.2</h3><p>Osaka is not the only VM-facing parameter in this release. ALLOW_TVM_PRAGUE (parameter number 95) introduces TIP-2935: serving historical block hashes from state using a sliding window of 8191 blocks. The system contract that hosts it has a 20-byte VM address and 83 bytes of runtime code that are completely identical to Ethereum’s EIP-2935 contract. (When the parameter takes effect, TRON writes this code directly into state, rather than replaying Ethereum’s pre-signed, keyless deployment transaction; the address is stored in the 21-byte TRON format prefixed with 0x41.)</p><p>It has its own prerequisites: it requires ALLOW_TVM_SHANGHAI to already be active, because the deployed runtime code contains PUSH0. Also, it does not backfill: the ring buffer writes one parent hash per block starting from the moment it takes effect. Therefore, slots corresponding to earlier blocks within the window will return bytes32(0) until it fills up roughly 8191 blocks later. It is an independent parameter that Super Representatives can vote on individually or bundle with Osaka. It deserves its own article, and that one is coming soon.</p><p><em>GreatVoyage-v4.8.2 is located in the release_v4.8.2 branch of </em><a href="https://github.com/tronprotocol/java-tron"><em>tronprotocol/java-tron</em></a><em>. The aforementioned features land in PRs </em><a href="https://github.com/tronprotocol/java-tron/pull/6720"><em>#6720</em></a><em> (P256VERIFY), </em><a href="https://github.com/tronprotocol/java-tron/pull/6656"><em>#6656</em></a><em> (CLZ), </em><a href="https://github.com/tronprotocol/java-tron/pull/6654"><em>#6654</em></a><em> (TIP-7883), </em><a href="https://github.com/tronprotocol/java-tron/pull/6611"><em>#6611</em></a><em> (EIP-7823), and </em><a href="https://github.com/tronprotocol/java-tron/pull/6780"><em>#6780</em></a><em> (TIP-871), respectively. TIP-2935 lands in </em><a href="https://github.com/tronprotocol/java-tron/pull/6686"><em>#6686</em></a><em>.</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d52c6ef7d3d0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/tvm-osaka-upgrade-passkeys-single-instruction-and-rebuilt-modexp-d52c6ef7d3d0">TVM Osaka Upgrade: Passkeys, Single-Instruction, and Rebuilt ModExp</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Trying TRON Post-Quantum (PQ) Signatures on the Testnet]]></title>
            <link>https://medium.com/tronnetwork/trying-tron-post-quantum-pq-signatures-on-the-testnet-cbf0d4770e1f?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/cbf0d4770e1f</guid>
            <category><![CDATA[tutorial]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Thu, 02 Jul 2026 15:23:39 GMT</pubDate>
            <atom:updated>2026-07-03T06:10:42.636Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hJEBEsGJbp9VnN5Y6pQFlQ.png" /></figure><blockquote><em>Target Audience: ordinary users, developers, and blockchain enthusiasts who want to try out post-quantum signatures on the </em><strong><em>Nile testnet</em></strong><em>.</em></blockquote><blockquote><em>You don’t need to understand cryptography — being comfortable with the command line and copy-paste is enough.</em></blockquote><blockquote><em>⚠️ Everything here happens on the </em><strong><em>testnet</em></strong><em> with </em><strong><em>test coins</em></strong><em>; no real assets are involved.</em></blockquote><h3>What this is, and why it’s worth trying</h3><p>Future quantum computers may be able to break the elliptic-curve signatures (ECDSA) in wide use today. To prepare ahead of time, TRON has added <strong>post-quantum (PQ) signatures</strong> at the protocol level, and is opening them up for early hands-on testing on the <strong>Nile testnet</strong> first.</p><p>You can create a post-quantum wallet and use it to send transactions. Each transaction is signed by a post-quantum algorithm, making it harder to forge even if quantum computers arrive.</p><p>TRON currently supports two NIST-standardized schemes for both system transactions and smart contracts, gated by two proposals:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*WLIqgpMMLAERm-V0xdw1ag.png" /></figure><p><em>Tip: both PQ signatures are more than 10x larger than a regular ECDSA signature, so PQ transactions consume more bandwidth — that’s the inherent cost of post-quantum signatures.</em></p><p>A quick size comparison of public keys and signatures:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bsHOgYCIB57BIBB5yGBhIA.png" /></figure><h3>Before you start</h3><ol><li><strong>Java 8 (JDK 8)</strong> — required to run wallet-cli (and to build your own Nile node).</li><li><strong>wallet-cli (post-quantum branch)</strong> — TRON’s official command-line wallet; PQ support lives on the feature/post-quantum branch:</li></ol><p>— Repo: <a href="https://github.com/tronprotocol/wallet-cli">https://github.com/tronprotocol/wallet-cli</a><br> — Branch: feature/post-quantum</p><p>3.<strong> A Nile node that supports PQ</strong> — used to broadcast your transactions. Pick one of:</p><p>— Connect to a public Nile endpoint directly (configured in Step 1, easiest);<br> — Or run your own Nile full node per the official docs: <a href="https://nileex.io/run/getRunPage">https://nileex.io/run/getRunPage</a></p><p>4.<strong> Test TRX</strong> — claim it for free from the Nile faucet: <a href="https://nileex.io/join/getJoinPage">https://nileex.io/join/getJoinPage</a></p><p>5. <strong>Block explorer</strong> — look up transactions / addresses / proposal status: <a href="https://nile.tronscan.org/">https://nile.tronscan.org</a></p><blockquote><em>⚠️ </em><strong><em>Key prerequisite: the PQ proposals must already be active on-chain.</em></strong> <em>A PQ transaction is only accepted after the ALLOW_FN_DSA_512 (Falcon) / ALLOW_ML_DSA_44 (Dilithium) proposals have passed and taken effect; otherwise it is rejected even if the signature is perfectly valid. These proposals are turned on by Super Representative vote, and the activation time is not fixed — keep an eye on the progress (official announcements + the explorer’s Proposals page).</em></blockquote><p>To check whether a scheme is enabled, use the command below to query the status of the two PQ parameters<strong>:</strong></p><pre>curl -s https://nile.trongrid.io/wallet/getchainparameters \<br> | grep -oE &#39;&quot;getAllow(FnDsa512|MlDsa44)&quot;[^}]*&#39;</pre><p>How to read the result: an entry containing value:1 means activated; if you only see the key with no value field, it is not yet activated. <a href="https://nile.trongrid.io/">https://nile.trongrid.io</a> can be replaced with any Nile HTTP node (including your own node, e.g. <a href="http://127.0.0.1:8090/">http://127.0.0.1:8090</a>). You can also run GetChainParameters in wallet-cli’s interactive mode to see the same values.</p><p>Download the wallet-cli source</p><pre>git clone -b feature/post-quantum https://github.com/tronprotocol/wallet-cli.git<br>cd wallet-cli</pre><h3>Step 1: Point the config at Nile, then build</h3><p>wallet-cli connects to mainnet by default. Edit src/main/resources/config.conf (or whatever config file you use), change config item fullnode.ip.list to below:</p><pre>fullnode = {<br>  ip.list = [<br>   &quot;grpc.nile.trongrid.io:50051&quot;<br>  ]<br>}</pre><p>Use the latest endpoints published by TronGrid/Nile; if you run your own PQ full node, replace fullnode with your own address (e.g. 127.0.0.1:50051).</p><p>Build only after editing the config, to produce the runnable JAR:</p><pre>./gradlew clean build</pre><p>After the build, the JAR is at build/libs/wallet-cli.jar — you’ll use it to start the wallet in the next step.</p><h3>Step 2: Create a PQ wallet</h3><p>Start the interactive wallet:</p><pre>java -jar build/libs/wallet-cli.jar</pre><p>Use RegisterWalletPQ to create a post-quantum wallet, with an optional scheme argument (defaults to Falcon-512 if omitted):</p><pre>wallet&gt; RegisterWalletPQ                # default FN_DSA_512 <br># or <br>wallet&gt; RegisterWalletPQ ML_DSA_44      # choose ML_DSA_44 </pre><p>Follow the prompts to enter your password twice. On success it writes an encrypted keystore under Wallet/ and prints your address:</p><pre>Please input password.<br>Please input password again.<br>RegisterWalletPQ successful, keystore file: <br>./Wallet/TXxxx...xxx.json</pre><blockquote>🔑 <strong><em>Note down this </em></strong><em>TXxxx…</em><strong><em> address</em></strong><em>, which you will find it in the next step.</em></blockquote><p>A PQ wallet is password-encrypted just like a regular wallet. The keystore has a scheme field that records which PQ scheme it uses.</p><h3>(Optional) Just want to see what a key looks like?</h3><p>GeneratePQKey[scheme] generates a keypair and prints it but does not save it — handy for a first look, after which you can import it with ImportWalletPQ.</p><h3>Step 3: Fund your PQ address with test coins</h3><p>A post-quantum address looks exactly the same as a regular T-address, so the faucet works as usual:</p><ol><li>Open the Nile faucet: <a href="https://nileex.io/join/getJoinPage">https://nileex.io/join/getJoinPage</a></li><li>Enter the TXxxx… address from the previous step and claim test TRX.</li><li>Search for your address on <a href="https://nile.tronscan.org/">https://nile.tronscan.org</a> to confirm it arrived.</li></ol><h3>Step 4: Send a post-quantum transaction</h3><p>Back in wallet-cli, log in with the address and password from before:</p><pre>wallet&gt; Login<br># select/enter your PQ wallet, then type the password</pre><p>Then transfer as usual — for example, send 1 TRX to some address (1 TRX = 1_000_000 sun):</p><pre>wallet&gt; SendCoin &lt;recipient TXxxx...&gt; 1000000</pre><p>The wallet signs automatically using your wallet’s PQ scheme; you do not need to perform any extra steps. A successful broadcast means Nile has accepted this post-quantum transaction 🎉.</p><p>Other commands (TransferAsset, TriggerContract, etc.) also sign with PQ automatically.</p><h3>Step 5: Verify it in the block explorer</h3><p>Look up your transaction on the <a href="https://nile.tronscan.org/">https://nile.tronscan.org</a> explorer to ensure it reaches finality and is recorded on-chain. If valid, you should see a <strong>PQ tag</strong> indicating the specific quantum-resistant algorithm used.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*IhRxp_gvBZVYYYWCqWeGYw.png" /></figure><p>The difference from a regular transaction is that the signature sits in the pq_auth_sig field (parallel with the previous signature field). Further, you can find all transaction details through API <a href="https://nile.trongrid.io/wallet/gettransactionbyid">https://nile.trongrid.io/wallet/gettransactionbyid</a>.</p><blockquote><strong>Backup and security (please read)</strong></blockquote><blockquote>This feature is currently for testnet experimentation and feedback.</blockquote><blockquote>When creating a wallet, securely save the persisted private key. Back up the keystore file + password as well.</blockquote><blockquote>Do not reuse testnet keys in any mainnet / real-asset context.</blockquote><blockquote>PQ private keys are very long and store them in a file kept offline.</blockquote><h3>Limitations in the current version</h3><p>This section lists features that PQ wallets currently cannot use, or that have known limitations, on the wallet-cli feature/post-quantum branch — so testers know in advance and avoid confusion.</p><ul><li><strong>Gas-free transfer (GasFreeTransfer)</strong>: relies on an off-chain EIP-712 permit signature (ECDSA secp256k1); since that protocol does not yet define a PQ scheme, it cannot be supported. Workaround: use a regular ECDSA wallet for GasFree scenarios.</li><li><strong>Mnemonic-related operations</strong>: PQ wallets do not generate BIP-39 mnemonics and cannot be exported or recovered through one. Backup alternative: use BackupWallet to export the private-key hex and ExportWalletKeystore to back up the JSON file.</li><li><strong>Ledger hardware wallet</strong>: Ledger firmware only supports ECDSA signatures and currently can’t handle post-quantum algorithms; the two are incompatible.</li></ul><p>These limitations will be lifted gradually as the surrounding toolchain gains native pq_auth_sig support; they are all temporary technical constraints for now.</p><h3>FAQ</h3><p><strong>Q1: My transaction was rejected by the node?</strong></p><p>The most common cause is that the target network hasn’t activated the corresponding proposal yet. A PQ transaction is only accepted after the ALLOW_FN_DSA_512 (Falcon) / ALLOW_ML_DSA_44 (Dilithium) proposal is active. Follow <strong>To check whether a scheme is enabled</strong> in Section 2 and use getchainparameters to confirm the switch’s value is 1; if it is 0 or the field is absent, it isn’t active yet and you must wait for the proposal to pass before retrying.</p><p><strong>Q2: My PQ address looks identical to a regular address — is that normal?</strong></p><p>Yes. PQ addresses are derived with the same formula as regular addresses and are indistinguishable before signing. To confirm a wallet’s type, check the scheme field in the keystore JSON.</p><p><strong>Q3: Can a single multisig transaction mix PQ wallets and regular wallets?</strong></p><p>Yes. In a multisig, each participant signs with the algorithm of their own keystore (PQ signs with PQ, regular signs with ECDSA/SM2) — they don’t interfere with each other.</p><h3>Feedback</h3><p>Hit a problem or have suggestions? Feedback is welcome in the TRON community / on GitHub:</p><ul><li>java-tron: <a href="https://github.com/tronprotocol/java-tron">https://github.com/tronprotocol/java-tron</a></li><li>PQ TIP: <a href="https://github.com/tronprotocol/tips/issues/899">https://github.com/tronprotocol/tips/issues/899</a></li><li>wallet-cli: <a href="https://github.com/tronprotocol/wallet-cli">https://github.com/tronprotocol/wallet-cli</a></li></ul><p><em>Have fun, and let’s get the blockchain ready for the post-quantum era together 🚀</em></p><p><em>— — End of guide — —</em></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cbf0d4770e1f" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/trying-tron-post-quantum-pq-signatures-on-the-testnet-cbf0d4770e1f">Trying TRON Post-Quantum (PQ) Signatures on the Testnet</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[TRON Post-Quantum Signature Design]]></title>
            <link>https://medium.com/tronnetwork/tron-post-quantum-signature-design-522c6e5e4023?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/522c6e5e4023</guid>
            <category><![CDATA[technology]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Wed, 01 Jul 2026 04:05:22 GMT</pubDate>
            <atom:updated>2026-07-02T15:27:04.905Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*oLYyvtlnVKWN99EJJLRFMw.png" /></figure><h3>Summary</h3><p>Introduce post-quantum (PQ) digital signature support at the TRON protocol layer. The first activation enables two post-quantum signature algorithms — Falcon-512 (FN_DSA_512) and Dilithium2 (ML_DSA_44) — covering all consensus-flow signatures. Falcon-512 remains the primary choice for its compact size; ML-DSA-44 is implemented in parallel as a NIST-finalized (FIPS 204) hedge against the still-draft FN-DSA standard. Each is independently gated by its own on-chain governance proposal. The design principle is to leave the Account structure unchanged — the address field carries both ECDSA- and PQ-derived addresses in an “algorithm-agnostic” way. New PQAuthSig fields are added to Transaction, BlockHeader, and HelloMessage payloads, and verification is routed to the matching path based on which signature field is set.</p><p>Target timeline: launch the testnet in Q2 2026, completing the deployment ~3 years ahead of the industry-projected quantum-threat threshold (~2029) and positioning TRON as the first major public blockchain to complete a full PQ migration.</p><h3>Problem</h3><h3>Motivation</h3><p>All major blockchains today (TRON, Bitcoin, Ethereum, BNB Smart Chain, etc.) use elliptic-curve cryptography (ECDSA) for consensus-flow signatures. The security of ECDSA rests on the discrete-logarithm problem, which would take billions of years for a classical computer to solve but only minutes for a quantum computer running Shor’s algorithm. The industry widely projects the <a href="https://arxiv.org/pdf/2603.28846">quantum-threat threshold to arrive around 2029</a>; on Bitcoin alone, over 6.9M BTC (~1/3 of supply) sit at addresses whose public keys are already exposed.</p><p>Cryptographic migration itself is highly complex: protocol changes, third-party security audits, and adoption across wallets, exchanges, and contract ecosystems typically take a long time. Waiting until the quantum threat actually arrives is too late; the work must start now.</p><h3>Current State</h3><ul><li>All TRON transaction and block signatures currently use secp256kl ECDSA, with addresses derived as 0x41 || Keccak-256(ecdsa_pk[1:])[12..32]. The protocol layer carries no post-quantum-signature fields.</li><li>The TVM precompiles ValidateMultiSign, BatchValidateSign, and ECRecover all depend on ECDSA and cannot be directly reused for PQ signatures, which require an explicit public key as an input parameter.</li></ul><h3>Post-Quantum Algorithm Challenges</h3><p>PQ algorithms, the same as ECDSA, are based on public-key / private-key pairs, but porting them to the protocol layer raises several core challenges.</p><h3>Explicit public-key transmission — the core problem to solve in this cycle</h3><p>ECDSA has the Swiss-army-knife ecrecover: given a 65-byte secp256kl signature, the node can recover the public key (65 bytes) and derive the account address (21 bytes). This lets the TRON transaction carry no public key at all; all upper-layer protocols rest on this implicit convention.</p><p>Falcon, ML-DSA, SLH-DSA, and other PQ algorithms have no equivalent recover primitive:</p><ul><li>Falcon key recovery is still at the academic-research stage; BouncyCastle 1.84 has not yet exposed any related API.</li><li>ML-DSA / SLH-DSA do not, by design, support recovering the public key from a signature.</li></ul><p>In other words, to verify a PQ signature, a node must first obtain the full public key. This is the first problem this round of protocol changes must solve. The concrete design choice boils down to where to store the public key. We weighed two paths:</p><ul><li>Option A — store the PQ public key on chain; transactions only reference it. The simple transfer TRX transaction body would still grow ≥ 5× because the Falcon signature alone is ~11× the size of an ECDSA signature. Additional costs: passively activated accounts have no public key on file, account state inflates significantly, wallets cannot sign without reading real-time on-chain data, and the protocol layer itself requires substantial new design — on-chain key-storage layout, the reference mechanism used from transactions, key-rotation semantics, etc. — none of which has a validated, mature precedent in any major chain today, translating into notable stability risk.</li><li>Option B — carry the PQ public key inside each transaction. Benefits: minimal protocol intrusion (account state fields are unchanged), zero friction for passively activated accounts, and stateless signing from wallets / SDKs. The only downside compared with Option A is that the transaction body grows &gt;= 10× (a cost that could be optimized over time).</li></ul><p>Weighing the three dimensions of “minimal intrusion into the existing protocol, lowest first-release implementation cost, smallest ecosystem-side change”, we choose Option B, which can be iteratively optimized as the scheme matures and more community feedback is incorporated, whereas Option A’s architectural problems (passive activation, Account-structure breakage) would be virtually irreversible once shipped. Implementation details are covered below in Proposed Design.</p><h3>Per-signature size inflation — known cost, optimizable in stages</h3><p>As mentioned above a side effect of carrying the public key is the jump in signature footprint: a Falcon-512 public key + signature is ~25× the ECDSA size. The table below compares ECDSA against three PQ candidates:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Tfj7WhQZuySLYnCITu44gQ.png" /></figure><p>Falcon-512 has the most compact size profile and is the primary algorithm; ML-DSA-44 is also supported, with a larger per-transaction footprint (~2.3× Falcon) accepted as the cost of having a FIPS-finalized fallback already wired into the protocol. SLH-DSA remains out of scope this cycle due to its signature size.</p><p>This constitutes a material protocol-layer overhead and is treated as an explicit trade-off rather than a minimized concern. As the initial launch design — with PQ adoption expected to stay low in the early phase — the size growth is acceptable and not a launch blocker. Future optimization paths include Falcon key-recovery mode, which can reduce per-transaction wire size, and a possible BLOCK_SIZE increase. The BLOCK_SIZE change must be proposed through a separate dedicated TIP under the standard governance process and should not be bundled with this PQ rollout.</p><h3>Design</h3><p>Core design principles: the Accountprotocol structure is completely unchanged. The account address is derived from the signing public key via Keccak-256, and the derivation is decoupled from the signing algorithm — ECDSA, Falcon, and ML-DSA public keys share the same slicing rule and produce addresses in the standard 21-byte T-prefixed form (e.g. TTW663tQYJTTCtHh6DWKAfexRhPMf2DxQ1).</p><p>Transactions and blocks add a PQAuthSig field to carry the full PQ signature along with its public key. This field coexists with the original signature field; it is neither a replacement nor mutually exclusive, except for block signatures, where only one of the two may be set. Nodes dispatch verification based on which field is present.</p><p>After obtaining the public key, both paths converge on the same permission-check flow: derive address → match against Permission.keys[] → accumulate weight → compare against threshold. A single transaction may carry a mix of ECDSA, Falcon, and ML-DSA signers, with their weights pooled into one sum.</p><h3>1. New PQ signature structure</h3><pre>message PQAuthSig {<br>  PQScheme scheme = 1; // Mandatory; UNKNOWN_PQ_SCHEME (proto3 default) is rejected at validation time.<br>  bytes public_key = 2;<br>  bytes signature = 3;<br>}<br>enum PQScheme {<br>  UNKNOWN_PQ_SCHEME = 0; // proto3 default; never registered, rejected at validation<br>  FN_DSA_512 = 1; // Falcon-512 (FIPS 206 draft)<br>  ML_DSA_44 = 2; // ML-DSA-44 (FIPS 204, finalized)<br>}<br>// Example: the transaction body gains a PQAuthSig field<br>message Transaction {<br>  …<br>  repeated bytes signature = 2;<br>  …<br>  repeated PQAuthSig pq_auth_sig = 6; // newly added field<br>}</pre><h3>2. Four PQ signature channels and field additions</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-dw12D45ThCK_LyvfY7tJA.png" /></figure><h3>3. Address derivation (identical form to ECDSA derivation)</h3><p>Address derivation (identical form to ECDSA derivation):</p><pre>pq_address = 0x41 ‖ Keccak-256(pq_public_key)[12..32]</pre><p>The address stays 21 bytes with the T prefix, fully compatible with the existing ECDSA address format; only the hash input differs. Collision probability is algorithm-independent and remains at $1/2^{160}$ .</p><h3>4. Signature target (unchanged)</h3><ul><li>Transaction signature target: <em>txid = SHA-256(Transaction.raw)</em></li><li>Block signature target: <em>blockHash = SHA-256(BlockHeader.raw)</em></li><li>Relay-identity signature target: <em>SHA-256(BigEndian(timestamp)) </em>(inherits the existing ECDSA digest construction)</li></ul><h3>5. TVM precompiles</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*69jJXZtfivOOA6n7XQ_48A.png" /></figure><p>We do not reuse 0x09 / 0x0A because the PQ verification interface verify(pk,msg,sig)→ bool provides no way to recover the public key — the caller must supply the full public key explicitly.</p><p><em>Falcon precompiles gate on </em><em>ALLOW_FN_DSA_512; ML-DSA precompiles gate on </em><em>ALLOW_ML_DSA_44; </em><em>0x1a is available when either is active.</em></p><h3>6. Governance activation</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ymmh18sU3zK2dDj-HD9CsA.png" /></figure><p>The algorithm-agnostic multi-sign precompile 0x0200001a ValidateMultiPQSig is enabled when either proposal is active.</p><h3>7. Performance</h3><p>Single-operation cost (500-run average, measured by <em>SignatureSchemeBenchmarkTest</em>):</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-SZHP9S6SV2np8dluX5GiA.png" /></figure><p>Both PQ schemes improve signature-verification CPU on the consensus hot path; the binding constraint is transaction size, not verify cost. TPS ceiling scales with the blended average transaction size against a roughly constant block-byte throughput:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Chb0iQ23DPScHBtk4f7CLA.png" /></figure><p>In the early transition phase, PQ adoption will be limited, keeping the size increase manageable. Falcon-512 serves as the default size-efficient choice, while ML-DSA-44 provides a FIPS-finalized fallback for specialized multi-sig use cases. The PQ functionality will soon live on the Nile testnet, where we are actively monitoring feature stability and gathering performance data to inform future enhancements. Moving forward, optimization work will focus on Falcon key-recovery for footprint reduction and, if needed, a possible BLOCK_SIZE increase proposed through a separate dedicated TIP under the standard governance process.</p><h3>Account Migration</h3><h3>Regular account Migration</h3><p>Regular accounts can choose either of the two paths below:</p><p>Path 1: in-place permission replacement (zero asset movement) — an AccountPermissionUpdateContractthat simultaneously adds a PQ-derived Key and rebalances the Permission so that no ECDSA-only signature set can meet the threshold.</p><p><em>⚠️ The rebalancing step is mandatory for quantum safety. Simply adding a PQ key while leaving the existing ECDSA key with enough weight to meet the threshold alone provides no actual PQ protection — a quantum attacker who breaks the ECDSA key still controls the account. The PQ key in that case adds only key-management overhead, not security.</em></p><p>Any configuration that requires at least one PQ signature in every passing signature set is acceptable. Examples:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*BcXolsLMKb3HAqEQHXcMaQ.png" /></figure><p>Operators choose the strictness based on tolerance for ECDSA continuity during the transition. Once the rebalancing is in effect, the old account address, assets, contract bindings, cross-chain whitelists, and DApp integrations are all preserved. Costs: the one-shot permission-update fee plus the standard MultiSignFee for any subsequent multi-sig transaction.</p><p>Path 2: asset migration, deprecating the old account. Operators must generate a brand-new PQ account, transfer all TRX / TRC10 / TRC20 / staked / delegated assets to the new account (staked / frozen resources must first be released via UnfreezeBalance / UnDelegateResource, then wait out the unlock window), and finally deprecate the old account. This fully cuts off the quantum attack surface, at the cost of transfer fees, the unlock waiting period, and address-change adaptation across external systems (exchanges, DApps, cross-chain bridges, contract whitelists).</p><h3>SR Account Configuration</h3><p>SR accounts — after PQ is enabled on mainnet, complete the Witness Permission switch and configure the pre-derived keypair through the localPqWitness section in config.conf. Each entry in localPqWitness.keys is a JSON key-file path. The key file itself specifies the scheme.</p><h3>Ecosystem Integration</h3><p>Wallets / SDKs / exchanges / block explorers — need to extend key management, address derivation, signature construction, node-capability detection, and pq_auth_sig field parsing. PQ keypairs can be generated with TRON’s Toolkit via the pq-key new command:</p><p>java -jar build/libs/Toolkit.jar pq-key new --scheme=ML_DSA_44</p><p>The command also supports seed-based generation through--seed.</p><h3>Open Questions / Discussion Points</h3><p>Given the early-stage nature of this proposal, multiple architectural elements are being actively refined beyond the previously discussed transaction size optimizations. Key areas currently under development include the economic framework and user-cost model, which encompasses PQ-specific transaction pricing, energy calibration for precompiles, and potential incentive structures like fee waivers. Additionally, work is focused on ensuring comprehensive ecosystem integration across SDKs and wallets, addressing hardware-wallet compatibility, key-derivation standards, and finalized API requirements. These efforts are being monitored through an open governance <a href="https://github.com/tronprotocol/tips/issues/899">TIP</a> and will reach finalization before the mainnet launch.</p><h3>References</h3><ul><li><a href="https://csrc.nist.gov/csrc/media/presentations/2025/fips-206-fn-dsa-(falcon)/images-media/fips_206-perlner_2.1.pdf">NIST FIPS 206 draft (FN-DSA / Falcon)</a></li><li><a href="https://csrc.nist.gov/pubs/fips/204/final">NIST FIPS 204 (ML-DSA)</a></li><li><a href="https://falcon-sign.info/falcon.pdf">Falcon specification</a></li><li><a href="https://eips.ethereum.org/EIPS/eip-8052">EIP-8052 (Ethereum Falcon-verification precompile draft)</a></li><li><a href="https://github.com/firedancer-io/firedancer/pull/9446">Solana Falcon-512 PR (Firedancer)</a></li><li><a href="https://algorand.co/blog/technical-brief-quantum-resistant-transactions-on-algorand-with-falcon-signatures">Algorand quantum-resistant transactions with Falcon</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=522c6e5e4023" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/tron-post-quantum-signature-design-522c6e5e4023">TRON Post-Quantum Signature Design</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Mainnet Democritus Announcement]]></title>
            <link>https://medium.com/tronnetwork/mainnet-democritus-announcement-39ee3e3cf69c?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/39ee3e3cf69c</guid>
            <category><![CDATA[announcements]]></category>
            <category><![CDATA[tron]]></category>
            <category><![CDATA[java-tron]]></category>
            <category><![CDATA[java-tron-new-release]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Fri, 06 Feb 2026 07:58:06 GMT</pubDate>
            <atom:updated>2026-02-06T08:02:03.216Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/988/1*JnQExnVCdtR2xLelscTtHg.png" /></figure><p>The TRON network has released the GreatVoyage-v4.8.1(Democritus) version (hereafter referred to as “Democritus”). This is a mandatory upgrade that introduces support for the ARM64 architecture, alongside several key updates and governance proposals. Please find the details below.</p><h3>Core</h3><h4>1. Expand compatibility for ARM64 architecture and JDK 17</h4><p>To further enrich the java-tron technical ecosystem, the Democritus version introduces support for the arm64 architecture. In arm64 environments, the system currently supports JDK 17 and the RocksDB database.</p><p><strong>ARM64 architecture</strong></p><ul><li><strong>Mandatory JDK 17</strong>: JDK 17 is the required Java runtime environment to ensure the operational stability of the node in the arm64 environments (based on JEP 237, 388, 391).</li><li><strong>Mandatory RocksDB</strong>: The database only supports <strong>RocksDB (v9.7.4)</strong>. LevelDB JNI does not support arm64 architecture and lacks maintenance, so the community-active RocksDB was chosen.</li><li><strong>Floating point computation adaptation</strong>: Floating-point calculations have been switched to use StrictMath via a proposal to ensure consistent results across different platforms. Before the proposal took effect, differences in floating-point implementations between arm64 and x86_64 architectures could lead to inconsistent results. Therefore, on arm64 architectures, results are kept consistent with x86_64 mainnet data via hardcoding. <strong>Warning</strong>: Private networks on x86_64 platforms using floating-point computation (specifically Bancor transactions involving pow) may face synchronization issues from genesis on arm64. In such cases, please use a database snapshot from an existing height to start arm64 nodes.</li><li><strong>Toolkit limitations</strong>: LevelDB-related commands (db archive and db convert) are not supported in arm64 environments.</li></ul><p><strong>Changes under x86_64 architecture</strong></p><ul><li><strong>Mandatory JDK 8</strong>: Since versions higher than JDK 8 have removed Java EE modules (per JEP 320), annotations such as @PostConstruct will fail, leading to NullPointerExceptions and block synchronization failures. Democritus introduces mandatory JDK 8 validation on x86_64 to ensure environment stability.</li><li><strong>RocksDB/LevelDB compatibility restrictions</strong>: Due to version discrepancies (x86_64 uses RocksDB v5.15.10 which supports LevelDB, while arm64 uses v9.7.4 which does not), forcing RocksDB to open LevelDB in an arm64 environment triggers “Database Corruption” errors. To ensure consistent cross-platform behavior and data migration, <strong>Democritus uniformly prohibits RocksDB from accessing LevelDB databases</strong> (Existing databases successfully opened via compatibility mode remain unaffected). Error prompts for LevelDB attempting to open RocksDB have also been optimized, and interfaces/exception logic have been standardized.</li><li><strong>Toolkit update</strong>: Previously, db convert defaulted to a “compatibility mode” that only updated the value of engine.properties to RocksDB while keeping the underlying data in LevelDB format. To align with arm64’s strict RocksDB requirements, the db convert command has been refactored to perform a <strong>non-compatibility conversion</strong> (previously the -safe flag logic). Consequently, the -safe parameter and “compatibility mode” have been removed to ensure seamless data migration across architectures.</li></ul><p><strong>Other changes</strong></p><p><em>JDK 17 Compatibility</em></p><ul><li>Null pointer compatibility: Optimized null pointer prompt information to facilitate problem positioning (based on JEP 358).</li><li>Number conversion exception compatibility: Optimized number conversion exception prompts and added conversion radix error prompts (based on JDK-8176425).</li><li>JDK version parsing compatibility: Adapted to JDK 10+ version number format changes (based on JEP 223).</li><li>var inference keyword: Supports var type inference mechanism (based on JEP 286).</li></ul><p><em>RocksDB Resource Optimization</em></p><ul><li>Increase max handle setting parameter: Added the parameter dbSettings.maxOpenFiles, default is 5000 (previously mandatory and unconfigurable), developers can adjust according to server load.</li><li>Resource release optimization: Set a reasonable lifecycle for RocksDB resources to release used resources in time, avoiding potential memory leak problems.</li></ul><p><em>To support JDK 17 and arm64 architecture, the following dependency changes were made:</em></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fEqaBMVTr2VFPLHlnQB0yg.png" /></figure><p><strong>Issue</strong>: <a href="https://github.com/tronprotocol/java-tron/issues/5954">https://github.com/tronprotocol/java-tron/issues/5954</a></p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6327">https://github.com/tronprotocol/java-tron/pull/6327</a> <a href="https://github.com/tronprotocol/java-tron/pull/6421">https://github.com/tronprotocol/java-tron/pull/6421</a> <a href="https://github.com/tronprotocol/java-tron/pull/6440">https://github.com/tronprotocol/java-tron/pull/6440</a> <a href="https://github.com/tronprotocol/java-tron/pull/6455">https://github.com/tronprotocol/java-tron/pull/6455</a> <a href="https://github.com/tronprotocol/java-tron/pull/6457">https://github.com/tronprotocol/java-tron/pull/6457</a> <a href="https://github.com/tronprotocol/java-tron/pull/6459">https://github.com/tronprotocol/java-tron/pull/6459</a> <a href="https://github.com/tronprotocol/java-tron/pull/6472">https://github.com/tronprotocol/java-tron/pull/6472</a> <a href="https://github.com/tronprotocol/java-tron/pull/6502">https://github.com/tronprotocol/java-tron/pull/6502</a></p><h3>TVM</h3><h4>1. Modify the behavior of SELFDESTRUCT</h4><p>Following the proposal to deprecate the SELFDESTRUCT instruction via <a href="https://github.com/tronprotocol/tips/blob/master/tip-652.md">TIP-652</a> in GreatVoyage-4.8.0 (Kant), the Democritus release formally introduces behavioral adjustments to SELFDESTRUCT. This change ensures deep compatibility with Ethereum’s EIP-6780, aligning the TVM (TRON Virtual Machine) with EVM standards. Detailed specifications can be found in <a href="https://github.com/tronprotocol/tips/blob/master/tip-6780.md">TIP-6780</a>.</p><p>In versions prior to Democritus, SELFDESTRUCT allowed a contract to terminate itself, transfer its funds to a designated address, and delete all associated account data (code, storage, and the account itself). Starting with the Democritus release, the behavior of the SELFDESTRUCT instruction is modified as follows:</p><p><strong>Restricted Execution Scenarios</strong></p><p>Account data deletion (including code, storage, and the account itself) is now only permitted if SELFDESTRUCT is invoked within the same transaction in which the contract was created.</p><p><em>Scenario 1: invoke </em><em>SELFDESTRUCT in a Subsequent Transaction (Standard Case)</em></p><ul><li>The contract account is <strong>not</strong> destroyed.</li><li>Execution of the current contract stops immediately.</li><li>No data is deleted, including storage keys, code, or the account itself. However, all assets (TRX, staked TRX, and TRC10 tokens) are transferred to the target address.</li><li>If the target address is the contract itself, the assets are not burned.</li></ul><p><em>Scenario 2: invoke </em><em>SELFDESTRUCT in the Same Transaction (Creation &amp; Destruction)</em></p><ul><li>Execution stops immediately.</li><li>All account data is purged.</li><li>All assets are transferred to the target address.</li><li>If the target address is the contract itself, the balance is reset to zero and the assets are burned.</li></ul><p><strong>Energy Cost Adjustment</strong></p><p>To increase the threshold for usage and further mitigate abuse, the Energy cost for the SELFDESTRUCT opcode has been increased from 0 to 5,000.</p><p><strong>NOTE</strong>: This feature is governed by TRON network parameter #94. It is disabled by default (value: 0) and can be enabled through a governance proposal vote. Once enabled, it cannot be disabled.</p><p><strong>TIP</strong>: <a href="https://github.com/tronprotocol/tips/blob/master/tip-6780.md">https://github.com/tronprotocol/tips/blob/master/tip-6780.md</a></p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6383">https://github.com/tronprotocol/java-tron/pull/6383</a> <a href="https://github.com/tronprotocol/java-tron/pull/6448">https://github.com/tronprotocol/java-tron/pull/6448</a></p><h3>Net</h3><h4>1. Fix “gt lastNum” and “gt highNoFork” error during block synchronizing</h4><p>The synchronization service previously outputted full exception stack traces during specific edge-case scenarios involving gt highNoFork and gt lastNum errors. To better align with standard error-level logging practices, this behavior has been adjusted. The service now logs only the specific exception message, suppressing the full stack trace to reduce log noise and improve readability.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6381">https://github.com/tronprotocol/java-tron/pull/6381</a></p><h4>2. Fix the light node incorrectly reporting a FORKED disconnection</h4><p>In versions prior to Democritus, light nodes often misidentified connection issues as FORKED during handshakes with Full Nodes of lower block heights. This occurred specifically when a Full Node’s highest solidified block was not present on the light node’s local main chain.</p><p>The Democritus release refines this logic by introducing a specific height threshold: a FORKED status is now only triggered if the light node’s lowest block height is lower than the Full Node’s highest solidified block height. In all other cases of chain mismatch, the error is correctly categorized as LIGHT_NODE_SYNC_FAIL.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6375">https://github.com/tronprotocol/java-tron/pull/6375</a></p><h4>3. Optimize P2P disconnection reason codes</h4><p>Prior to the Democritus release, certain P2P_DISCONNECT messages utilized vague reason codes, hindering accurate network troubleshooting. This update refines the error reporting logic for three specific scenarios to provide clearer diagnostic data:</p><ul><li><strong>Scenario 1</strong>: If a connection is terminated because a received block fails signature verification, the reason code is updated from UNKNOWN to BAD_BLOCK.</li><li><strong>Scenario 2</strong>: Previously, failures during the HelloMessage validation incorrectly triggered an UNEXPECTED_IDENTITY error, even when no identity-specific checks were performed. This has been corrected to INCOMPATIBLE_PROTOCOL to accurately reflect the validation failure.</li><li><strong>Scenario 3</strong>: When a P2P_HELLO message contains a block ID with a length other than 32 bytes, the disconnection reason is now reported as INCOMPATIBLE_PROTOCOL instead of UNKNOWN.</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6394">https://github.com/tronprotocol/java-tron/pull/6394</a></p><h4>4. Implement P2P message rate limit</h4><p>Prior to the Democritus release, P2P message processing was not rate-limited, leaving nodes vulnerable to resource exhaustion (bandwidth, CPU, and RAM) when handling high message volumes. To address this, Democritus introduces a per-peer rate limiting mechanism. If the frequency of specific messages from a single peer exceeds defined thresholds, the node will drop the messages and proactively disconnect from that peer. The following limits are applied based on message type and node state:</p><ul><li>SyncBlockChainMessage: Restricted to 3 QPS during the synchronization phase (defined as ChainInventory.remainNum &gt; 0).</li><li>FetchInvDataMessage: Restricted to 3 QPS during the block synchronization stage.</li><li>P2P_DISCONNECT: Processing is limited to 1 QPS.</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6393">https://github.com/tronprotocol/java-tron/pull/6393</a></p><h4>5. Optimize concurrent access to fields of PeerConnection</h4><p>The Democritus release optimizes concurrent access to PeerConnection by applying the volatile keyword to shared fields and refining the sequence of variable assignments. These changes ensure thread-safe visibility and prevent race conditions, significantly reducing exceptions caused by state inconsistencies during network synchronization.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6360">https://github.com/tronprotocol/java-tron/pull/6360</a></p><h3>Other Changes</h3><h4><strong>Configuration &amp; Dependencies</strong></h4><h4>1. Optimize the configuration switch for zkSNARK</h4><p>Added configuration item node.allowShieldedTransactionApi to replace node.fullNodeAllowShieldedTransaction.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6371">https://github.com/tronprotocol/java-tron/pull/6371</a> <a href="https://github.com/tronprotocol/java-tron/pull/6427">https://github.com/tronprotocol/java-tron/pull/6427</a></p><h4>2. Upgrade gradle to support jitpack publish</h4><p>Gradle version has been upgraded to 7.6.4, using the maven-publish plugin to support jitpack publishing.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6367">https://github.com/tronprotocol/java-tron/pull/6367</a></p><h4>3. Optimize local witness initialization logic</h4><p>The Democritus release refines the local witness initialization process. Private key and address initialization logic is now executed exclusively by witness nodes. If an invalid witness address is configured, the program will throw an exception and terminate. Additionally, the cryptography library has been upgraded from org.bouncycastle:bcprov-jdk15on:1.69 to org.bouncycastle:bcprov-jdk18on:1.79.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6368">https://github.com/tronprotocol/java-tron/pull/6368</a> <a href="https://github.com/tronprotocol/java-tron/pull/6452">https://github.com/tronprotocol/java-tron/pull/6452</a></p><h4>4. Optimize log prompts for missing Blackhole configuration</h4><p>The Democritus release improves the error logging for missing Blackhole account configurations. The updated logs provide more actionable guidance, explicitly notifying users to configure the Blackhole account address within the config.conf file.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6356">https://github.com/tronprotocol/java-tron/pull/6356</a></p><h4>5. Enrich FullNode command-line options</h4><p>Starting with the Democritus release, the standalone SolidityNode.jar and KeystoreFactory.jar have been merged into FullNode. Users can start the SolidityNode service using the command-line parameter—-solidity, or start the KeystoreFactory service using --keystore-factory. This unification reduces storage overhead and simplifies build and deployment workflows.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6397">https://github.com/tronprotocol/java-tron/pull/6397</a> <a href="https://github.com/tronprotocol/java-tron/pull/6450">https://github.com/tronprotocol/java-tron/pull/6450</a> <a href="https://github.com/tronprotocol/java-tron/pull/6446">https://github.com/tronprotocol/java-tron/pull/6446</a></p><h4>6. Synchronize config.conf with tron-deployment</h4><p>The Democritus version introduces full synchronization of configuration items between config.conf and the tron-deployment repository, and updates the seed node list in seed.node.ip.list.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6332">https://github.com/tronprotocol/java-tron/pull/6332</a></p><h4>7. Standardize full configuration and annotation guidelines</h4><p>The Democritus version introduces a standardized configuration file containing all supported parameters. <strong>Any configuration item not included in this file is considered invalid or deprecated.</strong> Additionally, this release defines specific annotation and commenting standards within the configuration files:</p><ul><li>Whole-line comments Must begin with the # prefix.</li><li>Comments appended to the end of a configuration line may use either # or //.</li><li>Configuration items without default values must be prefixed with # to serve as a commented-out template.</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6430">https://github.com/tronprotocol/java-tron/pull/6430</a></p><h4>8. Update dependencies</h4><p>Upgraded dependencies such as grpc-java, spring, jackson, and jetty:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*dZ4Khl9LKOgHUK9ZO4OInA.png" /></figure><p>Deleted dependencies:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/770/1*T-kAZdX2EJuJO1CKR3d2_w.png" /></figure><p>Additionally, the Democritus version upgrades the underlying network library libp2p, from 2.2.6 to 2.2.7. This version not only adds compilation support for JDK 17 but also introduces numerous optimizations and improvements:</p><ul><li>Added formal compilation support for JDK 17 (<a href="https://github.com/tronprotocol/libp2p/pull/113">#113</a>).</li><li>Upgraded grpc-netty and protobuf libraries (<a href="https://github.com/tronprotocol/libp2p/pull/110">#110</a>).</li><li>Optimized connection pool (connPool) and general resource allocation logic (<a href="https://github.com/tronprotocol/libp2p/pull/116">#116</a>).</li><li>Implemented a concurrent external IP acquisition mechanism with built-in validation (<a href="https://github.com/tronprotocol/libp2p/pull/120">#120</a>, <a href="https://github.com/tronprotocol/libp2p/pull/121">#121</a>).</li><li>Refined network detection logic (<a href="https://github.com/tronprotocol/libp2p/pull/122">#122</a>).</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6400">https://github.com/tronprotocol/java-tron/pull/6400</a> <a href="https://github.com/tronprotocol/java-tron/pull/6429">https://github.com/tronprotocol/java-tron/pull/6429</a> <a href="https://github.com/tronprotocol/java-tron/pull/6431">https://github.com/tronprotocol/java-tron/pull/6431</a> <a href="https://github.com/tronprotocol/java-tron/pull/6481">https://github.com/tronprotocol/java-tron/pull/6481</a></p><h4>9. Update code version to 4.8.1</h4><p>The version number has been formally defined as 4.8.1 to reflect the Democritus release.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6445">https://github.com/tronprotocol/java-tron/pull/6445</a></p><h4>Event Service</h4><h4>1. Optimize transaction info retrieval logic for Event Services</h4><p>The Democritus release addresses compatibility issues encountered during the retrieval of transaction info. To ensure data availability, if the event service fails to retrieve data from the transactionRetStore database, it will automatically perform a compatibility fallback to retrieve data from the transactionHistoryStore database.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6443">https://github.com/tronprotocol/java-tron/pull/6443</a> <a href="https://github.com/tronprotocol/java-tron/pull/6453">https://github.com/tronprotocol/java-tron/pull/6453</a></p><h4>2. Remove bloom filter write toggle</h4><p>The section-bloom database is used to store bloom filters for contract logs and their corresponding block indexes. When processing eth_getLogs requests, the node queries this database to quickly locate matching blocks. This is a critical step for efficient event retrieval.</p><p>Prior to the Democritus Release, writing to this database was controlled by the node.jsonrpc.httpFullNodeEnable configuration. If this setting was disabled, the node would not record block bloom filter data to the section-bloom database. Because these index data points cannot be retrospectively backfilled automatically, users were unable to query historical transaction events that occurred while the toggle was off — even if they enabled the configuration later.</p><p>Starting with the Democritus version, dependency on this configuration toggle has been removed. The node now persistently writes data to the section-bloom database by default. This change ensures the continuity and integrity of the bloom filter index, completely resolving the issue where eth_getLogs failed to retrieve historical data due to specific configuration states.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6372">https://github.com/tronprotocol/java-tron/pull/6372</a></p><h4>3. Optimize event service shutdown logic</h4><p>The Democritus version introduces an optimized shutdown logic for the HistoryEventService thread. By implementing a global state variable, isClosed, the system now ensures that resource deallocation occurs exactly once, even if the close function is invoked multiple times. This optimization effectively prevents redundant resource disposal and associated exceptions, significantly enhancing system stability during termination.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6463">https://github.com/tronprotocol/java-tron/pull/6463</a></p><h4>Test Case</h4><h4>1. Optimize resource management for test cases</h4><p>The Democritus version introduces a systematic optimization of resource management for unit testing. These enhancements significantly improve execution efficiency while further ensuring the cleanliness and stability of the testing environment.</p><ul><li><strong>Standardized Cleanup Mechanism</strong>: Implemented a more rigorous file cleanup protocol to ensure that all temporary data generated during testing is thoroughly removed post-execution.</li><li><strong>Improved Execution Performance</strong>: By optimizing high-latency test cases, the total duration of the unit testing suite has been reduced by up to 30%.</li><li><strong>Robust Resource Release</strong>: Addressed known resource leak issues and standardized the resource release logic.</li><li><strong>Enhanced Runtime Stability</strong>: Resolved specific NullPointerExceptions.</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6437">https://github.com/tronprotocol/java-tron/pull/6437</a> <a href="https://github.com/tronprotocol/java-tron/pull/6483">https://github.com/tronprotocol/java-tron/pull/6483</a> <a href="https://github.com/tronprotocol/java-tron/pull/6486">https://github.com/tronprotocol/java-tron/pull/6486</a></p><h4>2. Implement gRPC timeout mechanism</h4><p>When executing test cases repeatedly (e.g., over 100 times) on arm64, certain gRPC test cases would hang. To solve this, the Democritus version introduces a gRPC timeout mechanism. A 5-second execution timeout was added for individual gRPC test case, and a 30-second timeout for the entire test execution; if it times out, it breaks and continues executing subsequent logic.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6441">https://github.com/tronprotocol/java-tron/pull/6441</a> <a href="https://github.com/tronprotocol/java-tron/pull/6460">https://github.com/tronprotocol/java-tron/pull/6460</a></p><h4>3. Ensure automated termination of unit test</h4><p>The Democritus version introduces optimizations to the termination logic of the ConditionalStopTest unit test. Specifically, within SR scenarios, the logic has been refined to accurately identify stop conditions even when the block production sequence undergoes changes. This ensures that the unit test terminates correctly and automatically as expected.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6469">https://github.com/tronprotocol/java-tron/pull/6469</a></p><h4>4. Enhance log context isolation mechanism</h4><p>The Democritus version addresses the issue of global logger configuration pollution previously triggered by the TronErrorTest unit test. By strengthening the output of error and warning messages during the LogService configuration loading phase and explicitly restoring the logger context within unit tests, the system now ensures complete log environment isolation between different test cases. This improvement eliminates interference in logging behavior across test suites and provides clearer diagnostic data for rapidly locating Logback configuration loading anomalies.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6476">https://github.com/tronprotocol/java-tron/pull/6476</a></p><h4>5. Resolve CheckStyle violations in test cases</h4><p>Added a line break to a comment statement in the test case file to fix checkStyle issues in test cases.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6392">https://github.com/tronprotocol/java-tron/pull/6392</a></p><h4>Documents</h4><h4>1. Update readme for FullNode startup JVM parameters</h4><p>Adjusted the JVM startup parameters for java-tron on x86_64 and arm64 platforms, aiming to ensure that FullNode nodes can meet basic disaster recovery requirements under minimum hardware configurations; meanwhile, modified hardware requirements to recommend more stable machine configurations.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6478">https://github.com/tronprotocol/java-tron/pull/6478</a></p><h4>2. Fix README badge display errors</h4><p>The Democritus version fixed the issue where the GitHub badge at the top of the README document displayed as “unknown”, and modified the badge image link.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6340">https://github.com/tronprotocol/java-tron/pull/6340</a></p><h4>3. Update telegram info and doc link in README</h4><p>The Democritus version udpated the README document to add Telegram contact information for the official TRON development discussion group.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6364">https://github.com/tronprotocol/java-tron/pull/6364</a></p><h4>Others</h4><h4>1. TIP-767: Transitioning voting window configuration to chain governance</h4><p>To ensure high uniformity of governance parameters across the entire network and enhance protocol consistency, the Democritus version introduces TRON №.92 network parameter (PROPOSAL_EXPIRE_TIME), transitioning the configuration of proposal expiration time to on-chain governance.</p><p><strong>TIP</strong>: <a href="https://github.com/tronprotocol/tips/blob/master/tip-767.md">https://github.com/tronprotocol/tips/blob/master/tip-767.md</a></p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6399">https://github.com/tronprotocol/java-tron/pull/6399</a> <a href="https://github.com/tronprotocol/java-tron/pull/6454">https://github.com/tronprotocol/java-tron/pull/6454</a></p><h4>2. Fix protocol buffer syntax compatibility issue</h4><p>Fixed the hexadecimal casing error in the ReasonCode struct, resolving compilation compatibility issues in JavaScript environments.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6426">https://github.com/tronprotocol/java-tron/pull/6426</a></p><h3>API</h3><h4>1. Introduce the eth_getBlockReceipts API</h4><p>The Democritus version introduces the eth_getBlockReceipts interface, used to query all transaction receipts in a specified block. For genesis blocks, blocks already pruned by light nodes, and unproduced blocks, it returns null.</p><ul><li><strong>Parameters</strong>: Block identifier (required). Supports three types: a block number represented as a hexadecimal string, a block hash (with or without the 0x prefix), or a block tag (&quot;latest&quot;, &quot;earliest&quot;, &quot;finalized&quot;).</li><li><strong>Returns</strong>: An array of objects. Each object is a receipt for a transaction within that block, and follows the same structure as the response returned by <a href="https://developers.tron.network/reference/eth_gettransactionreceipt">eth_getTransactionReceipt</a>.</li></ul><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6379">https://github.com/tronprotocol/java-tron/pull/6379</a> <a href="https://github.com/tronprotocol/java-tron/pull/6433">https://github.com/tronprotocol/java-tron/pull/6433</a></p><h4>2. Introduce a new API to query the real-time vote count of witness</h4><p>The Democritus version introduces the getPaginatedNowWitnessList interface. This endpoint is designed to query real-time voting data for the current epoch and return a paginated list of witnesses sorted in descending order of their vote counts.</p><p><strong>Parameters</strong></p><ul><li>offset: long, start index, requires &gt;= 0.</li><li>limit: long, number of items to return, requires &gt; 0, upper limit is 1000.</li><li>visible: boolean, optional; controls whether the returned address is in base58check or hex format.</li></ul><p><strong>Returns</strong></p><ul><li>Success: witnesses array, each item is a Witness (containing address, vote count, URL, etc.), sorted descending by “real-time votes”.</li><li>Failure: No result. When invalid parameters (e.g., limit &lt;= 0, offset &lt; 0, or offset &gt;= total Witness count) returns {}, http code = 200.</li></ul><p>API-specific errors: When in a maintenance period and requesting non-solidified data, throws a maintenance period unavailable exception, http code = 200.</p><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6373">https://github.com/tronprotocol/java-tron/pull/6373</a> <a href="https://github.com/tronprotocol/java-tron/pull/6451">https://github.com/tronprotocol/java-tron/pull/6451</a></p><h4>3. Optimize the return data of eth_call</h4><p>In versions prior to Democritus, the eth_call interface provided limited feedback upon contract execution failure. It typically returned a generic error message (e.g., “REVERT opcode executed”) while leaving the data field empty. This lack of detailed execution context made it difficult for developers to diagnose and trace specific issues within the smart contract.</p><p>The Democritus version introduced JsonRpcException as the base class for all JsonRpc exceptions, and a JsonRpcErrorResolver class for data field generation logic.</p><p>Using the <a href="https://nile.tronscan.org/#/contract/TAFPPQK2NaqSPwKcaomLXJmwbxLB34x8Lr/code">demo contract</a> as an example, the following information was returned when calling the testInsufficientBalance method prior to the change:</p><pre>{<br> &quot;jsonrpc&quot;: &quot;2.0&quot;,<br> &quot;id&quot;: 1,<br> &quot;error&quot;: {<br>    &quot;code&quot;: -32000,<br>    &quot;message&quot;: &quot;REVERT opcode executed&quot;,<br>    &quot;data&quot;: &quot;{}&quot;<br>  }<br>}</pre><p>After modification: The data field returns error information (e.g., encoded revert reason), allowing developers to obtain the specific error reason via ABI parsing. (Consistent with Ethereum node strategy, returns unparsed data for everything except default Error(string)).</p><pre>{<br> &quot;jsonrpc&quot;: &quot;2.0&quot;,<br> &quot;id&quot;: 1,<br> &quot;error&quot;: {<br>    &quot;code&quot;: -32000,<br>    &quot;message&quot;: &quot;REVERT opcode executed&quot;,<br>    &quot;data&quot;: &quot;0xcf47918100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000064&quot;<br>  }<br>}</pre><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6369">https://github.com/tronprotocol/java-tron/pull/6369</a></p><h4>4. Performance optimization for eth_getLogs, eth_getFilterLogs</h4><p>Event query interfaces like eth_getLogs rely on a partialMatch function to query the bloom database. The query conditions are derived from 3 bitIndexes generated for each topic or address. Since the bloom filter has a bit limit (2048 bits), when the number of topics reaches 683, the total number of indexes (683 * 3 &gt; 2048) exceeds the filter capacity. This inevitably leads to bit collisions and redundant bitIndexes, resulting in duplicate database queries. To address this, the proposed optimization implements de-duplication of bitIndexes prior to execution, significantly reducing the frequency of database lookups.</p><p>The table below contrasts the duplication rate of bitIndex and execution time of partialMatch under different numbers of topics and addresses. It shows that as the number of topics increases, the higher the bitIndex duplication, the more significant the performance improvement after optimization.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/810/1*MJBJw6njlkkfRt8oD9N90w.png" /></figure><p><strong>Source Code</strong>: <a href="https://github.com/tronprotocol/java-tron/pull/6370">https://github.com/tronprotocol/java-tron/pull/6370</a></p><blockquote>To a wise and good man the whole earth is his fatherland. — — Democritus</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=39ee3e3cf69c" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/mainnet-democritus-announcement-39ee3e3cf69c">Mainnet Democritus Announcement</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[What is TIP-6780?]]></title>
            <link>https://medium.com/tronnetwork/tip-6780-change-to-the-selfdestruct-opcode-b992ed3885e6?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/b992ed3885e6</guid>
            <category><![CDATA[blockchain]]></category>
            <category><![CDATA[smart-contracts]]></category>
            <category><![CDATA[technology]]></category>
            <category><![CDATA[web3]]></category>
            <category><![CDATA[tron]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Tue, 18 Nov 2025 09:11:57 GMT</pubDate>
            <atom:updated>2025-11-19T05:29:55.392Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ANa890tMYk1_wz-6Mn_1GA.png" /></figure><h3><strong>1. Background</strong></h3><p><a href="https://github.com/tronprotocol/tips/blob/master/tip-652.md">TIP-652</a> proposed the deprecation of the SELFDESTRUCT opcode. This change discouraged its use in newly deployed contracts and suggested its functionality may be further limited in future TVM upgrades.</p><p>As an EVM-compatible public chain, TRON has introduced <a href="https://github.com/tronprotocol/tips/blob/master/tip-6780.md">TIP-6780</a> to align with Ethereum’s <a href="https://eips.ethereum.org/EIPS/eip-6780">EIP-6780</a> and maintain behavioral consistency with the EVM.</p><h3><strong>2. Changes</strong></h3><p>Previously, the SELFDESTRUCT opcode allowed a contract to destroy itself, transfer its entire balance to a specified address, and subsequently delete all associated data of the contract account (i.e., code, storage, and the account itself).</p><h4><strong>2.1 Core Change: Restriction on </strong>SELFDESTRUCT<strong> Usage Scenarios</strong></h4><p>Account data (i.e., code, storage, and the account itself) is only deleted if SELFDESTRUCT is executed within the contract’s creation transaction.</p><p><strong>Scenario 1: </strong><strong>SELFDESTRUCT Called in a Different Transaction (Default Case)</strong></p><ul><li>The account is not actually destroyed.</li><li>The current contract’s execution halts immediately.</li><li>No data is deleted, including storage keys, code, or the account itself.</li><li>However, all assets held by the contract (TRX, staked TRX, TRC-10 tokens) are transferred to the target address.</li><li>If the target address is the contract itself, the assets are not burned.</li></ul><p><strong>Scenario 2: </strong><strong>SELFDESTRUCT Called in the Same Transaction (Immediate Self-Destruction after Creation)</strong></p><p>In this scenario, the opcode’s legacy behavior is retained:</p><ul><li>The current contract’s execution halts immediately.</li><li>All account data is deleted.</li><li>All assets are transferred to the target address.</li><li>If the target address is the contract itself, its balance is set to 0, and the assets are burned.</li></ul><h4><strong>2.2 Energy Cost Adjustment</strong></h4><p>The fixed Energy cost of the SELFDESTRUCT opcode is adjusted from <strong>0</strong> to <strong>5,000</strong>. This raises the execution cost to further deter misuse.</p><h3>​<strong>3. Impact</strong></h3><h4><strong>3.1. Impact on Developers and Smart Contracts</strong></h4><p><strong>Hard Fork Requirement:</strong> This TIP is a consensus layer change that must be implemented via a hard fork.</p><p><strong>TRX Burning Behavior: </strong>Previously, with SELFDESTRUCT, a contract could burn its TRX by specifying itself as the target address. Now, this action is restricted:</p><ul><li>If the contract was not created in the current transaction, its TRX will not be burned, and no transfer occurs.</li><li>TRX can only be burned if the contract is created and SELFDESTRUCT is called within the same transaction.</li></ul><p><strong>Invalidated Design Patterns:</strong> Some solutions that rely on SELFDESTRUCT to implement security mechanisms or proxy upgrades are no longer secure or effective. For example:</p><ul><li>The pattern of using CREATE2 + SELFDESTRUCT to implement “upgradeable contracts” is broken.</li><li>The practice of relying on SELFDESTRUCT to destroy an account to protect sensitive data is no longer viable.</li></ul><h4><strong>3.2. Impact on the TRON Ecosystem</strong></h4><ul><li><strong>Enhanced Ethereum Compatibility:</strong> This change improves alignment with the EVM, simplifying the migration and integration of cross-chain infrastructure, developer tools, and decentralized applications (DApps).</li><li><strong>Improved Contract Security:</strong> This change encourages developers to adopt more robust and predictable contract design patterns, moving away from opcodes that are considered unstable or are planned for future deprecation.</li></ul><h3><strong>3. </strong>TRON<strong> On-Chain Data Analysis</strong></h3><h4><strong>3.1 Analysis of Contracts Containing the </strong><strong>SELFDESTRUCT Opcode</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/928/1*B2tJog-mAkWj1mpJ5ekA1g.png" /><figcaption><strong>Table 1:</strong> Contracts containing SELFDESTRUCT on TRON, by Asset Value.</figcaption></figure><p>As shown in the table, the number of contracts containing the SELFDESTRUCT opcode is very low, and the number of such contracts holding assets is even lower. Furthermore, none of these contracts have executed an actual SELFDESTRUCT transaction. The opcode is generally included as a mechanism to transfer assets out of the contract, a functionality that will remain unaffected after this proposal is implemented.</p><h4><strong>3.2 Analysis of SELFDESTRUCT Transactions</strong></h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*JYduGTnMJBC0CDxrYZulSA.png" /><figcaption><strong>Figure 1</strong>: Example of the “create-then-destroy” pattern shown in TRON’s internal transactions.</figcaption></figure><ol><li>An analysis of data from 2025 (up to October 17) reveals 957,324 internal transactions involving SELFDESTRUCT. The overwhelming majority — 957,316 (99.999%) — followed an identical pattern: the contract was created and self-destructed within the same transaction. This specific use case will not be affected after this proposal is implemented.<br><br>The remaining 8 transactions show a similar pattern: the contracts were also self-destructed on the same day they were created, and these addresses were never reactivated or reused after destruction.</li><li>A historical analysis of all SELFDESTRUCT transactions confirms that addresses that have self-destructed were never re-created afterwards.</li></ol><h3><strong>4. Conclusion</strong></h3><p>This proposal restricts the functionality of the SELFDESTRUCT opcode to enhance compatibility with Ethereum. Developers are strongly advised to avoid using SELFDESTRUCT in new smart contracts and instead adopt safer, more maintainable patterns for contract lifecycle management.</p><p>The change to the SELFDESTRUCT opcode will be included in an upcoming version release. Once released, it must be activated via <strong>network governance voting</strong> to take effect. Please stay tuned for the latest updates on the proposal via <a href="https://tronscan.org/#/proposals">TRONSCAN</a>.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=b992ed3885e6" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/tip-6780-change-to-the-selfdestruct-opcode-b992ed3885e6">What is TIP-6780?</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Committee Proposal 103]]></title>
            <link>https://medium.com/tronnetwork/committee-proposal-103-3d00872aaba0?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/3d00872aaba0</guid>
            <category><![CDATA[governance]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Thu, 26 Jun 2025 06:18:47 GMT</pubDate>
            <atom:updated>2025-06-26T06:18:47.354Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eyV0whYP_2PNUMBAuB2ZYQ.png" /></figure><p><strong>Committee Proposal №103</strong> is a voting request aimed at enabling chain parameters №83, №88, and №89 on the TRON network. These changes align the TRON Virtual Machine (TVM) with the Ethereum Cancun upgrade and introduce optimizations to the consensus layer’s verification mechanism. Please refer to <a href="https://github.com/tronprotocol/tips/issues/763">here</a> for the origin discussion. The № 103 committee proposal is already in effect, please refer to <a href="https://tronscan.org/#/proposal/103">here</a> for the voting details.</p><p>The proposal has officially taken effect as of <strong>2025–06–26 14:00 (SGT)</strong>. And this post provides a detailed breakdown of the proposal’s content and significance.</p><h3>What does this proposal include?</h3><p>Proposal 103 activates parameters defined in the following four TIPs:</p><ul><li><a href="https://github.com/tronprotocol/tips/issues/650"><strong>TIP-650</strong></a></li><li><a href="https://github.com/tronprotocol/tips/issues/651"><strong>TIP-651</strong></a></li><li><a href="https://github.com/tronprotocol/tips/issues/694"><strong>TIP-694</strong></a></li><li><a href="https://github.com/tronprotocol/tips/issues/745"><strong>TIP-745</strong></a></li></ul><h4>TIP-650: Transient Storage Opcodes</h4><p>Two new EVM-compatible opcodes are enabled:</p><ul><li>TLOAD (0x5c) — Load from transient storage</li><li>TSTORE (0x5d) — Store to transient storage</li></ul><p>Transient storage offers an energy-efficient alternative to memory for storing temporary data across internal calls within the same transaction, without persisting data beyond the transaction.</p><h4>TIP-651: Memory Copy Instruction</h4><p>One new opcode is enabled:</p><ul><li>MCOPY (0x5e) — Copy memory efficiently from one location to another</li></ul><p>This instruction provides energy optimization for contracts that need to manipulate memory regions directly.</p><h4>TIP-745: BLOB Opcodes for Cancun Compatibility</h4><p>Two new opcodes are enabled in placeholder form:</p><ul><li>BLOBHASH (0x49)</li><li>BLOBBASEFEE (0x4a)</li></ul><p>While these opcodes return default values (0) for now, they ensure forward compatibility with Ethereum Cancun bytecode.</p><h4>TIP-694: Consensus Layer Verification Enhancements</h4><p>This proposal strengthens validation logic in the consensus layer:</p><ul><li>Enforces a maximum size for account creation transactions to prevent bandwidth abuse</li><li>Validates total transaction sizes more strictly to avoid exceeding block limits</li><li>Ensures that the number of transaction results matches the number of invoked contracts</li><li>Applies stricter filtering for near-expiry transactions to preserve network bandwidth</li></ul><h3>What’s the benefit brought by this proposal?</h3><h4>For Virtual Machine (TVM) Compatibility:</h4><ul><li>Ensures alignment with Ethereum Cancun specs</li><li>Maintains bytecode-level compatibility with the EVM</li><li>Simplifies smart contract migration from Ethereum to TRON</li><li>Provides developers with the same energy-saving improvements</li></ul><h4>For Consensus Layer Security and Efficiency:</h4><ul><li>Strengthens block verification during sensitive periods (e.g., maintenance windows)</li><li>Prevents malicious blocks with non-standard timestamps</li><li>Refines Super Representative (SR) ranking algorithm for rare edge cases</li><li>Mitigates risk from oversized or malformed transactions</li></ul><p>Additionally, this proposal sets the groundwork for enhanced cross-platform compatibility in the future by signaling a transition from java.lang.Math to deterministic math libraries in Java-Tron. This ensures consistent behavior across environments and JDK versions.</p><h3>Summary</h3><p>Committee Proposal 103 enables TRON’s compatibility with the Ethereum Cancun upgrade and significantly enhances consensus layer verification. With the activation of new opcodes and stricter validation rules, the TRON network further improves its performance, security, and developer-friendliness.</p><p>The TRON Virtual Machine is now Cancun-compatible — enabling seamless DApp migration, cross-chain development, and more efficient contract execution.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=3d00872aaba0" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/committee-proposal-103-3d00872aaba0">Committee Proposal 103</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Committee Proposal 102]]></title>
            <link>https://medium.com/tronnetwork/committee-proposal-102-feced698a9ee?source=rss-3dc4ed14a538------2</link>
            <guid isPermaLink="false">https://medium.com/p/feced698a9ee</guid>
            <category><![CDATA[governance]]></category>
            <dc:creator><![CDATA[TRON Core Devs]]></dc:creator>
            <pubDate>Fri, 13 Jun 2025 06:23:29 GMT</pubDate>
            <atom:updated>2025-06-13T06:24:54.418Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*RO1q6-zBVWSVRINRwAkfyQ.png" /></figure><p>Committee proposal 102 is a voting request for modifying the № 5 and № 31 chain parameters on TRON network, adjusting the block reward from 16 TRX to 8 TRX, and the voting reward from 160 TRX to 128 TRX. Please refer to <a href="https://github.com/tronprotocol/tips/issues/738">here</a> for the origin discussion. The № 102 committee proposal is already in effect, please refer to <a href="https://tronscan.org/#/proposal/102">here</a> for the voting details, this post is dedicated to provide more details.</p><h3>Why does the TRON network need this proposal at this time?</h3><p>The implementation of a series of proposals within TRON’s tokenomics model has significantly impacted the TRX supply, resulting in a transition from inflation to deflation, but with a potential rebound trend showing recently. Especially after increasing the total energy limit from August to October 2024, the net increase of TRX supply shows a gradual increasing trend in recent months, indicating a potential resurgence of inflation.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*JFXffVWyJD-gGmxs" /><figcaption>Fig. 1 — The TRX supply shows a deflationary trend since 2022</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r-i9a2j1epuN8t9V" /><figcaption>Fig. 2 — The net increase of TRX supply shows a positive number some days in recent months</figcaption></figure><h3>The feasibility and reasonability of this proposal</h3><p>The community has widely and deeply discussed this proposal on Github and during multiple core devs community calls, and finally made consensus on enabling this proposal.</p><p>The previous TRX block rewards effectively stimulated network staking and transaction volume growth in the early stages. However, as the TRON network develops, the relatively high production rates of TRX may dilute the token’s value over time and reduce the incentive for long-term staking.</p><p>By reducing the TRX reward from 176 TRX to 136 TRX in total, the expected annual deflation rate will become about 1.29%, which better adapts the transaction volume and activities on the TRON network.</p><p>Diving into other mainstream public chains, most have designed mechanism to control the inflation rate:</p><ul><li><strong>BTC</strong> is well-known for halving every 4 years to cut the supply.</li><li><strong>ETH</strong> implemented EIP-1599 introducing base fee to accelerate burning in 2021, and significantly reduced ETH supply rate after the merge in 2022, bringing the inflation rate drop from about 4% to 0.3% at the moment, reduced by about 90%.</li><li><strong>SOL</strong> supply rate is pre-set, currently about 5.1%, and is designed to decrease by about 15% each year.</li></ul><p>The current supply rate of TRX has remained for more than 5 years, as the total energy limitation has been enlarged a lot and many chain parameters have been adjusted, it’s time to consider the proper TRX supply rate.</p><p>The biggest question during the discussion is that reducing TRX reward will decrease the benefit of staking holders. However, taking the advantage of energy renting into consideration, the expected comprehensive APR will change from about 9.15% to 7.08%, which is still attractive and competitive.</p><h3>What’s the benefit brought by this proposal?</h3><p>Enabling this calculation performance optimization brings several benefits:</p><ul><li><strong>Enhance Deflation:</strong> Lowering the TRX block rewards will enhance the network’s deflation rate, potentially increasing its value.</li><li><strong>Incentivize Staking:</strong> Leveraging the advantage of TRON’s staking model, the increase in TRX value can encourage more users to stake TRX to obtain the resources for transactions.</li><li><strong>Strengthen Network Security:</strong> Increased staking participation strengthens the network’s security by locking up more TRX.</li><li><strong>Improve Economic Incentives:</strong> Align token distribution with the maturity of the network, ensuring that incentives remain robust and meaningful for both new participants and long-term holders.</li></ul><h3>Summary</h3><p>After the proposal of reducing TRX reward takes effect, the annualized deflation rate of TRX is expected to increase from the previous 0.85% to 1.29%, which will further accelerate the deflation process of TRX, optimize TRON’s economic model, and enhance the long-term sustainability of the network.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=feced698a9ee" width="1" height="1" alt=""><hr><p><a href="https://medium.com/tronnetwork/committee-proposal-102-feced698a9ee">Committee Proposal 102</a> was originally published in <a href="https://medium.com/tronnetwork">TRON</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
    </channel>
</rss>