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(verify-bytecode): support using Blockscout instead of Etherscan #8482

Closed
1 of 2 tasks
blmalone opened this issue Jul 19, 2024 · 11 comments · Fixed by #8510
Closed
1 of 2 tasks

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

blmalone opened this issue Jul 19, 2024 · 11 comments · Fixed by #8510
Assignees
Labels
C-forge Command: forge Cmd-forge-verify Command: forge verify-contract/check good first issue Good for newcomers T-bug Type: bug T-feature Type: feature
Milestone

Comments

@blmalone
Copy link

blmalone commented Jul 19, 2024

Component

Forge

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

  • Foundry
  • Foundryup

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 blmalone added the T-bug Type: bug label Jul 19, 2024
@blmalone
Copy link
Author

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

@blmalone
Copy link
Author

@zerosnacks @yash-atreya bumping this 🙏🏻

@zerosnacks zerosnacks added T-feature Type: feature C-forge Command: forge Cmd-forge-verify Command: forge verify-contract/check good first issue Good for newcomers labels Jul 22, 2024
@zerosnacks
Copy link
Member

Hi @blmalone

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

/// Verification provider arguments
#[derive(Clone, Debug, Parser)]
pub struct VerifierArgs {
/// The contract verification provider to use.
#[arg(long, help_heading = "Verifier options", default_value = "etherscan", value_enum)]
pub verifier: VerificationProviderType,
/// The verifier URL, if using a custom provider
#[arg(long, help_heading = "Verifier options", env = "VERIFIER_URL")]
pub verifier_url: Option<String>,
}

#[command(flatten)]
pub verifier: VerifierArgs,
}

let verifier_url = self.verifier.verifier_url.clone();
println!("Start verifying contract `{}` deployed on {chain}", self.address);
self.verifier.verifier.client(&self.etherscan.key())?.verify(self, context).await.map_err(|err| {
if let Some(verifier_url) = verifier_url {
match Url::parse(&verifier_url) {
Ok(url) => {
if is_host_only(&url) {
return err.wrap_err(format!(
"Provided URL `{verifier_url}` is host only.\n Did you mean to use the API endpoint`{verifier_url}/api` ?"
))
}
}
Err(url_err) => {
return err.wrap_err(format!(
"Invalid URL {verifier_url} provided: {url_err}"
))
}
}
}
err
})
}
/// Returns the configured verification provider
pub fn verification_provider(&self) -> Result<Box<dyn VerificationProvider>> {
self.verifier.verifier.client(&self.etherscan.key())
}

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

pub async fn run(mut self) -> Result<()> {

Is this something you would like to work on?

@zerosnacks zerosnacks changed the title Using Blockscout instead of Etherscan with 'forge verify-bytecode' feat(verify-bytecode): support using Blockscout instead of Etherscan Jul 23, 2024
@mds1
Copy link
Collaborator

mds1 commented Jul 23, 2024

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

@mds1
Copy link
Collaborator

mds1 commented Jul 23, 2024

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
Copy link
Author

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 zerosnacks assigned zerosnacks and unassigned yash-atreya Jul 23, 2024
@zerosnacks
Copy link
Member

zerosnacks commented Jul 23, 2024

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
Copy link
Contributor

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
Copy link
Member

zerosnacks commented Jul 24, 2024

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
Copy link
Member

zerosnacks commented Jul 24, 2024

#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.

@zerosnacks zerosnacks added this to the v1.0.0 milestone Jul 26, 2024
@blmalone
Copy link
Author

@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: #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.

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 good first issue Good for newcomers T-bug Type: bug T-feature Type: feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants