certora-cli-beta-mirror 7.28.0__py3-none-any.whl → 8.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +10 -3
- certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +51 -16
- certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
- certora_cli/CertoraProver/castingInstrumenter.py +192 -0
- certora_cli/CertoraProver/certoraApp.py +52 -0
- certora_cli/CertoraProver/certoraBuild.py +694 -207
- certora_cli/CertoraProver/certoraBuildCacheManager.py +21 -17
- certora_cli/CertoraProver/certoraBuildDataClasses.py +8 -2
- certora_cli/CertoraProver/certoraBuildRust.py +88 -54
- certora_cli/CertoraProver/certoraBuildSui.py +112 -0
- certora_cli/CertoraProver/certoraCloudIO.py +97 -96
- certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +230 -84
- certora_cli/CertoraProver/certoraCollectRunMetadata.py +52 -6
- certora_cli/CertoraProver/certoraCompilerParameters.py +11 -0
- certora_cli/CertoraProver/certoraConfigIO.py +43 -35
- certora_cli/CertoraProver/certoraContext.py +128 -54
- certora_cli/CertoraProver/certoraContextAttributes.py +415 -234
- certora_cli/CertoraProver/certoraContextValidator.py +152 -105
- certora_cli/CertoraProver/certoraContractFuncs.py +34 -1
- certora_cli/CertoraProver/certoraParseBuildScript.py +8 -10
- certora_cli/CertoraProver/certoraType.py +10 -1
- certora_cli/CertoraProver/certoraVerifyGenerator.py +22 -4
- certora_cli/CertoraProver/erc7201.py +45 -0
- certora_cli/CertoraProver/splitRules.py +23 -18
- certora_cli/CertoraProver/storageExtension.py +351 -0
- certora_cli/EquivalenceCheck/Eq_default.conf +0 -1
- certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -1
- certora_cli/EquivalenceCheck/equivCheck.py +2 -1
- certora_cli/Mutate/mutateApp.py +41 -22
- certora_cli/Mutate/mutateAttributes.py +11 -0
- certora_cli/Mutate/mutateValidate.py +42 -2
- certora_cli/Shared/certoraAttrUtil.py +21 -5
- certora_cli/Shared/certoraUtils.py +180 -60
- certora_cli/Shared/certoraValidateFuncs.py +68 -26
- certora_cli/Shared/proverCommon.py +308 -0
- certora_cli/certoraCVLFormatter.py +76 -0
- certora_cli/certoraConcord.py +39 -0
- certora_cli/certoraEVMProver.py +4 -3
- certora_cli/certoraRanger.py +39 -0
- certora_cli/certoraRun.py +83 -223
- certora_cli/certoraSolanaProver.py +40 -128
- certora_cli/certoraSorobanProver.py +59 -4
- certora_cli/certoraSuiProver.py +93 -0
- certora_cli_beta_mirror-8.5.0.dist-info/LICENSE +15 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/METADATA +21 -5
- certora_cli_beta_mirror-8.5.0.dist-info/RECORD +81 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/WHEEL +1 -1
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/entry_points.txt +3 -0
- certora_jars/ASTExtraction.jar +0 -0
- certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
- certora_jars/Typechecker.jar +0 -0
- certora_cli_beta_mirror-7.28.0.dist-info/LICENSE +0 -22
- certora_cli_beta_mirror-7.28.0.dist-info/RECORD +0 -70
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/top_level.txt +0 -0
|
@@ -43,10 +43,10 @@ from tqdm import tqdm
|
|
|
43
43
|
|
|
44
44
|
import logging
|
|
45
45
|
|
|
46
|
-
|
|
47
46
|
cloud_logger = logging.getLogger("cloud")
|
|
48
47
|
|
|
49
48
|
MAX_FILE_SIZE = 25 * 1024 * 1024
|
|
49
|
+
SOLANA_MAX_FILE_SIZE = 2 * MAX_FILE_SIZE
|
|
50
50
|
NO_OUTPUT_LIMIT_MINUTES = 15
|
|
51
51
|
MAX_POLLING_TIME_MINUTES = 150
|
|
52
52
|
LOG_READ_FREQUENCY = 10
|
|
@@ -69,6 +69,17 @@ Response = requests.models.Response
|
|
|
69
69
|
|
|
70
70
|
FEATURES_REPORT_FILE = Path("featuresReport.json")
|
|
71
71
|
|
|
72
|
+
class EcoEnum(Util.NoValEnum):
|
|
73
|
+
EVM = Util.auto()
|
|
74
|
+
SOROBAN = Util.auto()
|
|
75
|
+
SOLANA = Util.auto()
|
|
76
|
+
SUI = Util.auto()
|
|
77
|
+
|
|
78
|
+
class ProductEnum(Util.NoValEnum):
|
|
79
|
+
PROVER = Util.auto()
|
|
80
|
+
RANGER = Util.auto()
|
|
81
|
+
CONCORD = Util.auto()
|
|
82
|
+
|
|
72
83
|
|
|
73
84
|
class TimeError(Exception):
|
|
74
85
|
"""A custom exception used to report on time elapsed errors"""
|
|
@@ -264,7 +275,9 @@ def compress_files(zip_file_path: Path, *resource_paths: Path, short_output: boo
|
|
|
264
275
|
cloud_logger.error(f"{GENERAL_ERR_PREFIX}" f"Could not compress {path}")
|
|
265
276
|
return False
|
|
266
277
|
|
|
267
|
-
|
|
278
|
+
# Solana binary files can become heavy, thus we need to increase size limit.
|
|
279
|
+
max_file_size = MAX_FILE_SIZE if not Attrs.is_rust_app() else SOLANA_MAX_FILE_SIZE
|
|
280
|
+
if zip_file_path.stat().st_size > max_file_size:
|
|
268
281
|
cloud_logger.error(f"{GENERAL_ERR_PREFIX} Max 25MB file size exceeded.")
|
|
269
282
|
return False
|
|
270
283
|
|
|
@@ -574,7 +587,7 @@ class CloudVerification:
|
|
|
574
587
|
"""
|
|
575
588
|
|
|
576
589
|
auth_data = {
|
|
577
|
-
"
|
|
590
|
+
"runName": self.runName,
|
|
578
591
|
"run_source": self.context.run_source,
|
|
579
592
|
"group_id": self.context.group_id,
|
|
580
593
|
"branch": self.context.prover_version if self.context.prover_version else '',
|
|
@@ -592,43 +605,32 @@ class CloudVerification:
|
|
|
592
605
|
|
|
593
606
|
jar_settings = Ctx.collect_jar_args(self.context)
|
|
594
607
|
|
|
595
|
-
if Attrs.
|
|
596
|
-
|
|
597
|
-
# unzip will also do that.
|
|
598
|
-
solana_jar_settings = []
|
|
599
|
-
if hasattr(self.context, 'build_script') and self.context.build_script:
|
|
600
|
-
solana_jar_settings.append(Path(self.context.rust_executables).name)
|
|
608
|
+
if Attrs.is_rust_app():
|
|
609
|
+
rust_jar_settings = [Path(self.context.files[0]).name]
|
|
601
610
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
if is_file:
|
|
609
|
-
solana_jar_settings.append(arg.split('../')[-1])
|
|
610
|
-
is_file = False
|
|
611
|
-
else:
|
|
612
|
-
solana_jar_settings.append(arg)
|
|
611
|
+
if Attrs.is_solana_app():
|
|
612
|
+
def paths_in_source_dir(attr_values: List[str]) -> str:
|
|
613
|
+
cwd_rel_in_sources = Util.get_certora_sources_dir() / self.context.cwd_rel_in_sources
|
|
614
|
+
values: list[str] = \
|
|
615
|
+
[os.path.relpath(cwd_rel_in_sources / value, Util.get_build_dir()) for value in attr_values]
|
|
616
|
+
return ','.join(values)
|
|
613
617
|
|
|
614
|
-
if
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
soroban_jar_settings.append(arg)
|
|
631
|
-
auth_data["jarSettings"] = soroban_jar_settings
|
|
618
|
+
if self.context.solana_summaries:
|
|
619
|
+
rust_jar_settings.append('-solanaSummaries')
|
|
620
|
+
rust_jar_settings.append(paths_in_source_dir(self.context.solana_summaries))
|
|
621
|
+
|
|
622
|
+
if self.context.solana_inlining:
|
|
623
|
+
rust_jar_settings.append('-solanaInlining')
|
|
624
|
+
rust_jar_settings.append(paths_in_source_dir(self.context.solana_inlining))
|
|
625
|
+
|
|
626
|
+
auth_data["jarSettings"] = rust_jar_settings + jar_settings
|
|
627
|
+
|
|
628
|
+
elif Attrs.is_sui_app():
|
|
629
|
+
sui_jar_settings = ['-movePath', Path(self.context.move_path).name]
|
|
630
|
+
auth_data["jarSettings"] = sui_jar_settings + jar_settings
|
|
631
|
+
|
|
632
|
+
elif Attrs.is_concord_app():
|
|
633
|
+
auth_data["jarSettings"] = jar_settings + ["-equivalenceCheck", "true"]
|
|
632
634
|
else:
|
|
633
635
|
auth_data["jarSettings"] = jar_settings
|
|
634
636
|
|
|
@@ -646,6 +648,22 @@ class CloudVerification:
|
|
|
646
648
|
|
|
647
649
|
auth_data["useLatestFe"] = self.context.fe_version == str(Util.FeValue.LATEST)
|
|
648
650
|
|
|
651
|
+
if Attrs.is_solana_app():
|
|
652
|
+
auth_data["ecosystem"] = EcoEnum.SOLANA.name
|
|
653
|
+
elif Attrs.is_soroban_app():
|
|
654
|
+
auth_data["ecosystem"] = EcoEnum.SOROBAN.name
|
|
655
|
+
elif Attrs.is_sui_app():
|
|
656
|
+
auth_data["ecosystem"] = EcoEnum.SUI.name
|
|
657
|
+
else:
|
|
658
|
+
auth_data["ecosystem"] = EcoEnum.EVM.name
|
|
659
|
+
|
|
660
|
+
if Attrs.is_ranger_app():
|
|
661
|
+
auth_data["product"] = ProductEnum.RANGER.name
|
|
662
|
+
elif Attrs.is_concord_app():
|
|
663
|
+
auth_data["product"] = ProductEnum.CONCORD.name
|
|
664
|
+
else:
|
|
665
|
+
auth_data["product"] = ProductEnum.PROVER.name
|
|
666
|
+
|
|
649
667
|
if Attrs.is_evm_app() and self.context.cache is not None:
|
|
650
668
|
auth_data["toolSceneCacheKey"] = self.context.cache
|
|
651
669
|
|
|
@@ -671,18 +689,21 @@ class CloudVerification:
|
|
|
671
689
|
auth_data["mutationTestId"] = self.context.mutation_test_id
|
|
672
690
|
return auth_data
|
|
673
691
|
|
|
692
|
+
def get_group_id_url(self) -> str:
|
|
693
|
+
return f"{self.get_domain()}/?groupIds={self.context.group_id}"
|
|
694
|
+
|
|
674
695
|
def print_group_id_url(self) -> None:
|
|
675
|
-
group_id_url =
|
|
696
|
+
group_id_url = self.get_group_id_url()
|
|
676
697
|
print(f"See all jobs generated from splitting the rules at {group_id_url}", flush=True)
|
|
677
698
|
|
|
678
699
|
def print_output_links(self) -> None:
|
|
679
700
|
print(f"Manage your jobs at {self.get_domain()}")
|
|
680
|
-
print(f"Follow your job and see verification results at {self.
|
|
701
|
+
print(f"Follow your job and see verification results at {self.url_print_format()}", flush=True)
|
|
681
702
|
|
|
682
703
|
def print_verification_summary(self) -> None:
|
|
683
704
|
report_exists = self.check_file_exists(params={"filename": "index.html", "certoraKey": self.context.key})
|
|
684
705
|
if report_exists:
|
|
685
|
-
print(f"Job is completed! View the results at {self.
|
|
706
|
+
print(f"Job is completed! View the results at {self.url_print_format()}")
|
|
686
707
|
print("Finished verification request", flush=True)
|
|
687
708
|
|
|
688
709
|
def __send_verification_request(self, cl_args: str) -> bool:
|
|
@@ -747,69 +768,34 @@ class CloudVerification:
|
|
|
747
768
|
result = compress_files(self.ZipFilePath, *paths,
|
|
748
769
|
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
749
770
|
elif Attrs.is_rust_app():
|
|
750
|
-
files_list = [Util.get_certora_metadata_file(),
|
|
771
|
+
files_list = [Util.get_certora_metadata_file(),
|
|
772
|
+
Util.get_configuration_layout_data_file(),
|
|
773
|
+
Util.get_build_dir() / Path(self.context.files[0]).name]
|
|
774
|
+
|
|
775
|
+
if Util.get_debug_log_file().exists():
|
|
776
|
+
files_list.append(Util.get_debug_log_file())
|
|
777
|
+
|
|
751
778
|
if Util.get_certora_sources_dir().exists():
|
|
752
779
|
files_list.append(Util.get_certora_sources_dir())
|
|
753
780
|
|
|
754
781
|
if hasattr(self.context, 'build_script') and self.context.build_script:
|
|
755
|
-
result = compress_files(self.logZipFilePath, Util.get_debug_log_file(),
|
|
756
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
757
|
-
|
|
758
|
-
if not result:
|
|
759
|
-
return False
|
|
760
|
-
files_list.append(self.logZipFilePath)
|
|
761
|
-
|
|
762
|
-
files_list.append(Util.get_build_dir() / Path(self.context.rust_executables).name)
|
|
763
|
-
|
|
764
|
-
# Create a .RustExecution file to classify zipInput as a rust source code
|
|
765
|
-
rust_execution_file = Util.get_build_dir() / ".RustExecution"
|
|
766
|
-
rust_execution_file.touch(exist_ok=True)
|
|
767
|
-
files_list.append(rust_execution_file)
|
|
768
|
-
|
|
769
|
-
additional_files = (getattr(self.context, 'solana_inlining', None) or []) + \
|
|
770
|
-
(getattr(self.context, 'solana_summaries', None) or [])
|
|
771
|
-
for file in additional_files:
|
|
772
|
-
files_list.append(Util.get_build_dir() / Path(file).name)
|
|
773
|
-
|
|
774
782
|
if attr_file := getattr(self.context, 'rust_logs_stdout', None):
|
|
775
783
|
files_list.append(Util.get_build_dir() / Path(attr_file).name)
|
|
776
784
|
if attr_file := getattr(self.context, 'rust_logs_stderr', None):
|
|
777
785
|
files_list.append(Util.get_build_dir() / Path(attr_file).name)
|
|
778
786
|
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
files_list.append(Path(arg))
|
|
792
|
-
is_file = False
|
|
793
|
-
|
|
794
|
-
if arg == '-solanaInlining':
|
|
795
|
-
is_file = True
|
|
796
|
-
elif arg == '-solanaSummaries':
|
|
797
|
-
is_file = True
|
|
798
|
-
result = compress_files(self.ZipFilePath, *files_list,
|
|
799
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
800
|
-
|
|
801
|
-
elif Attrs.is_soroban_app():
|
|
802
|
-
# We zip the wat file
|
|
803
|
-
for file in self.context.files:
|
|
804
|
-
files_list.append(Path(file))
|
|
805
|
-
result = compress_files(self.ZipFilePath, *files_list,
|
|
806
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
807
|
-
else:
|
|
808
|
-
raise Util.CertoraUserInputError(
|
|
809
|
-
'When running rust application, context should either have attribute "rust_executables" '
|
|
810
|
-
'provided by build_script execution, '
|
|
811
|
-
'or either is_solana_app(), is_soroban_app() should be set to True'
|
|
812
|
-
)
|
|
787
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
|
788
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
789
|
+
elif Attrs.is_sui_app():
|
|
790
|
+
files_list = [Util.get_certora_metadata_file(),
|
|
791
|
+
Util.get_configuration_layout_data_file(),
|
|
792
|
+
Util.get_build_dir() / Path(self.context.move_path).name]
|
|
793
|
+
|
|
794
|
+
if Util.get_certora_sources_dir().exists():
|
|
795
|
+
files_list.append(Util.get_certora_sources_dir())
|
|
796
|
+
|
|
797
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
|
798
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
813
799
|
|
|
814
800
|
else:
|
|
815
801
|
# Zip the log file first separately and again with the rest of the files, so it will not be decompressed
|
|
@@ -829,6 +815,8 @@ class CloudVerification:
|
|
|
829
815
|
Util.flush_stdout()
|
|
830
816
|
if not result:
|
|
831
817
|
return False
|
|
818
|
+
if self.context.test == str(Util.TestValue.CHECK_ZIP):
|
|
819
|
+
raise Util.TestResultsReady(self.ZipFilePath)
|
|
832
820
|
|
|
833
821
|
cloud_logger.debug("Uploading files...")
|
|
834
822
|
if self.upload(self.presigned_url, self.ZipFilePath):
|
|
@@ -866,6 +854,7 @@ class CloudVerification:
|
|
|
866
854
|
return False
|
|
867
855
|
|
|
868
856
|
file_upload_success = self.__compress_and_upload_zip_files()
|
|
857
|
+
|
|
869
858
|
if not file_upload_success:
|
|
870
859
|
return False
|
|
871
860
|
|
|
@@ -884,7 +873,7 @@ class CloudVerification:
|
|
|
884
873
|
self.runName, self.reportUrl, self.msg, self.get_domain(), str(self.userId), self.anonymousKey)
|
|
885
874
|
|
|
886
875
|
# Generate a json file for the VS Code extension with the relevant url
|
|
887
|
-
self.vscode_extension_info_writer.add_field("verification_report_url", self.
|
|
876
|
+
self.vscode_extension_info_writer.add_field("verification_report_url", self.url_print_format())
|
|
888
877
|
self.vscode_extension_info_writer.write_file()
|
|
889
878
|
|
|
890
879
|
if not wait_for_results or wait_for_results == str(Vf.WaitForResultOptions.NONE):
|
|
@@ -964,6 +953,8 @@ class CloudVerification:
|
|
|
964
953
|
for i in range(self.verification_request_retries):
|
|
965
954
|
try:
|
|
966
955
|
response = requests.post(verify_url, json=auth_data, headers=headers, timeout=60)
|
|
956
|
+
cloud_logger.debug(f"\n\n=================\n\nresponse - Status Code: {response.status_code}\n\n"
|
|
957
|
+
f"Headers:\n {response.headers}\n\nText:\n {response.text}\n\n=================\n\n")
|
|
967
958
|
if response is None:
|
|
968
959
|
continue
|
|
969
960
|
status = response.status_code
|
|
@@ -1171,6 +1162,12 @@ class CloudVerification:
|
|
|
1171
1162
|
Util.remove_file(self.ZipFilePath)
|
|
1172
1163
|
Util.remove_file(self.logZipFilePath)
|
|
1173
1164
|
|
|
1165
|
+
def url_print_format(self) -> str:
|
|
1166
|
+
if self.reportUrl and self.context.url_visibility == str(Vf.UrlVisibilityOptions.PRIVATE):
|
|
1167
|
+
return self.privatize_url()
|
|
1168
|
+
else:
|
|
1169
|
+
return self.reportUrl
|
|
1170
|
+
|
|
1174
1171
|
@lru_cache(maxsize=1, typed=False)
|
|
1175
1172
|
def get_domain(self) -> str:
|
|
1176
1173
|
"""
|
|
@@ -1186,3 +1183,7 @@ class CloudVerification:
|
|
|
1186
1183
|
domain = Util.SupportedServers.PRODUCTION.value
|
|
1187
1184
|
|
|
1188
1185
|
return domain
|
|
1186
|
+
|
|
1187
|
+
@lru_cache(maxsize=1)
|
|
1188
|
+
def privatize_url(self) -> str:
|
|
1189
|
+
return self.reportUrl.split('?anonymousKey=')[0]
|