2

In both of these questions, the user is asking if it's possible to get the error string from a revert or require. The answers say, basically, "Yes" and point to Truffle or other methods.

VM Exception while processing transaction: revert message

Getting error message from require()

My question is not "Can you get the error string?" but "How do you get the error string?"

Can someone explain to me how one might get the error string by querying directly against the node with the RPC (i.e. by using curl or similar, not using web3.js).

0

The error string is obtained by calling the debug_traceTransaction endpoint. However, in order to process the returned information to be human readable you'll need to do some work. I'm using Python for the following example.

When you query debug_traceTransaction, the final item within the returned structLogs array will look something like this:

{
    'depth': 0,
    'error': "",
    'gas': 7961655,
    'gasCost': 3,
    'memory': [
        "08c379a000000000000000000000000000000000000000000000000000000000", 
        "0000002000000000000000000000000000000000000000000000000000000000", 
        "0000001641646472657373206e6f742072656769737465726564000000000000", 
        "0000000000000000000000000000000000000000000000000000000000000000", 
        "00000000000000000000000066ab6d9362d4f35596279692f0251db635165871", 
        "00000000000000000000000033a4622b82d4c04a53e170c638b944ce27cffce3", 
        "0000000000000000000000000000000000000000000000000000000000000000", 
        "0000000000000000000000000000000000000000000000000000000000000000",
    ],
    'op': "REVERT",
    'pc': 5552,
    'stack': [  
        "0000000000000000000000000000000000000000000000000000000000000140", 
        "000000000000000000000000e0aa552a10d7ec8760fc6c246d391e698a82ddf9", 
        "00000000000000000000000000000000000000000000000000000000939e41a5", 
        "00000000000000000000000000000000000000000000000000000000000002e4", 
        "0000000000000000000000000000000000000000000000000000000000000001", 
        "0000000000000000000000000000000000000000000000000000000000000064", 
        "0000000000000000000000000000000000000000000000000000000000000000"
    ],
    'storage': {}
}

The first thing to look at is the final two values within the stack. As explained at www.ethervm.io, a REVERT opcode will have the following stack input:

  • the final value indicates the memory offset of the error string
  • the 2nd-to-last value gives the length of the string within memory

In the above example, the offset is 0 and the length is 64. These values are given in hexadecimal, so the length in base-10 is 100.

Next we look at the memory. From the stack, we know to look at the first hundred bytes. In a revert string the first 4 bytes are similar to a function selector, generated from a keccak of Error(string). So the remaining 96 are your error message.

Given that each byte is two characters long when written in hex, we want to convert the hexadecimal memory data within the slice 8:200:

>>> from hexbytes import HexBytes
>>> from eth_abi import decode_string
>>> memory = "".join(structLog[-1]['memory'])
>>> decode_abi(['string'], HexBytes(memory[8:200]))
(b'Address not registered')

...If this process seems tediously long or confusing, you now see why people usually point to tooling instead :)

>>> tx = token.transfer(accounts[1], 10000)

Transaction sent: 
0x1956e6ba3eee57929180ac7fe7a44468bae380a3d2534b038f525edc7b4a05fc
SecurityToken.transfer confirmed (Address not registered) - block: 20   gas 
used: 38345 (0.48%)
>>> tx.revert_msg
'Address not registered'
  • This is excellent. Thanks so much. I think it's true that one could decode this in exactly the same way as one would decode a function input to a function called Error(string). Is that correct? If yes, then all I really need is to find the start and length of the string which you've provided. Thanks. – Thomas Jay Rush Aug 1 at 0:24
  • Yes, you've explained it better than I did :) That's exactly what I'm doing when I call decode_abi. – iamdefinitelyahuman Aug 1 at 3:21

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.