diff --git a/CHANGELOG.md b/CHANGELOG.md index d2cdf074e99..a0d225eec5d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,13 @@ ### 21.2 Breaking Changes * `--skip-pow-validation-enabled` is now an error with `block import --format JSON`. This is because the JSON format doesn't include the nonce so the proof of work must be calculated. +* `eth_call` will not return a JSON-RPC result if the call fails, but will return an error instead. If it was for a revert the revert reason will be included. ### Additions and Improvements * Removed unused flags in default genesis configs [\#1812](https://github.com/hyperledger/besu/pull/1812) * `--skip-pow-validation-enabled` is now an error with `block import --format JSON`. This is because the JSON format doesn't include the nonce so the proof of work must be calculated. [\#1815](https://github.com/hyperledger/besu/pull/1815) * Added a new CLI option `--Xlauncher` to start a mainnet launcher. It will help to configure Besu easily. +* Return the revert reason from `eth_call` JSON-RPC api calls when the contract causes a revert. [\#1829](https://github.com/hyperledger/besu/pull/1829) ### Bug Fixes * Ethereum classic heights will no longer be reported in mainnet metrics. Issue [\#1751]((https://github.com/hyperledger/besu/pull/1751) Fix [\#1820](https://github.com/hyperledger/besu/pull/1820) diff --git a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java index a6ad106b6ba..65a95eaa5a9 100644 --- a/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java +++ b/ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCall.java @@ -20,12 +20,17 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.exception.InvalidJsonRpcParameters; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.BlockParameterOrBlockHash; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter; +import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcError; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcErrorResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcResponse; import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSuccessResponse; import org.hyperledger.besu.ethereum.api.query.BlockchainQueries; import org.hyperledger.besu.ethereum.core.Hash; +import org.hyperledger.besu.ethereum.mainnet.ValidationResult; +import org.hyperledger.besu.ethereum.processing.TransactionProcessingResult; +import org.hyperledger.besu.ethereum.transaction.TransactionInvalidReason; import org.hyperledger.besu.ethereum.transaction.TransactionSimulator; +import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult; public class EthCall extends AbstractBlockParameterOrBlockHashMethod { private final TransactionSimulator transactionSimulator; @@ -59,8 +64,10 @@ protected Object resultByBlockHash(final JsonRpcRequestContext request, final Ha .getValidationResult() .either( (() -> - new JsonRpcSuccessResponse( - request.getRequest().getId(), result.getOutput().toString())), + result.isSuccessful() + ? new JsonRpcSuccessResponse( + request.getRequest().getId(), result.getOutput().toString()) + : errorResponse(request, result)), reason -> new JsonRpcErrorResponse( request.getRequest().getId(), @@ -77,6 +84,33 @@ private JsonRpcSuccessResponse validRequestBlockNotFound(final JsonRpcRequestCon return new JsonRpcSuccessResponse(request.getRequest().getId(), null); } + private JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final TransactionSimulatorResult result) { + final JsonRpcError jsonRpcError; + + final ValidationResult validationResult = + result.getValidationResult(); + if (validationResult != null && !validationResult.isValid()) { + jsonRpcError = + JsonRpcErrorConverter.convertTransactionInvalidReason( + validationResult.getInvalidReason()); + } else { + final TransactionProcessingResult resultTrx = result.getResult(); + if (resultTrx != null && resultTrx.getRevertReason().isPresent()) { + jsonRpcError = JsonRpcError.REVERT_ERROR; + jsonRpcError.setData(resultTrx.getRevertReason().get().toHexString()); + } else { + jsonRpcError = JsonRpcError.INTERNAL_ERROR; + } + } + return errorResponse(request, jsonRpcError); + } + + private JsonRpcErrorResponse errorResponse( + final JsonRpcRequestContext request, final JsonRpcError jsonRpcError) { + return new JsonRpcErrorResponse(request.getRequest().getId(), jsonRpcError); + } + private JsonCallParameter validateAndGetCallParams(final JsonRpcRequestContext request) { final JsonCallParameter callParams = request.getRequiredParameter(0, JsonCallParameter.class); if (callParams.getTo() == null) { diff --git a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java index fc6f71a2a69..84f0c4efed3 100644 --- a/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java +++ b/ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthCallTest.java @@ -206,6 +206,7 @@ private JsonRpcRequestContext ethCallRequest( private void mockTransactionProcessorSuccessResult(final Bytes output) { final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class); + when(result.isSuccessful()).thenReturn(true); when(result.getValidationResult()).thenReturn(ValidationResult.valid()); when(result.getOutput()).thenReturn(output); when(transactionSimulator.process(any(), any())).thenReturn(Optional.of(result)); diff --git a/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth_latest/eth_call_revert.json b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth_latest/eth_call_revert.json new file mode 100644 index 00000000000..29fe8e1105a --- /dev/null +++ b/ethereum/api/src/test/resources/org/hyperledger/besu/ethereum/api/jsonrpc/eth_latest/eth_call_revert.json @@ -0,0 +1,24 @@ +{ + "request": { + "id": 3, + "jsonrpc": "2.0", + "method": "eth_call", + "params": [ + { + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "to": "0x0110000000000000000000000000000000000000" + }, + "0x11" + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 3, + "error": { + "code": -32000, + "message": "Execution reverted", + "data": "0x7d88c1856cc95352" + } + }, + "statusCode": 200 +} \ No newline at end of file