8

According to the newest version of the yellow paper and Solidity assembly specification, revert opcode can return an error code.

http://solidity.readthedocs.io/en/develop/assembly.html

revert(p, s) - end execution, revert state changes, return data mem[p..(p+s))

The revert function in pure solidity however, has 0 arguments. I guess it's not supporting a return code yet.

[Q]: How can I use the revert from the Solidity assembly to pass an error code to the calling web3 JavaScript application? If this is not possible, please explain why.

Update: see also Solidity: How can we write a error message in "require"?

  • Can we assume this limitation applies with the require message field as well? – GViz Oct 8 '18 at 20:58
  • 1
    Yes. Require relies on the revert opcode. – ivicaa Oct 9 '18 at 3:55
6
+50

As discussed in the comments, there is no easy way to get the revert reason in the Dapp. This feature might be supported in the future though.

Here is the initial EIP and its discussion:

https://github.com/ethereum/EIPs/blob/master/EIPS/eip-658.md https://github.com/ethereum/EIPs/pull/658


Previous answer

As I understand, it's not possible for a client such as web3 to read revert output, same as it's not possible to read the output in case of a normal transaction completion. Revert uses output data o as defined in the yellow paper which can be used for message calls but is ignored for transactions.

message calls also have an extra component—the output data denoted by the byte array o. This is ignored when executing transactions, however message calls can be initiated due to VM-code execution and in this case this information is used.

The effect of the REVERT opcode is given by the formula 140 which references output o.

Remix, however, shows the output when using JavaScript VM, because it executes transactions synchronously:

pragma solidity^0.4.11;

contract C {
    function testRevert() pure public returns (uint result) {
        uint memOffset;
        assembly {
             memOffset := msize() // Get the highest available block of memory
             mstore(add(memOffset, 0x00), 6) // Set value
             mstore(0x40, add(memOffset, 0x20)) // Update the msize offset to be our memory reference plus the amount of bytes we're using
             revert(memOffset, 0x20) // revert returning 1 byte
        }
    }
}

Decoded output:

{
    "0": "uint256: result 6"
}

When executing on testnets or mainnet, there is no output.

It should be possible to read the revert output when using low-level assembly call, delegatecall, callcode (I'm going to update this answer whenever I have a working code example).

I expect a try-catch-like feature will be added in Solidity when using its call, delegatecall, callcode and calling contracts via their interface (will update the answer whenever I have references).

  • 1
    @ivicaa you are right about the error event, I deleted it from my answer. Using the status field in the receipt is a good idea I think. All I found it this EIP github.com/ethereum/EIPs/blob/master/EIPS/eip-658.md which is the initial proposal for 0|1 status. – medvedev1088 Mar 2 '18 at 10:36
  • 1
    The ugly thing about the status field (0|1) is that again nothing more specific as error code can be returned to the DAPP UI. It's better than checking sentGas == usedGas as earlier, but effectively, in UI, you can only tell "It went through" or "Something went wrong.". But what exactly went wrong is lost in the summary. I guess one could go through the trace of the transaction to find the location, but it sounds for this usecase like a workaround. – ivicaa Mar 2 '18 at 10:40
  • 1
    @ivicaa Interestingly the EIP was initially titled "Embedding transaction return data in receipts" and later was changed to "Embedding transaction status code in receipts" github.com/ethereum/EIPs/pull/658/files/…. Not sure what's the reason for this. – medvedev1088 Mar 2 '18 at 10:41
  • 1
    In the discussion (github.com/ethereum/EIPs/pull/658) they're saying: "After consultation with others, I dropped it because of concerns about DoS and spam opportunities; return data isn't charged for (except for memory expansion) but if it's part of consensus, would have to be stored indefinitely with receipts. It's still a possibility to add this to later forks, but I didn't want to rush in something that wasn't fully thought out." -- IMHO not that optimal this decision. If there is a fear off DDoS, they could have just allow returning a byte.. would be better than 0/1. :-/ – ivicaa Mar 2 '18 at 10:48
  • 1
    @ivicaa also found there: "A copy of this EIP with different requirements would basically be the bare minimum. To address the DoS issue, it would likely also need to specify some form of gas cost for return data that ends up in receipts. Now would be a good time to start thinking about this, since we've got plenty of time before the next fork." I suspect there will be another EIP for improvements. – medvedev1088 Mar 2 '18 at 11:01

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.