ethereum/EIPs

New opcode: STATIC_CALL

vbuterin opened this issue ยท 17 comments

If block.number >= METROPOLIS_FORK_BLKNUM, then opcode 0xfa functions equivalently to a CALL, except it takes 6 arguments not including value, and calls the child with a STATIC flag on. Any calls, static or otherwise, made by an execution instance with a STATIC flag on will also have a STATIC flag on. Any attempts to make state-changing operations inside an execution instance with a STATIC flag on, including nonzero-value calls, creates, and SSTORE, SSTOREBYTES or SUICIDE operations, will instead throw an exception.

Rationale

This allows contracts to make calls that are clearly non-state-changing, reassuring developers and reviewers that re-entrancy bugs or other problems cannot possibly arise from that particular call; it is a pure function that returns an output and does nothing else. This may also make purely functional HLLs easier to implement.

would there be anyway for a contract to dectect if it was in static mode or not?

Suppose contract C has code def test(): ~call(msg.sender, 0, 1, 0, 0, 0, 0), call C.test(), see if it passes. That said, I don't see the need for it; solidity should only allow you to call constant functions in static mode, and non-constant functions only in non-static mode.

Sounds great! On the solidity side, this opcode could be utilized by all calls into functions marked as constant.

This looks like a good feature to me as well.

However, do you think there is a time to do a step back and see our call system from higher perspective? Just to know what design decisions where wrong, what is missing, and where should we go in the future?

axic commented

Agree with @chriseth that this nicely matches with what is marked as constant in Solidity and the ABI.

Also agree with @chfast that probably quickly adding different call semantics might not be the best approach, when the system could be reviewed in the first place with all the experience gathered so far over the 11 months of public testing.

So far we have CALL and DELEGATECALL (as far as I can see CALLCODE is useless now that DELEGATECALL exists). DELEGATECALL is essentially a hack that makes an account's code de-facto mutable. I don't think changing CALL is viable given how many contracts are relying on it. I think CALL/STATIC_CALL has precedent because C++ and other languages have a notion of "constant functions"; this is just what is necessary to make constant functions actually constant in a multi-user multi-contract environment where some of the things you're calling may be black boxes. We could also come up with other calling styles (eg. SANDBOXED_CALL in #117, which (in my modified interpretation) adds the restriction that the call can only change state in the destination address).

This is easy enough to implemen. Why STATIC_CALL rather than CONSTANT_CALL?

Because the static keyword is the most overused word in the world of programming languages.

Is there a way to call a function without putting that function onto the consensus state of any contract?

sjalq commented

I think this is a step in the right and the wrong direction at once.

To gain a lot from this we need a few concepts;

  1. Memioization: The ability to calculate a function, param set only once and store the answer. To do this the function cannot access volatile state, the volatile state must be passed in via parameters. The benefit for Ethereum is unclear at present; it may play out that memioization can reduce evaluation time and possibly cause a major drop in gas prices. It could be that it adds nothing and the cache costs more to maintain than to ignore.
  2. Side-effects: What this is ultimately about is the ability to call a "Query" in Command/Query Separation terms. To do that, we cannot simply call existing methods that were written with state changes in mind, we need to properly flag methods on the blockchain as having no side effects. The benefits for Ethereum get huge here; we can begin to build up a library of trust worthy functions that can also be parallelized to an astonishing degree depending on the problem. This will greatly reduce evaluation times and gas prices. To ensure non-side effecting calls, we can also not allow a Query to call a Command (function with side effects). We also need a mechanism to prevent calls to other contracts from pointing to Queries at compile time, but pointing to Commands when the other contracts get upgraded.

On the solidity side we will soon distinguish between functions that do not modify state but can read state and actual pure functions which only depend on their arguments (and not on the state).

Adding PURE_CALL can enforce that on EVM-level and would also allow some optimizations at execution time.

axic commented

@chriseth actually, the original proposal above allows the use of SLOAD so it would map to Solidity's view keyword and not to pure.

@axic yes, my comment was about adding both STATIC_CALL and PURE_CALL.

axic commented

@chriseth ๐Ÿ‘

Another idea about redesigning the call opcode: Currently, solidity performs a basic check to see whether the called address is at least a contract (it cannot check any further type information, but at least this creates some basic protection). With #150 this makes calls even more expensive on the gas side but not on the resource consumption side. In light of this, it might be good to provide a way to automatically include the extcodesize > 0 check as part of the call (of course, we still need the ability to send ether and also send ether with data to non-contract accounts, so this should only be a "flag" of the opcode).

Replaced by #214