Skip to content

feat(testing): run the full Sourcify corpus in shards behind ci:sourcify - #2183

Draft
nebasuke wants to merge 12 commits into
sourcify-corpus-v2from
sourcify-full-tier
Draft

nebasuke wants to merge 12 commits into
sourcify-corpus-v2from
sourcify-full-tier

Conversation

@nebasuke

@nebasuke nebasuke commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Three buckets of failure types:

  • Expected = yes. These are deliberately failing, e.g. us not supporting abicoder v1. These are safe to swallow for FUTURE contracts as well as they have a specific diagnostic attached.
  • Known failures (with issue ID), but a huge bucket. Unexpected failures, but too many to keep track of the contracts for now.
  • Known failures (with issue ID), but a small amount (<= 50). Here we keep track of the contracts, so we don't swallow future contracts that fail for the same error but in a different way.

Claude summary

Runs every verified solc 0.8.x contract on Sourcify (2,326,676 in the pinned release, 38 versions)
through run-corpus in eight shards, on the ci:sourcify label, on demand, and on pushes to
main that touch the v2 crates (the runner, its lock and its expected failures among them) or
the shared import resolver.

Shards from the lock file. corpus.lock now lists each per-version asset with its size,
contract count and sha256. lock shard --count N --index i bin-packs the assets by compressed
bytes, largest first onto the lightest shard, which tracks source text and therefore compile time
better than contract counts do: eight shards come out between 950 and 960 MB each without splitting
an asset, holding between 195k and 386k contracts. lock pr and lock release serve the PR tier
and the download, so the workflows parse nothing themselves.

One asset at a time. scripts/tasks/sourcify/run-assets.sh reads the asset lines, and for
each one downloads it from the release, checks the sha256, unpacks, runs run-corpus into one
JSONL per asset, and deletes it before the next. A shard's disk never holds more than one asset,
about 15 GB uncompressed for the largest. A failing asset does not stop the others.

Tasks, not YAML. task sourcify:build|testdata|pr|shard|report wrap the binary and the
script; sourcify_smoke.yml and the new sourcify_full.yml call them. The full workflow builds
once, fans out over the shard matrix, then one job restores every shard's JSONL and writes the
census, ending in the gate's verdict, to the job summary, an artifact and, on label runs, a sticky
PR comment. A failed gate is a result, not an error, so all three happen either way; a last Gate
step re-runs report --stale-check to fail the job.

Queue, don't cancel. The concurrency group has no cancel-in-progress, so a burst of merges
to main runs one census per merge, in order, and every commit keeps its own verdict.

Gated from the start. The first census over the whole corpus is triaged: every bucket is fixed in the
harness, tracked by an issue, or recorded as a deliberate divergence, so the report job fails on a new
bucket and on a listed one that stopped firing. An entry is keyed on the diagnostic code and narrowed
by a message prefix or a list of contracts where the code alone is too coarse; an issue-tracked entry
claiming 50 contracts or fewer must list them, so entries narrow as bugs get fixed. Deliberate
divergences on a dedicated code stay bucket-wide.

Resolver fixes (solidity_testing_utils::import_resolver, each with a unit test): a : inside
a Windows drive target was read as the context separator and the remapping dropped; ./ and ../
imports were remapped before being resolved against the importing file, so a ./=lib/ entry broke
every relative import; among matching remappings the longest prefix won where solc takes the longest
context first and, on a tie, the last one listed; a relative import from a URL source lost the port;
a remapping was not applied to the normalised relative path when an unremapped source happened
to exist; and an import spelled with // (utils//SafeERC20.sol) now resolves to that source
unit when the record also carries utils/SafeERC20.sol, as solc keeps them apart. Together these
were about 370 of the census's failures, spread over six buckets, and the harness no longer
prefixes a : to remappings itself.

Issues filed from the census, each with a repro the matching solc accepts and Slang rejects:
#2188 (override checks apply the solc 0.8.12 rule to 0.8.8–0.8.11, 194 contracts), #2189, #2190,
#2191 (three conditional-expression shapes), #2192 (duplicate indexed before 0.8.18), #2193
((msg, 'text');), #2194 (names hidden inside import cycles), #2195 (a constant imported through
two routes is ambiguous in assembly), #2253 (abi.decode(data, (address)) is address payable
in solc, exposed by #2185's conversion check), #2257 (an array literal of internal functions passed
to an overload). Conversions through a name an import cycle declares twice also fail under #2194
(16 contracts, noted there). #2149 covers the inherited-overload selector; #2179 (address-literal
overloads) and #2129 (receive-function buckets) are fixed and their entries gone.

Deliberate divergences, Bas's call each: pragma abicoder v1, pragma experimental SMTChecker,
a second abicoder pragma solc only rejects in one order, and the version pragmas solc's matcher
swallows (0.8.34.0, *0.8.7, ^0.8.1., ^0.8.20 - <0.8.31), and one event called without
emit, which solc before 0.8.4 let through after an emit of an overload of the same event. Two
entries record corpus artefacts that solc rejects too.

Retiring the tarball-based test command and the per-chain workflows is a separate PR after this
has run once; #2199, stacked on this, checks the ABI and storage layouts against the records'
artifacts.

Numbers

sourcify_full on CI (run 37973676027, this branch's head), eight shards, 15 minutes end to end:

contracts passed failed panicked
2,326,676 2,324,771 (99.92%) 1,905 0

21 buckets, all listed; the gate passes with --stale-check. The largest are pragma abicoder v1
(715, deliberate), #2149 (642), #2188 (194 over three codes) and the swallowed version pragmas
(137, deliberate).

@changeset-bot

changeset-bot Bot commented Sep 24, 2026 •

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: dbab9b0

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@nebasuke nebasuke added the ci:sourcify Runs Sourcify corpus for 0.8.x in a PR for Slang v2 label Sep 24, 2026
@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

🐰 Bencher Report

Branchsourcify-full-tier
Testbedci

⚠️ WARNING: Truncated view!

The full continuous benchmarking report exceeds the maximum length allowed on this platform.

🚨 2 Alerts

🐰 View full continuous benchmarking report in Bencher

@github-actions

github-actions Bot commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Sourcify corpus run for dbab9b0

contracts passed unexpected known issues deliberate panicked skipped
2326676 2324771 0 1005 900 0 0
  • Known issues per check: parse 4, bind 785, validate 216
  • Deliberate deviations per check: parse 870, bind 14, validate 19

Known issues

issue bucket contracts diagnostics examples message
#2149 bind:resolution/ambiguous-reference 642 1577 10_0x0218d22b2f134c5b3000dbcb768f71693238c856, 8453_0x1874152bf0b1cad19469c2ac0d9e51491c61830b, 8453_0x69cf9cf475d23aa68237aaa83d1fc5c88f0e8b87 No unique declaration found for 'execute'.
#2188 validate:semantic/missing-override-specifier 142 143 97_0x0e070ed600c6221b80a06a6fa3288f4f4d43e37a, 1_0x54275da4f379c5b8e6a90a453562c96f11e53830, 1_0x548f0034e8646d72c8ff7b46f604788929bc9f0b Overriding function is missing 'override' specifier.
#2194 bind:resolution/identifier-redeclaration 72 116 1_0x6b91713319be025dcb3b3a9f2c1ca70b465b5f9b, 56_0xfd09c6bcd60a9e3b83b8a1cf23236f28bf934efd, 11155111_0x010b00cd257d8b56fdde68e67cdcb17040feb06b Identifier already declared.
#2188 validate:semantic/overriding-non-virtual-member [32 listed] 32 47 97_0x30f6c7dc912fbb88e8f78c5c5ffacbc1db414e3f, 11155111_0xbc7a1b68d13c23f198b51640b87717b24e07d6c1, 100_0x237d4d7f9295a60d6b46421fa1a8af4d4416a7a5 Trying to override non-virtual function. Did you forget to add 'virtual'?
#2188 validate:semantic/override-visibility-differs [20 listed] 20 35 11155111_0xcdc564e19f0655ef129435fa42dc5beb26dcae5a, 1_0xd43be54c1aedf7ee4099104f2dae4ea88b18a249, 8453_0x1b4fae6e7464122ad8691abbf550647d92c5f092 Overriding function visibility differs.
#2194 bind:resolution/no-matching-callable-declaration [16 listed] 16 56 42220_0x05e9be6b03a64c6a0ff48b5bbc1d36fa058a7f5e, 42220_0x2d176d1fb534d2380168f2b91610c313609ed521, 42220_0x333d7dd86d9fc56a72e41d527374e85ee864b47d No matching declaration found after argument-dependent lookup.
#2257 bind:resolution/no-matching-callable-declaration [14 listed] 14 51 202601_0x02247eb911876cda8da99baf64e84ea68d6293d6, 202601_0x496c1bbf1150c5d8129393c5ecdcdf8a783a0f03, 202601_0x496fd88ecc6024a383edc7e8f1b636d2d342dab1 No matching declaration found after argument-dependent lookup.
#2150 bind:resolution/member-not-found [13 listed] 13 13 56_0x599547680f47d8596119452e4d44ff6659b7bf0d, 56_0x70e9d815984b6c9395975b5106151e86d6142bec, 1_0x1f58f1ba43a88b4ff3b4265449b26e28c08395ad Member 'standardize' not found or not visible after argument-dependent lookup.
#2189 validate:type-system/incompatible-conditional-branches [24 listed] 13 14 80002_0x053acb92ab46cfbf6fde6419c2e7e7e394557f80, 80002_0x5cc94047e4fe0266fd2686600d90511884b8c641, 80002_0x613d15a12136aa38b36c49976752b9bd30f30cec The true and false branches of this conditional expression have no common type.
#2259 bind:resolution/member-not-found [11 listed] 11 66 10_0x000000c9ec71b1a39055ec631200ed0022140074, 10_0x1fccc0807f25a58eb531a0b5b4bf3dce88808ed7, 10_0x7dffc9e7db5a96887666c1a6d215e5d3fb306d69 Member 'usingBatchTransfer' not found or not visible after argument-dependent lookup.
#2260 bind:resolution/member-not-found [11 listed] 11 23 252_0x0fd66456f10d9b850f37fa129236176b4f982864, 252_0x519bd566886a22f080c94b05ccc9f35902ec031b, 252_0xa46d25eebde2d136a14601ac2e0e0de8409114d1 Member 'exchange' not found or not visible after argument-dependent lookup.
#2195 bind:resolution/ambiguous-yul-reference [9 listed] 9 180 11155111_0x1322c8bfcbfb09fb9998245754d4dabe80756d3d, 11155111_0x8456aac7a9ccfd24c11aba831adcedd239053990, 10_0x1cfc4c4720504997bcdb86ee6ade450a2c48dcea Multiple matching identifiers for 'p'. Resolving overloaded identifiers is not supported.
#2251 bind:resolution/member-not-found [8 listed] 8 8 42161_0x0a3ae8b5a388d72ebf1e776fe7e5e0d98a61b474, 42161_0x4061106e15672785947c82fb9ae9c5fc67dc3fcf, 42161_0x5092808ad669e6064c74f1d2bc85bf096d3ee99f Member 'weightedSqrtPriceX96' not found or not visible after argument-dependent lookup.
#2253 validate:type-system/explicit-conversion-not-allowed [8 listed] 8 8 1_0x5be35b691f8275556b05ddf578e491a63c214889, 1_0xe4fe7c08f22de2db8edb31dee53ed30e88dbaf6c, 11155111_0x19bcd745544026e1b30b6331cabcc9c31a84a0a9 Explicit type conversion is not allowed from the argument's type to the target type.
#2261 bind:resolution/member-not-found [5 listed] 5 5 1_0x4b62ec784479c5520ec77de8d10c1a85d8f0850a, 11155111_0x2947e47abfd9b3de3c8667de04a45053ec4c19cf, 11155111_0x73998993d3d9a8aaff3fd2151a586a27ccf4b138 Member 'symbol' not found or not visible after argument-dependent lookup.
#2194 bind:resolution/identifier-not-found [4 listed] 4 4 97_0x08f0740c2ab229cefe40b12571652c7538f687f4, 97_0x60106f5a850ba3f94d7002a9c76a57d605012721, 97_0xe15ebd2609800e350cf3cd26c1d06afaeab08a8b Identifier not found.
#2192 parse:syntax/unexpected-terminal [Unexpected IndexedKeyword…] [4 listed] 4 4 1_0xd4559e5f507ed935f19208a5d50637898c192ab3, 137_0x19bdfecdf99e489bb4dc2c3dc04bdf443cc2a7f1, 137_0x5ed57b8f59f8d3bc805fc1087d8de93c78a87305 Unexpected IndexedKeyword. One of AtKeyword, CloseParen, Comma, ErrorKeyword, FromKeyword, GlobalKeyword, Identifier, LayoutKeyword, RevertKeyword, TransientKeyword was expected
#2193 validate:type-system/expression-not-a-value [1 listed] 1 1 80001_0x0c798de0dec0d17a33099d77149957dfe18905b0 This built-in cannot be used as a value.
Deliberate deviations (900 contracts)
bucket contracts narrowed to reason examples
parse:syntax/unsupported-abicoder-v1 715 pragma abicoder v1 selects the legacy ABI coder; Slang supports v2 only, on purpose. 1088_0x0000000000924fb1969e719eded2fed54afb183a, 1088_0x0000000009dc0fd7ba31d83a5d328b9bcaa0bc8d, 1_0x68c1c5ca6618611387242252887b6a5abd15319c
parse:syntax/incompatible-version-pragma 137 Four-component versions (pragma solidity 0.8.34.0;, ^0.8.17.0): solc's matcher ignores the fourth component, Slang rejects the malformed version on purpose. Every contract in this bucket has one. 43113_0x01365a11d5e977a8786330007b0884600450f528, 43113_0xf4bc57bee33f334ec5ee731be433ae4ce94bc538, 1_0x97ae13da39ba8f8b281a744308fa1b5ae302eb60
validate:structure/duplicate-abicoder-specifier 18 pragma abicoder v2 followed by pragma experimental ABIEncoderV2: solc only rejects the reverse order, Slang rejects any second selection. 1_0xd042a64eac89927fd92d1a5935e0e0cc30b2018c, 1_0xd9957a92d49d5207dd6c511954a5eb1c890f26b6, 137_0x93c9203ffd3b5416e6bf72959c673d9cde3f1e47
bind:resolution/member-not-found 13 [13 listed] Records solc rejects too when compiling all their sources: a broken file next to the target. 56_0x17414c35d28a6be093a945c70afd638dd5b726c0, 56_0x80e4dd3ba70dce6c58b7dc838dff9b02f1e4809b, 56_0x9d54c57f4c4c1e2cbee3b947fb5684313588c8d8
parse:syntax/unexpected-terminal 9 [Unexpected Pragma…] Version pragmas solc's matcher swallows (^0.8.1., ^0.8.20 - <0.8.31), rejected on purpose. 5_0x34855f952eb00dec7e2bd9ac5f201db364335817, 5_0xbf7101f4106f897cecf59eb858980d5a56695bd7, 4_0x1f9221158fccc919a0e91ae45e7ffdf3d618a5cb
parse:syntax/invalid-version-specifier 8 pragma solidity *0.8.7: solc's version matcher accepts the stray *, Slang rejects the malformed specifier. 11155111_0x1fe69747ab1118d3cc8f315d9c04652201b603e7, 11155111_0x0e1ee9797eceb77384733eb33a37ea39092c7e58, 97_0x4931459a69d855eeb5696796b0db8dcfcdc2d920
bind:resolution/identifier-not-library-name 1 [1 listed] Follow-on of the trailing-dot pragma rejected on purpose: a using directive naming a library from the file that failed to parse. 11155111_0x19e2b7829b7338f89b574289a29cc8b8ef7c4acb
bind:resolution/imported-declaration-not-found 1 [1 listed] Follow-on of a version pragma with a trailing dot (pragma solidity ^0.8.1.;), rejected on purpose: the file never parses, so nothing can be imported from it. 11155111_0x19e2b7829b7338f89b574289a29cc8b8ef7c4acb
bind:resolution/member-not-found 1 [1 listed] Follow-on of the trailing-dot pragma rejected on purpose: a member of the file that failed to parse. 11155111_0x19e2b7829b7338f89b574289a29cc8b8ef7c4acb
bind:resolution/no-matching-callable-declaration 1 [1 listed] An event called without emit, which solc before 0.8.4 missed after an emit of an overload of the same event. 3_0xd38232c64b617f89a4a7a16eab4ae869aa76c424
parse:syntax/unsupported-experimental-smt-checker 1 pragma experimental SMTChecker asks for a checker Slang does not ship; solc treats it as a no-op without a solver. 1_0xfd9cd8c0d18cd7e06958f3055e0ec3adbdba0b17
validate:semantic/linearisation-impossible 1 [1 listed] Not a divergence: this record bundles sources solc rejects for the same reason; the verified target is a single library. The harness compiles every file in a record, not the target's import closure. 56_0xfd09c6bcd60a9e3b83b8a1cf23236f28bf934efd

Gate: passed.

@nebasuke
nebasuke added this pull request to stack #2201 September 25, 2026 12:59
@nebasuke
nebasuke force-pushed the sourcify-full-tier branch from 34774e9 to 7e76dc6 Compare October 9, 2026 14:25
@nebasuke nebasuke removed the ci:sourcify Runs Sourcify corpus for 0.8.x in a PR for Slang v2 label Oct 9, 2026
The lock file now lists every per-version asset of the pinned release
with its size, and `lock shard` bin-packs them into shards by
compressed bytes, which tracks source text and so compile time better
than contract counts do: eight shards land within 1% of each other
without splitting an asset. A shard fetches, verifies, runs and deletes
one asset at a time, so its disk never holds more than one.

The workflow fires on the `ci:sourcify` label, on demand, and on pushes
to main that touch the v2 crates; main runs queue instead of cancelling
so every merge keeps its own verdict. The report stays report-only until
the first census is triaged into expected-failures.toml. Both workflows
now go through `task sourcify:*`, so the YAML carries no logic.
An empty dispatch value and a flow-style matrix; yamllint needs pipenv, which the sandbox lacks, so CI caught it.
Six gaps in the corpus import resolver, each worth a bucket of the
Sourcify census: a `:` inside a Windows drive target was read as the
context separator and the remapping dropped; `./` and `../` imports were
remapped before being resolved against the importing file, so `./=lib/`
broke every relative import; among matching remappings the longest
prefix won where solc takes the longest context first and, on a tie,
the last one listed; a relative import from a URL source lost its port;
and a remapping was skipped when a source happened to exist under the
unremapped name. About 370 contracts, spread over six diagnostic codes.
Every bucket of the first census over all 2,326,676 verified 0.8.x
contracts is now fixed in the harness, tracked by an issue with a repro
the matching solc accepts, or recorded as a deliberate divergence, so
the report job fails on a new bucket and on a listed one that stopped
firing. Issues from the census: #2188, #2189, #2190, #2191, #2192,
The full tier fired only on the label event, so a labelled PR had to be
relabelled after every push. It now runs on every push to a PR that
carries the label, skips unlabelled and fork PRs, and cancels a stale
PR run the way the benchmark workflows do; main pushes still queue.
A bucket keyed on the diagnostic code alone tolerated every future
occurrence of a generic code such as `identifier-not-found` because one
contract's follow-on failure was listed. An entry can now name a message
prefix and the contracts it covers; occurrences no entry matches are
unexpected. On the full corpus an issue-tracked entry claiming 50
contracts or fewer must list them, so an entry narrows as its bug gets
fixed. Deliberate divergences on a dedicated code stay bucket-wide.
#2175 fixed the misclassified `function receive(...)`, so its two
buckets no longer fire. #2185's explicit-conversion check exposes
#2253 on eight contracts: `abi.decode(data, (address))` is
`address payable` in solc.
#2184 fixed #2179; the 31 contracts left in its
`no-matching-callable-declaration` entry are an array literal of
internal functions passed to an overload (#2257), conversions through
a name an import cycle declares twice (#2194), and one event call
without `emit` that solc before 0.8.4 let through.
@nebasuke
nebasuke force-pushed the sourcify-full-tier branch from 8707da8 to f89ead7 Compare October 9, 2026 16:02
@nebasuke nebasuke added the ci:sourcify Runs Sourcify corpus for 0.8.x in a PR for Slang v2 label Oct 9, 2026
A failing gate is an expected outcome, but `report` only returned it
as an error after writing the census, so the job summary and the PR
comment after it were skipped and the sticky comment kept showing the
last green run. The verdict is now the report's closing section; the
Report step always runs with `--report-only`, and a final Gate step
re-runs `report` to fail the job. The smoke workflow writes its summary
before passing the PR tier's exit status on.
Collapsing `//` on both sides let `utils//SafeERC20.sol` resolve to
`utils/SafeERC20.sol` when a record carries both, so two library copies
solc keeps apart became one; the exact path now wins and the collapsed
comparison is only the fallback.
#2179 and #2180 are fixed; the 62 contracts left are #2150, #2251,
three new issues (#2259 private functions through `using` on a function
type, #2260 nested fixed-size arrays across locations in overloads,
#2261 a getter next to an inherited function), and records solc rejects
too when compiling all their sources.
…iberate

A failure asks something different of the reader depending on what
claims it: nothing (the gate fails), an issue (work to pick up) or a
deliberate entry (never to be fixed). The totals count each failing
contract once under its most urgent category, and the buckets come in
three tables in that order, the issue first in the work list and the
deliberate ones collapsed with their reasons. Everything is derived
from the gate's per-occurrence claims, so the report cannot disagree
with the verdict.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:sourcify Runs Sourcify corpus for 0.8.x in a PR for Slang v2

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant