4

In the code I return any Ether sent by mistake to contract C with the throw; statement inside the fallback function. I also want to make a log of this occasion. The following code doesn't work(throw; reverts any changes made to the blockchain).

contract C {
    event error(uint8 error);
    function(){
        error(1);
        throw;
    }
}

My questions:

  1. Since I have only 2300 gas available I can't call another contract that will make a log. Is it correct?

  2. What are my options then?

2 Answers 2

3
  1. Since I have only 2300 gas available I can't call another contract that will make a log. Is it correct?

The basic cost for calling another contract is 700 gas (cost of CALL opcode). So it's probably possible to call another contract to do the logging, but that extra level of indirection might just be clutter. What's not possible is writing to storage, which is a basic cost of 5,000 gas.

A fallback function can get more than 2,300 gas, but unless you're calling your own fallback, you cannot assume that your fallback function will have more than 2,300 gas. For more information see How much computation can be done in a fallback function?

  1. What are my options then?

Since it's not possible to log before a throw, an option is to refund manually (and log it) if and only if ether was sent. If the manual refund fails, your only option to force a refund is to throw but it's not possible to log this case.

contract C {
    event error(uint8 error);
    function() {
        if (msg.value > 0) {
            // manual refund and log it
            if (msg.sender.send(msg.value)) {
                error(1);
            }
            else {
                // force a refund but cannot log this case
                throw;
            }
        }
        else {
            error(2);
        }
    }
}

Note that msg.value > 0 is explicitly checked so that you can determine what you want done when msg.value is zero. This example logs another error code, but you could also do nothing (by removing the second else clause). When msg.value is zero, I don't think you want error(1) (as in @Xavier's answer) because no ether was sent by mistake to the contract and thus no refund was performed.

1
  • Note: CALL will not cost only 40 gas after EIP 150 hard fork. Commented Oct 19, 2016 at 13:44
1
  • You may have more than 2300 gas if your contract was called, for instance, with myContract.call.gas(10000).value(1 ether)() or with an unrecognised function signature.
  • You can attempt a return, such as:
function(){
    if (!msg.sender.send(msg.value)) {
        throw;
    } else {
        error(1);
    }
}
2
  • %c3%aatre, thank you very much, good sir!!! I was thinking along the same line. Quick question: how does an unrecognized function signature call looks like?
    – manidos
    Commented Aug 19, 2016 at 16:30
  • 1
    When calling a contract, the first 4 bytes of msg.data is the function signature to call: github.com/ethereum/wiki/wiki/Ethereum-Contract-ABI When receiving a message the contract will find a matching function to call. If none matches, then the fallback function is called. So an unrecognised function signature is any 4 bytes that is not 1 of the few function signatures. Commented Aug 19, 2016 at 17:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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