Skip to content
This repository has been archived by the owner on Jan 24, 2022. It is now read-only.

Validate storage layout #117

Merged
merged 26 commits into from
Sep 26, 2018
Merged

Validate storage layout #117

merged 26 commits into from
Sep 26, 2018

Conversation

spalladino
Copy link
Contributor

This is a new iteration of #92, which github is not allowing me to reopen.


When running zos-push, validate that the storage layout is compatible with the previous version of the contract, and abort push otherwise. All warnings are displayed to the user, eg:

$ zos push
Validating contract AnotherImplV1 before push
Variable 'uint256 value22' in contract ImplV1 was renamed to foo in contracts/mocks/ImplV1.sol:1.
Note that the new variable foo will have the value of value22 after upgrading. If this is not the desired behavior, add a new variable foo at the end of your contract instead.
New variable 'uint256 bar' was added in contract ImplV1 in contracts/mocks/ImplV1.sol:1
This pushes all variables after bar to a higher position in storage, causing the updated contract to read incorrect initial values. Only add new variables at the end of your contract to prevent this issue.

Storage layout is extracted from the contract's AST by the Storage class in lib, and is stored along with other contract data (such as bytecode hash) in the zos.network.json file. It is then retrieved for comparison on the next zos push. The format is a tuple (storage, types), similar to the format discussed in ethereum/solidity#4017, where storage contains the array of variables, with references to the types dictionary with detailed info on each type.

Comparison is handled by the Layout class in lib, and uses a modified levenshtein algorithm for calculating the minimum change between both storages. Changes are identified as additions (either at the end or mid-contract, with additions at the end computed at zero cost for the algorithm), deletions (end or mid-contract), or substitutions (renames, typechanges, or both).

Fixes #37
Spawns issues #112, #113, and #114

TBD: Should we add a feature toggle to disable it until the 3 issues above are ready?

@facuspagnuolo
Copy link
Contributor

@spalladino I think we should add a warning message in case we indentify that an enum or a struct is being used, at least until #113 and #114 are solved. Do you agree?

@spalladino
Copy link
Contributor Author

I'm afraid it could be a bit annoying, since any warnings halt the push operation altogether. How about showing the warning, but letting the operation go through? And it's always reversible if something is indeed broken.

@facuspagnuolo
Copy link
Contributor

@spalladino yes, I meant to do it that way, I think that simply printing a message to let the user know we are not performing full validations on structs and enums is ok for now, otherwise it could be a false positive

@spalladino
Copy link
Contributor Author

@facuspagnuolo added the following warning:

- Variable foo4 (AnotherImplV1) contain a struct or enum type, which are not being compared for layout changes in this version. Double-check that the storage layout of these types was not modified in the updated contract. Read more at https://docs.zeppelinos.org/docs/advanced.html#preserving-the-storage-structure.

Copy link
Contributor

@facuspagnuolo facuspagnuolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Left some minor comments

const newVersion = this._newVersionRequired()
return _(this.packageFile.contracts)
.toPairs()
.filter(([contractAlias, _contractName]) => newVersion || !onlyChanged || this.hasContractChanged(contractAlias))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would mean that contracts of different versions are going to be always pushed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at least until we implement zeppelinos/zos-cli#94

import { getBuildArtifacts } from "../utils/BuildArtifacts";

export function getStorageLayout(contract, artifacts) {
if (!artifacts) artifacts = getBuildArtifacts();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this works for every scenario where this function is called, I'll remove the artifacts parameter.

Copy link
Contributor Author

@spalladino spalladino Sep 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TBH I'd rather keep it for simplicity of use. I wouldn't rule out extracting these methods for external usage, so I'd prefer the API to be as easy to use as possible.

@@ -50,6 +54,11 @@ export default {
return this._getFromPath(this.getNodeModulesPath(dependency, contractName))
},

listBuildArtifacts() {
const buildDir = this.getLocalBuildDir()
return glob.sync(`${buildDir}/*.json`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fs cannot solve this right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not at the moment. I could move it to fs later, though.

@spalladino spalladino added the status:ready-to-merge Order mergify to merge label Sep 25, 2018
@facuspagnuolo
Copy link
Contributor

@spalladino I think there are some integration tests failing, would you mind looking at them?

@spalladino
Copy link
Contributor Author

It was the StatusFetcher/StatusComparator, due to the PR we merged recently that re-enabled them. I'll look into this later, but I really want to get this PR merged!

@mergify mergify bot merged commit d382d04 into master Sep 26, 2018
@facuspagnuolo facuspagnuolo deleted the feature/check-storage-layout branch September 28, 2018 22:59
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status:ready-to-merge Order mergify to merge
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants