BESU-146 - return better gas estimate service error message if possible (#436)

Signed-off-by: Anthony Buckle <anthonybuckle@gmail.com>
pull/423/head
CJ Hare 5 years ago committed by GitHub
parent b9e0b3bb66
commit 7bc8bb4d19
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 28
      ethereum/api/src/main/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGas.java
  2. 34
      ethereum/api/src/test/java/org/hyperledger/besu/ethereum/api/jsonrpc/internal/methods/EthEstimateGasTest.java

@ -14,6 +14,7 @@
*/
package org.hyperledger.besu.ethereum.api.jsonrpc.internal.methods;
import org.hyperledger.besu.ethereum.api.jsonrpc.JsonRpcErrorConverter;
import org.hyperledger.besu.ethereum.api.jsonrpc.RpcMethod;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.JsonRpcRequestContext;
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.parameters.JsonCallParameter;
@ -24,6 +25,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.response.JsonRpcSucces
import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
@ -53,7 +56,7 @@ public class EthEstimateGas implements JsonRpcMethod {
final BlockHeader blockHeader = blockHeader();
if (blockHeader == null) {
return errorResponse(requestContext);
return errorResponse(requestContext, JsonRpcError.INTERNAL_ERROR);
}
final JsonCallParameter modifiedCallParams =
@ -62,7 +65,7 @@ public class EthEstimateGas implements JsonRpcMethod {
return transactionSimulator
.process(modifiedCallParams, blockHeader.getNumber())
.map(gasEstimateResponse(requestContext))
.orElse(errorResponse(requestContext));
.orElse(errorResponse(requestContext, JsonRpcError.INTERNAL_ERROR));
}
private BlockHeader blockHeader() {
@ -87,10 +90,25 @@ public class EthEstimateGas implements JsonRpcMethod {
result.isSuccessful()
? new JsonRpcSuccessResponse(
request.getRequest().getId(), Quantity.create(result.getGasEstimate()))
: null;
: errorResponse(request, result.getValidationResult());
}
private JsonRpcErrorResponse errorResponse(final JsonRpcRequestContext request) {
return new JsonRpcErrorResponse(request.getRequest().getId(), JsonRpcError.INTERNAL_ERROR);
private JsonRpcErrorResponse errorResponse(
final JsonRpcRequestContext request,
final ValidationResult<TransactionValidator.TransactionInvalidReason> validationResult) {
JsonRpcError jsonRpcError = null;
if (validationResult != null) {
jsonRpcError =
JsonRpcErrorConverter.convertTransactionInvalidReason(
validationResult.getInvalidReason());
}
return errorResponse(request, jsonRpcError);
}
private JsonRpcErrorResponse errorResponse(
final JsonRpcRequestContext request, final JsonRpcError jsonRpcError) {
return new JsonRpcErrorResponse(
request.getRequest().getId(),
jsonRpcError == null ? JsonRpcError.INTERNAL_ERROR : jsonRpcError);
}
}

@ -30,6 +30,8 @@ import org.hyperledger.besu.ethereum.api.jsonrpc.internal.results.Quantity;
import org.hyperledger.besu.ethereum.api.query.BlockchainQueries;
import org.hyperledger.besu.ethereum.chain.Blockchain;
import org.hyperledger.besu.ethereum.core.BlockHeader;
import org.hyperledger.besu.ethereum.mainnet.TransactionValidator.TransactionInvalidReason;
import org.hyperledger.besu.ethereum.mainnet.ValidationResult;
import org.hyperledger.besu.ethereum.transaction.CallParameter;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulator;
import org.hyperledger.besu.ethereum.transaction.TransactionSimulatorResult;
@ -105,13 +107,37 @@ public class EthEstimateGasTest {
.isEqualToComparingFieldByField(expectedResponse);
}
@Test
public void shouldReturnErrorWhenTransactionProcessorReturnsTxInvalidReason() {
final JsonRpcRequestContext request = ethEstimateGasRequest(callParameter());
mockTransientProcessorResultTxInvalidReason(
TransactionInvalidReason.UPFRONT_COST_EXCEEDS_BALANCE);
final JsonRpcResponse expectedResponse =
new JsonRpcErrorResponse(null, JsonRpcError.TRANSACTION_UPFRONT_COST_EXCEEDS_BALANCE);
Assertions.assertThat(method.response(request))
.isEqualToComparingFieldByField(expectedResponse);
}
private void mockTransientProcessorResultTxInvalidReason(final TransactionInvalidReason reason) {
final TransactionSimulatorResult mockTxSimResult = getMockTransactionSimulatorResult(false);
when(mockTxSimResult.getValidationResult()).thenReturn(ValidationResult.invalid(reason));
}
private void mockTransientProcessorResultGasEstimate(
final long gasEstimate, final boolean isSuccessful) {
final TransactionSimulatorResult result = mock(TransactionSimulatorResult.class);
when(result.getGasEstimate()).thenReturn(gasEstimate);
final TransactionSimulatorResult mockTxSimResult =
getMockTransactionSimulatorResult(isSuccessful);
when(mockTxSimResult.getGasEstimate()).thenReturn(gasEstimate);
}
private TransactionSimulatorResult getMockTransactionSimulatorResult(final boolean isSuccessful) {
final TransactionSimulatorResult mockTxSimResult = mock(TransactionSimulatorResult.class);
when(transactionSimulator.process(eq(modifiedCallParameter()), eq(1L)))
.thenReturn(Optional.of(result));
when(result.isSuccessful()).thenReturn(isSuccessful);
.thenReturn(Optional.of(mockTxSimResult));
when(mockTxSimResult.isSuccessful()).thenReturn(isSuccessful);
return mockTxSimResult;
}
private JsonCallParameter callParameter() {

Loading…
Cancel
Save