ethereum / EIPs

The Ethereum Improvement Proposal repository
https://eips.ethereum.org/
Creative Commons Zero v1.0 Universal
12.82k stars 5.23k forks source link

New Opcode: INJECTED_STATIC_CALL #199

Closed pipermerriam closed 7 years ago

pipermerriam commented 7 years ago

I propose a new opcode, INJECTED_STATIC_CALL which would be built off of the semantics of STATIC_CALL from EIP116. The INJECTED_STATIC_CALL opcode would operate in the same manner as STATIC_CALL, disallowing any state modifying actions. This opcode would take one additional address argument. The code executed by INJECTED_STATIC_CALL would be executed in the context of the storage for the given address.

The motivation for this opcode comes from a gap in functionality that EIP144 may leave. EIP144 will allow external calls to query the storage of arbitrary contracts using EVM code. The addition of this new opcode would enable this same functionality for contracts.

Arachnid commented 7 years ago

What's the motivating use-case for this? As far as I'm concerned, contracts only being able to interact with each other via their exposed public APIs is an asset, not a liability.

danfinlay commented 7 years ago

As long as it only allows reads, what liability could it create? The whole blockchain is public anyways, this just makes some of that data easier to read.

Arachnid commented 7 years ago

I'm concerned that it will encourage people to ignore or avoid the interfaces publicly exposed by contracts, and I haven't heard a compelling use-case for offering it.

All of the data in a contract can be accessed offchain, and that's fine, but I think there's a good argument for requiring contracts to talk to each other only via their ABIs.

pipermerriam commented 7 years ago

@Arachnid in all previous context's that I've done development I think I would agree but for smart contract development I think this fits well. Here are the use cases that I see as compelling.

  1. It is easy to reach the gas limit in contract development. One of the common ways I've gone about reducing size is munging all of my getters together. Instead of function getA, function getB, function getC you end up with function getABC which returns all 3 values. There are cases where the combined getter API is good but there are also plenty of cases where it results in harder to read code. This opcode would allow for contract developers to write the right getter API rather than the one that reduces the deploy gas costs.

  2. Contracts don't always expose the data you need in the format you need. In the traditional web world, we typically would just write some code to translate the data into the format we want. In contract development this type of data munging can be prohibitively expensive. Allowing direct access to the storage will allow this type of data munging in a much more efficient way.

  3. Being able to fetch only the piece of data you need reduces gas costs for the contracts reading that data.

Arguments against that I've heard.

  1. What about contracts that make you pay for their data. Since the data is already available to the outside world, I think that this pattern is fundamentally flawed. It is trivial to circumvent these types of paywalls.
pipermerriam commented 7 years ago

Another thing that I like this feature for is situations where you contracts that just act as views on top of an underlying database contract. With a sufficiently complex database contract it becomes very difficult to forecast what read APIs you may need going forward. In the current world this requires that you build in the ability to get at 100% of the data up front. This new opcode would allow you to only build the initial API that you need for reading data (or none at all) with the knowledge that you can implement that API in the view contracts that sit in front of the DB contract.

nmushegian commented 7 years ago

I thought hiding private state (from other on-chain consumers) was a design feature of the EVM. injectCall is just sugar for something you can already off chain

pipermerriam commented 7 years ago

I thought hiding private state (from other on-chain consumers) was a design feature of the EVM.

Given that it is relatively trivial to circumvent the "privateness" of that data I'd posture that this isn't a very solid or reliable feature.

injectCall is just sugar for something you can already off chain

Along that reasoning, since you can already do this off chain, why not allow it on-chain as well.

nmushegian commented 7 years ago

Given that it is relatively trivial to circumvent the "privateness" of that data I'd posture that this isn't a very solid or reliable feature.

You can read the data from my Super Authoritative Oracle Aggregator and resubmit it, but I can still charge the first consumer on-chain who wants the "real" thing. These and probably other building blocks stop working. I bet there will be some kind of obfuscation arms race if this is enabled.

nmushegian commented 7 years ago

Along that reasoning, since you can already do this off chain, why not allow it on-chain as well.

Ok and along that reasoning, we should be able to read historic log state into contract state.

pipermerriam commented 7 years ago

Ok and along that reasoning, we should be able to read historic log state into contract state.

And if we legalize marijuana we'll probably have to legalize heroin and cocaine as well. Can not use that style of argument?

I can still charge the first consumer on-chain who wants the "real" thing.

This is purely my opinion, but the business model of contract's which charge other contracts for data feels flawed and not worth protecting. It is borderline trivial to circumvent or undermine these systems.

I'd also point out that were this to be implemented, it doesn't preclude oracles from charging for information. It just eliminates the ability to charge for information that is already on the blockchain.

nmushegian commented 7 years ago

It just eliminates the ability to charge for information that is already on the blockchain.

This essentially forces all architectures to be push-oriented instead of allowing pull-oriented data flows. This may be viable, but it really needs us to try working through some non trivial examples and see if it forces awkward constraints on systems that use monetized feeds

nmushegian commented 7 years ago

I would love input from anyone who was in the original "allow private state or not" debate. @gavofyork maybe?

pipermerriam commented 7 years ago

More discussion over at the BTCRelay repository relevant to this. https://github.com/ethereum/btcrelay/issues/44

I'd present that as further evidence that private state is a flawed concept. Monetized feeds are fine, but money is paying for the data to be put into the blockchain (much like what oraclize.it does). If the payment is for data that is already on chain then there will be ways to circumvent that payment (which can be done today with the current EVM).

nmushegian commented 7 years ago

If the payment is for data that is already on chain then there will be ways to circumvent that payment (which can be done today with the current EVM).

I guess the point is that you actually can't fully circumvent it and preserve the EVM's trust properties, and it was a deliberate choice to force this out of this layer in order to enable certain kinds of dapps.

Another way to say this is that certain kinds of "metadata" should be treated as off chain data (like logs and maybe private state). I believe this enables a kind of pull-oriented dataflow which might be more efficient if we want 'pay for new data' feature (I'd need time to make that argument). Whether or not this is sufficient reason to have private state is not clear to me.

I don't find the btcrelay discussion to be convincing one way or the other, it's not an interesting "already in the state but unaccessible" case if I understand correctly. I'd really like to see what the people who deliberately discussed this and then decided this way have to say. I think this happened because of a blog post during POC phase or something like that.

pipermerriam commented 7 years ago

I'd really like to see what the people who deliberately discussed this and then decided this way have to say

I am interested in this as well. @vbuterin ? can you provide any information about previous conversations that have happened resulting in the choice to make contract state "private" by default?

vbuterin commented 7 years ago

I think that aside from preserving a bit of data feed monetizability the idea was to preserve an object-oriented programming principle, where contracts would interact with each other through calls instead of directly reading into each other's state. One practical benefit of this is that right now it's theoretically possible to make hardforks that heavily reorganize the way that storage and code work, eg. completely rewriting how storage is organized and then making appropriate modifications to code to fit into the new model, but allowing contracts to access external storage would make this trickier, as you would have to deal with the case where code of contract A acts on storage of contract B. DELEGATECALL also does this, but it's less bad because you can transform the code at runtime whereas with INJECTED_STATIC_CALL it's the storage that would need to be transformed.

Arachnid commented 7 years ago

I'm against this onchain because of the abstraction issues Vitalik mentions, unless someone can cite a compelling use case in which this functionality would be vital.

On Fri, May 5, 2017 at 5:14 AM vbuterin notifications@github.com wrote:

I think that aside from preserving a bit of data feed monetizability the idea was to preserve an object-oriented programming principle, where contracts would interact with each other through calls instead of directly reading into each other's state. One practical benefit of this is that right now it's theoretically possible to make hardforks that heavily reorganize the way that storage and code work, eg. completely rewriting how storage is organized and then making appropriate modifications to code to fit into the new model, but allowing contracts to access external storage would make this trickier, as you would have to deal with the case where code of contract A acts on storage of contract B. DELEGATECALL also does this, but it's less bad because you can transform the code at runtime whereas with INJECTED_STATIC_CALL it's the storage that would need to be transformed.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/ethereum/EIPs/issues/199#issuecomment-299366095, or mute the thread https://github.com/notifications/unsubscribe-auth/AABFyfsCLpwBHjpfQ8vVCpOF0ThXFQnQks5r2qIQgaJpZM4Lx2kv .

pipermerriam commented 7 years ago

I don't feel strongly enough about this proposal to try and push it forward. Thanks @vbuterin for the context on the original decision.