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

Not upgrading if bytecode and creation code have not changed #2

Open
KholdStare opened this issue Nov 29, 2022 · 3 comments
Open

Not upgrading if bytecode and creation code have not changed #2

KholdStare opened this issue Nov 29, 2022 · 3 comments

Comments

@KholdStare
Copy link

KholdStare commented Nov 29, 2022

Hey!

I was wondering if there is a way to prevent re-deployment of code that basically has not changed (e.g. reformatting, adding comments, or changing function order). Currently those can cause false-positive storage incompatibilities with isUpgradeSafe. However, implementation address is the thing that is actually checked for a difference to know whether something is changed or not. There is no control over this, and a contract will get redeployed in this case.

Is there a way to see if implementation bytecode is identical (even if solidity code has slight cosmetic changes), and opt out of upgrading a contract in that case? I think solidity outputs different bytecode if the source changes (a section towards the end of the bytecode), I'm assuming for verification purposes. Any way to check only the implementation bytecode and no anything that depends on the source?

@0xPhaze
Copy link
Owner

0xPhaze commented Nov 30, 2022

The thing is that in that case, your bytecode will have changed, that's why it's re-deploying. As a quick fix, you can add the parameter keepExisting = true to setUpContract / setUpProxy and manually set it to false once you want to explicitly have new deployments (or use the global var UPGRADE_SCRIPTS_KEEP_EXISTING=true.
Also, be sure to compile the contracts without a metadata hash (foundry.toml setting: bytecode_hash = "none") which may change the bytecode due to comments being altered. Checking for functional equality of the code would be too hard to do.

And I would love to make the script detecting storage layout changes smarter by parsing the ast output or performing some other more in-depth storage analysis, but for the moment I don't feel knowledgable enough to catch odd edge cases. That's why it's better to err on the cautious side, but I might look into that more.

@KholdStare
Copy link
Author

KholdStare commented Nov 30, 2022

Thanks for pointing out the bytecode_hash = "none" option. Unfortunately we don't want to turn that off so that we can verify.

Here is my intuition - Currently because bytecode_hash = "ipfs" for verification purposes, the "overall" bytecode changes even when there are cosmetic changes. However let's say that the "implementation" portion of the bytecode, what is essentially generated when bytecode_hash = "none", remains unchanged. In these cases, it doesn't make sense to redeploy the contract.

I wonder if it would be possible in pseudocode:

function needsUpgrade() returns (bool) {
  if (oldImplementationAddress == newImplementationAddress) return false;

  console.log("Need upgrade");
  
  if (oldBytecodeWithoutHash == newBytecodeWithoutHash && UPGRADE_SCRIPTS_SKIP_METADATA_CHANGE) {
    console.log("Skipping upgrade because only metadata changed");
    return false;
  }

  return true;
}

Not sure if it's easily possible to get the bytecode of a contract without the hash inside upgrade scripts themselves.

Does it make sense?

@0xPhaze
Copy link
Owner

0xPhaze commented Dec 2, 2022

That does make sense.
https://docs.soliditylang.org/en/latest/metadata.html#encoding-of-the-metadata-hash-in-the-bytecode
I could match for that part and exclude it.

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

No branches or pull requests

2 participants