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

feat(forge verify-bytecode): support alternative block explorers + predeploys #8510

Merged
merged 42 commits into from
Aug 21, 2024

Conversation

zerosnacks
Copy link
Member

@zerosnacks zerosnacks commented Jul 24, 2024

Motivation

Resolves #8482 (excl. interaction error depending on #8549)

Adds --verifier and --verifier-url arguments

Solution

  • Adds support for all verification services supported by forge verify (excluding Sourcify, to be implemented in a follow-up) but opens the door for its future implementation.
  • Includes a significant refactor (structure, not logic) to more closely tie verify-bytecode into the existing verification abstraction by adding a verify_bytecode method to be called on the verifier. This should make it easier to maintain.
  • Moves verify command from lib into its own module.
  • Adds support for skipping verification of a particular bytecode type (creation | runtime) by using --ignore.
  • Support verifying predeployed/genesis contracts which do not have a creation tx. Methodology specified here: feat(forge verify-bytecode): support alternative block explorers + predeploys #8510 (comment)
  • Adds various tests

@zerosnacks
Copy link
Member Author

See: #8482 (comment), current PR does not address specific issue but is a strict improvement I feel.

@zerosnacks zerosnacks added this to the v1.0.0 milestone Jul 31, 2024
@zerosnacks zerosnacks added T-feature Type: feature C-forge Command: forge Cmd-forge-verify Command: forge verify-contract/check labels Jul 31, 2024
@yash-atreya
Copy link
Member

yash-atreya commented Aug 2, 2024

@zerosnacks @mattsse @mds1
I've uncovered an issue with the blockscout API. When trying to get the contract creation data such as, creator and creation tx hash, etherscan correctly returns the contract creator in case of a CREATE2 deployment. However, blockscout returns the default CREATE2 deployer address i.e 0x4e59b44847b379578588920ca78fbf26c0b4956c.

Try blockscout to get creation data of OP SystemConfig contract: https://eth.blockscout.com/api?module=contract&action=getcontractcreation&contractaddresses=0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1

VS

Try etherscan: https://api.etherscan.io/api?module=contract&action=getcontractcreation&contractaddresses=0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1&apiKey=YourApiKey

This breaks the fork simulation to get the runtime code, as the nonce is different from the actual contract creator. Verifying creation code still works though.

@yash-atreya
Copy link
Member

yash-atreya commented Aug 2, 2024

@zerosnacks @mattsse @mds1 I've uncovered an issue with the blockscout API. When trying to get the contract creation data such as, creator and creation tx hash, etherscan correctly returns the contract creator in case of a CREATE2 deployment. However, blockscout returns the default CREATE2 deployer address i.e 0x4e59b44847b379578588920ca78fbf26c0b4956c.

Try blockscout to get creation data of OP SystemConfig contract: https://eth.blockscout.com/api?module=contract&action=getcontractcreation&contractaddresses=0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1

VS

Try etherscan: https://api.etherscan.io/api?module=contract&action=getcontractcreation&contractaddresses=0xba2492e52F45651B60B8B38d4Ea5E2390C64Ffb1&apiKey=YourApiKey

This breaks the fork simulation to get the runtime code, as the nonce is different from the actual contract creator. Verifying creation code still works though.

Ref #8482 (comment), adding the --ignore makes much more sense now, but it is still a half-baked solution.

Moreover, adding the --ignore to run forge vb on genesis contracts, as suggested here #8482 (comment), is non-trivial since we depend upon the creation tx to run the fork sim and get runtime code. So doing --ignore creationcode, wouldn't work as runtime verification would fail with the current methodology.

What we could do is --ignore creationcode and then just directly try to match deployedBytecode from the artifact with the onchain runtime code instead of running and deploying on a fork. I think this would suffice your usecase of verifying predeployed contracts ?? @blmalone @mds1

Precendence: user provideded > explorer
@yash-atreya
Copy link
Member

yash-atreya commented Aug 9, 2024

@mds1 replying to #8510 (comment).

Regarding constructor args, let me play it back to verify my understanding.

Yeah that's mostly right.

If those two args are not provided, default to etherscan.

Except this part. We don't default to etherscan as this would require the user passing an etherscan API key even if they're using blockscout.

Additionally, when comparing runtime bytecode equivalence, do we skip immutable references?

By skipping immutables, do you mean we don't check the immutables that are embedded in the runtime code?
If yes, then NO; we do check them. Runtime codes are compared entirely.

@yash-atreya yash-atreya requested a review from klkvr August 9, 2024 10:14
@blmalone
Copy link

blmalone commented Aug 9, 2024

@yash-atreya on @mds1's comment:

Additionally, when comparing runtime bytecode equivalence, do we skip immutable references? If so, this can let users pass dummy constructor arguments and simplify UX further. I think either approach (skipping vs. not skipping immutables) is ok, I don't feel strongly here

This is something we've since chatted about internally and believe it'll be a very useful feature. Skipping immutable checking is super useful for checking the runtime code without the constructor args being needed.

By skipping immutables, do you mean we don't check the immutables that are embedded in the runtime code?
If yes, then NO; we do check them. Runtime codes are compared entirely.

Exactly.

@mds1
Copy link
Collaborator

mds1 commented Aug 9, 2024

@yash-atreya that all sounds good!

By skipping immutables, do you mean we don't check the immutables that are embedded in the runtime code?
If yes, then NO; we do check them. Runtime codes are compared entirely.

Got it, in general I think that's the better and stronger approach. To take a step further, you can do: if no constructor arguments are passed AND no API key is passed (so forge has no constructor args), then it skips checking immutables. That would help cases like #8617. In this case you would also want to include a message in the output indicating this difference

@yash-atreya
Copy link
Member

@mds1 @blmalone in favor of adding the feature of skipping immutable references, however as a follow on PR. The scope of this PR has already increased from supporting alternative block explorers to predeploys as well.

@klkvr please drop your final review and we can merge?

@blmalone
Copy link

@yash-atreya cool, we will look to test this asap 👍🏻

@yash-atreya yash-atreya changed the title feat(forge verify-bytecode): support alternative block explorers feat(forge verify-bytecode): support alternative block explorers + predeploys Aug 13, 2024
Copy link
Member

@klkvr klkvr left a comment

Choose a reason for hiding this comment

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

lgtm

pending conflict

@blmalone
Copy link

@yash-atreya @klkvr There seems to be a test failing that's preventing a merge here.

Copy link
Member

@mattsse mattsse left a comment

Choose a reason for hiding this comment

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

send it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-forge Command: forge Cmd-forge-verify Command: forge verify-contract/check T-feature Type: feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

feat(verify-bytecode): support using Blockscout instead of Etherscan
7 participants