Exceptions in Solidity, STOP vs. RETURN

chrisethchriseth Member Posts: 170 ✭✭✭
edited July 2015 in Solidity
Moved here from https://github.com/ethereum/cpp-ethereum/issues/2469 .

by nmushegian:

I recall reading that unrecognized function signatures cause a STOP operation, and that ends execution and applies the transaction state changes. Is that right? Do I have to do this:
contract Safe {
    function() { 
        1/0; // throw somehow
    }
}
If so that is terrible =[

Can we get a compiler mode which is very generous with using exceptions so we can be safe calling our own contracts?

I'm really hoping the evm doesn't have to change to make STOP an implicit return or if there was a try-like mechanism to prevent your callees from stopping you..

Can you point me to documentation? Hoping I just misunderstood how this contraption works

Comments

  • chrisethchriseth Member Posts: 170 ✭✭✭
    edited July 2015
    Thank you for your questions, although I am not sure if I understand you correctly in each point.

    I will try to clarify the documentation, but also explain it here: If a contract receives a message whose function identifier does not match any function defined by the contract, it will throw an exception (this is neither done with STOP nor with RETURN) which will revert all changes made in the current call stack frame (e.g. only this single contract). This will lead the CALL opcode to return false; the current implementation of Solidity will check for this return code and again throw an exception if it is false, but ONLY if the function was not called via "call" or "send".

    The reason behind this is the following:
    If you call a function via "SomeContractType t = ...; t.someFunction();" and this leads to an exception, it means that t is actually NOT of type SomeContractType and the assumed effect of the function call did not occur, a situation which cannot be salvaged by regular means. So the safest thing we can do is revert all changes, because something is really going wrong and we should not leave it "partly done".

    If you call a function via "someAddress.send(value)" or "someAddress.call(signature, arg1, arg2, ...)", then you do not know which kind of contract is at that address (or whether there is a contract at all). So a function identifier mismatch should be quite common and thus not lead to an exceptional situation. If you want to check whether the send or call worked, you can simply check the return value. If it is false, it did not work, i.e. your call did not have any effect because everything was reverted. Having said that, you should probably also limit the gas as part of the call - otherwise the called contract might "drain" you. For send, the gas is already limited to zero, i.e. the called contract will only have the gas stipend.

    If you want your own contract to not throw an exception if it receives an invalid message, because you want to be able to receive funds from anywhere:
    Implement the fallback function (function() {...}). If this function is present, it will be called if no other function matches.

    Concerning "... so we can be safe calling our own contracts": If you call your own contracts, you know their signature and what they are doing, so you should never end up in a function identifier mismatch situation.

    It would be great to hear about situations where you encounter these problems and whether we could solve them in a different way.
  • nikolainikolai Member Posts: 1
    This clarifies a lot, thanks.
    So there is no way to distinguish between a return due to an exception and a normal "return 0x0". That's not so bad, a small price to pay to safely be able to "try" state changes.

    The issue I'm trying to address is if I let users provide callback contracts, but I don't want them to be able to STOP. They should be guaranteed to return whether by normal means or some exception.

    Or is STOP the same as RETURN 0 as well?
  • chrisethchriseth Member Posts: 170 ✭✭✭
    You can distinguish between a return due to an exception and a normal return: If you call a method, that call will also throw (you cannot catch it yet), if you use send or call, it will return false.

    "RETURN 0 0" is exactly the same as "STOP".

    Using unknown callback functions is always problematic, because of gas usage: If you do not limit gas, there is always the danger of the callback function containing an infinite loop. If you do limit gas, you have to decide where to put this hard limit...
    I think the safest way now is to use call and limit the gas so that the callback can set a flag but not much more.
  • tcimolitcimoli Cagliari - ItalyMember Posts: 35
    edited May 2016
    When you say:

    >I will try to clarify the documentation, but also explain it here: If a contract receives a message whose function identifier does not match any function defined by the contract, it will throw an exception

    what do you mean by "a contract receives a message"? You mean using the call?

    To better understand what you said, I tried with the following code:
    bool success = secondContract.call.value(1).gas(55555)("piiiiing");
    where no methode exists with name "piiiing", but strangely no error was returned: I also debugged it (in MIX), and I found that the unnamed function was called instead of piiiing.

    Then I changed the code into:
    bool success = secondContract.call.value(1).gas(55555)("ping");
    to correctly call the methode caled ping, but also in this case the unnamed function was called.

    I am a bit puzzled.
    1) How do I perform a call to a methode?
    2) Why it never returns an erorr?
Sign In or Register to comment.