1

let's say I have something like this

function usuallyCheapFunction() external {
    ... do something cheap...
    if(rareCondition == true) {
        expensiveCleanupFunction();
    }
}

function expensiveCleanupFunction() internal {
   ... shuffle around some storage ...
}

Users would call usuallyCheapFunction() to do something, expecting cheap transaction price. Sometimes the contract needs to do some expensive cleanup - is it possible in this case to supply gas from the contract to call expensiveCleanupFunction() so that the call does not cause out-of-gas? If so, how would this look like?

2 Answers 2

1

For now it is not possible to pay for gas from contract's balance, though this may change in future, but smart contract may refund gas transaction publisher spent on housekeeping function:

modifier refundable () {
    uint256 gasBefore = gasleft ();
    _;
    tx.origin.send (tx.gasprice * (gasleft () - gasBefore));
}

function expensiveCleanupFunction() refundable internal {
    ... shuffle around some storage ...
}

This will not refund gas in case smart contract does not have enough ether, though. If you need to refund even in case of insufficient balance, do something like this:

mapping (address => uint256) private refundBalance;

modifier refundable () {
    uint256 gasBefore = gasleft ();
    _;
    uint256 toRefund = tx.gasprice * (gasleft () - gasBefore);
    if (!tx.origin.send (toRefund))
        refundBalance [tx.origin] += toRefund;
}

function withdraw () public {
    uint256 toTransfer = refundBalance [msg.sender];
    refundBalance [msg.sender] = 0;
    msg.sender.transfer (toTransfer);
}

function expensiveCleanupFunction () refundable internal {
    ... shuffle around some storage ...
}

So in case instant refund failed, smart contracts increments refund balance of the users, and once smart contract balance will be resupplied, user will be able to withdraw his refund.

0

It is not possible to do this in a single transaction, as each operation in Solidity compiles down to an opcode, and each opcode has an associated cost. All of these costs are greater than 0, so there is no way to 'cleanup' a transaction and allow it to use more gas (i.e., generate more opcodes).

Generally, if you are running into scenarios where this is the case, it is best to refactor the contract to behave in such a way that does not use as much gas in a single transaction. If possible, you can split a single function into multiple functions, called at different points (different transactions), that save the state of the contract.

See this repo for a list of opcode costs.

4
  • I'm not sure I understand your answer. Are you saying the cost of executing usuallyCheapFunction is always the same, independently of whether rareCondition == true or not? Also I don't want to 'cleanup the transaction' - I want to run some expensive code sometimes, and supply extra gas from the contract to supplement the gas sent by the caller. Commented Aug 21, 2018 at 18:22
  • No, the cost of usuallyCheapFunction will fluctuate if rareConidition == true (the user must pay more gas to not have the transaction fail if the rareCondition is triggered). And, at the present moment, the contract cannot supply extra gas. This is a potential feature in Serenity when it comes out, but as it stands now, this is not possible. Take a look at this blog post from Vitalik for more information. Commented Aug 21, 2018 at 18:26
  • In that case, what refactoring options do I have to ensure that expensiveCleanupFunction() is being executed (at some point, can be asynchronous), without relying on an external trusted entity? Commented Aug 21, 2018 at 18:33
  • It really depends on what it is intended to do. If the transaction is dealing with the person receiving ETH/Tokens, you could lock the tokens in the contract until the person calls the function in a second transaction. If it has to do with state transitions, try to optimize the storage of your contract. In general, it is best to do as little as possible in Solidity, to minimize cost as well as maximize security. Commented Aug 21, 2018 at 18:36

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.