Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document the resiliency of storage usage #5293

Closed
fulldecent opened this issue Oct 23, 2018 · 6 comments
Closed

Document the resiliency of storage usage #5293

fulldecent opened this issue Oct 23, 2018 · 6 comments

Comments

@fulldecent
Copy link
Contributor

Production applications are using upgradeable contract patterns. This includes some models where storage for one contract is shared between multiple logical implementations (DELEGATECALL).

A critical assumption of these implementations is that the storage "API" for Solidity is the same between any Solidity versions as long as the variable name is the same.

Example:

contract Proxy {
    ... a proxy using `DELEGATECALL`
}

contract Version1 {
    int public meaningOfLife;
    function setMeaningOfLife() external;
}

contract Version2 {
    int public meaningOfLife;
}

Deployment strategy:

  1. Deploy Proxy, Version1 and Version2
  2. Point Proxy to delegate to Version1 backend implementation
  3. Change Proxy to delegate to Version2

Test case:

  1. Access meaningOfLife on Proxy

Expected outcome:

  • Version2 implementation accesses the same storage that Version1 did in the same way

Actual outcome:

  • Undefined by language documentation

Work plan

  1. Identify ways that Solidity touches storage
  2. Document the way that Solidity translates code which uses storage into user-facing documentation
  3. Consider this documentation as part of the "API" of Solidity. Any backwards incompatible change to that documentation would be a feature-breaking release and require a major version increase to Solidity.

Discussion

A naive person might think you just sha3(variableName, [class::functionName]) to choose the storage location. If that is the case then we need to document what happen for two contracts that share the same private variable name.

A naive person might think you just sha3(contractName, [functionName,] variableName). This means that contract names are significant to byte code compilation. This would be surprising.

In both cases, this is related to the contract inheritance model because we are considering how private variables will work and if names can be reused.

REFERENCE: #3729

@chriseth
Copy link
Contributor

This has been part of the documentation for a very long time: https://solidity.readthedocs.io/en/v0.4.25/miscellaneous.html#layout-of-state-variables-in-storage

There is a pending pull request to improve the specification: #5023

There is also a pending PR to extract the storage layout from the compiler (don't remember the number for now).

We could add to the documentation that this layout is considered to be part of the API, although in my opinion, it is obvious that any change there would be a breaking change because of the way library calls work.

@fulldecent
Copy link
Contributor Author

Thank you for the reference, I totally missed that. And to be honest, I'm embarrassed, I should have asked on SO first.

Now that I am reading it, "starting from position 0" could be stronger. Does this mean that all inherits come before inheriting contracts? I am assuming this would be a depth-first search of dependencies based on the order of inheritance declared.

@chriseth
Copy link
Contributor

chriseth commented Nov 5, 2018

The storage is laid out according to the C3-linearized order of contracts starting with the most base-ward contract. One issue to document is whether state variables from different contracts can share a storage slot - that should be checked. Would you like to add that to the documentation?

@fulldecent
Copy link
Contributor Author

I have stolen your nugget and another into


Can you please explain "whether state variables from different contracts can share a storage slot".

If referring to two inherited contracts of the same inheriting contract, then yes this is a tautology. Yes, as soon as you have two arrays they will share storage because, theoretically, keccak256 could collide.

Or if you are asking "does EVM isolate storage for each account or are we just lucky that there are no collisions?" Then answer is "they are isolated" as per the Yellow Paper section 4.1 -- the world state is a mapping of accounts to state and therefore the states are isolated.

@chriseth
Copy link
Contributor

I took the liberty to modify your PR a little to answer the request above.

@fulldecent
Copy link
Contributor Author

Cool, thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants