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?

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.

  • Note: CALL will not cost only 40 gas after EIP 150 hard fork. – Raine Revere Oct 19 '16 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);
    }
}
  • %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 Aug 19 '16 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. – Xavier Leprêtre B9lab Aug 19 '16 at 17:58

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.