diff --git a/common/src/main/java/org/tron/core/Constant.java b/common/src/main/java/org/tron/core/Constant.java index 3a2c59d513..5d3f3099c9 100644 --- a/common/src/main/java/org/tron/core/Constant.java +++ b/common/src/main/java/org/tron/core/Constant.java @@ -65,7 +65,7 @@ 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_NESTING_DEPTH = 20; public static final int MAX_TOKEN_COUNT = 100_000; } 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..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 @@ -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; } 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 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 ---