0

I'm trying to figure out a solution to this problem, to do with transaction confirmation order and setting values to 0

pragma solidity ^0.5.17;

contract Test {
    uint256 amount;

    constructor() public {}

    function join() public {
        amount += 100;
    }

    function leave() public {
        amount -= 100;
    }
}

Given these transactions (tested on ropsten):

tx 1) Call Join Confirmed amount == 100

tx 2) Call Join (gas price 1) Pending amount == 100 should tx3 get mined first

tx 3) Call Leave (gas price 100) Pending amount == 0

However tx 2 will always fail with an out of gas error for as long as the amount is set back to 0. This doesn't happen if the value is any higher than 0. My understanding is that it costs more gas to set a value to its 0 state instead of a positive integer, and the gas estimation isn't taking this into account. I've tried delete hoping this would give a gas refund to compensate for the too-low gas limit, but it still failed.

Is there an elegant way to handle this scenario? The only ways I can think of are over-estimating the gas for all join transactions, which has its obvious drawbacks, or never setting amount back to 0.

Boyswan
  • 224
  • 1
  • 4
  • 12

1 Answers1

2

You are making correct observations.

by setting it to 0 you delete storage, and get gas refund. This is why it takes less amount of gas. But gas refunds have top limit, so you can't use it to store ETH.

It costs 20,000 gas to store one value in a slot (source:https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L41 )

it costs 2,200 gas to load one value from a storage slot (source: https://github.com/ethereum/go-ethereum/blob/d13c59fef0926af0ef0cff0a2e793f95d46442f0/params/protocol_params.go#L89)

That's why you are seeing different gas consumption values.

Just set your gasLimit to some empirically found roughly-estimated value.

Do a trace of your transaction and you will see all gas consumption values.

Now, the way gas refunds work is that during the state transition function, you're asked for the full gas for the run of your contract. During this run, all gas refunds are accumulated in StateDB (temporary state object). At the end of the state transition function, you will get refunds for all storage releases your contract is going to make. This is why you have to set higher gas limit that Etherscan shows, because lets say your contract needs 15,000 gas to run, after storage is released (say for 5,000 gas) , Etherscan will show like the transaction needed 10,000 gas. This is not true because you have got gas refunds at the end, but at the beginning you needed the whole amount of gas (15,000). Gas refunds are sponsored by the miner, his account is going to get less ETH because he is paying you these refunds.

Nulik
  • 6,748
  • 10
  • 60
  • 129
  • Thanks for the reply, this makes sense. I wasn't sure whether it's good practise to manually set gasLimits higher to be safe (with the caveat of transactions 'seeming' more expensive), or leave it down to the providers gas estimation. – Boyswan Jan 14 '21 at 17:26