I’m generally against asserting that we will never decrease gas costs. In order for gas accounting to function appropriately we need the power/authority to be able to tune them up/down as hardware/software changes with time. While I can appreciate that having this ability makes things harder, I believe it is necessary for keeping Ethereum competitive.

I am not saying we should not decrease costs of operations. I am pointing out that there was complexity in EIP which was not on the plain sight. And it should have been given more weight when discussing the alternatives.

MicahZoltu:

IIUC, it sounds like you are sort of arguing that Ethereum 1.x is in maintenance mode and we basically shouldn’t be doing any active development on it that isn’t necessary for Ethereum 2.0? Any changes to the EVM should be proposed targeting Ethereum 2.0 instead?

Yes. It has already been proposed by Vitalik at DevCon3, October 2017, in his “Modest Proposal for 2.0”. He suggested to keep Ethereum 1.0 “safe and conservative”. Of course, Ethereum 1x initiative kind of goes opposite to that, but only because we believe that there are SOME changes necessary to keep Ethereum 1.0 alive.

No this does not work, because the idea behind transfer and send is that you are also allowed to send Ether to contracts which have a payable fallback. These hence execute (given a solidity-compiled contract) the code to select a function: if none is found, it checks if there is a (payable) fallback. (Hence forwarding 0 gas will immediately result in an out of gas error).

You misunderstand; the EVM itself enforces the gas stipend. If you make a call to another contract that sends value with 0 gas, the recipient contract gets 2300 gas regardless.

jochem-brouwer:

Besides all this I agree with @AlexeyAkhunov to remove it altogether. I think in most cases writing to the same storage slot in a contract twice should be removed at compile time. At least in transactions which only happen during a single call this can be removed at compile-time. There might be some cases that this is harder if there are calls to other contracts (which call back into the current contract), but I think with some tricks this might also be possible. Hence the only case where this EIP is applicable is where a contract calls another one, which calls back into the current one. In all other cases more than single-writes to the same storage slot can be removed at compile time.

That’s the whole point of the EIP - to make the use of temporary storage for cross-contract calls practical. Examples include mutexes and setting temporary token allowances.

MicahZoltu:

IF we can gain the necessary confidence that this bug isn’t exploitable against any active contracts in the wild, why is maintaining this invariant necessary? Not only was the invariant only implied, not explicitly stated, but if no one is depending on it what do we gain by maintaining it?

It was explicitly designed in as an invariant, because it’s useful to be able to reason straightforwardly about ‘value sends’ while still providing the target contract with the opportunity to execute a little code. I don’t think we should throw that out, even in the (hypothetical and very unlikely) situation that we can without breaking anything already deployed.

You misunderstand; the EVM itself enforces the gas stipend. If you make a call to another contract that sends value with 0 gas, the recipient contract gets 2300 gas regardless.

This is how I understood it but I wasn’t aware that this was done by the EVM. Is there an issue with removing this gas stipend in the case that send and transfer use the new call context you described for 2.?

You misunderstand; the EVM itself enforces the gas stipend. If you make a call to another contract that sends value with 0 gas, the recipient contract gets 2300 gas regardless.

I did not know this and assumed you could always forward 0 gas, making transfers to any existing contract impossible.

Arachnid:

That’s the whole point of the EIP - to make the use of temporary storage for cross-contract calls practical. Examples include mutexes and setting temporary token allowances.

I see, this is a good use case.

But in that case, I actually think that reducing the stipend is also an interesting option. I misunderstood that the stipend was not the same as the forwarded gas in a call (because solidity forwards this exact amount). Why is this stipend there in the first place? What is the reason for this? Why must we not explicitly forward an amount of gas and why is there a minimum of 2300?

But in that case, I actually think that reducing the stipend is also an interesting option. I misunderstood that the stipend was not the same as the forwarded gas in a call (because solidity forwards this exact amount). Why is this stipend there in the first place? What is the reason for this? Why must we not explicitly forward an amount of gas and why is there a minimum of 2300?

The stipend exists to ensure that a contract that’s sent ether always has the opportunity to log an event to record that fact.

But in that case, I actually think that reducing the stipend is also an interesting option. I misunderstood that the stipend was not the same as the forwarded gas in a call (because solidity forwards this exact amount). Why is this stipend there in the first place? What is the reason for this? Why must we not explicitly forward an amount of gas and why is there a minimum of 2300?

Proper understanding the stipend requires a bit of history.
Stipend to contracts was in EVM from the beginning. But, unfortunately, the case where call value was “0” was forgotten (or rather it was thought that people won’t do it), so there is no stipend in this case. That is why, sending 0 wei to a contract would fail some time in the past, whereas sending non-zero amount would succeed.

Solidity made a work around to fix this - it now generates the code that checks that if the target of the CALL is a contract, and the Call Value is 0, then it adds 2300 to gas given to the call. This part is not in the EVM, it is a patch to fix the usability issue. The more fundamental fix would be to change EVM, but it was never done

The stipend exists to ensure that a contract that’s sent ether always has the opportunity to log an event to record that fact.

AlexeyAkhunov:

Proper understanding the stipend requires a bit of history.
Stipend to contracts was in EVM from the beginning. But, unfortunately, the case where call value was “0” was forgotten (or rather it was thought that people won’t do it), so there is no stipend in this case. That is why, sending 0 wei to a contract would fail some time in the past, whereas sending non-zero amount would succeed.

Solidity made a work around to fix this - it now generates the code that checks that if the target of the CALL is a contract, and the Call Value is 0, then it adds 2300 to gas given to the call. This part is not in the EVM, it is a patch to fix the usability issue. The more fundamental fix would be to change EVM, but it was never done

This is starting to make a little bit more sense. However, I still do not understand that there always is a minimum of 2300 gas forwarded (and via above text this is apparently the minimum if the endowment > 0). What if I want to transfer Ether but want to explicitly revoke that anything is logged (so gas forwarded is now less than 375). I don’t see why this always has to be minimally 2300.

So this is also the reason why a lot of (older) contracts always send 1 wei with their CALLs to other contracts?

Couldn’t you have it forward as much gas as is required? I’m not understanding why removing this would default it back to 0.

At present, any time you send value with 0 gas, the recipient gets 2300 gas instead. If we removed the stipend from the EVM, in this event the recipient would get 0 gas and immediately fail. This would break a lot of existing code, as well as breaking the current assumption that you can always at least log an event when sent ether.

AlexeyAkhunov:

Stipend to contracts was in EVM from the beginning. But, unfortunately, the case where call value was “0” was forgotten (or rather it was thought that people won’t do it), so there is no stipend in this case. That is why, sending 0 wei to a contract would fail some time in the past, whereas sending non-zero amount would succeed.

That’s not a mistake - the intention is just to provide a stipend when necessary to log receiving ether. There’s no reason to log receiving 0 ether.

To be fair, adding new opcodes for transient storage has the exact same issue, just it’s harder to be exploited. Although transient, it’s still a (temporary) state change and can affect things similarly.

I have always been very bothered by the stipend. Not only does it depend on gas prices not changing in order to provide the value that people want it to provide, it also makes it so receiver contracts can’t do interesting things on receipt of ETH when the caller doesn’t provide much gas. There are a number of interesting things one could do in a contract’s default function that are not possible because contract authors (and the EVM and Solidity) keep limiting the gas provided to receivers.

TL;DR: the invariant that people want to maintain is one that I don’t think ever should have existed and should be removed. If not for Ethereum 1.x, then for 2.0.

To be fair, adding new opcodes for transient storage has the exact same issue, just it’s harder to be exploited. Although transient, it’s still a (temporary) state change and can affect things similarly

I disagree here. The transient storage would not be used to store things like token balances. No one would think of using transient storage for that. It could be used to buffer any changes done in the other frames - but it will be amenable to separate analysis, not mixed up with the analysis of the storage.
I take your comment as an agreement that transient storage is safer, because it is harder to exploit, and because it does not implicate pre-existing contracts

Solidity made a work around to fix this - it now generates the code that checks that if the target of the CALL is a contract, and the Call Value is 0, then it adds 2300 to gas given to the call. This part is not in the EVM, it is a patch to fix the usability issue. The more fundamental fix would be to change EVM, but it was never done

Are you sure about this? I just tested 0.4.24, and it makes the call with a gas value of 0.

jochem-brouwer:

This is starting to make a little bit more sense. However, I still do not understand that there always is a minimum of 2300 gas forwarded (and via above text this is apparently the minimum if the endowment > 0). What if I want to transfer Ether but want to explicitly revoke that anything is logged (so gas forwarded is now less than 375). I don’t see why this always has to be minimally 2300.

The idea is that you shouldn’t be able to do that - contracts should always be able to react to being sent ether. Also, why would you want to?

MicahZoltu:

I have always been very bothered by the stipend. Not only does it depend on gas prices not changing in order to provide the value that people want it to provide, it also makes it so receiver contracts can’t do interesting things on receipt of ETH when the caller doesn’t provide much gas. There are a number of interesting things one could do in a contract’s default function that are not possible because contract authors (and the EVM) keep limiting the gas provided to receivers.

TL;DR: the invariant that people want to maintain is one that I don’t think ever should have existed and should be removed. If not for Ethereum 1.x, then for 2.0.

I don’t follow your argument; removing the stipend would make things worse in this regard, not better.

I don’t follow your argument; removing the stipend would make things worse in this regard, not better.

Solidity’s address.call.value(x)() does exactly what I think all of the ETH sending mechanisms should do, which is provide all gas (minus stack unwind gas) like it does for any other contract call. I would be fine if CALL with 0 gas either passed 0 gas (and thus failed, because you didn’t use the opcode correctly) or if it passed along all gas like every other contract call does (a reasonable default). My problem lies in the fact that it sends a hard-coded value that is different from what gets sent along with every other contract call and people rely on that amount to prevent certain behaviors that can’t be guaranteed in a world where gas prices change with time (as seen in this EIP).

Note: The above argument is not proposing a migration strategy, only that the pattern people seem keen on keeping (which seems to be the foundation of some arguments here) is a bad pattern IMO and should never have been implemented in the first place and we should not favor a solution just because it retains that pattern.

Solidity’s address.call.value(x)() does exactly what I think all of the ETH sending mechanisms should do, which is provide all gas (minus stack unwind gas) like it does for any other contract call. I would be fine if CALL with 0 gas either passed 0 gas (and thus failed, because you didn’t use the opcode correctly) or if it passed along all gas like every other contract call does (a reasonable default). My problem lies in the fact that it sends a hard-coded value that is different from what gets sent along with every other contract call and people rely on that amount to prevent certain behaviors that can’t be guaranteed in a world where gas prices change with time (as seen in this EIP).

Right, I understand your objection. But removing the stipend - allowing calls-with-value to have less than 2300 gas - would make the situation worse, since callees could no longer have any guarantees over what they can do when sent value - and would break a lot of existing code.

Can you clarify, what happens if someone issues a CALL with value and specifies 500 gas? Does the EVM increase the gas provided to 2300, or does it make the call with 500 gas? I was under the impression that the bump to 2300 was only if 0 was specified for gas.

Are you sure about this? I just tested 0.4.24, and it makes the call with a gas value of 0.

You are right, I don’t know where I got from that solidity always forwards 2300 gas. It indeed forwards 0 gas.

Arachnid:

The idea is that you shouldn’t be able to do that - contracts should always be able to react to being sent ether. Also, why would you want to?

I don’t know why you would want this, but I just find this a weird design rationale. This whole stipend makes EIPs harder to review because we now always have to check if you can’t do any fancy tricks with the 2300 - 700 (700 for CALL) gas via reentrancy. I agree with @MicahZoltu that this stipend is dangerous especially if gas prices change. For example in EIP150, what if someone had a contract which logged extcodesize of the called contract at some point and then suddenly could not because this gas was increased (2300 gas was not enough suddenly). I find that this stipend constrains us a lot. That being said we can’t lower this stipend because this will break stuff aswel.

What if we do the same thing for EIP 1283 but now use a new opcode which does exactly the same as SSTORE but also implements EIP 1283 on dirty storage. (This might be an EIP which has been proposed before, sorry if that is the case).