foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.1k stars 1.67k forks source link

feat(`verify-bytecode`): support using Blockscout instead of Etherscan #8482

Closed blmalone closed 2 weeks ago

blmalone commented 1 month ago

Component

Forge

Have you ensured that all of these are up to date?

What version of Foundry are you on?

forge 0.2.0 (e903484 2024-07-19T00:18:41.070490000Z)

What command(s) is the bug in?

forge verify-bytecode

Operating System

macOS (Apple Silicon)

Describe the bug

This is very important for Op Labs to get working.

I want to do bytecode verification on networks that don't have Etherscan setup. e.g. https://metalscan.io/ https://explorer.mode.network/

They seem to have BlockScout explorers and as far as I understand blockscout has made their api etherscan compatible i.e. https://docs.blockscout.com/for-users/api/rpc-endpoints

e.g.

const url = `https://${baseURL}/api?module=contract&action=getcontractcreation&contractaddresses=${contractAddress}`;

// where baseURL can be a blockscout URL OR an etherscan URL

Is this something I can configure with foundry?

blmalone commented 1 month ago

@yash-atreya Is this something that's possible right now or is this a feature request?

blmalone commented 1 month ago

@zerosnacks @yash-atreya bumping this 🙏🏻

zerosnacks commented 1 month ago

Hi @blmalone

I don't think it is currently supported but should be easy to add, happy to accept a PR for this

https://github.com/foundry-rs/foundry/blob/2544793db0896f8f34e661195f8ad90a76dfc279/crates/verify/src/lib.rs#L42-L52

https://github.com/foundry-rs/foundry/blob/2544793db0896f8f34e661195f8ad90a76dfc279/crates/verify/src/lib.rs#L147-L149

https://github.com/foundry-rs/foundry/blob/2544793db0896f8f34e661195f8ad90a76dfc279/crates/verify/src/lib.rs#L218-L245

Should be added in (or split out into a utility file to prevent code duplication)

https://github.com/foundry-rs/foundry/blob/2544793db0896f8f34e661195f8ad90a76dfc279/crates/verify/src/bytecode.rs#L105

Is this something you would like to work on?

mds1 commented 1 month ago

Hey @yash-atreya just confirming you are working on this? If so that would be a big help for us! 🙏

mds1 commented 1 month ago

Also just to confirm the issue here: I see https://book.getfoundry.sh/reference/config/etherscan says that we should be able to use:

[etherscan]
unknown_chain = { key = "ABCDEFG", url = "<etherscan api url for this chain>" }

to handle a case like this. @blmalone did this not work, and the scope of this issue is to make sure forge verify-bytecode picks that up? Or is native support for blockscout needed for another reason?

blmalone commented 1 month ago

When I change my foundry.toml to look like this:

[etherscan]
unknown_chain = { key = "", url = "https://explorer.mode.network/" }

and then I run the command:

forge verify-bytecode 0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010 L2StandardBridge --rpc-url https://mainnet.mode.network/ --json

I get the following error:

Response result is unexpectedly empty: status=1, message=OK

AFAIK, you can use https://explorer.mode.network/ like you can the Etherscan api e.g.

https://explorer.mode.network/api?module=account&action=txlist&address=0x4dbd4fc535ac27206064b68ffcf827b0a60bab3f&startblock=0&endblock=99999999&page=1&offset=1000&sort=desc&apikey=YourApiKeyToken

This isn't working for me, does the forge verify-bytecode command know about the etherscan property in the foundry.toml?

zerosnacks commented 1 month ago

Hey @yash-atreya just confirming you are working on this? If so that would be a big help for us! 🙏

@mds1 Yash will be out until the 27th so I re-assigned this to me given the priority, I previously assigned it to him as he is most familiar with this code. I'm aiming to get a PR up before tomorrow EOD.

ChiTimesChi commented 1 month ago

Hey @blmalone. I recall having some verification issues with blockscout when I was using a foundry.toml config. There were two non trivial things that might have been fixed since then, but that could help your case:

  1. The blockscout URL needs to end with "api?" (yes, that includes the question mark).
  2. The key is technically not required, but an empty string was giving me all kinds of troubles. Replacing it with some random string helped.

So that would look like this in your case:

[etherscan]
mode = { key = "GM", url = "https://explorer.mode.network/api?" }
zerosnacks commented 1 month ago

Was able to narrow down the error of Response result is unexpectedly empty: status=1, message=OK to

etherscan.contract_creation_data(args.address).await?

This is presumably because 0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010 is a special system contract initiated at Genesis that has no matching transaction hash and deployer address and is therefore not handled properly.

It might be possible to add a specific workaround for this edge case for you, open to suggestions.

Related code: https://github.com/foundry-rs/block-explorers/blob/d44051a4e5fd4a522739b3c2be6df6aeebca849b/crates/block-explorers/src/contract.rs#L454-L489 + https://github.com/foundry-rs/block-explorers/blob/d44051a4e5fd4a522739b3c2be6df6aeebca849b/crates/block-explorers/src/errors.rs#L29-L30

The message returned by Blockscout is "{\"message\":\"OK\",\"result\":[],\"status\":\"1\"}" with RUST_LOG=trace ETHERSCAN_API_KEY="A" forge verify-bytecode 0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010 L2StandardBridge --rpc-url "https://mainnet.mode.network"

zerosnacks commented 1 month ago

https://github.com/foundry-rs/foundry/pull/8510 is a draft PR that implements --verifier-url / --verifier (etherscan, sourcify, blockscout, oklink) support to forge verify-bytecode which should make it easier to pass alternative verifiers by CLI which I do think is a strict improvement but does not resolve your issue.

blmalone commented 1 month ago

@zerosnacks Thanks for looking into this.

This is presumably because 0xC0d3c0d3c0D3c0d3C0D3c0D3C0d3C0D3C0D30010 is a special system contract initiated at Genesis that has no matching transaction hash and deployer address and is therefore not handled properly.

It might be possible to add a specific workaround for this edge case for you, open to suggestions.

Good point, this is a predeploy contract and it's runtime code is set at genesis so there won't be a creation transaction.

On a related note, the fix for the following issue actually checks for a creation transaction in order to determine the constructor args: https://github.com/foundry-rs/foundry/issues/8545.

Supporting predeploy contracts would be super helpful for us and our ongoing work with delivering the Superchain at Op Labs.

Does having an additional flag that tells the forge vb command to only check either the runtime or init code provide a workaround that makes sense here? i.e. default to checking both init and runtime code but if a user says for example: forge vb ... ... --ignore initcode then only the runtime code will be checked.