Upgrade Contract: Question on storage layout issues

So I have an "interesting" issue at my hands, where a change on a contract requires changes to the storage layout, more specifically additional variables added. (UUPS proxy).

I have been reading up what I am able to come over on the subject, and understand that changing the order of the variables or included contracts, will/can change the storage layout.

What I want to do is update a struct, so the question then is if this is possible or not. The problem is that none of the information I have been able to locate addresses how structs are treated in regards to the storage layout.

I would be grateful if someone has additional resources on this subject if they can let me know where I can go for more information.

In addition, I remember reading a topic in the past that about something like you were able to verify the storage layout by reviewing the bytecode, and that way could verify if an upgrade would change it. Would be grateful for any information about this as well.

Thanks

I have been doing some tests and from what I can see:
The storage inside a struct behaves like regular contract storage. What I mean by that is that you can add new storage variables at the bottom of the struct without affecting the current storage data/layout.

This includes if the struct is above the mappings that utilize the struct in the file.

Note: Similar if you try to add a new storage variable in between the others inside a struct, it will push the others out of sync with stored data for the mappings that use the struct.

With this in mind, it seems that if you take the storage layout rules in mind, updating a struct with additional storage variables is not an issue.

If anyone has any more detailed information on how exactly the struct storage layout is organized, it would be interesting to read up more on it.

Yeah, I think so, for more details, I think you can have a look at the documentation: Layout of State Variables in Storage | Solidity 0.8.11

1 Like

Thanks for the information.

After reading through the storage documentation I have done a bunch more tests on the blockchain, and thought I would share my findings for anyone else that might stumble upon the thread.

I have tested this on Solidity 8.4, though unless the storage layout change in the future it will most probably be the same in newer versions as well. Just remember to double-check the documentation to see if any breaking/major changes are listed to the storage layout. And always make sure you verify that what you want to do works on the blockchain on a set of test contracts before doing the same change on your live contract.

  • Before you do any changes, make sure you use the command-line compiler for your Solidity version and export the storage layout. Please note that the JS compiler cant export the storage layout. For more information check: https://docs.soliditylang.org/en/latest/using-the-compiler.html#using-the-commandline-compiler

  • Then after you have made your changes, export the storage layout again and compare the two. Easiest here is to utilize a merge software to see the differences. The key thing you need to look for here is to ensure that all of the changes you did to the storage layout appear at the bottom of the list. If they appear in between your old storage layout variables, it means that you will most probably overwrite storage positions. (There are edge cases where this might not happen due to total storage size, but unless you know what I refer to, treat all cases as it will overwrite storage positions).

Here is some more information point-based, in no order of importance.

  1. If your storage layout is currently handled across many contracts that are extended, you can rearrange it into one of them. As long as you export the storage layout first, and then ensure you place the variables into the file so that the storage layout stays the same, it will work great. Doing this can avoid having to keep extending a contract when making changes.

  2. If your contract extends other contracts, the order of importance when the storage layout is created is ordered by the first extended contract, then through them in order, and then the main contract.

  3. The order of the contract methods does not affect the storage layout, you can add new methods in between current, or change a method without it affecting the storage layout.

  4. Constant variables do not affect the storage layout. You can create new ones, in the middle of other storage variables without it affecting the storage layout.

  5. Events does not affect the storage layout, so you can add new ones in between current ones, or change one without affecting the storage layout.

  6. The order of struct's does not affect the storage layout, so you can add a new struct in between variables without it affecting the storage layout.

  7. The storage area inside a struct, behave as an separated storage layout, what I mean with this, is that you treat each struct as their own storage layout when considering changes, and always add the new variable at the bottom of the struct.