Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion certora_autosetup/autosetup/autosetup.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,10 @@ def run(self, main_contract_handle: ContractHandle, skip_warmup: bool = False) -
# Step 5: Generate the user-facing sanity spec at certora/specs/sanity-{C}.spec.
# It directly imports the summary aggregator, call resolution, and (when present) erc7201.
# Must run after ERC-7201 detection (in setup_prover) so the erc7201 import is included.
self.rule_generator.generate_sanity_specs({main_contract_name: summary_spec_path})
self.rule_generator.generate_sanity_specs(
{main_contract_name: summary_spec_path},
reset_call_resolution_spec=not self.config.skip_call_resolution,
)

# Step 6: Load bytes mappings
self._load_bytes_mappings()
Expand Down
15 changes: 13 additions & 2 deletions certora_autosetup/setup/sanity_rule_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,24 @@ def __init__(self, certora_dir: Path, log_func: Callable[..., None] | None = Non
self.certora_dir = certora_dir
self.log = log_func if log_func else lambda msg, level="INFO": print(f"[{level}] {msg}")

def generate_sanity_specs(self, per_contract_summaries_specs: Dict[str, Path]) -> None:
def generate_sanity_specs(
self,
per_contract_summaries_specs: Dict[str, Path],
reset_call_resolution_spec: bool = False,
) -> None:
"""Create per-contract sanity specs at certora/specs/sanity-{C}.spec.

Each spec is the bundled sanity.spec body with three imports prepended:
summary aggregator, call-resolution, and (when present) erc7201. Skip-if-exists
so user edits survive re-runs. Also touches an empty call-resolution
spec so the import resolves before call_resolution.py runs.

When ``reset_call_resolution_spec`` is set, the call-resolution spec is emptied
even if it already exists. It is a generated artifact that call_resolution.py
rewrites during warmup; a stale, populated one left over from a previous run
would be typechecked (via the sanity spec's import) against the freshly-trimmed
base config before call resolution regenerates it, failing with
"<contract> does not exist". Callers pass this whenever call resolution will run.
"""
sanity_template = self.certora_dir / "sanity.spec"
if not sanity_template.exists():
Expand All @@ -49,7 +60,7 @@ def generate_sanity_specs(self, per_contract_summaries_specs: Dict[str, Path]) -

call_res_spec = user_call_resolution_spec_path(project_root, contract_name)
call_res_spec.parent.mkdir(parents=True, exist_ok=True)
if not call_res_spec.exists():
if reset_call_resolution_spec or not call_res_spec.exists():
call_res_spec.write_text("")

if target_spec.exists():
Expand Down
Loading