certora-cli-alpha-master 20241217.5.52.971947__tar.gz → 20241217.16.7.546354__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of certora-cli-alpha-master might be problematic. Click here for more details.
- {certora_cli_alpha_master-20241217.5.52.971947/certora_cli_alpha_master.egg-info → certora_cli_alpha_master-20241217.16.7.546354}/PKG-INFO +2 -2
- certora_cli_alpha_master-20241217.16.7.546354/README.md +1 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraCloudIO.py +90 -46
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraConfigIO.py +7 -3
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraContext.py +16 -64
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraContextAttributes.py +43 -27
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraContextValidator.py +7 -12
- certora_cli_alpha_master-20241217.16.7.546354/certora_cli/EVMVerifier/certoraParseBuildScript.py +36 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/mutateApp.py +16 -7
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/certoraUtils.py +6 -9
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/certoraValidateFuncs.py +14 -7
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/certoraRun.py +3 -5
- certora_cli_alpha_master-20241217.16.7.546354/certora_cli/certoraSolanaProver.py +153 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/rustMutator.py +108 -38
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354/certora_cli_alpha_master.egg-info}/PKG-INFO +2 -2
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli_alpha_master.egg-info/SOURCES.txt +2 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli_alpha_master.egg-info/entry_points.txt +1 -0
- certora_cli_alpha_master-20241217.16.7.546354/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_jars/Typechecker.jar +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/setup.py +4 -3
- certora_cli_alpha_master-20241217.5.52.971947/README.md +0 -1
- certora_cli_alpha_master-20241217.5.52.971947/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/LICENSE +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/MANIFEST.in +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_bins/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollector.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollectorFactory.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollectorSol.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollectorSolBased.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollectorVy.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/CompilerCollectorYul.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/Compiler/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraBuild.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraBuildCacheManager.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraBuildDataClasses.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraCollectRunMetadata.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraCompilerParameters.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraContextClass.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraContractFuncs.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraExtensionInfo.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraJobList.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraMiniSpecParser.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraNodeFilters.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraSourceFinders.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraType.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EVMVerifier/certoraVerifyGenerator.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/equivCheck.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/mutateAttributes.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/mutateConstants.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/mutateUtil.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Mutate/mutateValidate.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/ExpectedComparator.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/certoraAttrUtil.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/Shared/certoraLogging.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/certoraEqCheck.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli/certoraMutate.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli_alpha_master.egg-info/dependency_links.txt +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli_alpha_master.egg-info/requires.txt +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_cli_alpha_master.egg-info/top_level.txt +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/certora_jars/__init__.py +0 -0
- {certora_cli_alpha_master-20241217.5.52.971947 → certora_cli_alpha_master-20241217.16.7.546354}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: certora-cli-alpha-master
|
3
|
-
Version: 20241217.
|
3
|
+
Version: 20241217.16.7.546354
|
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 77317ff. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
@@ -0,0 +1 @@
|
|
1
|
+
Commit 77317ff. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
@@ -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
|
|
@@ -744,34 +771,51 @@ class CloudVerification:
|
|
744
771
|
paths.append(Path(self.context.bytecode_spec))
|
745
772
|
result = compress_files(self.ZipFilePath, *paths,
|
746
773
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
747
|
-
elif Attrs.
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
|
755
|
-
|
756
|
-
|
757
|
-
|
774
|
+
elif Attrs.is_rust_app():
|
775
|
+
files_list = [Util.get_certora_metadata_file()]
|
776
|
+
|
777
|
+
if hasattr(self.context, 'build_script') and self.context.build_script:
|
778
|
+
if self.context.prover_resource_files:
|
779
|
+
for value in self.context.prover_resource_files:
|
780
|
+
_, file_path = value.split(':')
|
781
|
+
cur_path = (Path(self.context.conf_file).parent / Path(file_path)).resolve()
|
782
|
+
shutil.copy(cur_path, Util.get_build_dir())
|
783
|
+
files_list.append(Util.get_build_dir() / cur_path.name)
|
784
|
+
|
785
|
+
result = zip_rust_files(self.ZipFilePath, self.context, *files_list)
|
786
|
+
|
787
|
+
elif Attrs.is_solana_app():
|
788
|
+
# We zip the ELF files and the two configuration files
|
789
|
+
jar_args = Ctx.collect_jar_args(self.context)
|
758
790
|
|
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
791
|
for file in self.context.files:
|
772
|
-
|
773
|
-
|
792
|
+
files_list.append(Path(file))
|
793
|
+
is_file = False
|
794
|
+
for arg in jar_args:
|
795
|
+
if is_file:
|
796
|
+
files_list.append(Path(arg))
|
797
|
+
is_file = False
|
798
|
+
|
799
|
+
if arg == '-solanaInlining':
|
800
|
+
is_file = True
|
801
|
+
elif arg == '-solanaSummaries':
|
802
|
+
is_file = True
|
803
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
774
804
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
805
|
+
|
806
|
+
elif Attrs.is_soroban_app():
|
807
|
+
# We zip the wat file
|
808
|
+
for file in self.context.files:
|
809
|
+
files_list.append(Path(file))
|
810
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
811
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
812
|
+
else:
|
813
|
+
raise Util.CertoraUserInputError(
|
814
|
+
'When running rust application, context should either have attribute "rust_executables" '
|
815
|
+
'provided by build_script execution, '
|
816
|
+
'or either is_solana_app(), is_soroban_app() should be set to True'
|
817
|
+
)
|
818
|
+
|
775
819
|
else:
|
776
820
|
# Zip the log file first separately and again with the rest of the files, so it will not be decompressed
|
777
821
|
# 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
|
@@ -5,19 +5,13 @@ import logging
|
|
5
5
|
import os
|
6
6
|
import re
|
7
7
|
import sys
|
8
|
-
import shutil
|
9
|
-
import platform
|
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,15 +106,10 @@ 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.
|
109
|
+
if context.is_tac or Attrs.is_rust_app():
|
110
|
+
# For Rust app we assume the files holds the executable for the prover, currently we support a single file
|
116
111
|
run_args.append(context.files[0])
|
117
112
|
|
118
|
-
if Attrs.is_wasm_app():
|
119
|
-
if hasattr(context, 'wasm_file') and context.wasm_file:
|
120
|
-
run_args.append(str(context.wasm_file))
|
121
|
-
else:
|
122
|
-
run_args.append(context.files[0])
|
123
|
-
|
124
113
|
if Attrs.is_evm_app() and context.cache is not None:
|
125
114
|
run_args.extend(['-cache', context.cache])
|
126
115
|
|
@@ -158,7 +147,7 @@ class ProverParser(AttrUtil.ContextAttributeParser):
|
|
158
147
|
console = Console()
|
159
148
|
console.print("\n\nThe Certora Prover - A formal verification tool for smart contracts")
|
160
149
|
# Using sys.stdout.write() as print() would color some of the strings here
|
161
|
-
sys.stdout.write("\n\nUsage:
|
150
|
+
sys.stdout.write(f"\n\nUsage: {sys.argv[0]} <Files> <Flags>\n\n")
|
162
151
|
sys.stdout.write("Files are Solidity, Vyper contract files, a shared object Solana contract file, "
|
163
152
|
"or a conf file. Solidity contracts are denoted as file:contract "
|
164
153
|
"e.g. f.sol:A. If the contract name is identical to the file name, "
|
@@ -171,7 +160,7 @@ class ProverParser(AttrUtil.ContextAttributeParser):
|
|
171
160
|
console.print("3. list (L): gets multiple strings as a value, flags may also appear multiple times")
|
172
161
|
console.print("4. map (M): collection of key, value pairs\n\n")
|
173
162
|
|
174
|
-
Attrs.
|
163
|
+
Attrs.get_attribute_class().print_attr_help()
|
175
164
|
console.print("\n\nYou can find detailed documentation of the supported flags here: "
|
176
165
|
f"{Util.print_rich_link(CLI_DOCUMENTATION_URL)}\n\n")
|
177
166
|
|
@@ -527,52 +516,15 @@ def run_local_spec_check(with_typechecking: bool, context: CertoraContext) -> No
|
|
527
516
|
raise Util.CertoraUserInputError("Cannot run local checks because of missing a suitable java installation. "
|
528
517
|
"To skip local checks run with the --disable_local_typechecking flag")
|
529
518
|
|
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
|
-
|
557
|
-
cmd = f"cargo build --target={context.wasm_target} --release --features certora"
|
558
|
-
Util.run_shell_command(cmd, env=env, cwd=context.cargo_dir)
|
559
519
|
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
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}")
|
520
|
+
def build_rust_app(context: CertoraContext) -> None:
|
521
|
+
if context.build_script:
|
522
|
+
run_script_and_parse_json(context)
|
523
|
+
if not context.rust_executables:
|
524
|
+
raise Util.CertoraUserInputError("failed to get target executable")
|
525
|
+
else:
|
526
|
+
if not context.files:
|
527
|
+
raise Util.CertoraUserInputError("'files' or 'build_script' must be set for Rust projects")
|
528
|
+
if len(context.files) > 1:
|
529
|
+
raise Util.CertoraUserInputError("Rust projects must specify exactly one executable in 'files'.")
|
530
|
+
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,7 @@ class CommonAttributes(AttrUtil.Attributes):
|
|
149
161
|
disables_build_cache=False
|
150
162
|
)
|
151
163
|
|
164
|
+
|
152
165
|
class DeprecatedAttributes(AttrUtil.Attributes):
|
153
166
|
AUTO_NONDET_DIFFICULT_INTERNAL_FUNCS = AttrUtil.AttributeDefinition(
|
154
167
|
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
@@ -418,17 +431,6 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
418
431
|
disables_build_cache=False
|
419
432
|
)
|
420
433
|
|
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
434
|
NO_MEMORY_SAFE_AUTOFINDERS = AttrUtil.AttributeDefinition(
|
433
435
|
arg_type=AttrUtil.AttrArgType.BOOLEAN,
|
434
436
|
# This is a hidden flag, the following two attributes are left intentionally as comments to help devs
|
@@ -1384,6 +1386,20 @@ class BackendAttributes(AttrUtil.Attributes):
|
|
1384
1386
|
disables_build_cache=False
|
1385
1387
|
)
|
1386
1388
|
|
1389
|
+
|
1390
|
+
class RustAttributes(AttrUtil.Attributes):
|
1391
|
+
|
1392
|
+
BUILD_SCRIPT = AttrUtil.AttributeDefinition(
|
1393
|
+
help_msg="Python script to build the project",
|
1394
|
+
default_desc="Using default building command",
|
1395
|
+
argparse_args={
|
1396
|
+
'action': AttrUtil.UniqueStore
|
1397
|
+
},
|
1398
|
+
affects_build_cache_key=False,
|
1399
|
+
disables_build_cache=False
|
1400
|
+
)
|
1401
|
+
|
1402
|
+
|
1387
1403
|
class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes, InternalUseAttributes,
|
1388
1404
|
BackendAttributes):
|
1389
1405
|
FILES = AttrUtil.AttributeDefinition(
|
@@ -1399,9 +1415,9 @@ class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes,
|
|
1399
1415
|
)
|
1400
1416
|
|
1401
1417
|
|
1402
|
-
class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
|
1418
|
+
class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
|
1403
1419
|
FILES = AttrUtil.AttributeDefinition(
|
1404
|
-
attr_validation_func=Vf.
|
1420
|
+
attr_validation_func=Vf.validate_soroban_extension,
|
1405
1421
|
arg_type=AttrUtil.AttrArgType.LIST,
|
1406
1422
|
help_msg="binary .wat files for the Prover",
|
1407
1423
|
default_desc="",
|
@@ -1412,19 +1428,10 @@ class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAt
|
|
1412
1428
|
disables_build_cache=False
|
1413
1429
|
)
|
1414
1430
|
|
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
1431
|
|
1425
|
-
class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
|
1432
|
+
class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
|
1426
1433
|
FILES = AttrUtil.AttributeDefinition(
|
1427
|
-
attr_validation_func=Vf.
|
1434
|
+
attr_validation_func=Vf.validate_solana_extension,
|
1428
1435
|
arg_type=AttrUtil.AttrArgType.LIST,
|
1429
1436
|
help_msg="contract files for analysis SOLANA_FILE.so or a conf file",
|
1430
1437
|
|
@@ -1460,9 +1467,9 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1460
1467
|
def application_by_suffix(file: str) -> Type[AttrUtil.Attributes]:
|
1461
1468
|
if file.endswith(Util.EVM_EXTENSIONS):
|
1462
1469
|
return EvmProverAttributes
|
1463
|
-
elif file.endswith(Util.
|
1470
|
+
elif file.endswith(Util.SOROBAN_EXEC_EXTENSION):
|
1464
1471
|
return SorobanProverAttributes
|
1465
|
-
elif file.endswith(Util.
|
1472
|
+
elif file.endswith(Util.SOLANA_EXEC_EXTENSION):
|
1466
1473
|
return SolanaProverAttributes
|
1467
1474
|
elif file.endswith('.conf'):
|
1468
1475
|
raise Util.CertoraUserInputError(f"Cannot use conf files inside a conf file: {file}")
|
@@ -1472,6 +1479,7 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1472
1479
|
cli_files = []
|
1473
1480
|
cli_conf_files = []
|
1474
1481
|
files = []
|
1482
|
+
build_script = None
|
1475
1483
|
for arg in args:
|
1476
1484
|
if arg.startswith('-'):
|
1477
1485
|
break # Stop processing when a flag is detected
|
@@ -1485,6 +1493,10 @@ def detect_application_class(args: List[str]) -> Type[AttrUtil.Attributes]:
|
|
1485
1493
|
with conf_file_path.open() as conf_file:
|
1486
1494
|
configuration = json5.load(conf_file, allow_duplicate_keys=False)
|
1487
1495
|
files = configuration.get('files', [])
|
1496
|
+
build_script = configuration.get('build_script')
|
1497
|
+
|
1498
|
+
if build_script:
|
1499
|
+
return SorobanProverAttributes
|
1488
1500
|
|
1489
1501
|
if len(cli_conf_files) == 0:
|
1490
1502
|
files = cli_files
|
@@ -1516,9 +1528,13 @@ def is_solana_app() -> bool:
|
|
1516
1528
|
return get_attribute_class() == SolanaProverAttributes
|
1517
1529
|
|
1518
1530
|
|
1519
|
-
def
|
1531
|
+
def is_soroban_app() -> bool:
|
1520
1532
|
return get_attribute_class() == SorobanProverAttributes
|
1521
1533
|
|
1522
1534
|
|
1535
|
+
def is_rust_app() -> bool:
|
1536
|
+
return is_soroban_app() or is_solana_app()
|
1537
|
+
|
1538
|
+
|
1523
1539
|
def is_evm_app() -> bool:
|
1524
1540
|
return get_attribute_class() == EvmProverAttributes
|
@@ -409,8 +409,7 @@ def check_contract_name_arg_inputs(context: CertoraContext) -> None:
|
|
409
409
|
def valid_input_file(filename: str) -> bool:
|
410
410
|
pattern_match_sol = bool(re.match(r'([\w.$]+)\.sol:([\w$]+)', Path(filename).name))
|
411
411
|
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
|
412
|
+
return pattern_match_sol or ends_with_extension
|
414
413
|
|
415
414
|
|
416
415
|
def check_files_attribute(context: CertoraContext) -> None:
|
@@ -492,7 +491,7 @@ def check_mode_of_operation(context: CertoraContext) -> None:
|
|
492
491
|
raise Util.CertoraUserInputError(
|
493
492
|
f"Cannot use conf files inside a conf file: {','.join(conf_files_inside_conf_file)}")
|
494
493
|
|
495
|
-
special_file_suffixes = [".tac", ".json"] +
|
494
|
+
special_file_suffixes = [".tac", ".json"] + [Util.SOLANA_EXEC_EXTENSION, Util.SOROBAN_EXEC_EXTENSION]
|
496
495
|
for input_file in context.files:
|
497
496
|
special_file_type = next((suffix for suffix in special_file_suffixes if input_file.endswith(suffix)), None)
|
498
497
|
|
@@ -710,7 +709,6 @@ def validate_certora_key() -> str:
|
|
710
709
|
raise Util.CertoraUserInputError(f"environment variable {KEY_ENV_VAR} has an illegal length")
|
711
710
|
return key
|
712
711
|
|
713
|
-
|
714
712
|
def check_files_input(file_list: List[str]) -> None:
|
715
713
|
"""
|
716
714
|
Verifies that correct input was inserted as input to files.
|
@@ -719,8 +717,8 @@ def check_files_input(file_list: List[str]) -> None:
|
|
719
717
|
The allowed disjoint cases are:
|
720
718
|
1. Use a single .conf file
|
721
719
|
2. Use a single .tac file
|
722
|
-
3. Use a single .
|
723
|
-
4. Use a single .
|
720
|
+
3. Use a single .so file
|
721
|
+
4. Use a single .wasm file
|
724
722
|
5. Use any number of [contract.sol:nickname ...] (at least one is guaranteed by argparser)
|
725
723
|
@param file_list: A list of strings representing file paths
|
726
724
|
@raise CertoraUserInputError if more than one of the modes above was used
|
@@ -733,13 +731,10 @@ def check_files_input(file_list: List[str]) -> None:
|
|
733
731
|
if '.conf' in file:
|
734
732
|
raise Util.CertoraUserInputError(
|
735
733
|
f'The conf file {file} cannot be accompanied with other files')
|
736
|
-
if file.endswith(Util.
|
734
|
+
if file.endswith(Util.SOLANA_EXEC_EXTENSION):
|
737
735
|
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
|
-
|
736
|
+
if file.endswith(Util.SOROBAN_EXEC_EXTENSION):
|
737
|
+
raise Util.CertoraUserInputError(f'The Soroban file {file} cannot be accompanied with other files')
|
743
738
|
|
744
739
|
def set_wait_for_results_default(context: CertoraContext) -> None:
|
745
740
|
if context.wait_for_results is None:
|
certora_cli_alpha_master-20241217.16.7.546354/certora_cli/EVMVerifier/certoraParseBuildScript.py
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
import subprocess
|
2
|
+
import json
|
3
|
+
from pathlib import Path
|
4
|
+
|
5
|
+
from EVMVerifier.certoraContextClass import CertoraContext
|
6
|
+
from Shared import certoraUtils as Util
|
7
|
+
import os
|
8
|
+
|
9
|
+
|
10
|
+
def run_script_and_parse_json(context: CertoraContext) -> None:
|
11
|
+
if not context.build_script:
|
12
|
+
return
|
13
|
+
try:
|
14
|
+
env = os.environ.copy()
|
15
|
+
result = subprocess.run(["python3", Path(context.build_script).resolve(), '--json'], capture_output=True, text=True,
|
16
|
+
env=env, cwd=Path(context.build_script).resolve().parent)
|
17
|
+
|
18
|
+
# Check if the script executed successfully
|
19
|
+
if result.returncode != 0:
|
20
|
+
raise Util.CertoraUserInputError(f"Error running the script {context.build_script}\n{result.stderr}")
|
21
|
+
|
22
|
+
json_obj = json.loads(result.stdout)
|
23
|
+
|
24
|
+
if not json_obj or not json_obj.get("success"):
|
25
|
+
raise Util.CertoraUserInputError(f"{result.stderr}\nBuild from {context.build_script} failed")
|
26
|
+
|
27
|
+
context.rust_project_directory = json_obj.get("project_directory")
|
28
|
+
context.rust_sources = json_obj.get("sources")
|
29
|
+
context.rust_executables = json_obj.get("executables")
|
30
|
+
|
31
|
+
except FileNotFoundError as e:
|
32
|
+
raise Util.CertoraUserInputError(f"File not found: {e}")
|
33
|
+
except json.JSONDecodeError as e:
|
34
|
+
raise Util.CertoraUserInputError(f"Error decoding JSON: {e}")
|
35
|
+
except Exception as e:
|
36
|
+
raise Util.CertoraUserInputError(f"An unexpected error occurred: {e}")
|
@@ -715,11 +715,7 @@ class MutateApp:
|
|
715
715
|
self.server = self.config_server()
|
716
716
|
|
717
717
|
def is_soroban_run(self) -> bool:
|
718
|
-
|
719
|
-
files = self.prover_context.files
|
720
|
-
except AttributeError:
|
721
|
-
return False
|
722
|
-
return Util.CARGO_FILE in files or any(Path(path).suffix == '.wasm' for path in files)
|
718
|
+
return (hasattr(self.prover_context, 'build_script') and self.prover_context is not None)
|
723
719
|
|
724
720
|
def config_server(self) -> str:
|
725
721
|
"""
|
@@ -873,6 +869,16 @@ class MutateApp:
|
|
873
869
|
self.backup_paths = []
|
874
870
|
|
875
871
|
def submit_soroban(self) -> None:
|
872
|
+
|
873
|
+
try:
|
874
|
+
original_run_result = self.run_certora_prover(self.conf, self.mutation_test_id, msg=MConstants.ORIGINAL)
|
875
|
+
except Exception as e:
|
876
|
+
raise Util.CertoraUserInputError(f"Orig run: {e}")
|
877
|
+
if not original_run_result:
|
878
|
+
raise Util.CertoraUserInputError("No Orig results")
|
879
|
+
result_link = original_run_result.rule_report_link
|
880
|
+
assert result_link, "submit_soroban: Null result_link"
|
881
|
+
|
876
882
|
mutation_logger.info("Generating mutants and submitting...")
|
877
883
|
generated_mutants: List[Mutant] = self.get_universal_mutator_mutants()
|
878
884
|
|
@@ -1341,7 +1347,8 @@ class MutateApp:
|
|
1341
1347
|
for mutant in self.universal_mutator:
|
1342
1348
|
file_to_mutate = Path(os.path.normpath(mutant[MConstants.FILE_TO_MUTATE]))
|
1343
1349
|
mutants_location = Path(mutant[MConstants.MUTANTS_LOCATION])
|
1344
|
-
|
1350
|
+
num_of_mutants = mutant[MConstants.NUM_MUTANTS]
|
1351
|
+
run_universal_mutator(file_to_mutate, self.prover_context.build_script, mutants_location, num_of_mutants)
|
1345
1352
|
self.add_dir_to_mutants(ret_mutants, mutants_location, file_to_mutate)
|
1346
1353
|
return ret_mutants
|
1347
1354
|
|
@@ -1784,7 +1791,9 @@ class MutateApp:
|
|
1784
1791
|
|
1785
1792
|
# all keys in prover_context must exist as attribute of certoraRun
|
1786
1793
|
def check_prover_context(self) -> None:
|
1787
|
-
|
1794
|
+
attributes = Attrs.SorobanProverAttributes.attribute_list() if self.is_soroban_run() \
|
1795
|
+
else Attrs.EvmProverAttributes.attribute_list()
|
1796
|
+
prover_attrs = [attr.get_conf_key() for attr in attributes]
|
1788
1797
|
for key in vars(self.prover_context).keys():
|
1789
1798
|
if key not in prover_attrs:
|
1790
1799
|
raise Util.CertoraUserInputError(f"{key} not a valid attribute in a conf file")
|