fix(plugin): keep injected artifacts within the localStorage quota - #12
Merged
MatiasOS merged 2 commits intoSep 11, 2026
Merged
Conversation
Every injected artifact carried its whole build info - the full solc standard JSON input, with every source in the compilation job - and contracts compiled in the same job each carried their own copy. Once a project pulls in OpenZeppelin or forge-std, that runs to megabytes per contract and the localStorage write in the served page fails on quota. A local chain has no Sourcify or Etherscan fallback, so every deployed contract then shows as unverified. The explorer reads four scalar fields of it: solcVersion, solcLongVersion, input.language and input.settings.evmVersion. Source resolution still falls back to input.sources, so both loaders now keep the parsed build info local, resolve the source against it, and attach only those four fields. With forge-std's Test.sol imported into the example project's Counter, the payload injected for three deployments drops from 1.6M characters to 5.6K. Refs openscan-explorer/explorer#402
A failed injection was invisible in the terminal and vague in the browser: the inline script reduced any error to a generic console warning, and the previous value stayed in localStorage. Hardhat derives deployment addresses from deployer and nonce, so after a redeploy a new contract could pick up an old contract's ABI and source. Remove the key before writing it, so a failed write leaves nothing behind, and put the error name in the browser warning so QuotaExceededError is recognisable at a glance. Warn in the terminal, once per process, when the serialised payload passes 2M characters - roughly where the tightest localStorage quotas give out. Refs openscan-explorer/explorer#402
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.
Part of openscan-explorer/explorer#402: the plugin half. The explorer's own ingestion paths (dev server, ZIP import) have the same problem and follow in a separate PR.
Problem
The plugin hands artifacts to the explorer by inlining a script into
index.htmlthat writes them tolocalStorage["OPENSCAN_ARTIFACTS_JSON_V1"]. Every artifact carried its entire build info — the full solc standard JSON input, with every source in the compilation job — and contracts compiled in the same job each carried their own copy.On a project of realistic size that outgrows the browser's
localStoragequota.setItemthrowsQuotaExceededError, the inlinecatchreduces it to a genericconsole.warn, and the explorer finds no local artifact for any address. A local chain has no Sourcify/Etherscan fallback, so every deployed contract shows as unverified, and nothing in the terminal hints at why. A failed write also left the previous value in place, so after an earlier deploy the explorer could map stale artifacts onto reused deterministic addresses.Fix
Trim build info to what the explorer reads (
artifacts.ts,deployment-tracker.ts). The explorer reads four scalar fields ofbuildInfo:solcVersion,solcLongVersion,input.languageandinput.settings.evmVersion. That holds on explorermainand in the1.2.5-alphabundle this plugin pins (checked innode_modules/@openscan/explorer/assets). A newtoExplorerBuildInfokeeps exactly those. Both loaders now parse the build info into a local, runresolveSourceCodeagainst it (the #399 fallback still needsinput.sources), then attach only the trimmed fields.ArtifactData.buildInfois typed asExplorerBuildInfoinstead ofunknown.No explorer change or release is needed: every field it reads is still there.
Harden the injection (
services/webapp.ts):removeItembeforesetItem, so a failed write leaves the key empty instead of holding the previous deploy's artifacts.QuotaExceededErroris recognisable at a glance.Size reduction
Measured on the example project with forge-std's
Test.soltemporarily imported intoCounter.sol(not committed), soCounterandTestTokenshare a ~800K-character build info. Deployed via Ignition and viascripts/deploy.ts, then read the payload straight from the servedindex.html:Bytes shrink more than characters. Before, 20 non-Latin-1 characters from the forge-std sources made Chromium store the whole value as UTF-16 (2 bytes per character); after, none remain and it is stored at 1 byte per character.
buildInfobefore → afterCounter(Ignition)Counter(raw deploy,DeploymentTracker)TestToken(Ignition)TestToken's build info was already small, so what remains of its entry is mostly ABI and source. The trimmedbuildInfois a constant 134 characters however large the compilation job is and however many contracts share it, so the saving grows with project size. This fixture stays under Chromium's quota even before the fix: it demonstrates the reduction, not the quota failure itself.Verification
sourceCodeis still present for every entry after the trim.0.8.29+commit.ab55807cand EVM versioncancun.localStorageholds the 5,613-character value, and there is no[openscan] Failed to inject artifactswarning.WebappService: a small payload prints no warning, an oversized one prints exactly one across repeated page loads, and the script removes the key before setting it and logs the error name.pnpm buildandpnpm lintpass.Not included
injectDevArtifacts) and the ZIP import attach the full build info through their own paths. Normalising insidesaveJsonFilesToStoragebelongs in the explorer repo, as does the drag-and-drop import that stores"undefined".testscript, as noted in fix(plugin): resolve contract sources from nested directories #11.