8

I run a geth/parity nodes for broadcasting user's transactions to Ethereum blockchain. Some of contract functions provide reasons for revert (see examble below):

contract Example {
  function test (uint i) {
    require(i == 1, "ERROR_CODE")
  }
}

As I understand it is not possible to get revert reason string with eth_getTransactionReceipt. However I still need to get revert reason for failed transactions.

How to get revert reason ("ERROR_CODE" in example above) for past failed transactions? (at least for transactions in last 20 blocks)

5

Using eth_Call to execute function:

Example.test(0x0000000000000000000000000000000000000000000000000000000000000002) 

of Example contract we will receive following reply from geth node:

0x08c379a00000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a4552524f525f434f444500000000000000000000000000000000000000000000

Which gives following output arguments:

arg0: 0x08c379a
arg1: 0x20
arg2: 0x0a
arg3: 0x4552524f525f434f444500000000000000000000000000000000000000000000

where arg3 == 'ERROR_CODE' (utf8 + hex encoded)

So, I suppose, for fully syched node we can use eth_Call with explicit indication of failed transaction block number:

{
  method: "eth_Call",
  params: [
    {
      from: '0x...address',
      to: '0x...contract',
      value: '0x0',
      data: "0x29e99f070000000000000000000000000000000000000000000000000000000000000002"
    }, 
    FALED_TRANSACTION_BLOCK_NR
  ]
}

However this is not convenient way of getting error codes.. Is there any other way?

3

In solidity 0.4.22 the require and revert reason were added. As can be seen here, they are abi-encoded as if it were a call to a function "Error(string)".

This blog post gives an example: an eth_call to a function

function myFunction(uint256 input) public view returns (uint256) {
    require(input >= 5, "myFunction only accepts arguments which are greather than or equal to 5");
    return input * input - 25;
}

with an invalid input argument (less than 5 in this example), will return

0x08c379a0000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000476d7946756e6374696f6e206f6e6c79206163636570747320617267756d656e747320776869636820617265206772656174686572207468616e206f7220657175616c20746f203500000000000000000000000000000000000000000000000000

which is

0x08c379a0                                                       // Function selector
0000000000000000000000000000000000000000000000000000000000000020 // Offset of string return value
0000000000000000000000000000000000000000000000000000000000000047 // Length of string return value (the revert reason)
6d7946756e6374696f6e206f6e6c79206163636570747320617267756d656e74 // first 32 bytes of the revert reason
7320776869636820617265206772656174686572207468616e206f7220657175 // next 32 bytes of the revert reason
616c20746f203500000000000000000000000000000000000000000000000000 // last 7 bytes of the revert reason

So decoding the returned string will give you the revert reason.

With Web3j this could be done like:

public Optional<String> getRevertReason(EthCall ethCall) {
    String errorMethodId = "0x08c379a0"; // Numeric.toHexString(Hash.sha3("Error(string)".getBytes())).substring(0, 10)
    List<TypeReference<Type>> revertReasonTypes = Collections.singletonList(TypeReference.create((Class<Type>) AbiTypes.getType("string")));

    if (!ethCall.hasError() && ethCall.getValue() != null && ethCall.getValue().startsWith(errorMethodId)) {
        String encodedRevertReason = ethCall.getValue().substring(errorMethodId.length());
        List<Type> decoded = FunctionReturnDecoder.decode(encodedRevertReason, revertReasonTypes);
        Utf8String decodedRevertReason = (Utf8String) decoded.get(0);
        return Optional.of(decodedRevertReason.getValue());
    }
    return Optional.empty();
}
2

After being really annoyed for a long time I wrote a bash script to fetch the revert reason from geth by a tx hash:

https://gist.github.com/gluk64/fdea559472d957f1138ed93bcbc6f78a

  • this is really helpful, could you also help me do the same for metamask failed transactions – cryptoKTM Oct 7 at 6:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.