Repository navigation
Unify and improve rate limiting for TRX and BLOCK INVENTORY Messages #6659
Description
Activity
I checked the current implementation in
P2pEventHandlerImpland the report looks valid on the latest local codebase.For
INVENTORYmessages, the TRX-side guard is currently usingtronInTrxInventoryElement.getCount(10)beforemessageStatistics.addTcpInMessage(msg), so the decision is based only on the historical 10-second window and does not includemessage.getHashList().size()from the current batch. That means a large current TRX inventory can still pass the pre-check even when it should push the peer over the threshold.For
BLOCKinventories, I can confirm there is no equivalent pre-check in the same path today. The block inventory element counters already exist inMessageStatistics, so adding a symmetric limit there should be straightforward.A reasonable implementation is:
- keep the pre-dispatch guard in
P2pEventHandlerImpl - change the TRX condition to
count + currentSize > limit - add a dedicated BLOCK limit using
tronInBlockInventoryElement.getCount(10) + currentSize
One detail to keep in mind: because the rate-limit check happens before
addTcpInMessage(msg), the comparison should intentionally include the current message size, otherwise the check will continue to undercount the batch that is currently being processed.- keep the pre-dispatch guard in
@lxcmyf Thanks for the thorough analysis — the description matches what I see in the code as well.
A few additional observations worth noting:
On the timing of the check
The rate-limit guard runs before
addTcpInMessage(msg)is called, which meanstronInTrxInventoryElement.getCount(10)only reflects hashes accepted in previous messages, not the one currently being evaluated. So the effective window is always one batch behind. IncludingcurrentSizein the comparison (count + currentSize > limit) is the correct fix — it closes this gap by treating the current batch as already committed before making the drop decision.On BLOCK INVENTORY threshold design
tronInBlockInventoryElementalready exists inMessageStatisticsalongside the TRX counterpart, so no new counter infrastructure is needed. The reason BLOCK INV warrants its own configurable threshold rather than reusingmaxTpsis that block announcement frequency operates on a different scale than transaction throughput. Under normal conditions a node receives only a handful of block hashes per slot, so a dedicated and lower limit is more appropriate than inheriting the transaction rate cap.Hello, I have a suggestion, could we change the transaction abbreviation 'TRX' in the code? It's easily mistaken for TRON's native token.
@abn2357 Thanks for the suggestion. The abbreviation
TRXhere stands for Transaction, not TRON's native token. It has been used consistently throughout the codebase for a long time — for example,TrxMessage,TrxInventoryMessage, and related statistics counters all follow this convention. Renaming it would require touching a large number of files and classes, with a high risk of introducing unintended side effects. Given that this is an established internal naming convention rather than a user-facing identifier, we'd prefer to keep it as-is for now.- added a parent issue
on Apr 9, 2026 I agree the key bug here is that the rate-limit check is evaluating the historical counter without accounting for the batch currently being processed, so the decision is effectively one message behind. Folding
currentSizeinto the comparison is the right way to close that gap.Also agree on separating the BLOCK INVENTORY threshold from
maxTps. Even though the counter plumbing already exists, the expected traffic pattern is very different from TRX INV, so sharing the same cap would be too coarse.One small thing I’d make sure to cover in the implementation is boundary behavior: when
count + currentSize == limit, should that still pass and only reject>cases? It would be good to lock that down in tests so the config semantics stay predictable.Thanks for confirming. On the boundary behavior: the current implementation uses
>, meaningcount + currentSize == limitstill passes — only strictly exceeding the threshold triggers a drop. This is consistent with the existing TRX logic, with the semantics of "allow up to the limit, reject beyond it".Makes sense. If
>is the intended policy, I’d just suggest locking both== limitand> limitcases into tests so that boundary behavior stays explicit and doesn’t drift later.Makes sense. If
>is the intended policy, I’d just suggest locking both== limitand> limitcases into tests so that boundary behavior stays explicit and doesn’t drift later.@lxcmyf Thanks, that makes sense.
Agreed — locking down both boundary cases in tests is important to make the behavior explicit and prevent future regressions.
We’ll cover at least:
- count + currentSize == limit → should pass
- count + currentSize > limit → should be rejected
This keeps the semantics consistent with the current “allow up to the limit, reject beyond it” policy, while ensuring the behavior remains stable as the code evolves.
Summary
When processing INVENTORY messages, TRON nodes have already implemented a rate limiting mechanism for TRX-type inventories. However, the current logic only counts the number of inventory elements within a historical time window and does not take into account the number of hashes contained in the current message. In addition, BLOCK-type INVENTORY messages currently lack a similar rate limiting mechanism.
The proposed optimizations are:
These improvements aim to provide more accurate control over inventory intake rate, improve node resource management, and enhance P2P network stability.
Root Cause
In the InventoryHandler or related processing logic:
1. Incomplete Rate Limiting for TRX INVENTORY
The current TRX rate limiting logic is:
This logic only relies on the historical count (
count) and does not include the size of the current message (message.getHashList().size()).2. Missing Rate Limiting for BLOCK INVENTORY
BLOCK-type INVENTORY messages have no rate limiting control:
As a result, BLOCK INVENTORY intake is unbounded and lacks unified configuration control.
Reproduction
Start a node and connect it to the P2P network.
TRX scenario:
BLOCK scenario:
Impact
Suggested Fix
Apply a unified rate limiting optimization for INVENTORY messages:
1. TRX INVENTORY Enhancement
Include the current message size in the rate limiting check:
2. BLOCK INVENTORY Rate Limiting (New)
Introduce a configurable parameter:
Calculate based on a 10-second sliding window:
Add rate limiting logic:
Core Logic
count + message.getHashList().size() > maxLimitMeaning:
Historical count + current message size > threshold → drop the messageBenefits