Skip to content

Improvements to proof-loading speed on reruns #308

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 21 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
359a066
.flake8, pyproject: ignore python files in forge submodule
ehildenb Jan 17, 2024
764fc50
.gitignore: ignore generate foundry files
ehildenb Jan 17, 2024
750a34e
pyproject.toml: exclude foundry test data in autoflake
ehildenb Jan 17, 2024
1387d5f
kontrol/foundry: avoid opening all versions of proofs when only one c…
ehildenb Jan 17, 2024
288c037
kontrol/foundry: more debugging information, variable renames, expand…
ehildenb Jan 18, 2024
c723be5
kontrol/{solc_to_k,prove}: add properties {Method,Constructor}.is_{te…
ehildenb Jan 18, 2024
b02d222
kontrol/prove: rename internal function run_prover => _run_prover to …
ehildenb Jan 19, 2024
4e209b2
kontrol/prove: remove deadcode
ehildenb Jan 22, 2024
5b03bb8
kontrol/prove: avoid setting up kore-server for proofs that are loade…
ehildenb Jan 22, 2024
f86b519
Set Version: 0.1.126
rv-auditor Jan 22, 2024
fe71c73
kontrol/prove: formatting
ehildenb Jan 22, 2024
cf2cc76
Set Version: 0.1.127
rv-auditor Jan 22, 2024
7eb7335
Merge branch 'master' into repo-cleanup
ehildenb Jan 23, 2024
e9c7667
Set Version: 0.1.128
rv-auditor Jan 23, 2024
bf365a6
Revert "kontrol/{solc_to_k,prove}: add properties {Method,Constructor…
ehildenb Jan 23, 2024
ed9b806
kontrol/foundry: correctly interpret % in proof directory name
ehildenb Jan 23, 2024
b6f4d06
Set Version: 0.1.129
rv-auditor Jan 23, 2024
f3e3fb7
Merge branch 'master' into repo-cleanup
ehildenb Jan 23, 2024
3271bef
Set Version: 0.1.129
rv-auditor Jan 23, 2024
59ff384
Merge branch 'master' into repo-cleanup
anvacaru Jan 24, 2024
07d26d7
Set Version: 0.1.130
rv-auditor Jan 24, 2024
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
2 changes: 2 additions & 0 deletions .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ extend-ignore = B950,E,W1,W2,W3,W4,W5
per-file-ignores =
*/__init__.py: F401
type-checking-strict = true
exclude =
src/tests/integration/test-data
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
/dist/
__pycache__/
.coverage
src/tests/integration/test-data/foundry/cache
src/tests/integration/test-data/foundry/lib
src/tests/integration/test-data/foundry/out
2 changes: 1 addition & 1 deletion package/version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.129
0.1.130
4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"

[tool.poetry]
name = "kontrol"
version = "0.1.129"
version = "0.1.130"
description = "Foundry integration for KEVM"
authors = [
"Runtime Verification, Inc. <[email protected]>",
Expand Down Expand Up @@ -48,10 +48,12 @@ remove-all-unused-imports = true
ignore-init-module-imports = true
remove-duplicate-keys = true
remove-unused-variables = true
exclude = "src/tests/integration/test-data"

[tool.black]
line-length = 120
skip-string-normalization = true

[tool.mypy]
disallow_untyped_defs = true
exclude = "src/tests/integration/test-data"
2 changes: 1 addition & 1 deletion src/kontrol/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
if TYPE_CHECKING:
from typing import Final

VERSION: Final = '0.1.129'
VERSION: Final = '0.1.130'
43 changes: 21 additions & 22 deletions src/kontrol/foundry.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,15 @@ def matching_sigs(self, test: str) -> list[str]:
test_sigs = self.matching_tests([test])
return test_sigs

def get_test_id(self, test: str, id: int | None) -> str:
matching_proofs = self.proofs_with_test(test)
if not matching_proofs:
raise ValueError(f'Found no matching proofs for {test}.')
if id is None:
if len(matching_proofs) > 1:
raise ValueError(
f'Found {len(matching_proofs)} matching proofs for {test}. Use the --version flag to choose one.'
)
test_id = single(matching_proofs).id
return test_id
else:
for proof in matching_proofs:
if proof.id.endswith(str(id)):
return proof.id
raise ValueError('No proof matching this predicate.')
def get_test_id(self, test: str, version: int | None) -> str:
matching_proof_ids = self.proof_ids_with_test(test, version)
if len(matching_proof_ids) == 0:
raise ValueError(f'Found no matching proofs for {test}:{version}.')
if len(matching_proof_ids) > 1:
raise ValueError(
f'Found {len(matching_proof_ids)} matching proofs for {test}:{version}. Use the --version flag to choose one.'
)
return single(matching_proof_ids)

@staticmethod
def success(s: KInner, dst: KInner, r: KInner, c: KInner, e1: KInner, e2: KInner) -> KApply:
Expand Down Expand Up @@ -379,13 +372,19 @@ def help_info() -> list[str]:
)
return res_lines

def proofs_with_test(self, test: str) -> list[Proof]:
proofs = [
self.get_optional_proof(pid)
for pid in listdir(self.proofs_dir)
if re.search(single(self._escape_brackets([test])), pid.split(':')[0])
def proof_ids_with_test(self, test: str, version: int | None = None) -> list[str]:
regex = single(self._escape_brackets([test]))
all_proof_ids: list[tuple[str, str, int]] = []
for pid in listdir(self.proofs_dir):
proof_dir = '%'.join(pid.split('%')[0:-1])
proof_name = pid.split('%')[1].split(':')[0]
proof_version = int(pid.split(':')[1])
all_proof_ids.append((proof_dir, proof_name, proof_version))
proof_ids = [
(pd, pn, pv) for pd, pn, pv in all_proof_ids if re.search(regex, pn) and (version is None or version == pv)
]
return [proof for proof in proofs if proof is not None]
_LOGGER.info(f'Found {len(proof_ids)} matching proofs for {regex}:{version}: {proof_ids}')
return [f'{pd}%{pn}:{pv}' for pd, pn, pv in proof_ids]

def get_apr_proof(self, test_id: str) -> APRProof:
proof = Proof.read_proof_data(self.proofs_dir, test_id)
Expand Down
23 changes: 10 additions & 13 deletions src/kontrol/prove.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,30 +86,30 @@ def foundry_prove(
for test in constructor_tests:
test.method.update_digest(foundry.digest_file)

def run_prover(test_suite: list[FoundryTest]) -> list[APRProof]:
def _run_prover(_test_suite: list[FoundryTest]) -> list[APRProof]:
return _run_cfg_group(
tests=test_suite,
tests=_test_suite,
foundry=foundry,
prove_options=prove_options,
rpc_options=rpc_options,
)

if prove_options.run_constructor:
_LOGGER.info(f'Running initialization code for contracts in parallel: {constructor_names}')
results = run_prover(constructor_tests)
results = _run_prover(constructor_tests)
failed = [proof for proof in results if not proof.passed]
if failed:
raise ValueError(f'Running initialization code failed for {len(failed)} contracts: {failed}')

_LOGGER.info(f'Running setup functions in parallel: {setup_method_names}')
results = run_prover(setup_method_tests)
results = _run_prover(setup_method_tests)

failed = [proof for proof in results if not proof.passed]
if failed:
raise ValueError(f'Running setUp method failed for {len(failed)} contracts: {failed}')

_LOGGER.info(f'Running test functions in parallel: {test_names}')
results = run_prover(test_suite)
results = _run_prover(test_suite)
return results


Expand Down Expand Up @@ -186,6 +186,10 @@ def _run_cfg_group(
rpc_options: RPCOptions,
) -> list[APRProof]:
def init_and_run_proof(test: FoundryTest) -> APRFailureInfo | None:
if Proof.proof_data_exists(test.id, foundry.proofs_dir):
apr_proof = foundry.get_apr_proof(test.id)
if apr_proof.passed:
return None
start_server = rpc_options.port is None
with legacy_explore(
foundry.kevm,
Expand Down Expand Up @@ -600,8 +604,6 @@ def _init_cterm(
'STORAGESLOTSET_CELL': KApply('.Set'),
}

constraints = None

if calldata is not None:
init_subst['CALLDATA_CELL'] = calldata

Expand All @@ -616,12 +618,7 @@ def _init_cterm(
init_term = Subst(init_subst)(empty_config)
init_cterm = CTerm.from_kast(init_term)
init_cterm = KEVM.add_invariant(init_cterm)
if constraints is None:
return init_cterm
else:
for constraint in constraints:
init_cterm = init_cterm.add_constraint(constraint)
return init_cterm
return init_cterm


def _final_cterm(
Expand Down
4 changes: 2 additions & 2 deletions src/tests/integration/test_foundry_prove.py
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ def test_foundry_merge_nodes(foundry: Foundry, bug_report: BugReport | None, ser


def check_pending(foundry: Foundry, test: str, pending: list[int]) -> None:
proofs = foundry.proofs_with_test(test)
proofs = [foundry.get_optional_proof(pid) for pid in foundry.proof_ids_with_test(test)]
apr_proofs: list[APRProof] = [proof for proof in proofs if type(proof) is APRProof]
proof = single(apr_proofs)
assert [node.id for node in proof.pending] == pending
Expand Down Expand Up @@ -378,7 +378,7 @@ def test_foundry_remove_node(
node=4,
)

proof = single(foundry.proofs_with_test(test))
proof = foundry.get_optional_proof(single(foundry.proof_ids_with_test(test)))
assert type(proof) is APRProof
assert proof.pending

Expand Down