mirror of https://github.com/hyperledger/besu
Include revert reason if available in eth_getTransactionReceipt (#1603)
Signed-off-by: Adrian Sutton <adrian.sutton@consensys.net>pull/2/head
parent
690d3dd621
commit
895e526cec
@ -0,0 +1,46 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eth; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthGetTransactionReceiptWithRevertReason; |
||||
|
||||
public class ExpectSuccessfulEthGetTransactionReceiptWithReason implements Condition { |
||||
|
||||
private final EthGetTransactionReceiptWithRevertReason transaction; |
||||
private final String expectedRevertReason; |
||||
|
||||
public ExpectSuccessfulEthGetTransactionReceiptWithReason( |
||||
final EthGetTransactionReceiptWithRevertReason transaction, |
||||
final String expectedRevertReason) { |
||||
this.transaction = transaction; |
||||
this.expectedRevertReason = expectedRevertReason; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
WaitUtils.waitFor(() -> assertThat(revertReasonMatches(node, expectedRevertReason)).isTrue()); |
||||
} |
||||
|
||||
private boolean revertReasonMatches(final Node node, final String expectedRevertReason) { |
||||
return node.execute(transaction) |
||||
.filter( |
||||
transactionReceipt -> |
||||
transactionReceipt.getRevertReason().contains(expectedRevertReason)) |
||||
.isPresent(); |
||||
} |
||||
} |
@ -0,0 +1,43 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.condition.eth; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.WaitUtils; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.condition.Condition; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.Node; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth.EthGetTransactionReceiptWithRevertReason; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.net.CustomRequestFactory.TransactionReceiptWithRevertReason; |
||||
|
||||
public class ExpectSuccessfulEthGetTransactionReceiptWithoutReason implements Condition { |
||||
|
||||
private final EthGetTransactionReceiptWithRevertReason transaction; |
||||
|
||||
public ExpectSuccessfulEthGetTransactionReceiptWithoutReason( |
||||
final EthGetTransactionReceiptWithRevertReason transaction) { |
||||
this.transaction = transaction; |
||||
} |
||||
|
||||
@Override |
||||
public void verify(final Node node) { |
||||
WaitUtils.waitFor(() -> assertThat(revertReasonIsEmpty(node)).isTrue()); |
||||
} |
||||
|
||||
private boolean revertReasonIsEmpty(final Node node) { |
||||
return node.execute(transaction) |
||||
.map(TransactionReceiptWithRevertReason::getRevertReason) |
||||
.filter(String::isEmpty) |
||||
.isPresent(); |
||||
} |
||||
} |
@ -0,0 +1,55 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.account.Accounts; |
||||
|
||||
import java.io.IOException; |
||||
import java.math.BigInteger; |
||||
import java.util.Collections; |
||||
|
||||
import org.web3j.abi.FunctionEncoder; |
||||
import org.web3j.abi.datatypes.Function; |
||||
import org.web3j.crypto.Credentials; |
||||
import org.web3j.protocol.core.methods.response.EthSendTransaction; |
||||
import org.web3j.tx.RawTransactionManager; |
||||
|
||||
public class CallSmartContractFunction implements Transaction<EthSendTransaction> { |
||||
|
||||
private static final BigInteger GAS_PRICE = BigInteger.valueOf(1000); |
||||
private static final BigInteger GAS_LIMIT = BigInteger.valueOf(3000000); |
||||
private static final Credentials BENEFACTOR_ONE = |
||||
Credentials.create(Accounts.GENESIS_ACCOUNT_ONE_PRIVATE_KEY); |
||||
|
||||
private final String functionName; |
||||
private final String contractAddress; |
||||
|
||||
public CallSmartContractFunction(final String functionName, final String contractAddress) { |
||||
this.functionName = functionName; |
||||
this.contractAddress = contractAddress; |
||||
} |
||||
|
||||
@Override |
||||
public EthSendTransaction execute(final NodeRequests node) { |
||||
final Function function = |
||||
new Function(functionName, Collections.emptyList(), Collections.emptyList()); |
||||
final RawTransactionManager transactionManager = |
||||
new RawTransactionManager(node.eth(), BENEFACTOR_ONE); |
||||
try { |
||||
return transactionManager.sendTransaction( |
||||
GAS_PRICE, GAS_LIMIT, contractAddress, FunctionEncoder.encode(function), BigInteger.ZERO); |
||||
} catch (IOException e) { |
||||
throw new IllegalStateException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,44 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.acceptance.dsl.transaction.eth; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.NodeRequests; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.Transaction; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.net.CustomRequestFactory.EthGetTransactionReceiptWithRevertReasonResponse; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.transaction.net.CustomRequestFactory.TransactionReceiptWithRevertReason; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.Optional; |
||||
|
||||
public class EthGetTransactionReceiptWithRevertReason |
||||
implements Transaction<Optional<TransactionReceiptWithRevertReason>> { |
||||
private final String transactionHash; |
||||
|
||||
public EthGetTransactionReceiptWithRevertReason(final String transactionHash) { |
||||
this.transactionHash = transactionHash; |
||||
} |
||||
|
||||
@Override |
||||
public Optional<TransactionReceiptWithRevertReason> execute(final NodeRequests node) { |
||||
try { |
||||
final EthGetTransactionReceiptWithRevertReasonResponse response = |
||||
node.custom().ethGetTransactionReceiptWithRevertReason(transactionHash).send(); |
||||
assertThat(response.hasError()).isFalse(); |
||||
return Optional.ofNullable(response.getResult()); |
||||
} catch (final IOException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,28 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
pragma solidity >=0.4.0 <0.6.0; |
||||
|
||||
// compile with: |
||||
// solc RevertReason.sol --bin --abi --optimize --overwrite -o . |
||||
// then create web3j wrappers with: |
||||
// web3j solidity generate -b ./generated/RevertReason.bin -a ./generated/RevertReason.abi -o ../../../../../ -p tech.pegasys.pantheon.tests.web3j.generated |
||||
contract RevertReason { |
||||
|
||||
function revertWithRevertReason() public pure returns (bool) { |
||||
revert("RevertReason"); |
||||
} |
||||
|
||||
function revertWithoutRevertReason() public pure returns (bool) { |
||||
revert(); |
||||
} |
||||
} |
@ -0,0 +1,60 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.web3j; |
||||
|
||||
import static tech.pegasys.pantheon.tests.web3j.generated.RevertReason.FUNC_REVERTWITHOUTREVERTREASON; |
||||
import static tech.pegasys.pantheon.tests.web3j.generated.RevertReason.FUNC_REVERTWITHREVERTREASON; |
||||
|
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.AcceptanceTestBase; |
||||
import tech.pegasys.pantheon.tests.acceptance.dsl.node.PantheonNode; |
||||
import tech.pegasys.pantheon.tests.web3j.generated.RevertReason; |
||||
|
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
import org.web3j.protocol.core.methods.response.EthSendTransaction; |
||||
|
||||
public class RevertReasonAcceptanceTest extends AcceptanceTestBase { |
||||
|
||||
private PantheonNode minerNode; |
||||
|
||||
@Before |
||||
public void setUp() throws Exception { |
||||
minerNode = pantheon.createMinerNodeWithRevertReasonEnabled("miner-node-withRevertReason"); |
||||
cluster.start(minerNode); |
||||
} |
||||
|
||||
@Test |
||||
public void mustRevertWithRevertReason() { |
||||
final RevertReason revertReasonContract = |
||||
minerNode.execute(contractTransactions.createSmartContract(RevertReason.class)); |
||||
final EthSendTransaction transaction = |
||||
minerNode.execute( |
||||
contractTransactions.callSmartContract( |
||||
FUNC_REVERTWITHREVERTREASON, revertReasonContract.getContractAddress())); |
||||
minerNode.verify( |
||||
eth.expectSuccessfulTransactionReceiptWithReason( |
||||
transaction.getTransactionHash(), "RevertReason")); |
||||
} |
||||
|
||||
@Test |
||||
public void mustRevertWithoutRevertReason() { |
||||
final RevertReason revertReasonContract = |
||||
minerNode.execute(contractTransactions.createSmartContract(RevertReason.class)); |
||||
final EthSendTransaction transaction = |
||||
minerNode.execute( |
||||
contractTransactions.callSmartContract( |
||||
FUNC_REVERTWITHOUTREVERTREASON, revertReasonContract.getContractAddress())); |
||||
minerNode.verify( |
||||
eth.expectSuccessfulTransactionReceiptWithoutReason(transaction.getTransactionHash())); |
||||
} |
||||
} |
@ -0,0 +1 @@ |
||||
[{"constant":true,"inputs":[],"name":"revertWithRevertReason","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"},{"constant":true,"inputs":[],"name":"revertWithoutRevertReason","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"pure","type":"function"}] |
@ -0,0 +1 @@ |
||||
608060405234801561001057600080fd5b5060d18061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806311f95f6f146037578063ff489d31146051575b600080fd5b603d6057565b604080519115158252519081900360200190f35b603d6095565b6040805162461bcd60e51b815260206004820152600c60248201526b2932bb32b93a2932b0b9b7b760a11b6044820152905160009181900360640190fd5b6000806000fdfea265627a7a723058202dd24b599e57aa54899e1beceec3fb4a5001fccb4be994e8d18aa03cc123708764736f6c634300050a0032 |
@ -0,0 +1,166 @@ |
||||
/* |
||||
* Copyright 2019 ConsenSys AG. |
||||
* |
||||
* 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. |
||||
*/ |
||||
package tech.pegasys.pantheon.tests.web3j.generated; |
||||
|
||||
import java.math.BigInteger; |
||||
import java.util.Arrays; |
||||
|
||||
import org.web3j.abi.TypeReference; |
||||
import org.web3j.abi.datatypes.Bool; |
||||
import org.web3j.abi.datatypes.Function; |
||||
import org.web3j.abi.datatypes.Type; |
||||
import org.web3j.crypto.Credentials; |
||||
import org.web3j.protocol.Web3j; |
||||
import org.web3j.protocol.core.RemoteCall; |
||||
import org.web3j.tx.Contract; |
||||
import org.web3j.tx.TransactionManager; |
||||
import org.web3j.tx.gas.ContractGasProvider; |
||||
|
||||
/** |
||||
* Auto generated code. |
||||
* |
||||
* <p><strong>Do not modify!</strong> |
||||
* |
||||
* <p>Please use the <a href="https://docs.web3j.io/command_line.html">web3j command line tools</a>, |
||||
* or the org.web3j.codegen.SolidityFunctionWrapperGenerator in the <a |
||||
* href="https://github.com/web3j/web3j/tree/master/codegen">codegen module</a> to update. |
||||
* |
||||
* <p>Generated with web3j version 4.3.0. |
||||
*/ |
||||
@SuppressWarnings("rawtypes") |
||||
public class RevertReason extends Contract { |
||||
private static final String BINARY = |
||||
"608060405234801561001057600080fd5b5060d18061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060325760003560e01c806311f95f6f146037578063ff489d31146051575b600080fd5b603d6057565b604080519115158252519081900360200190f35b603d6095565b6040805162461bcd60e51b815260206004820152600c60248201526b2932bb32b93a2932b0b9b7b760a11b6044820152905160009181900360640190fd5b6000806000fdfea265627a7a723058202dd24b599e57aa54899e1beceec3fb4a5001fccb4be994e8d18aa03cc123708764736f6c634300050a0032"; |
||||
|
||||
public static final String FUNC_REVERTWITHREVERTREASON = "revertWithRevertReason"; |
||||
|
||||
public static final String FUNC_REVERTWITHOUTREVERTREASON = "revertWithoutRevertReason"; |
||||
|
||||
@Deprecated |
||||
protected RevertReason( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
Credentials credentials, |
||||
BigInteger gasPrice, |
||||
BigInteger gasLimit) { |
||||
super(BINARY, contractAddress, web3j, credentials, gasPrice, gasLimit); |
||||
} |
||||
|
||||
protected RevertReason( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
Credentials credentials, |
||||
ContractGasProvider contractGasProvider) { |
||||
super(BINARY, contractAddress, web3j, credentials, contractGasProvider); |
||||
} |
||||
|
||||
@Deprecated |
||||
protected RevertReason( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
TransactionManager transactionManager, |
||||
BigInteger gasPrice, |
||||
BigInteger gasLimit) { |
||||
super(BINARY, contractAddress, web3j, transactionManager, gasPrice, gasLimit); |
||||
} |
||||
|
||||
protected RevertReason( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
TransactionManager transactionManager, |
||||
ContractGasProvider contractGasProvider) { |
||||
super(BINARY, contractAddress, web3j, transactionManager, contractGasProvider); |
||||
} |
||||
|
||||
public RemoteCall<Boolean> revertWithRevertReason() { |
||||
final Function function = |
||||
new Function( |
||||
FUNC_REVERTWITHREVERTREASON, |
||||
Arrays.<Type>asList(), |
||||
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {})); |
||||
return executeRemoteCallSingleValueReturn(function, Boolean.class); |
||||
} |
||||
|
||||
public RemoteCall<Boolean> revertWithoutRevertReason() { |
||||
final Function function = |
||||
new Function( |
||||
FUNC_REVERTWITHOUTREVERTREASON, |
||||
Arrays.<Type>asList(), |
||||
Arrays.<TypeReference<?>>asList(new TypeReference<Bool>() {})); |
||||
return executeRemoteCallSingleValueReturn(function, Boolean.class); |
||||
} |
||||
|
||||
@Deprecated |
||||
public static RevertReason load( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
Credentials credentials, |
||||
BigInteger gasPrice, |
||||
BigInteger gasLimit) { |
||||
return new RevertReason(contractAddress, web3j, credentials, gasPrice, gasLimit); |
||||
} |
||||
|
||||
@Deprecated |
||||
public static RevertReason load( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
TransactionManager transactionManager, |
||||
BigInteger gasPrice, |
||||
BigInteger gasLimit) { |
||||
return new RevertReason(contractAddress, web3j, transactionManager, gasPrice, gasLimit); |
||||
} |
||||
|
||||
public static RevertReason load( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
Credentials credentials, |
||||
ContractGasProvider contractGasProvider) { |
||||
return new RevertReason(contractAddress, web3j, credentials, contractGasProvider); |
||||
} |
||||
|
||||
public static RevertReason load( |
||||
String contractAddress, |
||||
Web3j web3j, |
||||
TransactionManager transactionManager, |
||||
ContractGasProvider contractGasProvider) { |
||||
return new RevertReason(contractAddress, web3j, transactionManager, contractGasProvider); |
||||
} |
||||
|
||||
public static RemoteCall<RevertReason> deploy( |
||||
Web3j web3j, Credentials credentials, ContractGasProvider contractGasProvider) { |
||||
return deployRemoteCall( |
||||
RevertReason.class, web3j, credentials, contractGasProvider, BINARY, ""); |
||||
} |
||||
|
||||
@Deprecated |
||||
public static RemoteCall<RevertReason> deploy( |
||||
Web3j web3j, Credentials credentials, BigInteger gasPrice, BigInteger gasLimit) { |
||||
return deployRemoteCall(RevertReason.class, web3j, credentials, gasPrice, gasLimit, BINARY, ""); |
||||
} |
||||
|
||||
public static RemoteCall<RevertReason> deploy( |
||||
Web3j web3j, TransactionManager transactionManager, ContractGasProvider contractGasProvider) { |
||||
return deployRemoteCall( |
||||
RevertReason.class, web3j, transactionManager, contractGasProvider, BINARY, ""); |
||||
} |
||||
|
||||
@Deprecated |
||||
public static RemoteCall<RevertReason> deploy( |
||||
Web3j web3j, |
||||
TransactionManager transactionManager, |
||||
BigInteger gasPrice, |
||||
BigInteger gasLimit) { |
||||
return deployRemoteCall( |
||||
RevertReason.class, web3j, transactionManager, gasPrice, gasLimit, BINARY, ""); |
||||
} |
||||
} |
Loading…
Reference in new issue