autosetup: converge the compilation-workaround loop instead of timing out - #134
Open
shellygr wants to merge 3 commits into
Open
autosetup: converge the compilation-workaround loop instead of timing out#134shellygr wants to merge 3 commits into
shellygr wants to merge 3 commits into
Conversation
A contract pinned to an absent compiler was rewritten to whichever compiler was default, regardless of what its pragma allows. For an exact pragma the rewrite cannot compile, so the next pass re-detects the mismatch and re-pins — the two workarounds undo each other until the retry budget or the job timeout ends it. The fallback is now a per-contract plan: each pinned contract is offered only compilers its pragma admits, and an unreadable or unparseable pragma still takes the first candidate. When a contract has no viable substitute the run raises UnsatisfiableSolcPinError naming the contract, its pragma and the binary to install, instead of retrying a substitution that cannot work. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The loop compares each pass against its own starting state, so it only notices a pass that changed nothing. Two workarounds that undo each other each change the conf relative to their own baseline, and alternate across passes, so the loop runs to the retry budget — one full certoraRun per pass. Record every (workaround, conf delta) applied in the run. A pass whose changes have all been made before means something is undoing them, so stop there and name them. A pass that also lands a new change is still converging and continues. missing_library_harness is exempt via progress_outside_conf: regenerating its harness covers one more library each time, which is real progress the conf does not show. Its own _harnessed_libs guard bounds it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Six defects found by review of the two commits below it: - Candidate order put whatever `solc` is on PATH ahead of the project's own default, so a wide pragma could pick an unrelated compiler. The default now comes first and plain solc is the last resort. - A non-UTF-8 source (an accented byte in a header comment) raised out of read_pragma_from_source_file and killed the loop; it now reads as an unknown pragma. - parse_pragma_constraint understands `=X.Y.Z` and `~X.Y.Z`, and reports a disjunction as unknown rather than mis-parsing it. - The terminal raise is gated on a pin the conf actually carries, so a pin seeded from the default compiler no longer fails the run. - certora-fixconf reports the unsatisfiable pin and still writes back the fixes already applied, instead of exiting on a traceback. - The change ledger is scoped to one run of the loop: fixconf runs it twice on one manager, and the second run may legitimately re-apply the first's changes. An exempt workaround no longer vetoes repeat detection for the whole pass — it only keeps its own changes out of the ledger. The note on missing_library_harness now states what its guard keys on and that max_retries is what bounds it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
The incident
A corpus project mixing
pragma solidity 0.6.4;(37 files) and0.8.17(16 files) burned a full60-minute job timeout in the compilation-workaround loop without ever converging:
solc6.4is not installed. The fallback was version-blind — it rewrote every contract pinned to themissing binary to whatever compiler was default, with no reference to the pragma — so the
substitution could never compile and the mismatch detector re-pinned it every pass.
The existing guard could not see this: it compares a pass against its own starting state, so it
only catches a pass that changed nothing. Two workarounds that undo each other each change the conf
relative to their own baseline, and they alternate across passes.
The fixes
1. The fallback is a per-contract plan. Each contract pinned to the missing binary is offered
only compilers its pragma admits (
pragma_admits->True/False/None, whereNonemeansthe spec could not be parsed and is treated as no evidence). When a contract has no viable
substitute the run raises
UnsatisfiableSolcPinErrornaming the contract, its pragma and the binaryto install, rather than retrying a substitution that cannot work.
2. A change ledger, as the general backstop. Every apply records
(workaround, conf delta)forthe run. A pass whose changes have all been made before means something is undoing them, so the loop
stops and names them; a pass that also lands a new change is still converging. The delta deliberately
excludes the previous value — otherwise each half of an A-undoes-B cycle looks novel forever.
The regression test drives the real shape — missing pin, substitute, re-pin — with the pragma
unreadable so the pragma guard deliberately does not apply: 3 compiles instead of 273.
Review
An adversarial review of the first two commits confirmed six defects, all fixed in
311ea7eandcovered by tests: candidate ordering preferring an unrelated PATH
solcover the project default; aUnicodeDecodeErrorcrash on a non-UTF-8 source;=X.Y.Z/~X.Y.Z/ disjunction pragma spellings;the terminal raise firing on a pin autosetup seeded itself;
certora-fixconfexiting on a tracebackand losing the fixes it had already written; and the ledger persisting across the two loop runs
fixconf makes on one manager.
Known, not fixed here
missing_library_harnesscascades into nestedFooHarnessHarness...harnesses when a link errorrecurs, because its
_harnessed_libsguard is keyed on the consumer name and the same apply replacesthat name with the harness's. It is bounded only by
max_retries. Pre-existing and independent ofthese commits (reproduced with the ledger disabled); the comment no longer claims that guard bounds
it. Worth its own change.
517 passed, 9 skipped; pyright clean.🤖 Generated with Claude Code