fix(deploy): make Blockscout verification work without an RPC and bound its runtime#55
Merged
Merged
Conversation
…nd its runtime
verify-blockscout.sh never verified anything for callers that don't export
ETH_RPC_URL, and could run for MAX_CHECKS*CHECK_DELAY seconds PER contract:
- --guess-constructor-args hard-fails without an RPC ("You have to provide a
valid RPC URL"), so every submission silently failed. Constructor args are
now derived offline from the broadcast file: creation tx input minus the
compiled creation bytecode (forge inspect), falling back to letting
Blockscout extract them when the prefix doesn't match.
- Bare contract names carry no compiler version, which forge also errors on;
the version is now read from the build artifact metadata.
- The status poll now runs in rounds across all pending contracts, bounding
the worst case at INITIAL_WAIT + MAX_CHECKS*CHECK_DELAY regardless of
contract count (previously ~100 minutes for a 20-contract deploy, which
blew every step timeout before a single check passed). Blind resubmits on
every failed check are gone.
- Some Blockscout deployments 301 to a canonical host (optimism.blockscout.com
-> explorer.optimism.io); forge's verification POST doesn't survive the
redirect, so the final host is resolved up front, and the status-poll curl
follows redirects.
- Submission responses are truncated in logs (some instances echo the entire
standard-json back, megabytes per contract).
Validated end-to-end against the 2026-07-11 crowdstake.fun deploys: all 20
broadcast contracts verified on Gnosis, Arbitrum, and Optimism Blockscout
with exit 0.
llvcianov
pushed a commit
to llvcianov/crowdstake.fun
that referenced
this pull request
Jul 19, 2026
The 'Verify on Blockscout' step has timed out after 5 minutes on every deploy run and never verified anything: etherform's verify-blockscout.sh passes --guess-constructor-args, which hard-fails without an RPC (the workflow exports RPC_URL, a variable forge doesn't read), and its per-contract retry loop has a ~100-minute worst case for a 20-contract deploy. Pin the etherform sparse-checkout to fix/blockscout-verify-hang (BreadchainCoop/etherform#55), which derives constructor args offline from the broadcast file and polls in bounded rounds. Repoint to main once that PR merges. Drop the now-unused RPC_URL env from the verify step and tune the polling (INITIAL_WAIT=30, CHECK_DELAY=20, MAX_CHECKS=6) to a 150s hard bound, well inside the 5-minute step timeout.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
verify-blockscout.shhas never successfully verified anything for consumers that don't exportETH_RPC_URL(e.g. crowdstake.fun's deploy workflow, which exportsRPC_URL— a variable forge doesn't read), and its retry loop is effectively unbounded:--guess-constructor-argshard-errors withYou have to provide a valid RPC URL to use --guess-constructor-args featurewhen no RPC is configured. The|| trueswallowed it, so Phase 1 submitted nothing.MAX_CHECKS × CHECK_DELAY= 300 s per contract. A 20-contract deploy has a ~100-minute worst case — the first contract alone blows a 5-minute step timeout, so the step gets killed before anything verifies. This is exactly what happened on crowdstake.fun runs 29133058331 / 29133083853 / 29133084514 (2026-07-11):The action 'Verify on Blockscout' has timed out after 5 minuteson every run, zero contracts verified.curl -sfstatus checks fail on the 301.Fix (interface unchanged:
BLOCKSCOUT_URL,BROADCAST_FILE,MAX_CHECKS,CHECK_DELAY,INITIAL_WAIT)inputminus the compiled creation bytecode (forge inspect <name> bytecode). No RPC needed at all. Falls back to letting Blockscout extract args from the creation tx if the prefix doesn't match (e.g. library placeholders).--compiler-versionfrom the build artifact metadata (forge inspect <name> metadata).-Lto the status-poll curl.INITIAL_WAIT + MAX_CHECKS × CHECK_DELAYregardless of contract count, with early exit when everything is verified. Dropped the blind resubmit-on-every-check.Validation
Ran the fixed script end-to-end against the 2026-07-11 crowdstake.fun
DeployCrowdStakeDeployerbroadcasts: all 20 broadcast contracts verified with exit 0 on each of:https://gnosis.blockscout.com)https://arbitrum.blockscout.com)https://optimism.blockscout.com→ auto-resolved toexplorer.optimism.io)including the redirect-host path and the constructor-args derivation for contracts with 1, 2, and 10 constructor arguments.
Note for consumers:
_deploy-testnet.ymlkeeps working unchanged (it exportedETH_RPC_URL, which is simply no longer needed). Callers with tight step timeouts can now tuneINITIAL_WAIT/CHECK_DELAY/MAX_CHECKSto a hard bound.