certora-fv-amenability: static FV-amenability scorer (phase 1)#87
Draft
shellygr wants to merge 13 commits into
Draft
certora-fv-amenability: static FV-amenability scorer (phase 1)#87shellygr wants to merge 13 commits into
shellygr wants to merge 13 commits into
Conversation
Foundation for a full pydantic model of the solc compact AST as dumped by certoraRun --dump_asts. schema/schema.json is the OpenZeppelin solidity-ast 0.4.62 JSON Schema (MIT, see schema/NOTICE); models will be hand-authored and machine-verified against it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…mance tests, fixtures 74 hand-authored pydantic v2 models (Solidity + Yul compact AST), discriminated unions with an UnknownNode fallback per union, single-point forward-ref rebuild, a loader for the 3-level --dump_asts structure (single-parse-per-source, Vyper raw passthrough, per-source degradation), traversal utilities incl. the frozen byte-compatible legacy parent-graph builder, a 151-case schema-conformance suite against the vendored schema, and real .asts.json fixtures generated via certoraRun for solc 0.6.12 / 0.7.6 / 0.8.30. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…olden test Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
setup_prover: declared-contracts and inheritance extraction go through a shared _iter_contract_declarations (typed find_all with a raw-scan fallback for sources the models cannot parse); generate_ast_graph delegates to the relocated byte-compatible parent-graph builder. auto_munges: .code detection iterates typed MemberAccess nodes (per-node raw salvage on unparsable sources) and decodes src offsets via parse_src. Parity with the legacy raw algorithms is pinned by tests/solidity_ast/test_consumer_migration.py on the real fixtures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…enums, cached loads Review findings addressed: iter_nodes_of_type gives typed-first iteration with a raw flat-map sweep for nodes the typed walk cannot reach (e.g. under an unknown future nodeType), used by both migrated consumers so no ContractDefinition or .code MemberAccess can be hidden; InlineAssembly.evmVersion/flags are open strings (a closed fork enum would demote whole files on the next solc release — conformance test carries the allowlisted deviation); .code patches now read and target the source file the offsets refer to (not the compilation unit's main file) and are deduplicated across units; the dump is loaded once per setup run via AstDump.load_cached; union tag sets got a drift-guard test. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
roundtrip_diffs() compares a re-serialized typed tree against the exact source JSON (model_dump with exclude_unset; the internalFunctionIDs de-stamping is the one reversed normalization). Wired into the __main__ validator (with a --json machine mode for corpus sweeps) and pinned on the committed fixtures. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Corpus-driven: real certoraRun fixtures for solc 0.4.26 and 0.5.17 exposed the full legacy dialect, now handled typed (no raw-dict fallback): lenient defaults for fields that did not exist yet (mutability, virtual, tryCall, kind, abstract), string-form documentation and ElementaryTypeNameExpression.typeName, the pre-0.6 InlineAssembly shape (operations text, keyed externalReferences, no Yul AST), file-level EventDefinition (solc >= 0.8.22, missing from the vendored schema), and modeled 0.4-era FunctionDefinition flags. Every deviation from the schema is machine-tracked in the conformance test (LENIENT_REQUIRED / DELIBERATELY_OPEN / FIELD_ALLOWLIST). All five fixtures hold the same strict invariants: fully typed parse, zero unknown nodes, zero unmodeled fields, exact round-trip. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the producing solc version is known, a gated field absent at or above its introduction gate fails the source instead of silently reading as None (crash over wrong results); fixtures now always parse with their version so the gates stay exercised. virtual is None below 0.6 (everything was implicitly overridable — False would mislead). effective_mutability/effective_kind derive the pre-gate values faithfully from constant/isConstructor without touching the serialized form. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Empirical solc ladder over every release 0.4.24-0.8.36 pinned the exact gate boundaries: FunctionCall.tryCall from 0.6.0 and InlineAssembly.evmVersion from 0.6.2 (both previously gated later, i.e. under-enforced). solc 0.7.2 alone omits isLValue on enum-member MemberAccess nodes — a bug window, present before and after, so it is lenient (None) rather than gated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…solidity_ast stream_ast_files's four call sites collapse into the typed layer: new AstDump.stream_units() (per-compilation-unit typed streaming with unit_filter and solc_version gates) and stream_raw_units() (raw pairs for the byte-compat parent-graph pass, which now accepts streamed units). All three consumers stream instead of whole-file loading; load_cached is gone (the memory win outweighs the shared parse), stream_ast_files removed with its purpose. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New module certora_autosetup/amenability implementing the FV-amenability metric: score how amenable a Solidity project is to automatic formal verification with autosetup — low (needs a full reference implementation), medium (scoped customization needed), or high (expected to pass as-is). Phase 1 is the deterministic static scorer, built on the typed solidity_ast package: twelve signals over the compact AST (inline-assembly density, free-memory-pointer manipulation, delegatecall trampolines, inline bit-mask surgery vs accessor encapsulation, function length, unchecked nonlinear arithmetic, mixed bitvector+nonlinear theory per function, curated-summary library hit-rate against setup/function_summaries.json, computed-slot storage access, low-level call surface, dynamic loops, and scene-shape normalizers). Aggregation is a weighted mean plus hard rules (per-signal caps, severe-count floor), all tunable in weights.yaml only. Every evidence item carries project-relative file:line. CLI: certora-fv-amenability <project_root> [--ast-dump PATH] — pure JSON in/out so SaaS/CI clients can invoke it directly. Compiling is a hard precondition: with no AST dump available the tool exits 1 with a distinct "does-not-compile" error object; there is deliberately no raw-source fallback scoring. Tests run against a committed dump of a self-authored bait contract that trips every signal (with a clean control contract that must trip none); scoring hard-rules and the CLI paths are covered end-to-end. Validated on a real protocol of the motivating class: it lands "low" with evidence pinpointing each hand-written pathology, while a benign fixture scores "high". Phase 2 (graphcore LLM judge over a versioned rubric) and phase 3 (calibration against labeled autosetup outcomes) follow separately. Co-Authored-By: Claude Fable 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.
What
New module
certora_autosetup/amenability/+ CLIcertora-fv-amenability: score how amenable a Solidity project is to automatic formal verification with autosetup —Phase 1 (this PR) is the deterministic static scorer. Phase 2 adds a graphcore-based LLM judge over a versioned rubric data file; phase 3 calibrates the weights against labeled autosetup outcomes. Both follow separately.
Note: branch is based on
shelly/solidity-ast-pydantic(#76) — this PR builds on the typed AST package and should land after it.How
Twelve signals over the typed compact AST (
solidity_ast.find_all/walk), each a pure functionAnalysisContext -> SignalResultwith a score in [0,1] (1 = amenable), raw counters, and evidence carrying project-relative file:line:asm_densityasm_fp_manipulationmstore(0x40, …)— free-memory pointer as a first-class objectasm_trampolinedelegatecallforwarding layersbitmask_stylefunction_lengthunchecked_nonlinearuncheckednonlinear arithmetic with symbolic operandsmixed_theorycurated_summary_hitsmulDiv/sqrt/… vs libraries with curated summaries (readssetup/function_summaries.json)storage_packingsload/sstoreon computed slots (incl. via Yul locals) — hand-rolled layouts that break storage analysisexternal_call_surfacedynamic_loopssurface_shapeAggregation = weighted mean + hard rules (high-severity findings from FP-manipulation / trampoline / storage-packing cap the level at medium; N severe signals force low). All weights and thresholds live in
weights.yaml— calibration never touches code.Compiling is a hard precondition: the CLI takes
--ast-dump(acertoraRun --dump_astsoutput) or discovers one under.certora_internal/; with neither it exits 1 with a distinctdoes-not-compileJSON error. There is deliberately no raw-source fallback.Testing
tests/test_amenability.py(19 tests) runs against a committed AST dump of a self-authored bait contract (tests/fixtures/amenability/signals_bait.sol):PackedBooktrips every signal on purpose — each per-signal test asserts detection, evidence anchoring, and function attribution — while theCleanVaultcontrol (incl. the good accessor-encapsulated bit pattern) must produce zero evidence. Scoring hard rules and both CLI exits are covered end-to-end. Regenerate the dump withtests/fixtures/amenability/generate.py(dev-only).pyright: 0 errors on the module.🤖 Generated with Claude Code