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.
Files changed (54) hide show
  1. certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +10 -3
  2. certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +51 -16
  3. certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
  4. certora_cli/CertoraProver/castingInstrumenter.py +192 -0
  5. certora_cli/CertoraProver/certoraApp.py +52 -0
  6. certora_cli/CertoraProver/certoraBuild.py +694 -207
  7. certora_cli/CertoraProver/certoraBuildCacheManager.py +21 -17
  8. certora_cli/CertoraProver/certoraBuildDataClasses.py +8 -2
  9. certora_cli/CertoraProver/certoraBuildRust.py +88 -54
  10. certora_cli/CertoraProver/certoraBuildSui.py +112 -0
  11. certora_cli/CertoraProver/certoraCloudIO.py +97 -96
  12. certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +230 -84
  13. certora_cli/CertoraProver/certoraCollectRunMetadata.py +52 -6
  14. certora_cli/CertoraProver/certoraCompilerParameters.py +11 -0
  15. certora_cli/CertoraProver/certoraConfigIO.py +43 -35
  16. certora_cli/CertoraProver/certoraContext.py +128 -54
  17. certora_cli/CertoraProver/certoraContextAttributes.py +415 -234
  18. certora_cli/CertoraProver/certoraContextValidator.py +152 -105
  19. certora_cli/CertoraProver/certoraContractFuncs.py +34 -1
  20. certora_cli/CertoraProver/certoraParseBuildScript.py +8 -10
  21. certora_cli/CertoraProver/certoraType.py +10 -1
  22. certora_cli/CertoraProver/certoraVerifyGenerator.py +22 -4
  23. certora_cli/CertoraProver/erc7201.py +45 -0
  24. certora_cli/CertoraProver/splitRules.py +23 -18
  25. certora_cli/CertoraProver/storageExtension.py +351 -0
  26. certora_cli/EquivalenceCheck/Eq_default.conf +0 -1
  27. certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -1
  28. certora_cli/EquivalenceCheck/equivCheck.py +2 -1
  29. certora_cli/Mutate/mutateApp.py +41 -22
  30. certora_cli/Mutate/mutateAttributes.py +11 -0
  31. certora_cli/Mutate/mutateValidate.py +42 -2
  32. certora_cli/Shared/certoraAttrUtil.py +21 -5
  33. certora_cli/Shared/certoraUtils.py +180 -60
  34. certora_cli/Shared/certoraValidateFuncs.py +68 -26
  35. certora_cli/Shared/proverCommon.py +308 -0
  36. certora_cli/certoraCVLFormatter.py +76 -0
  37. certora_cli/certoraConcord.py +39 -0
  38. certora_cli/certoraEVMProver.py +4 -3
  39. certora_cli/certoraRanger.py +39 -0
  40. certora_cli/certoraRun.py +83 -223
  41. certora_cli/certoraSolanaProver.py +40 -128
  42. certora_cli/certoraSorobanProver.py +59 -4
  43. certora_cli/certoraSuiProver.py +93 -0
  44. certora_cli_beta_mirror-8.5.0.dist-info/LICENSE +15 -0
  45. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/METADATA +21 -5
  46. certora_cli_beta_mirror-8.5.0.dist-info/RECORD +81 -0
  47. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/WHEEL +1 -1
  48. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/entry_points.txt +3 -0
  49. certora_jars/ASTExtraction.jar +0 -0
  50. certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
  51. certora_jars/Typechecker.jar +0 -0
  52. certora_cli_beta_mirror-7.28.0.dist-info/LICENSE +0 -22
  53. certora_cli_beta_mirror-7.28.0.dist-info/RECORD +0 -70
  54. {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
- if zip_file_path.stat().st_size > MAX_FILE_SIZE:
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
- "process": self.context.process, "runName": self.runName,
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.is_solana_app():
596
- # We need to strip "../" path component from all file paths because
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
- else:
603
- for file in self.context.files:
604
- solana_jar_settings.append(file.split('../')[-1])
605
-
606
- is_file = False
607
- for arg in jar_settings:
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 arg == '-solanaInlining':
615
- is_file = True
616
- elif arg == '-solanaSummaries':
617
- is_file = True
618
- auth_data["jarSettings"] = solana_jar_settings
619
- elif Attrs.is_soroban_app():
620
- # We need to strip "../" path component from all file paths because
621
- # unzip will also do that.
622
- soroban_jar_settings = []
623
- # not needed - should be in files
624
- if hasattr(self.context, 'build_script') and self.context.build_script:
625
- soroban_jar_settings.append(Path(self.context.rust_executables).name)
626
- else:
627
- for file in self.context.files:
628
- soroban_jar_settings.append(file.split('../')[-1])
629
- for arg in jar_settings:
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 = f"{self.get_domain()}/?groupIds={self.context.group_id}"
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.reportUrl}", flush=True)
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.reportUrl}")
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(), Util.get_configuration_layout_data_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
- result = compress_files(self.ZipFilePath, *files_list,
780
- short_output=Ctx.is_minimal_cli_output(self.context))
781
-
782
- elif Attrs.is_solana_app():
783
- # We zip the ELF files and the two configuration files
784
- jar_args = Ctx.collect_jar_args(self.context)
785
-
786
- for file in self.context.files:
787
- files_list.append(Path(file))
788
- is_file = False
789
- for arg in jar_args:
790
- if is_file:
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.reportUrl)
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]