diff --git a/CHANGELOG.md b/CHANGELOG.md index 13575e7c2b0..5080389666c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ ### Additions and Improvements - Added `benchmark` subcommand to `evmtool` [#5754](https://github.com/hyperledger/besu/issues/5754) +- JSON output is now compact by default. This can be overridden by the new `--json-pretty-print-enabled` CLI option. [#5766](https://github.com/hyperledger/besu/pull/5766) ### Bug Fixes - Make smart contract permissioning features work with london fork [#5727](https://github.com/hyperledger/besu/pull/5727) diff --git a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java index c72a9766920..e0330170b7f 100644 --- a/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java +++ b/besu/src/main/java/org/hyperledger/besu/cli/BesuCommand.java @@ -27,6 +27,7 @@ import static org.hyperledger.besu.ethereum.api.graphql.GraphQLConfiguration.DEFAULT_GRAPHQL_HTTP_PORT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_ENGINE_JSON_RPC_PORT; import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_JSON_RPC_PORT; +import static org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcConfiguration.DEFAULT_PRETTY_JSON_ENABLED; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.DEFAULT_RPC_APIS; import static org.hyperledger.besu.ethereum.api.jsonrpc.RpcApis.VALID_APIS; import static org.hyperledger.besu.ethereum.api.jsonrpc.authentication.EngineAuthService.EPHEMERAL_JWT_FILE; @@ -779,6 +780,11 @@ static class JsonRPCHttpOptionGroup { paramLabel = MANDATORY_LONG_FORMAT_HELP, description = "Specifies the maximum request content length. (default: ${DEFAULT-VALUE})") private final Long rpcHttpMaxRequestContentLength = DEFAULT_MAX_REQUEST_CONTENT_LENGTH; + + @Option( + names = {"--json-pretty-print-enabled"}, + description = "Enable JSON pretty print format (default: ${DEFAULT-VALUE})") + private final Boolean prettyJsonEnabled = DEFAULT_PRETTY_JSON_ENABLED; } // JSON-RPC Websocket Options @@ -2443,6 +2449,7 @@ && rpcHttpAuthenticationCredentialsFile() == null jsonRpcConfiguration.setMaxBatchSize(jsonRPCHttpOptionGroup.rpcHttpMaxBatchSize); jsonRpcConfiguration.setMaxRequestContentLength( jsonRPCHttpOptionGroup.rpcHttpMaxRequestContentLength); + jsonRpcConfiguration.setPrettyJsonEnabled(jsonRPCHttpOptionGroup.prettyJsonEnabled); return jsonRpcConfiguration; } diff --git a/besu/src/test/resources/everything_config.toml b/besu/src/test/resources/everything_config.toml index d0bb8c2cf76..459346dc537 100644 --- a/besu/src/test/resources/everything_config.toml +++ b/besu/src/test/resources/everything_config.toml @@ -87,6 +87,7 @@ rpc-http-tls-cipher-suites=["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384","TLS_ECDHE_R rpc-http-max-batch-size=1 rpc-http-max-request-content-length = 5242880 rpc-max-logs-range=100 +json-pretty-print-enabled=false # PRIVACY TLS privacy-tls-enabled=false diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java index e1a655657fa..d2a2cb37428 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/handlers/JsonRpcObjectExecutor.java @@ -36,7 +36,7 @@ import io.vertx.ext.web.RoutingContext; public class JsonRpcObjectExecutor extends AbstractJsonRpcExecutor { - private static final ObjectWriter jsonObjectWriter = createObjectWriter(); + private final ObjectWriter jsonObjectWriter = createObjectWriter(); public JsonRpcObjectExecutor( final JsonRpcExecutor jsonRpcExecutor, @@ -64,7 +64,7 @@ String getRpcMethodName(final RoutingContext ctx) { return jsonObject.getString("method"); } - private static void handleJsonObjectResponse( + private void handleJsonObjectResponse( final HttpServerResponse response, final JsonRpcResponse jsonRpcResponse, final RoutingContext ctx) @@ -90,9 +90,12 @@ private static HttpResponseStatus status(final JsonRpcResponse response) { }; } - private static ObjectWriter createObjectWriter() { - return getJsonObjectMapper() - .writerWithDefaultPrettyPrinter() + private ObjectWriter createObjectWriter() { + ObjectWriter writer = + jsonRpcConfiguration.isPrettyJsonEnabled() + ? getJsonObjectMapper().writerWithDefaultPrettyPrinter() + : getJsonObjectMapper().writer(); + return writer .without(JsonGenerator.Feature.FLUSH_PASSED_TO_STREAM) .with(JsonGenerator.Feature.AUTO_CLOSE_TARGET); } diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java index cb77d9ce818..2ed9c56d540 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/JsonRpcConfiguration.java @@ -38,6 +38,7 @@ public class JsonRpcConfiguration { public static final int DEFAULT_MAX_ACTIVE_CONNECTIONS = 80; public static final int DEFAULT_MAX_BATCH_SIZE = 1024; public static final long DEFAULT_MAX_REQUEST_CONTENT_LENGTH = 5 * 1024 * 1024; // 5MB + public static final boolean DEFAULT_PRETTY_JSON_ENABLED = false; private boolean enabled; private int port; @@ -55,6 +56,7 @@ public class JsonRpcConfiguration { private int maxActiveConnections; private int maxBatchSize; private long maxRequestContentLength; + private boolean prettyJsonEnabled; public static JsonRpcConfiguration createDefault() { final JsonRpcConfiguration config = new JsonRpcConfiguration(); @@ -66,6 +68,7 @@ public static JsonRpcConfiguration createDefault() { config.setMaxActiveConnections(DEFAULT_MAX_ACTIVE_CONNECTIONS); config.setMaxBatchSize(DEFAULT_MAX_BATCH_SIZE); config.setMaxRequestContentLength(DEFAULT_MAX_REQUEST_CONTENT_LENGTH); + config.setPrettyJsonEnabled(DEFAULT_PRETTY_JSON_ENABLED); return config; } @@ -196,6 +199,14 @@ public void setHttpTimeoutSec(final long httpTimeoutSec) { this.httpTimeoutSec = httpTimeoutSec; } + public boolean isPrettyJsonEnabled() { + return prettyJsonEnabled; + } + + public void setPrettyJsonEnabled(final boolean prettyJsonEnabled) { + this.prettyJsonEnabled = prettyJsonEnabled; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java index d881c866da7..bdef98bb039 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/filter/EthJsonRpcHttpServiceTest.java @@ -45,8 +45,7 @@ private Hash recordPendingTransaction(final int blockNumber, final int transacti @Test public void getFilterChanges_noBlocks() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ ]%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[]}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close(); @@ -60,7 +59,7 @@ public void getFilterChanges_oneBlock() throws Exception { BlockchainSetupUtil blockchainSetupUtil = startServiceWithEmptyChain(DataStorageFormat.FOREST); final String expectedRespBody = String.format( - "{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ \"0x10aaf14a53caf27552325374429d3558398a36d3682ede6603c2c6511896e9f9\" ]%n}"); + "{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[\"0x10aaf14a53caf27552325374429d3558398a36d3682ede6603c2c6511896e9f9\"]}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close(); @@ -75,8 +74,7 @@ public void getFilterChanges_oneBlock() throws Exception { @Test public void getFilterChanges_noTransactions() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ ]%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[]}"); final ResponseBody body = ethNewPendingTransactionFilter(1).body(); final String result = getResult(body); body.close(); @@ -96,18 +94,14 @@ public void getFilterChanges_oneTransaction() throws Exception { final Response resp = ethGetFilterChanges(2, result); assertThat(resp.code()).isEqualTo(200); final String expectedRespBody = - String.format( - "{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : [ \"" - + transactionHash - + "\" ]%n}"); + String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":[\"" + transactionHash + "\"]}"); assertThat(resp.body().string()).isEqualTo(expectedRespBody); } @Test public void uninstallFilter() throws Exception { startService(); - final String expectedRespBody = - String.format("{%n \"jsonrpc\" : \"2.0\",%n \"id\" : 2,%n \"result\" : true%n}"); + final String expectedRespBody = String.format("{\"jsonrpc\":\"2.0\",\"id\":2,\"result\":true}"); final ResponseBody body = ethNewBlockFilter(1).body(); final String result = getResult(body); body.close();