Skip to content

Commit c2383f7

Browse files
Merge pull request #6271 from waynercheung/feat/harden_filters
feat(jsonrpc): check maxSubTopics and maxBlockRange to be consistent with eth
2 parents 10186b0 + fd89088 commit c2383f7

File tree

19 files changed

+287
-69
lines changed

19 files changed

+287
-69
lines changed

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@
88
import java.util.Set;
99
import lombok.Getter;
1010
import lombok.Setter;
11-
import org.tron.common.cron.CronExpression;
1211
import org.tron.common.args.GenesisBlock;
1312
import org.tron.common.config.DbBackupConfig;
13+
import org.tron.common.cron.CronExpression;
1414
import org.tron.common.logsfilter.EventPluginConfig;
1515
import org.tron.common.logsfilter.FilterQuery;
1616
import org.tron.common.setting.RocksDbSettings;
@@ -495,6 +495,13 @@ public class CommonParameter {
495495
@Getter
496496
@Setter
497497
public boolean jsonRpcHttpPBFTNodeEnable = false;
498+
@Getter
499+
@Setter
500+
public int jsonRpcMaxBlockRange = 5000;
501+
@Getter
502+
@Setter
503+
public int jsonRpcMaxSubTopics = 1000;
504+
498505
@Getter
499506
@Setter
500507
public int maxTransactionPendingSize;

common/src/main/java/org/tron/common/utils/ByteUtil.java

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -479,40 +479,41 @@ public static byte[] setBit(byte[] data, int pos, int val) {
479479

480480
public static byte[] compress(byte[] data) throws EventBloomException {
481481
Deflater deflater = new Deflater();
482-
deflater.setInput(data);
483482

484-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
483+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length)) {
484+
deflater.setInput(data);
485+
deflater.finish();
486+
byte[] buffer = new byte[1024];
485487

486-
deflater.finish();
487-
byte[] buffer = new byte[1024];
488-
while (!deflater.finished()) {
489-
int count = deflater.deflate(buffer); // returns the generated code... index
490-
outputStream.write(buffer, 0, count);
491-
}
492-
try {
493-
outputStream.close();
488+
while (!deflater.finished()) {
489+
int count = deflater.deflate(buffer); // returns the generated code... index
490+
outputStream.write(buffer, 0, count);
491+
}
492+
493+
return outputStream.toByteArray();
494494
} catch (IOException e) {
495495
throw new EventBloomException("compress data failed");
496+
} finally {
497+
deflater.end();
496498
}
497-
byte[] output = outputStream.toByteArray();
498-
499-
return output;
500499
}
501500

502501
public static byte[] decompress(byte[] data) throws IOException, DataFormatException {
503502
Inflater inflater = new Inflater();
504-
inflater.setInput(data);
505503

506-
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
507-
byte[] buffer = new byte[1024];
508-
while (!inflater.finished()) {
509-
int count = inflater.inflate(buffer);
510-
outputStream.write(buffer, 0, count);
511-
}
512-
outputStream.close();
513-
byte[] output = outputStream.toByteArray();
504+
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length)) {
505+
inflater.setInput(data);
506+
byte[] buffer = new byte[1024];
507+
508+
while (!inflater.finished()) {
509+
int count = inflater.inflate(buffer);
510+
outputStream.write(buffer, 0, count);
511+
}
514512

515-
return output;
513+
return outputStream.toByteArray();
514+
} finally {
515+
inflater.end();
516+
}
516517
}
517518

518519
}

common/src/main/java/org/tron/core/Constant.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,8 @@ public class Constant {
145145
public static final String NODE_JSONRPC_HTTP_SOLIDITY_PORT = "node.jsonrpc.httpSolidityPort";
146146
public static final String NODE_JSONRPC_HTTP_PBFT_ENABLE = "node.jsonrpc.httpPBFTEnable";
147147
public static final String NODE_JSONRPC_HTTP_PBFT_PORT = "node.jsonrpc.httpPBFTPort";
148+
public static final String NODE_JSONRPC_MAX_BLOCK_RANGE = "node.jsonrpc.maxBlockRange";
149+
public static final String NODE_JSONRPC_MAX_SUB_TOPICS = "node.jsonrpc.maxSubTopics";
148150

149151
public static final String NODE_DISABLED_API_LIST = "node.disabledApi";
150152

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,8 @@ public static void clearParam() {
202202
PARAMETER.jsonRpcHttpFullNodeEnable = false;
203203
PARAMETER.jsonRpcHttpSolidityNodeEnable = false;
204204
PARAMETER.jsonRpcHttpPBFTNodeEnable = false;
205+
PARAMETER.jsonRpcMaxBlockRange = 5000;
206+
PARAMETER.jsonRpcMaxSubTopics = 1000;
205207
PARAMETER.nodeMetricsEnable = false;
206208
PARAMETER.metricsStorageEnable = false;
207209
PARAMETER.metricsPrometheusEnable = false;
@@ -507,6 +509,16 @@ public static void setParam(final Config config) {
507509
config.getBoolean(Constant.NODE_JSONRPC_HTTP_PBFT_ENABLE);
508510
}
509511

512+
if (config.hasPath(Constant.NODE_JSONRPC_MAX_BLOCK_RANGE)) {
513+
PARAMETER.jsonRpcMaxBlockRange =
514+
config.getInt(Constant.NODE_JSONRPC_MAX_BLOCK_RANGE);
515+
}
516+
517+
if (config.hasPath(Constant.NODE_JSONRPC_MAX_SUB_TOPICS)) {
518+
PARAMETER.jsonRpcMaxSubTopics =
519+
config.getInt(Constant.NODE_JSONRPC_MAX_SUB_TOPICS);
520+
}
521+
510522
if (config.hasPath(Constant.VM_MIN_TIME_RATIO)) {
511523
PARAMETER.minTimeRatio = config.getDouble(Constant.VM_MIN_TIME_RATIO);
512524
}

framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1327,7 +1327,7 @@ public LogFilterElement[] getLogs(FilterRequest fr) throws JsonRpcInvalidParamsE
13271327

13281328
long currentMaxBlockNum = wallet.getNowBlock().getBlockHeader().getRawData().getNumber();
13291329
//convert FilterRequest to LogFilterWrapper
1330-
LogFilterWrapper logFilterWrapper = new LogFilterWrapper(fr, currentMaxBlockNum, wallet);
1330+
LogFilterWrapper logFilterWrapper = new LogFilterWrapper(fr, currentMaxBlockNum, wallet, true);
13311331

13321332
return getLogsByLogFilterWrapper(logFilterWrapper, currentMaxBlockNum);
13331333
}

framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogBlockQuery.java

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,21 @@ public LogBlockQuery(LogFilterWrapper logFilterWrapper, SectionBloomStore sectio
3939
this.currentMaxBlockNum = currentMaxBlockNum;
4040

4141
if (logFilterWrapper.getFromBlock() == Long.MAX_VALUE) {
42-
minSection = (int) (currentMaxBlockNum / Bloom.BLOOM_BIT_SIZE);
4342
minBlock = currentMaxBlockNum;
4443
} else {
45-
minSection = (int) (logFilterWrapper.getFromBlock() / Bloom.BLOOM_BIT_SIZE);
4644
minBlock = logFilterWrapper.getFromBlock();
4745
}
46+
minSection = (int) (minBlock / Bloom.BLOOM_BIT_SIZE);
4847

4948
if (logFilterWrapper.getToBlock() == Long.MAX_VALUE) {
50-
maxSection = (int) (currentMaxBlockNum / Bloom.BLOOM_BIT_SIZE);
5149
maxBlock = currentMaxBlockNum;
5250
} else {
53-
maxSection = (int) (logFilterWrapper.getToBlock() / Bloom.BLOOM_BIT_SIZE);
5451
maxBlock = logFilterWrapper.getToBlock();
5552
if (maxBlock > currentMaxBlockNum) {
5653
maxBlock = currentMaxBlockNum;
5754
}
5855
}
56+
maxSection = (int) (maxBlock / Bloom.BLOOM_BIT_SIZE);
5957
}
6058

6159
public List<Long> getPossibleBlock() throws ExecutionException, InterruptedException,
@@ -71,7 +69,7 @@ public List<Long> getPossibleBlock() throws ExecutionException, InterruptedExcep
7169
BitSet blockNumBitSet = new BitSet(capacity);
7270
blockNumBitSet.set(0, capacity);
7371

74-
//works serial
72+
// works serial
7573
for (int[][] conditionsIndex : allConditionsIndex) {
7674
BitSet bitSet = subMatch(conditionsIndex);
7775
blockNumBitSet.and(bitSet);

framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilter.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.tron.common.bloom.Bloom;
1414
import org.tron.common.crypto.Hash;
1515
import org.tron.common.runtime.vm.DataWord;
16+
import org.tron.core.config.args.Args;
1617
import org.tron.core.exception.JsonRpcInvalidParamsException;
1718
import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest;
1819
import org.tron.protos.Protocol.TransactionInfo.Log;
@@ -35,6 +36,8 @@ public class LogFilter {
3536
@Setter
3637
private Bloom[][] filterBlooms;
3738

39+
// The maximum number of topic criteria allowed, vm.LOG4 - vm.LOG0
40+
private final int maxTopics = 4;
3841

3942
public LogFilter() {
4043
}
@@ -66,8 +69,8 @@ public LogFilter(FilterRequest fr) throws JsonRpcInvalidParamsException {
6669

6770
if (fr.getTopics() != null) {
6871
//restrict depth of topics, because event has a signature and most 3 indexed parameters
69-
if (fr.getTopics().length > 4) {
70-
throw new JsonRpcInvalidParamsException("topics size should be <= 4");
72+
if (fr.getTopics().length > maxTopics) {
73+
throw new JsonRpcInvalidParamsException("topics size should be <= " + maxTopics);
7174
}
7275
for (Object topic : fr.getTopics()) {
7376
if (topic == null) {
@@ -79,6 +82,10 @@ public LogFilter(FilterRequest fr) throws JsonRpcInvalidParamsException {
7982
throw new JsonRpcInvalidParamsException("invalid topic(s): " + topic);
8083
}
8184
} else if (topic instanceof ArrayList) {
85+
int maxSubTopics = Args.getInstance().getJsonRpcMaxSubTopics();
86+
if (maxSubTopics > 0 && ((ArrayList<?>) topic).size() > maxSubTopics) {
87+
throw new JsonRpcInvalidParamsException("exceed max topics: " + maxSubTopics);
88+
}
8289

8390
List<byte[]> t = new ArrayList<>();
8491
for (Object s : ((ArrayList) topic)) {

framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterAndResult.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ public class LogFilterAndResult extends FilterResult<LogFilterElement> {
1616

1717
public LogFilterAndResult(FilterRequest fr, long currentMaxBlockNum, Wallet wallet)
1818
throws JsonRpcInvalidParamsException {
19-
this.logFilterWrapper = new LogFilterWrapper(fr, currentMaxBlockNum, wallet);
19+
// eth_newFilter, no need to check block range
20+
this.logFilterWrapper = new LogFilterWrapper(fr, currentMaxBlockNum, wallet, false);
2021
result = new LinkedBlockingQueue<>();
2122
this.updateExpireTime();
2223
}

framework/src/main/java/org/tron/core/services/jsonrpc/filters/LogFilterWrapper.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import org.apache.commons.lang3.StringUtils;
88
import org.tron.common.utils.ByteArray;
99
import org.tron.core.Wallet;
10+
import org.tron.core.config.args.Args;
1011
import org.tron.core.exception.JsonRpcInvalidParamsException;
1112
import org.tron.core.services.jsonrpc.JsonRpcApiUtil;
1213
import org.tron.core.services.jsonrpc.TronJsonRpc.FilterRequest;
@@ -23,8 +24,8 @@ public class LogFilterWrapper {
2324
@Getter
2425
private final long toBlock;
2526

26-
public LogFilterWrapper(FilterRequest fr, long currentMaxBlockNum, Wallet wallet)
27-
throws JsonRpcInvalidParamsException {
27+
public LogFilterWrapper(FilterRequest fr, long currentMaxBlockNum, Wallet wallet,
28+
boolean checkBlockRange) throws JsonRpcInvalidParamsException {
2829

2930
// 1.convert FilterRequest to LogFilter
3031
this.logFilter = new LogFilter(fr);
@@ -86,6 +87,12 @@ public LogFilterWrapper(FilterRequest fr, long currentMaxBlockNum, Wallet wallet
8687
throw new JsonRpcInvalidParamsException("please verify: fromBlock <= toBlock");
8788
}
8889
}
90+
91+
// till now, it needs to check block range for eth_getLogs
92+
int maxBlockRange = Args.getInstance().getJsonRpcMaxBlockRange();
93+
if (checkBlockRange && maxBlockRange > 0 && (toBlockSrc - fromBlockSrc) > maxBlockRange) {
94+
throw new JsonRpcInvalidParamsException("exceed max block range: " + maxBlockRange);
95+
}
8996
}
9097

9198
this.fromBlock = fromBlockSrc;

framework/src/main/resources/config-localtest.conf

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ node {
161161
# httpSolidityPort = 8555
162162
# httpPBFTEnable = true
163163
# httpPBFTPort = 8565
164+
# maxBlockRange = 5000
165+
# maxSubTopics = 1000
164166
}
165167

166168
}

framework/src/main/resources/config.conf

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,14 @@ node {
291291
# httpSolidityPort = 8555
292292
# httpPBFTEnable = true
293293
# httpPBFTPort = 8565
294+
295+
# The maximum blocks range to retrieve logs for eth_getLogs, default value is 5000,
296+
# should be > 0, otherwise means no limit.
297+
# maxBlockRange = 5000
298+
299+
# The maximum number of allowed topics within a topic criteria, default value is 1000,
300+
# should be > 0, otherwise means no limit.
301+
# maxSubTopics = 1000
294302
}
295303

296304
# Disabled api list, it will work for http, rpc and pbft, both fullnode and soliditynode,

framework/src/test/java/org/tron/core/config/args/ArgsTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,8 @@ public void testInitService() {
173173
Assert.assertFalse(Args.getInstance().isJsonRpcHttpFullNodeEnable());
174174
Assert.assertFalse(Args.getInstance().isJsonRpcHttpSolidityNodeEnable());
175175
Assert.assertFalse(Args.getInstance().isJsonRpcHttpPBFTNodeEnable());
176+
Assert.assertEquals(5000, Args.getInstance().getJsonRpcMaxBlockRange());
177+
Assert.assertEquals(1000, Args.getInstance().getJsonRpcMaxSubTopics());
176178
Args.clearParam();
177179
// test set all true value
178180
storage.put("node.rpc.enable", "true");
@@ -184,6 +186,8 @@ public void testInitService() {
184186
storage.put("node.jsonrpc.httpFullNodeEnable", "true");
185187
storage.put("node.jsonrpc.httpSolidityEnable", "true");
186188
storage.put("node.jsonrpc.httpPBFTEnable", "true");
189+
storage.put("node.jsonrpc.maxBlockRange", "10");
190+
storage.put("node.jsonrpc.maxSubTopics", "20");
187191
config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage));
188192
// test value
189193
Args.setParam(config);
@@ -196,6 +200,8 @@ public void testInitService() {
196200
Assert.assertTrue(Args.getInstance().isJsonRpcHttpFullNodeEnable());
197201
Assert.assertTrue(Args.getInstance().isJsonRpcHttpSolidityNodeEnable());
198202
Assert.assertTrue(Args.getInstance().isJsonRpcHttpPBFTNodeEnable());
203+
Assert.assertEquals(10, Args.getInstance().getJsonRpcMaxBlockRange());
204+
Assert.assertEquals(20, Args.getInstance().getJsonRpcMaxSubTopics());
199205
Args.clearParam();
200206
// test set all false value
201207
storage.put("node.rpc.enable", "false");
@@ -207,6 +213,8 @@ public void testInitService() {
207213
storage.put("node.jsonrpc.httpFullNodeEnable", "false");
208214
storage.put("node.jsonrpc.httpSolidityEnable", "false");
209215
storage.put("node.jsonrpc.httpPBFTEnable", "false");
216+
storage.put("node.jsonrpc.maxBlockRange", "5000");
217+
storage.put("node.jsonrpc.maxSubTopics", "1000");
210218
config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage));
211219
// test value
212220
Args.setParam(config);
@@ -219,6 +227,8 @@ public void testInitService() {
219227
Assert.assertFalse(Args.getInstance().isJsonRpcHttpFullNodeEnable());
220228
Assert.assertFalse(Args.getInstance().isJsonRpcHttpSolidityNodeEnable());
221229
Assert.assertFalse(Args.getInstance().isJsonRpcHttpPBFTNodeEnable());
230+
Assert.assertEquals(5000, Args.getInstance().getJsonRpcMaxBlockRange());
231+
Assert.assertEquals(1000, Args.getInstance().getJsonRpcMaxSubTopics());
222232
Args.clearParam();
223233
// test set random value
224234
storage.put("node.rpc.enable", "false");
@@ -230,6 +240,8 @@ public void testInitService() {
230240
storage.put("node.jsonrpc.httpFullNodeEnable", "true");
231241
storage.put("node.jsonrpc.httpSolidityEnable", "false");
232242
storage.put("node.jsonrpc.httpPBFTEnable", "true");
243+
storage.put("node.jsonrpc.maxBlockRange", "30");
244+
storage.put("node.jsonrpc.maxSubTopics", "40");
233245
config = ConfigFactory.defaultOverrides().withFallback(ConfigFactory.parseMap(storage));
234246
// test value
235247
Args.setParam(config);
@@ -242,6 +254,8 @@ public void testInitService() {
242254
Assert.assertTrue(Args.getInstance().isJsonRpcHttpFullNodeEnable());
243255
Assert.assertFalse(Args.getInstance().isJsonRpcHttpSolidityNodeEnable());
244256
Assert.assertTrue(Args.getInstance().isJsonRpcHttpPBFTNodeEnable());
257+
Assert.assertEquals(30, Args.getInstance().getJsonRpcMaxBlockRange());
258+
Assert.assertEquals(40, Args.getInstance().getJsonRpcMaxSubTopics());
245259
Args.clearParam();
246260
}
247261
}

framework/src/test/java/org/tron/core/jsonrpc/JsonRpcTest.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,8 @@ public void testGetConditions() {
284284
topics,
285285
null),
286286
100,
287-
null);
287+
null,
288+
false);
288289

289290
LogBlockQuery logBlockQuery = new LogBlockQuery(logFilterWrapper, null, 100, null);
290291
int[][][] conditions = logBlockQuery.getConditions();
@@ -331,7 +332,8 @@ public void testGetConditionWithHashCollision() {
331332
topics,
332333
null),
333334
100,
334-
null);
335+
null,
336+
false);
335337

336338
LogBlockQuery logBlockQuery = new LogBlockQuery(logFilterWrapper, null, 100, null);
337339
int[][][] conditions = logBlockQuery.getConditions();

0 commit comments

Comments
 (0)