Skip to content

Commit 7cb986a

Browse files
zeusoo001claude
authored andcommitted
feat: fix TRX inv rate limit bug and add BLOCK inv rate limit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 980c707 commit 7cb986a

6 files changed

Lines changed: 137 additions & 17 deletions

File tree

common/src/main/java/org/tron/common/parameter/CommonParameter.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,9 @@ public class CommonParameter {
119119
public int maxTps; // clearParam: 1000
120120
@Getter
121121
@Setter
122+
public int maxBlockInvPerSecond = 10; // default: 10 block inv hashes/s per peer
123+
@Getter
124+
@Setter
122125
public int minParticipationRate;
123126
@Getter
124127
public P2pConfig p2pConfig;

common/src/main/java/org/tron/core/config/args/NodeConfig.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public class NodeConfig {
3535
private boolean openPrintLog = true;
3636
private boolean openTransactionSort = false;
3737
private int maxTps = 1000;
38+
private int maxBlockInvPerSecond = 10;
3839
// Config key "isOpenFullTcpDisconnect" cannot auto-bind — read manually in fromConfig()
3940
@Getter(lombok.AccessLevel.NONE)
4041
@Setter(lombok.AccessLevel.NONE)
@@ -452,6 +453,11 @@ private void postProcess() {
452453
inactiveThreshold = 1;
453454
}
454455

456+
// maxBlockInvPerSecond: minimum 1
457+
if (maxBlockInvPerSecond < 1) {
458+
maxBlockInvPerSecond = 1;
459+
}
460+
455461
// maxFastForwardNum: clamp to [1, MAX_ACTIVE_WITNESS_NUM]
456462
if (maxFastForwardNum > MAX_ACTIVE_WITNESS_NUM) {
457463
maxFastForwardNum = MAX_ACTIVE_WITNESS_NUM;

common/src/main/resources/reference.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ node {
227227
# Threshold for broadcast transactions received from each peer per second,
228228
# transactions exceeding this are discarded
229229
maxTps = 1000
230+
# Max block inv hashes accepted per peer per second. Minimum: 1.
231+
maxBlockInvPerSecond = 10
230232

231233
isOpenFullTcpDisconnect = false
232234
inactiveThreshold = 600 // seconds

framework/src/main/java/org/tron/core/config/args/Args.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,7 @@ private static void applyNodeConfig(NodeConfig nc) {
615615
PARAMETER.minActiveConnections = nc.getMinActiveConnections();
616616
PARAMETER.maxConnectionsWithSameIp = nc.getMaxConnectionsWithSameIp();
617617
PARAMETER.maxTps = nc.getMaxTps();
618+
PARAMETER.maxBlockInvPerSecond = nc.getMaxBlockInvPerSecond();
618619
PARAMETER.minParticipationRate = nc.getMinParticipationRate();
619620
PARAMETER.nodeListenPort = nc.getListenPort();
620621
PARAMETER.nodeEnableIpv6 = nc.isEnableIpv6();

framework/src/main/java/org/tron/core/net/P2pEventHandlerImpl.java

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import org.tron.core.net.service.effective.EffectiveCheckService;
3737
import org.tron.core.net.service.handshake.HandshakeService;
3838
import org.tron.core.net.service.keepalive.KeepAliveService;
39+
import org.tron.core.net.service.statistics.MessageStatistics;
3940
import org.tron.p2p.P2pEventHandler;
4041
import org.tron.p2p.connection.Channel;
4142
import org.tron.protos.Protocol;
@@ -91,6 +92,7 @@ public class P2pEventHandlerImpl extends P2pEventHandler {
9192
private byte MESSAGE_MAX_TYPE = 127;
9293

9394
private int maxCountIn10s = Args.getInstance().getMaxTps() * 10;
95+
private int maxBlockInvIn10s = Args.getInstance().getMaxBlockInvPerSecond() * 10;
9496

9597
public P2pEventHandlerImpl() {
9698
Set<Byte> set = new HashSet<>();
@@ -149,19 +151,8 @@ private void processMessage(PeerConnection peer, byte[] data) {
149151
msg = TronMessageFactory.create(data);
150152
type = msg.getType();
151153

152-
if (INVENTORY.equals(type)) {
153-
InventoryMessage message = (InventoryMessage) msg;
154-
Protocol.Inventory.InventoryType inventoryType = message.getInventoryType();
155-
int count = peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement
156-
.getCount(10);
157-
if (inventoryType.equals(Protocol.Inventory.InventoryType.TRX) && count > maxCountIn10s) {
158-
logger.warn("Drop inventory from Peer {}, cur:{}, max:{}",
159-
peer.getInetAddress(), count, maxCountIn10s);
160-
if (Args.getInstance().isOpenPrintLog()) {
161-
logger.warn("[overload]Drop tx list is: {}", ((InventoryMessage) msg).getHashList());
162-
}
163-
return;
164-
}
154+
if (INVENTORY.equals(type) && !checkInvRateLimit(peer, (InventoryMessage) msg)) {
155+
return;
165156
}
166157

167158
peer.getPeerStatistics().messageStatistics.addTcpInMessage(msg);
@@ -224,6 +215,32 @@ private void processMessage(PeerConnection peer, byte[] data) {
224215
}
225216
}
226217

218+
private boolean checkInvRateLimit(PeerConnection peer, InventoryMessage msg) {
219+
InventoryType invType = msg.getInventoryType();
220+
int currentSize = msg.getInventory().getIdsCount();
221+
MessageStatistics stats = peer.getPeerStatistics().messageStatistics;
222+
223+
if (invType == InventoryType.TRX) {
224+
int count = stats.tronInTrxInventoryElement.getCount(10);
225+
if (count + currentSize > maxCountIn10s) {
226+
logger.warn("Drop TRX inv from {}, window:{}, cur:{}, max:{}",
227+
peer.getInetAddress(), count, currentSize, maxCountIn10s);
228+
if (Args.getInstance().isOpenPrintLog()) {
229+
logger.warn("[overload] Drop tx list: {}", msg.getHashList());
230+
}
231+
return false;
232+
}
233+
} else if (invType == InventoryType.BLOCK) {
234+
int count = stats.tronInBlockInventoryElement.getCount(10);
235+
if (count + currentSize > maxBlockInvIn10s) {
236+
logger.warn("Drop BLOCK inv from {}, window:{}, cur:{}, max:{}",
237+
peer.getInetAddress(), count, currentSize, maxBlockInvIn10s);
238+
return false;
239+
}
240+
}
241+
return true;
242+
}
243+
227244
private void updateLastInteractiveTime(PeerConnection peer, TronMessage msg) {
228245
MessageTypes type = msg.getType();
229246

framework/src/test/java/org/tron/core/net/P2pEventHandlerImplTest.java

Lines changed: 95 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ public static void init() throws Exception {
3434
public void testProcessInventoryMessage() throws Exception {
3535
CommonParameter parameter = CommonParameter.getInstance();
3636
parameter.setMaxTps(10);
37+
parameter.setMaxBlockInvPerSecond(10);
3738

3839
PeerStatistics peerStatistics = new PeerStatistics();
3940

@@ -75,7 +76,7 @@ public void testProcessInventoryMessage() throws Exception {
7576

7677
count = peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement.getCount(10);
7778

78-
Assert.assertEquals(110, count);
79+
Assert.assertEquals(10, count); // 100 hashes dropped: 10+100=110 > maxCountIn10s(100)
7980

8081
list.clear();
8182
for (int i = 0; i < 100; i++) {
@@ -88,7 +89,7 @@ public void testProcessInventoryMessage() throws Exception {
8889

8990
count = peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement.getCount(10);
9091

91-
Assert.assertEquals(110, count);
92+
Assert.assertEquals(10, count); // still dropped: window=10, 10+100=110 > 100
9293

9394
list.clear();
9495
for (int i = 0; i < 200; i++) {
@@ -101,7 +102,7 @@ public void testProcessInventoryMessage() throws Exception {
101102

102103
count = peer.getPeerStatistics().messageStatistics.tronInBlockInventoryElement.getCount(10);
103104

104-
Assert.assertEquals(200, count);
105+
Assert.assertEquals(0, count); // 200 hashes dropped: 0+200=200 > maxBlockInvIn10s(100)
105106

106107
list.clear();
107108
for (int i = 0; i < 100; i++) {
@@ -114,10 +115,100 @@ public void testProcessInventoryMessage() throws Exception {
114115

115116
count = peer.getPeerStatistics().messageStatistics.tronInBlockInventoryElement.getCount(10);
116117

117-
Assert.assertEquals(300, count);
118+
Assert.assertEquals(100, count); // passes: window=0, 0+100=100, not > 100
118119

119120
}
120121

122+
@Test
123+
public void testCheckInvRateLimitTrxBoundary() throws Exception {
124+
// maxTps=10 → maxCountIn10s=100
125+
CommonParameter parameter = CommonParameter.getInstance();
126+
parameter.setMaxTps(10);
127+
parameter.setMaxBlockInvPerSecond(10);
128+
129+
PeerStatistics peerStatistics = new PeerStatistics();
130+
PeerConnection peer = mock(PeerConnection.class);
131+
Mockito.when(peer.getPeerStatistics()).thenReturn(peerStatistics);
132+
133+
P2pEventHandlerImpl handler = new P2pEventHandlerImpl();
134+
Method method = handler.getClass()
135+
.getDeclaredMethod("processMessage", PeerConnection.class, byte[].class);
136+
method.setAccessible(true);
137+
138+
// Fill window to 91: send 91 TRX hashes → passes (0+91=91 ≤ 100)
139+
List<Sha256Hash> list91 = new ArrayList<>();
140+
for (int i = 0; i < 91; i++) {
141+
list91.add(new Sha256Hash(i, new byte[32]));
142+
}
143+
InventoryMessage msg91 = new InventoryMessage(list91, InventoryType.TRX);
144+
method.invoke(handler, peer, msg91.getSendBytes());
145+
Assert.assertEquals(91,
146+
peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement.getCount(10));
147+
148+
// Send 9 more TRX hashes → passes (91+9=100, not > 100)
149+
List<Sha256Hash> list9 = new ArrayList<>();
150+
for (int i = 0; i < 9; i++) {
151+
list9.add(new Sha256Hash(i, new byte[32]));
152+
}
153+
InventoryMessage msg9 = new InventoryMessage(list9, InventoryType.TRX);
154+
method.invoke(handler, peer, msg9.getSendBytes());
155+
Assert.assertEquals(100,
156+
peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement.getCount(10));
157+
158+
// Send 1 more TRX hash → DROPPED (100+1=101 > 100)
159+
List<Sha256Hash> list1 = new ArrayList<>();
160+
list1.add(new Sha256Hash(0, new byte[32]));
161+
InventoryMessage msg1 = new InventoryMessage(list1, InventoryType.TRX);
162+
method.invoke(handler, peer, msg1.getSendBytes());
163+
Assert.assertEquals(100, // count unchanged: message was dropped
164+
peer.getPeerStatistics().messageStatistics.tronInTrxInventoryElement.getCount(10));
165+
}
166+
167+
@Test
168+
public void testCheckInvRateLimitBlockBoundary() throws Exception {
169+
// maxBlockInvPerSecond=10 → maxBlockInvIn10s=100
170+
CommonParameter parameter = CommonParameter.getInstance();
171+
parameter.setMaxTps(1000);
172+
parameter.setMaxBlockInvPerSecond(10);
173+
174+
PeerStatistics peerStatistics = new PeerStatistics();
175+
PeerConnection peer = mock(PeerConnection.class);
176+
Mockito.when(peer.getPeerStatistics()).thenReturn(peerStatistics);
177+
178+
P2pEventHandlerImpl handler = new P2pEventHandlerImpl();
179+
Method method = handler.getClass()
180+
.getDeclaredMethod("processMessage", PeerConnection.class, byte[].class);
181+
method.setAccessible(true);
182+
183+
// Send 101 BLOCK hashes → DROPPED (0+101=101 > 100)
184+
List<Sha256Hash> list101 = new ArrayList<>();
185+
for (int i = 0; i < 101; i++) {
186+
list101.add(new Sha256Hash(i, new byte[32]));
187+
}
188+
InventoryMessage msgBlock101 = new InventoryMessage(list101, InventoryType.BLOCK);
189+
method.invoke(handler, peer, msgBlock101.getSendBytes());
190+
Assert.assertEquals(0,
191+
peer.getPeerStatistics().messageStatistics.tronInBlockInventoryElement.getCount(10));
192+
193+
// Send 100 BLOCK hashes → passes (0+100=100, not > 100)
194+
List<Sha256Hash> list100 = new ArrayList<>();
195+
for (int i = 0; i < 100; i++) {
196+
list100.add(new Sha256Hash(i, new byte[32]));
197+
}
198+
InventoryMessage msgBlock100 = new InventoryMessage(list100, InventoryType.BLOCK);
199+
method.invoke(handler, peer, msgBlock100.getSendBytes());
200+
Assert.assertEquals(100,
201+
peer.getPeerStatistics().messageStatistics.tronInBlockInventoryElement.getCount(10));
202+
203+
// Send 1 more BLOCK hash → DROPPED (100+1=101 > 100)
204+
List<Sha256Hash> list1 = new ArrayList<>();
205+
list1.add(new Sha256Hash(0, new byte[32]));
206+
InventoryMessage msgBlock1 = new InventoryMessage(list1, InventoryType.BLOCK);
207+
method.invoke(handler, peer, msgBlock1.getSendBytes());
208+
Assert.assertEquals(100, // count unchanged: message was dropped
209+
peer.getPeerStatistics().messageStatistics.tronInBlockInventoryElement.getCount(10));
210+
}
211+
121212
@Test
122213
public void testUpdateLastInteractiveTime() throws Exception {
123214
PeerConnection peer = new PeerConnection();

0 commit comments

Comments
 (0)