diff --git a/CHANGELOG.md b/CHANGELOG.md index fdfb1212d50..b098443f6dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ ### Bug Fixes - do not create ignorable storage on revert storage-variables subcommand [#5830](https://github.com/hyperledger/besu/pull/5830) - fix duplicate key errors in EthScheduler-Transactions [#5857](https://github.com/hyperledger/besu/pull/5857) +- Don't put control characters, escaped or otherwise, in t8n stacktraces [#5910](https://github.com/hyperledger/besu/pull/5910) ### Download Links diff --git a/ethereum/evmtool/build.gradle b/ethereum/evmtool/build.gradle index c5604d7a52c..f92f6d3f937 100644 --- a/ethereum/evmtool/build.gradle +++ b/ethereum/evmtool/build.gradle @@ -62,6 +62,7 @@ dependencies { testImplementation 'org.assertj:assertj-core' testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'org.mockito:mockito-core' + testImplementation 'org.mockito:mockito-junit-jupiter' testRuntimeOnly 'org.junit.vintage:junit-vintage-engine' diff --git a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java index eec78ee50d1..8b636b9a8c0 100644 --- a/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java +++ b/ethereum/evmtool/src/main/java/org/hyperledger/besu/evmtool/T8nServerSubCommand.java @@ -178,7 +178,7 @@ public void disposeTracer(final OperationTracer tracer) { t.printStackTrace(ps); ObjectNode json = objectMapper.createObjectNode(); json.put("error", t.getMessage()); - json.put("stacktrace", baos.toString(StandardCharsets.UTF_8)); + json.put("stacktrace", baos.toString(StandardCharsets.UTF_8).replaceAll("\\s", " ")); t.printStackTrace(System.out); diff --git a/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/T8nServerSubCommandTest.java b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/T8nServerSubCommandTest.java new file mode 100644 index 00000000000..2f658eeb323 --- /dev/null +++ b/ethereum/evmtool/src/test/java/org/hyperledger/besu/evmtool/T8nServerSubCommandTest.java @@ -0,0 +1,58 @@ +/* + * Copyright Hyperledger Besu Contributors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + */ +package org.hyperledger.besu.evmtool; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.vertx.core.http.HttpServerRequest; +import io.vertx.core.http.HttpServerResponse; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Answers; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class T8nServerSubCommandTest { + + @Mock HttpServerRequest httpServerRequest; + + @Mock(answer = Answers.RETURNS_SELF) + HttpServerResponse httpServerResponse; + + @Test + void exceptionEncodedProperlyInJSON() { + T8nServerSubCommand subject = new T8nServerSubCommand(); + ObjectMapper objectMapper = new ObjectMapper(); + + when(httpServerRequest.response()).thenReturn(httpServerResponse); + + // Should trigger a NPE within the try block. + subject.handleT8nRequest(httpServerRequest, objectMapper, null, null); + + ArgumentCaptor responseCodeCaptor = ArgumentCaptor.forClass(Integer.class); + ArgumentCaptor responseStringCaptor = ArgumentCaptor.forClass(String.class); + + verify(httpServerResponse).setStatusCode(responseCodeCaptor.capture()); + verify(httpServerResponse).end(responseStringCaptor.capture()); + + assertThat(responseCodeCaptor.getValue()).isEqualTo(500); + assertThat(responseStringCaptor.getValue()).doesNotContain("\\t"); + } +}