certora-cli-alpha-master 20241216.19.20.76131__tar.gz → 20241219.20.36.174596__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {certora_cli_alpha_master-20241216.19.20.76131/certora_cli_alpha_master.egg-info → certora_cli_alpha_master-20241219.20.36.174596}/PKG-INFO +2 -2
- certora_cli_alpha_master-20241219.20.36.174596/README.md +1 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraBuild.py +11 -1
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraCloudIO.py +95 -47
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraConfigIO.py +7 -3
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraContext.py +23 -65
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraContextAttributes.py +51 -36
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraContextValidator.py +13 -15
- certora_cli_alpha_master-20241219.20.36.174596/certora_cli/EVMVerifier/certoraParseBuildScript.py +36 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraType.py +1 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/mutateApp.py +16 -7
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/certoraUtils.py +8 -10
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/certoraValidateFuncs.py +14 -7
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/certoraRun.py +3 -5
- certora_cli_alpha_master-20241219.20.36.174596/certora_cli/certoraSolanaProver.py +153 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/rustMutator.py +135 -77
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596/certora_cli_alpha_master.egg-info}/PKG-INFO +2 -2
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli_alpha_master.egg-info/SOURCES.txt +2 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli_alpha_master.egg-info/entry_points.txt +1 -0
- certora_cli_alpha_master-20241219.20.36.174596/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_jars/Typechecker.jar +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/setup.py +4 -3
- certora_cli_alpha_master-20241216.19.20.76131/README.md +0 -1
- certora_cli_alpha_master-20241216.19.20.76131/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/LICENSE +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/MANIFEST.in +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_bins/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollector.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollectorFactory.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollectorSol.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollectorSolBased.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollectorVy.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/CompilerCollectorYul.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/Compiler/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraBuildCacheManager.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraBuildDataClasses.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraCollectRunMetadata.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraCompilerParameters.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraContextClass.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraContractFuncs.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraExtensionInfo.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraJobList.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraMiniSpecParser.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraNodeFilters.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraSourceFinders.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EVMVerifier/certoraVerifyGenerator.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/equivCheck.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/mutateAttributes.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/mutateConstants.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/mutateUtil.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Mutate/mutateValidate.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/ExpectedComparator.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/certoraAttrUtil.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/Shared/certoraLogging.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/certoraEqCheck.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli/certoraMutate.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli_alpha_master.egg-info/dependency_links.txt +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli_alpha_master.egg-info/requires.txt +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_cli_alpha_master.egg-info/top_level.txt +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/certora_jars/__init__.py +0 -0
- {certora_cli_alpha_master-20241216.19.20.76131 → certora_cli_alpha_master-20241219.20.36.174596}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: certora-cli-alpha-master
|
3
|
-
Version:
|
3
|
+
Version: 20241219.20.36.174596
|
4
4
|
Summary: Runner for the Certora Prover
|
5
5
|
Home-page: https://pypi.org/project/certora-cli-alpha-master
|
6
6
|
Author: Certora
|
@@ -23,4 +23,4 @@ Requires-Dist: StrEnum
|
|
23
23
|
Requires-Dist: tomli
|
24
24
|
Requires-Dist: universalmutator
|
25
25
|
|
26
|
-
Commit
|
26
|
+
Commit a0a7788. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
@@ -0,0 +1 @@
|
|
1
|
+
Commit a0a7788. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
@@ -1577,7 +1577,17 @@ class CertoraBuildGenerator:
|
|
1577
1577
|
while queue:
|
1578
1578
|
pop = queue.pop(0)
|
1579
1579
|
if isinstance(pop, dict) and node_id_attrb in pop:
|
1580
|
-
|
1580
|
+
idAttr = pop[node_id_attrb]
|
1581
|
+
if isinstance(idAttr, int):
|
1582
|
+
container[int(idAttr)] = pop
|
1583
|
+
elif isinstance(idAttr, list) and len(idAttr) == 1 and isinstance(idAttr[0], int):
|
1584
|
+
# In the bug reported in https://certora.atlassian.net/browse/CERT-7643 the id field is a list
|
1585
|
+
# instead of a single integer - we except that the first element of the list is the actual id
|
1586
|
+
# and unpack it.
|
1587
|
+
container[int(idAttr[0])] = pop
|
1588
|
+
else:
|
1589
|
+
raise Exception(f"Unexpected type of attribute `{node_id_attrb}`, was {idAttr}, expected an integer or an int-typed list of length 1")
|
1590
|
+
|
1581
1591
|
for key, value in pop.items():
|
1582
1592
|
if (node_type_attrb in pop and
|
1583
1593
|
pop[node_type_attrb] == "InlineAssembly" and key == "externalReferences"):
|
@@ -1,7 +1,9 @@
|
|
1
|
+
import glob
|
1
2
|
import itertools
|
2
3
|
import json
|
3
4
|
import os
|
4
5
|
import re
|
6
|
+
import shutil
|
5
7
|
import uuid
|
6
8
|
|
7
9
|
import requests
|
@@ -190,21 +192,41 @@ def parse_json(response: Response) -> Dict[str, Any]:
|
|
190
192
|
return json_response
|
191
193
|
|
192
194
|
|
193
|
-
def
|
195
|
+
def zip_rust_files(zip_file_path: Path, context: CertoraContext, *resource_paths: Path) -> bool:
|
196
|
+
patterns = ["*.rs", "*.so", "*.wasm", "Cargo.toml", "Cargo.lock", "justfile"]
|
197
|
+
exclude_dirs = [".certora_internal"]
|
198
|
+
|
199
|
+
root_directory = Path(context.rust_project_directory)
|
200
|
+
if not root_directory.is_dir():
|
201
|
+
raise ValueError(f"The given directory {root_directory} is not valid.")
|
202
|
+
|
194
203
|
with zipfile.ZipFile(zip_file_path, 'w', zipfile.ZIP_DEFLATED) as zip_obj:
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
204
|
+
for source in context.rust_sources:
|
205
|
+
for file in glob.glob(f'{root_directory.joinpath(source)}', recursive=True):
|
206
|
+
file_path = Path(file)
|
207
|
+
if any(excluded in file_path.parts for excluded in exclude_dirs):
|
208
|
+
continue
|
209
|
+
if file_path.is_file() and any(file_path.match(pattern) for pattern in patterns):
|
210
|
+
zip_obj.write(file_path, Util.CERTORA_SOURCES / file_path.relative_to(root_directory))
|
211
|
+
if context.build_script and Path(context.build_script).exists():
|
212
|
+
zip_obj.write(Path(context.build_script),
|
213
|
+
Util.CERTORA_SOURCES / Path(context.build_script).absolute().relative_to(root_directory))
|
214
|
+
if context.conf_file and Path(context.conf_file).exists():
|
215
|
+
zip_obj.write(Path(context.conf_file),
|
216
|
+
Util.CERTORA_SOURCES / Path(context.conf_file).absolute().relative_to(root_directory))
|
217
|
+
if Util.get_last_conf_file():
|
218
|
+
zip_obj.write(Util.get_last_conf_file(),
|
219
|
+
Util.CERTORA_SOURCES / Util.get_last_conf_file().relative_to(Util.get_build_dir()))
|
220
|
+
|
221
|
+
rust_executable = root_directory.joinpath(context.rust_executables)
|
222
|
+
zip_obj.write(rust_executable, rust_executable.relative_to(rust_executable.parent))
|
223
|
+
for path in resource_paths:
|
224
|
+
zip_obj.write(path, os.path.relpath(path, Util.get_build_dir()))
|
225
|
+
if path.suffix == '.txt':
|
226
|
+
zip_obj.write(path, Util.CERTORA_SOURCES / path.relative_to(Util.get_build_dir()))
|
205
227
|
|
206
228
|
if zip_file_path.stat().st_size > MAX_FILE_SIZE:
|
207
|
-
cloud_logger.error(f"{GENERAL_ERR_PREFIX} Max 25MB file size exceeded.")
|
229
|
+
cloud_logger.error(f"{GENERAL_ERR_PREFIX} Max 25MB file size exceeded. File is located at {zip_file_path}")
|
208
230
|
return False
|
209
231
|
return True
|
210
232
|
|
@@ -600,8 +622,12 @@ class CloudVerification:
|
|
600
622
|
# We need to strip "../" path component from all file paths because
|
601
623
|
# unzip will also do that.
|
602
624
|
solana_jar_settings = []
|
603
|
-
|
604
|
-
solana_jar_settings.append(
|
625
|
+
if hasattr(self.context, 'build_script') and self.context.build_script:
|
626
|
+
solana_jar_settings.append(Path(self.context.rust_executables).name)
|
627
|
+
|
628
|
+
else:
|
629
|
+
for file in self.context.files:
|
630
|
+
solana_jar_settings.append(file.split('../')[-1])
|
605
631
|
|
606
632
|
is_file = False
|
607
633
|
for arg in jar_settings:
|
@@ -616,18 +642,19 @@ class CloudVerification:
|
|
616
642
|
elif arg == '-solanaSummaries':
|
617
643
|
is_file = True
|
618
644
|
auth_data["jarSettings"] = solana_jar_settings
|
619
|
-
elif Attrs.
|
645
|
+
elif Attrs.is_soroban_app():
|
620
646
|
# We need to strip "../" path component from all file paths because
|
621
647
|
# unzip will also do that.
|
622
|
-
|
623
|
-
|
624
|
-
|
648
|
+
soroban_jar_settings = []
|
649
|
+
# not needed - should be in files
|
650
|
+
if hasattr(self.context, 'build_script') and self.context.build_script:
|
651
|
+
soroban_jar_settings.append(Path(self.context.rust_executables).name)
|
625
652
|
else:
|
626
653
|
for file in self.context.files:
|
627
|
-
|
654
|
+
soroban_jar_settings.append(file.split('../')[-1])
|
628
655
|
for arg in jar_settings:
|
629
|
-
|
630
|
-
auth_data["jarSettings"] =
|
656
|
+
soroban_jar_settings.append(arg)
|
657
|
+
auth_data["jarSettings"] = soroban_jar_settings
|
631
658
|
else:
|
632
659
|
auth_data["jarSettings"] = jar_settings
|
633
660
|
|
@@ -738,40 +765,61 @@ class CloudVerification:
|
|
738
765
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
739
766
|
elif Attrs.is_evm_app() and self.context.is_bytecode:
|
740
767
|
# We zip the bytecode jsons and the spec
|
741
|
-
paths = [
|
768
|
+
paths = [Util.get_certora_build_file(), Util.get_certora_verify_file(),
|
769
|
+
Util.get_certora_metadata_file()]
|
770
|
+
if Util.get_certora_sources_dir().exists():
|
771
|
+
paths.append(Util.get_certora_sources_dir())
|
772
|
+
|
742
773
|
for bytecode_json in self.context.bytecode_jsons:
|
743
774
|
paths.append(Path(bytecode_json))
|
744
775
|
paths.append(Path(self.context.bytecode_spec))
|
745
776
|
result = compress_files(self.ZipFilePath, *paths,
|
746
777
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
747
|
-
elif Attrs.
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
778
|
+
elif Attrs.is_rust_app():
|
779
|
+
files_list = [Util.get_certora_metadata_file()]
|
780
|
+
|
781
|
+
if hasattr(self.context, 'build_script') and self.context.build_script:
|
782
|
+
if self.context.prover_resource_files:
|
783
|
+
for value in self.context.prover_resource_files:
|
784
|
+
_, file_path = value.split(':')
|
785
|
+
cur_path = (Path(self.context.conf_file).parent / Path(file_path)).resolve()
|
786
|
+
shutil.copy(cur_path, Util.get_build_dir())
|
787
|
+
files_list.append(Util.get_build_dir() / cur_path.name)
|
788
|
+
|
789
|
+
result = zip_rust_files(self.ZipFilePath, self.context, *files_list)
|
790
|
+
|
791
|
+
elif Attrs.is_solana_app():
|
792
|
+
# We zip the ELF files and the two configuration files
|
793
|
+
jar_args = Ctx.collect_jar_args(self.context)
|
758
794
|
|
759
|
-
if arg == '-solanaInlining':
|
760
|
-
is_file = True
|
761
|
-
elif arg == '-solanaSummaries':
|
762
|
-
is_file = True
|
763
|
-
result = compress_files(self.ZipFilePath, *paths,
|
764
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
765
|
-
elif Attrs.is_wasm_app():
|
766
|
-
# We zip the wat file
|
767
|
-
paths = []
|
768
|
-
if hasattr(self.context, 'wasm_file') and self.context.wasm_file:
|
769
|
-
result = compress_files_wasm(self.ZipFilePath, self.context)
|
770
|
-
else:
|
771
795
|
for file in self.context.files:
|
772
|
-
|
773
|
-
|
796
|
+
files_list.append(Path(file))
|
797
|
+
is_file = False
|
798
|
+
for arg in jar_args:
|
799
|
+
if is_file:
|
800
|
+
files_list.append(Path(arg))
|
801
|
+
is_file = False
|
802
|
+
|
803
|
+
if arg == '-solanaInlining':
|
804
|
+
is_file = True
|
805
|
+
elif arg == '-solanaSummaries':
|
806
|
+
is_file = True
|
807
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
774
808
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
809
|
+
|
810
|
+
elif Attrs.is_soroban_app():
|
811
|
+
# We zip the wat file
|
812
|
+
for file in self.context.files:
|
813
|
+
files_list.append(Path(file))
|
814
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
815
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
816
|
+
else:
|
817
|
+
raise Util.CertoraUserInputError(
|
818
|
+
'When running rust application, context should either have attribute "rust_executables" '
|
819
|
+
'provided by build_script execution, '
|
820
|
+
'or either is_solana_app(), is_soroban_app() should be set to True'
|
821
|
+
)
|
822
|
+
|
775
823
|
else:
|
776
824
|
# Zip the log file first separately and again with the rest of the files, so it will not be decompressed
|
777
825
|
# on each run in order to save space
|
@@ -53,7 +53,6 @@ def read_from_conf_file(context: CertoraContext) -> None:
|
|
53
53
|
context namespace if the key was not set in the command line (command line shadows conf data).
|
54
54
|
@param context: A namespace containing options from the command line
|
55
55
|
"""
|
56
|
-
|
57
56
|
conf_file_path = Path(context.files[0])
|
58
57
|
assert conf_file_path.suffix == ".conf", f"conf file must be of type .conf, instead got {conf_file_path}"
|
59
58
|
|
@@ -86,6 +85,11 @@ def check_conf_content(conf: Dict[str, Any], context: CertoraContext) -> None:
|
|
86
85
|
f" file ({conf_val})")
|
87
86
|
else:
|
88
87
|
raise Util.CertoraUserInputError(f"{option} appears in the conf file but is not a known attribute. ")
|
88
|
+
|
89
89
|
if 'files' not in conf:
|
90
|
-
|
91
|
-
|
90
|
+
if Attrs.is_rust_app() and hasattr(context, 'build_script') and context.build_script is not None:
|
91
|
+
context.files = conf.get('files', None) # Override the current .conf file
|
92
|
+
else:
|
93
|
+
raise Util.CertoraUserInputError("Mandatory 'files' attribute is missing from the configuration")
|
94
|
+
else:
|
95
|
+
context.files = conf['files'] # Override the current .conf file
|
@@ -1,23 +1,17 @@
|
|
1
1
|
import argparse
|
2
2
|
import hashlib
|
3
3
|
import json
|
4
|
-
import logging
|
5
4
|
import os
|
6
5
|
import re
|
7
6
|
import sys
|
8
|
-
import
|
9
|
-
import platform
|
7
|
+
import logging
|
10
8
|
|
11
|
-
# tomllib was added to python 3.11 this import is for supporting older versions
|
12
|
-
if sys.version_info >= (3, 11):
|
13
|
-
import tomllib
|
14
|
-
else:
|
15
|
-
import tomli as tomllib
|
16
9
|
|
17
10
|
from pathlib import Path
|
18
11
|
from typing import Dict, List, Optional, Any
|
19
12
|
from rich.console import Console
|
20
13
|
|
14
|
+
from EVMVerifier.certoraParseBuildScript import run_script_and_parse_json
|
21
15
|
|
22
16
|
scripts_dir_path = Path(__file__).parent.resolve() # containing directory
|
23
17
|
sys.path.insert(0, str(scripts_dir_path))
|
@@ -112,14 +106,15 @@ def get_local_run_cmd(context: CertoraContext) -> str:
|
|
112
106
|
@return: A command for running the prover locally
|
113
107
|
"""
|
114
108
|
run_args = []
|
115
|
-
if context.is_tac or Attrs.is_solana_app():
|
116
|
-
run_args.append(context.files[0])
|
117
109
|
|
118
|
-
if
|
119
|
-
|
120
|
-
|
121
|
-
|
110
|
+
if hasattr(context, 'rust_executables') and hasattr(context, 'rust_project_directory'):
|
111
|
+
run_args.append(os.path.join(context.rust_project_directory, context.rust_executables))
|
112
|
+
elif context.is_tac or Attrs.is_rust_app():
|
113
|
+
# For Rust app we assume the files holds the executable for the prover, currently we support a single file
|
114
|
+
try:
|
122
115
|
run_args.append(context.files[0])
|
116
|
+
except Exception:
|
117
|
+
raise RuntimeError("get_local_run_cmd: cannot find context.files[0]")
|
123
118
|
|
124
119
|
if Attrs.is_evm_app() and context.cache is not None:
|
125
120
|
run_args.extend(['-cache', context.cache])
|
@@ -158,7 +153,7 @@ class ProverParser(AttrUtil.ContextAttributeParser):
|
|
158
153
|
console = Console()
|
159
154
|
console.print("\n\nThe Certora Prover - A formal verification tool for smart contracts")
|
160
155
|
# Using sys.stdout.write() as print() would color some of the strings here
|
161
|
-
sys.stdout.write("\n\nUsage:
|
156
|
+
sys.stdout.write(f"\n\nUsage: {sys.argv[0]} <Files> <Flags>\n\n")
|
162
157
|
sys.stdout.write("Files are Solidity, Vyper contract files, a shared object Solana contract file, "
|
163
158
|
"or a conf file. Solidity contracts are denoted as file:contract "
|
164
159
|
"e.g. f.sol:A. If the contract name is identical to the file name, "
|
@@ -171,7 +166,7 @@ class ProverParser(AttrUtil.ContextAttributeParser):
|
|
171
166
|
console.print("3. list (L): gets multiple strings as a value, flags may also appear multiple times")
|
172
167
|
console.print("4. map (M): collection of key, value pairs\n\n")
|
173
168
|
|
174
|
-
Attrs.
|
169
|
+
Attrs.get_attribute_class().print_attr_help()
|
175
170
|
console.print("\n\nYou can find detailed documentation of the supported flags here: "
|
176
171
|
f"{Util.print_rich_link(CLI_DOCUMENTATION_URL)}\n\n")
|
177
172
|
|
@@ -242,7 +237,7 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
|
|
242
237
|
|
243
238
|
validator = Cv.CertoraContextValidator(context)
|
244
239
|
validator.validate()
|
245
|
-
if Attrs.is_evm_app():
|
240
|
+
if Attrs.is_evm_app() or Attrs.is_rust_app():
|
246
241
|
current_build_directory = Util.get_build_dir()
|
247
242
|
if context.build_dir is not None and current_build_directory != context.build_dir:
|
248
243
|
Util.reset_certora_internal_dir(context.build_dir)
|
@@ -527,52 +522,15 @@ def run_local_spec_check(with_typechecking: bool, context: CertoraContext) -> No
|
|
527
522
|
raise Util.CertoraUserInputError("Cannot run local checks because of missing a suitable java installation. "
|
528
523
|
"To skip local checks run with the --disable_local_typechecking flag")
|
529
524
|
|
530
|
-
def set_cargo_name(context: CertoraContext) -> None:
|
531
|
-
mode = "r" if platform.system().lower() == 'windows' else "rb"
|
532
|
-
with open(context.cargo_file, mode) as f:
|
533
|
-
cargo_data = tomllib.load(f)
|
534
|
-
|
535
|
-
if 'package' in cargo_data and 'name' in cargo_data['package']:
|
536
|
-
context.cargo_name = cargo_data['package']['name'].replace('-', '_')
|
537
|
-
|
538
|
-
def build_wasm(context: CertoraContext) -> None:
|
539
|
-
if len(context.files) != 1:
|
540
|
-
raise Util.CertoraUserInputError(f"expected a single wasm file ({Util.CARGO_FILE} or .wat file)."
|
541
|
-
f" Got: {context.files}")
|
542
|
-
file_path = Path(context.files[0])
|
543
|
-
if file_path.name != Util.CARGO_FILE:
|
544
|
-
return
|
545
|
-
context.cargo_dir = file_path.parent
|
546
|
-
context.cargo_file = file_path
|
547
|
-
set_cargo_name(context)
|
548
|
-
run_wasm_compiler(context)
|
549
|
-
|
550
|
-
|
551
|
-
def run_wasm_compiler(context: CertoraContext) -> None:
|
552
|
-
env = os.environ.copy()
|
553
|
-
env['RUSTFLAGS'] = "-C strip=none --emit=llvm-ir -C debuginfo=2"
|
554
|
-
try:
|
555
|
-
context_logger.info("Executing build process...")
|
556
525
|
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
cmd = f"wat2wasm {wat_file} --debug-names -o {intermediate_wasm}"
|
569
|
-
Util.run_shell_command(cmd, cwd=context.cargo_dir, env=env)
|
570
|
-
|
571
|
-
cmd = f"wasm2wat {intermediate_wasm} -o {wat_file}"
|
572
|
-
Util.run_shell_command(cmd, cwd=context.cargo_dir, env=env)
|
573
|
-
|
574
|
-
intermediate_wasm.unlink()
|
575
|
-
shutil.copy(context.wasm_file, context.cargo_dir)
|
576
|
-
|
577
|
-
except Exception as e:
|
578
|
-
raise RuntimeError(f"Failed to build wasm file\n{e}")
|
526
|
+
def build_rust_app(context: CertoraContext) -> None:
|
527
|
+
if context.build_script:
|
528
|
+
run_script_and_parse_json(context)
|
529
|
+
if not context.rust_executables:
|
530
|
+
raise Util.CertoraUserInputError("failed to get target executable")
|
531
|
+
else:
|
532
|
+
if not context.files:
|
533
|
+
raise Util.CertoraUserInputError("'files' or 'build_script' must be set for Rust projects")
|
534
|
+
if len(context.files) > 1:
|
535
|
+
raise Util.CertoraUserInputError("Rust projects must specify exactly one executable in 'files'.")
|
536
|
+
context.rust_executables = context.files[0]
|
@@ -1,4 +1,5 @@
|
|
1
1
|
import logging
|
2
|
+
|
2
3
|
import json5
|
3
4
|
import sys
|
4
5
|
from pathlib import Path
|
@@ -37,6 +38,17 @@ def validate_prover_args(value: str) -> str:
|
|
37
38
|
|
38
39
|
|
39
40
|
class CommonAttributes(AttrUtil.Attributes):
|
41
|
+
COMPILATION_STEPS_ONLY = AttrUtil.AttributeDefinition(
|
42
|
+
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
43
|
+
help_msg="Compile the spec and the code without sending a verification request to the cloud",
|
44
|
+
default_desc="Sends a request after source compilation and spec syntax checking",
|
45
|
+
argparse_args={
|
46
|
+
'action': AttrUtil.STORE_TRUE
|
47
|
+
},
|
48
|
+
affects_build_cache_key=False,
|
49
|
+
disables_build_cache=False
|
50
|
+
)
|
51
|
+
|
40
52
|
MSG = AttrUtil.AttributeDefinition(
|
41
53
|
attr_validation_func=Vf.validate_msg,
|
42
54
|
help_msg="Add a message description to your run",
|
@@ -149,6 +161,15 @@ class CommonAttributes(AttrUtil.Attributes):
|
|
149
161
|
disables_build_cache=False
|
150
162
|
)
|
151
163
|
|
164
|
+
BUILD_DIR = AttrUtil.AttributeDefinition(
|
165
|
+
attr_validation_func=Vf.validate_build_dir,
|
166
|
+
argparse_args={
|
167
|
+
'action': AttrUtil.UniqueStore
|
168
|
+
},
|
169
|
+
affects_build_cache_key=False,
|
170
|
+
disables_build_cache=False
|
171
|
+
)
|
172
|
+
|
152
173
|
class DeprecatedAttributes(AttrUtil.Attributes):
|
153
174
|
AUTO_NONDET_DIFFICULT_INTERNAL_FUNCS = AttrUtil.AttributeDefinition(
|
154
175
|
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
@@ -418,17 +439,6 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
418
439
|
disables_build_cache=False
|
419
440
|
)
|
420
441
|
|
421
|
-
COMPILATION_STEPS_ONLY = AttrUtil.AttributeDefinition(
|
422
|
-
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
423
|
-
help_msg="Compile the spec and the code without sending a verification request to the cloud",
|
424
|
-
default_desc="Sends a request after source compilation and spec syntax checking",
|
425
|
-
argparse_args={
|
426
|
-
'action': AttrUtil.STORE_TRUE
|
427
|
-
},
|
428
|
-
affects_build_cache_key=False,
|
429
|
-
disables_build_cache=False
|
430
|
-
)
|
431
|
-
|
432
442
|
NO_MEMORY_SAFE_AUTOFINDERS = AttrUtil.AttributeDefinition(
|
433
443
|
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
434
444
|
# This is a hidden flag, the following two attributes are left intentionally as comments to help devs
|
@@ -637,15 +647,6 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
637
647
|
disables_build_cache=False
|
638
648
|
)
|
639
649
|
|
640
|
-
BUILD_DIR = AttrUtil.AttributeDefinition(
|
641
|
-
attr_validation_func=Vf.validate_build_dir,
|
642
|
-
argparse_args={
|
643
|
-
'action': AttrUtil.UniqueStore
|
644
|
-
},
|
645
|
-
affects_build_cache_key=False,
|
646
|
-
disables_build_cache=False
|
647
|
-
)
|
648
|
-
|
649
650
|
DISABLE_LOCAL_TYPECHECKING = AttrUtil.AttributeDefinition(
|
650
651
|
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
651
652
|
argparse_args={
|
@@ -1384,6 +1385,20 @@ class BackendAttributes(AttrUtil.Attributes):
|
|
1384
1385
|
disables_build_cache=False
|
1385
1386
|
)
|
1386
1387
|
|
1388
|
+
|
1389
|
+
class RustAttributes(AttrUtil.Attributes):
|
1390
|
+
|
1391
|
+
BUILD_SCRIPT = AttrUtil.AttributeDefinition(
|
1392
|
+
help_msg="Python script to build the project",
|
1393
|
+
default_desc="Using default building command",
|
1394
|
+
argparse_args={
|
1395
|
+
'action': AttrUtil.UniqueStore
|
1396
|
+
},
|
1397
|
+
affects_build_cache_key=False,
|
1398
|
+
disables_build_cache=False
|
1399
|
+
)
|
1400
|
+
|
1401
|
+
|
1387
1402
|
class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes, InternalUseAttributes,
|
1388
1403
|
BackendAttributes):
|
1389
1404
|
FILES = AttrUtil.AttributeDefinition(
|
@@ -1399,9 +1414,9 @@ class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes,
|
|
1399
1414
|
)
|
1400
1415
|
|
1401
1416
|
|
1402
|
-
class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
|
1417
|
+
class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
|
1403
1418
|
FILES = AttrUtil.AttributeDefinition(
|
1404
|
-
attr_validation_func=Vf.
|
1419
|
+
attr_validation_func=Vf.validate_soroban_extension,
|
1405
1420
|
arg_type=AttrUtil.AttrArgType.LIST,
|
1406
1421
|
help_msg="binary .wat files for the Prover",
|
1407
1422
|
default_desc="",
|
@@ -1412,19 +1427,10 @@ class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAt
|
|
1412
1427
|
disables_build_cache=False
|
1413
1428
|
)
|
1414
1429
|
|
1415
|
-
WASM_TARGET = AttrUtil.AttributeDefinition(
|
1416
|
-
default_desc="",
|
1417
|
-
argparse_args={
|
1418
|
-
'action': AttrUtil.UniqueStore,
|
1419
|
-
'default': "wasm32-unknown-unknown"
|
1420
|
-
},
|
1421
|
-
affects_build_cache_key=False,
|
1422
|
-
disables_build_cache=False
|
1423
|
-
)
|
1424
1430
|
|
1425
|
-
class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
|
1431
|
+
class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
|
1426
1432
|
FILES = AttrUtil.AttributeDefinition(
|
1427
|
-
attr_validation_func=Vf.
|
1433
|
+
attr_validation_func=Vf.validate_solana_extension,
|
1428
1434
|
arg_type=AttrUtil.AttrArgType.LIST,
|
1429
1435
|
help_msg="contract files for analysis SOLANA_FILE.so or a conf file",
|
1430
1436
|
|
@@ -1460,9 +1466,9 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1460
1466
|
def application_by_suffix(file: str) -> Type[AttrUtil.Attributes]:
|
1461
1467
|
if file.endswith(Util.EVM_EXTENSIONS):
|
1462
1468
|
return EvmProverAttributes
|
1463
|
-
elif file.endswith(Util.
|
1469
|
+
elif file.endswith(Util.SOROBAN_EXEC_EXTENSION):
|
1464
1470
|
return SorobanProverAttributes
|
1465
|
-
elif file.endswith(Util.
|
1471
|
+
elif file.endswith(Util.SOLANA_EXEC_EXTENSION):
|
1466
1472
|
return SolanaProverAttributes
|
1467
1473
|
elif file.endswith('.conf'):
|
1468
1474
|
raise Util.CertoraUserInputError(f"Cannot use conf files inside a conf file: {file}")
|
@@ -1472,6 +1478,7 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1472
1478
|
cli_files = []
|
1473
1479
|
cli_conf_files = []
|
1474
1480
|
files = []
|
1481
|
+
build_script = None
|
1475
1482
|
for arg in args:
|
1476
1483
|
if arg.startswith('-'):
|
1477
1484
|
break # Stop processing when a flag is detected
|
@@ -1485,6 +1492,10 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1485
1492
|
with conf_file_path.open() as conf_file:
|
1486
1493
|
configuration = json5.load(conf_file, allow_duplicate_keys=False)
|
1487
1494
|
files = configuration.get('files', [])
|
1495
|
+
build_script = configuration.get('build_script')
|
1496
|
+
|
1497
|
+
if build_script:
|
1498
|
+
return SorobanProverAttributes
|
1488
1499
|
|
1489
1500
|
if len(cli_conf_files) == 0:
|
1490
1501
|
files = cli_files
|
@@ -1516,9 +1527,13 @@ def is_solana_app() -> bool:
|
|
1516
1527
|
return get_attribute_class() == SolanaProverAttributes
|
1517
1528
|
|
1518
1529
|
|
1519
|
-
def
|
1530
|
+
def is_soroban_app() -> bool:
|
1520
1531
|
return get_attribute_class() == SorobanProverAttributes
|
1521
1532
|
|
1522
1533
|
|
1534
|
+
def is_rust_app() -> bool:
|
1535
|
+
return is_soroban_app() or is_solana_app()
|
1536
|
+
|
1537
|
+
|
1523
1538
|
def is_evm_app() -> bool:
|
1524
1539
|
return get_attribute_class() == EvmProverAttributes
|
@@ -173,14 +173,17 @@ class CertoraContextValidator:
|
|
173
173
|
"'disable_source_finders' is set to true while 'dynamic_bound' is set to 1 or higher"
|
174
174
|
)
|
175
175
|
context.disable_source_finders = True
|
176
|
-
|
176
|
+
package_name = Util.get_package_and_version()[1]
|
177
177
|
# if --fe_version was not set then if the package is alpha/beta we set it to latest else we set it to production
|
178
178
|
if not context.fe_version:
|
179
|
-
lastest_packages = [Util.
|
180
|
-
if
|
179
|
+
lastest_packages = [Util.ALPHA_PACKAGE_MASTER_NAME, Util.BETA_PACKAGE_NAME, Util.BETA_MIRROR_PACKAGE_NAME]
|
180
|
+
if package_name in lastest_packages:
|
181
181
|
context.fe_version = str(Util.FeValue.LATEST)
|
182
182
|
else:
|
183
183
|
context.fe_version = str(Util.FeValue.PRODUCTION)
|
184
|
+
if Util.ALPHA_PACKAGE_NAME in package_name and not context.prover_version:
|
185
|
+
raise Util.CertoraUserInputError('When running an "alpha release", a specific branch must be supplied '
|
186
|
+
'via --prover_version. For example: "--prover_version master"')
|
184
187
|
|
185
188
|
check_conflicting_branch_and_hash(context)
|
186
189
|
set_wait_for_results_default(context)
|
@@ -409,8 +412,7 @@ def check_contract_name_arg_inputs(context: CertoraContext) -> None:
|
|
409
412
|
def valid_input_file(filename: str) -> bool:
|
410
413
|
pattern_match_sol = bool(re.match(r'([\w.$]+)\.sol:([\w$]+)', Path(filename).name))
|
411
414
|
ends_with_extension = any(filename.endswith(ext) for ext in Util.VALID_FILE_EXTENSIONS)
|
412
|
-
|
413
|
-
return pattern_match_sol or ends_with_extension or is_cargo_file
|
415
|
+
return pattern_match_sol or ends_with_extension
|
414
416
|
|
415
417
|
|
416
418
|
def check_files_attribute(context: CertoraContext) -> None:
|
@@ -492,7 +494,7 @@ def check_mode_of_operation(context: CertoraContext) -> None:
|
|
492
494
|
raise Util.CertoraUserInputError(
|
493
495
|
f"Cannot use conf files inside a conf file: {','.join(conf_files_inside_conf_file)}")
|
494
496
|
|
495
|
-
special_file_suffixes = [".tac", ".json"] +
|
497
|
+
special_file_suffixes = [".tac", ".json"] + [Util.SOLANA_EXEC_EXTENSION, Util.SOROBAN_EXEC_EXTENSION]
|
496
498
|
for input_file in context.files:
|
497
499
|
special_file_type = next((suffix for suffix in special_file_suffixes if input_file.endswith(suffix)), None)
|
498
500
|
|
@@ -710,7 +712,6 @@ def validate_certora_key() -> str:
|
|
710
712
|
raise Util.CertoraUserInputError(f"environment variable {KEY_ENV_VAR} has an illegal length")
|
711
713
|
return key
|
712
714
|
|
713
|
-
|
714
715
|
def check_files_input(file_list: List[str]) -> None:
|
715
716
|
"""
|
716
717
|
Verifies that correct input was inserted as input to files.
|
@@ -719,8 +720,8 @@ def check_files_input(file_list: List[str]) -> None:
|
|
719
720
|
The allowed disjoint cases are:
|
720
721
|
1. Use a single .conf file
|
721
722
|
2. Use a single .tac file
|
722
|
-
3. Use a single .
|
723
|
-
4. Use a single .
|
723
|
+
3. Use a single .so file
|
724
|
+
4. Use a single .wasm file
|
724
725
|
5. Use any number of [contract.sol:nickname ...] (at least one is guaranteed by argparser)
|
725
726
|
@param file_list: A list of strings representing file paths
|
726
727
|
@raise CertoraUserInputError if more than one of the modes above was used
|
@@ -733,13 +734,10 @@ def check_files_input(file_list: List[str]) -> None:
|
|
733
734
|
if '.conf' in file:
|
734
735
|
raise Util.CertoraUserInputError(
|
735
736
|
f'The conf file {file} cannot be accompanied with other files')
|
736
|
-
if file.endswith(Util.
|
737
|
+
if file.endswith(Util.SOLANA_EXEC_EXTENSION):
|
737
738
|
raise Util.CertoraUserInputError(f'The Solana file {file} cannot be accompanied with other files')
|
738
|
-
if file.endswith(Util.
|
739
|
-
raise Util.CertoraUserInputError(
|
740
|
-
f'When using the tool in WASM mode, you can only provide a single Cargo.toml file or .wat file.'
|
741
|
-
f'{num_files} files were given.')
|
742
|
-
|
739
|
+
if file.endswith(Util.SOROBAN_EXEC_EXTENSION):
|
740
|
+
raise Util.CertoraUserInputError(f'The Soroban file {file} cannot be accompanied with other files')
|
743
741
|
|
744
742
|
def set_wait_for_results_default(context: CertoraContext) -> None:
|
745
743
|
if context.wait_for_results is None:
|