From dbc49fe0730a6d7273074304d3aa8bfad6064f59 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 16 Jun 2026 14:53:51 +0800 Subject: [PATCH 1/5] decrease MAX_NESTING_DEPTH and TOKEN_COUNT --- common/src/main/java/org/tron/core/Constant.java | 5 +++-- common/src/main/java/org/tron/json/JSON.java | 2 +- .../java/org/tron/core/services/jsonrpc/JsonRpcServlet.java | 2 +- .../org/tron/core/services/jsonrpc/JsonRpcServletTest.java | 2 +- framework/src/test/java/org/tron/json/JsonTest.java | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 3a2c59d513..ecd1e20817 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -65,7 +65,8 @@ public class Constant { public static final String LOCAL_HOST = "127.0.0.1"; // JSON parsing (DoS protection) - public static final int MAX_NESTING_DEPTH = 100; - public static final int MAX_TOKEN_COUNT = 100_000; + public static final int MAX_NESTING_DEPTH = 20; + public static final int MAX_HTTP_TOKEN_COUNT = 2_000; + public static final int MAX_JSON_RPC_TOKEN_COUNT = 20_000; } diff --git a/common/src/main/java/org/tron/json/JSON.java b/common/src/main/java/org/tron/json/JSON.java index 571b9515ad..c6b442ab54 100644 --- a/common/src/main/java/org/tron/json/JSON.java +++ b/common/src/main/java/org/tron/json/JSON.java @@ -60,7 +60,7 @@ public final class JSON { private static JsonFactory buildFactory() { return JsonFactory.builder().streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(Constant.MAX_NESTING_DEPTH) - .maxTokenCount(Constant.MAX_TOKEN_COUNT) + .maxTokenCount(Constant.MAX_HTTP_TOKEN_COUNT) .build()).build(); } diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java index a332757457..fa6a829305 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java @@ -39,7 +39,7 @@ private static ObjectMapper buildMapper() { JsonFactory factory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(Constant.MAX_NESTING_DEPTH) - .maxTokenCount(Constant.MAX_TOKEN_COUNT) + .maxTokenCount(Constant.MAX_JSON_RPC_TOKEN_COUNT) .build()) .build(); return new ObjectMapper(factory); diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java index c5e87384b9..2da82595ce 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java @@ -384,7 +384,7 @@ public void excessivelyNestedRequest_returnsParseError() throws Exception { @Test public void tooManyTokens_returnsParseError() throws Exception { - int limit = Constant.MAX_TOKEN_COUNT; + int limit = Constant.MAX_JSON_RPC_TOKEN_COUNT; StringBuilder sb = new StringBuilder("["); for (int i = 0; i < limit; i++) { if (i > 0) { diff --git a/framework/src/test/java/org/tron/json/JsonTest.java b/framework/src/test/java/org/tron/json/JsonTest.java index eb9fed8ff2..1dd91241ed 100644 --- a/framework/src/test/java/org/tron/json/JsonTest.java +++ b/framework/src/test/java/org/tron/json/JsonTest.java @@ -371,7 +371,7 @@ public void testTypeUtilsCoercion() { public void testJsonMapperHasConfiguredConstraints() { StreamReadConstraints sr = JSON.MAPPER.getFactory().streamReadConstraints(); assertEquals(Constant.MAX_NESTING_DEPTH, sr.getMaxNestingDepth()); - assertEquals((long) Constant.MAX_TOKEN_COUNT, sr.getMaxTokenCount()); + assertEquals((long) Constant.MAX_HTTP_TOKEN_COUNT, sr.getMaxTokenCount()); } @Test From 8ad6a2acb7619ee0f36945dd352dbe81d00a4b99 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 16 Jun 2026 15:33:15 +0800 Subject: [PATCH 2/5] specify message for StreamConstraintsException --- .../org/tron/core/services/jsonrpc/JsonRpcServlet.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java index fa6a829305..2b128724c6 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.core.JsonFactory; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.StreamReadConstraints; +import com.fasterxml.jackson.core.exc.StreamConstraintsException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; @@ -114,7 +115,11 @@ protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws I return; } } catch (JsonProcessingException e) { - writeJsonRpcError(resp, JsonRpcError.PARSE_ERROR, "JSON parse error", null, false); + if (e instanceof StreamConstraintsException) { + writeJsonRpcError(resp, JsonRpcError.PARSE_ERROR, e.getMessage(), null, false); + } else { + writeJsonRpcError(resp, JsonRpcError.PARSE_ERROR, "JSON parse error", null, false); + } return; } From a4ffedb8202fffb7c11f5fd70ebf2de8502cc0e9 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Tue, 16 Jun 2026 15:50:15 +0800 Subject: [PATCH 3/5] change MAX_HTTP_TOKEN_COUNT to 5000 --- common/src/main/java/org/tron/core/Constant.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index ecd1e20817..f2a4a3eaf1 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -66,7 +66,7 @@ public class Constant { // JSON parsing (DoS protection) public static final int MAX_NESTING_DEPTH = 20; - public static final int MAX_HTTP_TOKEN_COUNT = 2_000; + public static final int MAX_HTTP_TOKEN_COUNT = 5_000; public static final int MAX_JSON_RPC_TOKEN_COUNT = 20_000; } From 704570804d1f15faa17564dea74116c68abc39d0 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 17 Jun 2026 15:46:39 +0800 Subject: [PATCH 4/5] change MAX_NESTING_DEPTH from 100 to 20 --- common/src/main/java/org/tron/core/Constant.java | 3 +-- common/src/main/java/org/tron/json/JSON.java | 2 +- .../java/org/tron/core/services/jsonrpc/JsonRpcServlet.java | 2 +- .../java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java | 2 +- .../org/tron/core/services/jsonrpc/JsonRpcServletTest.java | 2 +- framework/src/test/java/org/tron/json/JsonTest.java | 2 +- 6 files changed, 6 insertions(+), 7 deletions(-) diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index f2a4a3eaf1..5d3f3099c9 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -66,7 +66,6 @@ public class Constant { // JSON parsing (DoS protection) public static final int MAX_NESTING_DEPTH = 20; - public static final int MAX_HTTP_TOKEN_COUNT = 5_000; - public static final int MAX_JSON_RPC_TOKEN_COUNT = 20_000; + public static final int MAX_TOKEN_COUNT = 100_000; } diff --git a/common/src/main/java/org/tron/json/JSON.java b/common/src/main/java/org/tron/json/JSON.java index c6b442ab54..571b9515ad 100644 --- a/common/src/main/java/org/tron/json/JSON.java +++ b/common/src/main/java/org/tron/json/JSON.java @@ -60,7 +60,7 @@ public final class JSON { private static JsonFactory buildFactory() { return JsonFactory.builder().streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(Constant.MAX_NESTING_DEPTH) - .maxTokenCount(Constant.MAX_HTTP_TOKEN_COUNT) + .maxTokenCount(Constant.MAX_TOKEN_COUNT) .build()).build(); } diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java index 2b128724c6..ca249da4e5 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/JsonRpcServlet.java @@ -40,7 +40,7 @@ private static ObjectMapper buildMapper() { JsonFactory factory = JsonFactory.builder() .streamReadConstraints(StreamReadConstraints.builder() .maxNestingDepth(Constant.MAX_NESTING_DEPTH) - .maxTokenCount(Constant.MAX_JSON_RPC_TOKEN_COUNT) + .maxTokenCount(Constant.MAX_TOKEN_COUNT) .build()) .build(); return new ObjectMapper(factory); diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index 825b1ff2f3..fab27a9859 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -1143,7 +1143,7 @@ private TransactionJson buildCreateSmartContractTransaction(byte[] ownerAddress, String abiStr = "{" + "\"entrys\":" + args.getAbi() + "}"; try { JsonFormat.merge(abiStr, abiBuilder, args.isVisible()); - } catch (JsonFormat.ParseException | StackOverflowError e) { + } catch (Exception e) { throw new JsonRpcInvalidParamsException("invalid abi"); } } diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java index 2da82595ce..c5e87384b9 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java @@ -384,7 +384,7 @@ public void excessivelyNestedRequest_returnsParseError() throws Exception { @Test public void tooManyTokens_returnsParseError() throws Exception { - int limit = Constant.MAX_JSON_RPC_TOKEN_COUNT; + int limit = Constant.MAX_TOKEN_COUNT; StringBuilder sb = new StringBuilder("["); for (int i = 0; i < limit; i++) { if (i > 0) { diff --git a/framework/src/test/java/org/tron/json/JsonTest.java b/framework/src/test/java/org/tron/json/JsonTest.java index 1dd91241ed..eb9fed8ff2 100644 --- a/framework/src/test/java/org/tron/json/JsonTest.java +++ b/framework/src/test/java/org/tron/json/JsonTest.java @@ -371,7 +371,7 @@ public void testTypeUtilsCoercion() { public void testJsonMapperHasConfiguredConstraints() { StreamReadConstraints sr = JSON.MAPPER.getFactory().streamReadConstraints(); assertEquals(Constant.MAX_NESTING_DEPTH, sr.getMaxNestingDepth()); - assertEquals((long) Constant.MAX_HTTP_TOKEN_COUNT, sr.getMaxTokenCount()); + assertEquals((long) Constant.MAX_TOKEN_COUNT, sr.getMaxTokenCount()); } @Test From 7fd59e3a550f0b349b155fc5697526282cad8d25 Mon Sep 17 00:00:00 2001 From: jiangyuanshu <317787106@qq.com> Date: Wed, 17 Jun 2026 17:20:21 +0800 Subject: [PATCH 5/5] test(api): assert StreamConstraintsException message on json-rpc parse errors Verify the new branch in JsonRpcServlet that surfaces the specific StreamConstraintsException message (nesting depth / token count) instead of the generic "JSON parse error", while non-constraint parse failures keep the generic message. Co-Authored-By: Claude Opus 4.8 --- .../services/jsonrpc/JsonRpcServletTest.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java index c5e87384b9..d6c843b5ae 100644 --- a/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java +++ b/framework/src/test/java/org/tron/core/services/jsonrpc/JsonRpcServletTest.java @@ -3,6 +3,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doAnswer; @@ -62,6 +63,8 @@ public void invalidJson_returnsParseError() throws Exception { JsonNode body = MAPPER.readTree(resp.getContentAsString()); assertFalse(body.isArray()); assertEquals(-32700, body.get("error").get("code").asInt()); + // A non-constraint JsonProcessingException keeps the generic message (else branch). + assertEquals("JSON parse error", body.get("error").get("message").asText()); assertEquals("2.0", body.get("jsonrpc").asText()); assertTrue(body.get("id").isNull()); } @@ -378,8 +381,14 @@ public void excessivelyNestedRequest_returnsParseError() throws Exception { MockHttpServletResponse resp = doPost(sb.toString()); assertEquals(200, resp.getStatus()); - assertEquals(-32700, - MAPPER.readTree(resp.getContentAsString()).get("error").get("code").asInt()); + JsonNode error = MAPPER.readTree(resp.getContentAsString()).get("error"); + assertEquals(-32700, error.get("code").asInt()); + // StreamConstraintsException message must be surfaced verbatim, not the generic text, + // so callers can tell which constraint (nesting depth) was hit. + String message = error.get("message").asText(); + assertNotEquals("JSON parse error", message); + assertTrue("expected a nesting-depth constraint message, got: " + message, + message.contains("nesting depth") && message.contains("exceeds the maximum allowed")); } @Test @@ -396,8 +405,14 @@ public void tooManyTokens_returnsParseError() throws Exception { MockHttpServletResponse resp = doPost(sb.toString()); assertEquals(200, resp.getStatus()); - assertEquals(-32700, - MAPPER.readTree(resp.getContentAsString()).get("error").get("code").asInt()); + JsonNode error = MAPPER.readTree(resp.getContentAsString()).get("error"); + assertEquals(-32700, error.get("code").asInt()); + // StreamConstraintsException message must be surfaced verbatim, not the generic text, + // so callers can tell which constraint (token count) was hit. + String message = error.get("message").asText(); + assertNotEquals("JSON parse error", message); + assertTrue("expected a token-count constraint message, got: " + message, + message.contains("Token count") && message.contains("exceeds the maximum allowed")); } // --- helpers ---