certora-cli-beta-mirror 7.28.0__py3-none-any.whl → 7.29.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 (31) hide show
  1. certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +48 -13
  2. certora_cli/CertoraProver/certoraBuild.py +61 -30
  3. certora_cli/CertoraProver/certoraBuildDataClasses.py +5 -2
  4. certora_cli/CertoraProver/certoraBuildRust.py +77 -41
  5. certora_cli/CertoraProver/certoraCloudIO.py +29 -64
  6. certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +205 -70
  7. certora_cli/CertoraProver/certoraCollectRunMetadata.py +3 -1
  8. certora_cli/CertoraProver/certoraConfigIO.py +14 -15
  9. certora_cli/CertoraProver/certoraContext.py +13 -5
  10. certora_cli/CertoraProver/certoraContextAttributes.py +95 -26
  11. certora_cli/CertoraProver/certoraContextValidator.py +39 -5
  12. certora_cli/CertoraProver/certoraParseBuildScript.py +7 -10
  13. certora_cli/CertoraProver/certoraVerifyGenerator.py +12 -0
  14. certora_cli/CertoraProver/splitRules.py +3 -1
  15. certora_cli/Mutate/mutateApp.py +3 -3
  16. certora_cli/Shared/certoraAttrUtil.py +10 -0
  17. certora_cli/Shared/certoraUtils.py +9 -1
  18. certora_cli/Shared/certoraValidateFuncs.py +7 -0
  19. certora_cli/certoraRanger.py +71 -0
  20. certora_cli/certoraRun.py +11 -13
  21. certora_cli/certoraSolanaProver.py +7 -0
  22. certora_cli/certoraSorobanProver.py +253 -4
  23. certora_cli_beta_mirror-7.29.0.dist-info/LICENSE +15 -0
  24. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/METADATA +18 -4
  25. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/RECORD +30 -29
  26. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/WHEEL +1 -1
  27. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/entry_points.txt +1 -0
  28. certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
  29. certora_jars/Typechecker.jar +0 -0
  30. certora_cli_beta_mirror-7.28.0.dist-info/LICENSE +0 -22
  31. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/top_level.txt +0 -0
@@ -351,7 +351,6 @@ class EvmAttributes(AttrUtil.Attributes):
351
351
 
352
352
  SOLC_EXPERIMENTAL_VIA_IR = AttrUtil.AttributeDefinition(
353
353
  arg_type=AttrUtil.AttrArgType.BOOLEAN,
354
- help_msg="Pass the `--experimental-via-ir` flag to the Solidity compiler",
355
354
  default_desc="",
356
355
  argparse_args={
357
356
  'action': AttrUtil.STORE_TRUE
@@ -527,7 +526,7 @@ class EvmAttributes(AttrUtil.Attributes):
527
526
  affects_build_cache_key=True,
528
527
  disables_build_cache=False,
529
528
  config_data=AttributeJobConfigData(
530
- main_section=MainSection.PACKAGES
529
+ main_section=MainSection.NEW_SECTION
531
530
  )
532
531
  )
533
532
 
@@ -545,9 +544,10 @@ class EvmAttributes(AttrUtil.Attributes):
545
544
 
546
545
  STRICT_SOLC_OPTIMIZER = AttrUtil.AttributeDefinition(
547
546
  arg_type=AttrUtil.AttrArgType.BOOLEAN,
548
- help_msg="Allow Solidity compiler optimizations that can interfere with internal function finders",
549
- default_desc="Disables optimizations that may invalidate the bytecode annotations that identify "
550
- "internal functions",
547
+ # This is a hidden flag, the following two attributes are left intentionally as comments to help devs
548
+ # help_msg="Allow Solidity compiler optimizations that can interfere with internal function finders",
549
+ # default_desc="Disables optimizations that may invalidate the bytecode annotations that identify "
550
+ # "internal functions",
551
551
  argparse_args={
552
552
  'action': AttrUtil.STORE_TRUE
553
553
  },
@@ -573,7 +573,8 @@ class EvmAttributes(AttrUtil.Attributes):
573
573
 
574
574
  YUL_ABI = AttrUtil.AttributeDefinition(
575
575
  attr_validation_func=Vf.validate_json_file,
576
- help_msg="An auxiliary ABI file for yul contracts",
576
+ # This is a hidden flag, the following two attributes are left intentionally as comments to help devs
577
+ # help_msg="An auxiliary ABI file for yul contracts",
577
578
  default_desc="",
578
579
  argparse_args={
579
580
  'action': AttrUtil.UniqueStore
@@ -604,7 +605,7 @@ class EvmAttributes(AttrUtil.Attributes):
604
605
  affects_build_cache_key=True, # not sure, better be careful
605
606
  disables_build_cache=False,
606
607
  config_data=AttributeJobConfigData(
607
- main_section=MainSection.LINKS
608
+ main_section=MainSection.NEW_SECTION
608
609
  )
609
610
  )
610
611
 
@@ -640,9 +641,10 @@ class EvmAttributes(AttrUtil.Attributes):
640
641
 
641
642
  STORAGE_EXTENSION_HARNESSES = AttrUtil.AttributeDefinition(
642
643
  attr_validation_func=Vf.validate_storage_extension_harness_attr,
643
- help_msg="List of ContractA=ContractB where ContractB is the name of a 'storage extension prototype`. "
644
- "See the documentation for details",
645
- default_desc="",
644
+ # The docs aren't ready yet. The flag is hidden; the lines below are commented to help us devs
645
+ # help_msg="List of ContractA=ContractB where ContractB is the name of a 'storage extension prototype`. "
646
+ # "See the documentation for details",
647
+ # default_desc="",
646
648
  disables_build_cache=False,
647
649
  affects_build_cache_key=True,
648
650
  arg_type=AttrUtil.AttrArgType.LIST,
@@ -738,7 +740,8 @@ class EvmAttributes(AttrUtil.Attributes):
738
740
  'action': AttrUtil.UniqueStore
739
741
  },
740
742
  affects_build_cache_key=False,
741
- disables_build_cache=False
743
+ disables_build_cache=False,
744
+ config_data=None
742
745
  )
743
746
 
744
747
  BUILD_CACHE = AttrUtil.AttributeDefinition(
@@ -751,11 +754,13 @@ class EvmAttributes(AttrUtil.Attributes):
751
754
  affects_build_cache_key=False,
752
755
  disables_build_cache=False
753
756
  )
757
+
754
758
  FUNCTION_FINDER_MODE = AttrUtil.AttributeDefinition(
755
759
  attr_validation_func=Vf.validate_function_finder_mode,
756
- help_msg="Use `relaxed` mode to increase internal function finders precision, "
757
- "but may cause `stack too deep` errors unless using `via-ir`",
758
- default_desc="Takes less stack space but internal functions may be missed",
760
+ # This is a hidden flag, the following two attributes are left intentionally as comments to help devs
761
+ # help_msg="Use `relaxed` mode to increase internal function finders precision, "
762
+ # "but may cause `stack too deep` errors unless using `via-ir`",
763
+ # default_desc="Takes less stack space but internal functions may be missed",
759
764
  argparse_args={
760
765
  'nargs': AttrUtil.SINGLE_OR_NONE_OCCURRENCES,
761
766
  'action': AttrUtil.UniqueStore,
@@ -819,11 +824,17 @@ class EvmAttributes(AttrUtil.Attributes):
819
824
  disables_build_cache=False
820
825
  )
821
826
 
827
+ EQUIVALENCE_CONTRACTS = AttrUtil.AttributeDefinition(
828
+ attr_validation_func=Vf.validate_equivalence_contracts,
829
+ arg_type=AttrUtil.AttrArgType.STRING,
830
+ affects_build_cache_key=False,
831
+ disables_build_cache=False
832
+ )
833
+
822
834
  BYTECODE_JSONS = AttrUtil.AttributeDefinition(
823
835
  attr_validation_func=Vf.validate_json_file,
824
836
  arg_type=AttrUtil.AttrArgType.LIST,
825
837
  jar_flag='-bytecode',
826
- help_msg="List of EVM bytecode JSON descriptors",
827
838
  default_desc="",
828
839
  argparse_args={
829
840
  'nargs': AttrUtil.ONE_OR_MORE_OCCURRENCES,
@@ -836,7 +847,6 @@ class EvmAttributes(AttrUtil.Attributes):
836
847
  BYTECODE_SPEC = AttrUtil.AttributeDefinition(
837
848
  attr_validation_func=Vf.validate_spec_file,
838
849
  jar_flag='-spec',
839
- help_msg="Spec to use for the provided bytecodes",
840
850
  default_desc="",
841
851
  argparse_args={
842
852
  'action': AttrUtil.UniqueStore
@@ -961,6 +971,20 @@ class EvmAttributes(AttrUtil.Attributes):
961
971
  disables_build_cache=False
962
972
  )
963
973
 
974
+ EXCLUDE_METHOD = AttrUtil.AttributeDefinition(
975
+ attr_validation_func=Vf.validate_method_flag,
976
+ jar_flag='-excludeMethod',
977
+ arg_type=AttrUtil.AttrArgType.LIST,
978
+ help_msg="Filter out methods to be verified by their signature",
979
+ default_desc="Verifies all public or external methods. In invariants pure and view functions are ignored",
980
+ argparse_args={
981
+ 'nargs': AttrUtil.ONE_OR_MORE_OCCURRENCES,
982
+ 'action': AttrUtil.APPEND
983
+ },
984
+ affects_build_cache_key=False,
985
+ disables_build_cache=False
986
+ )
987
+
964
988
  OPTIMISTIC_CONTRACT_RECURSION = AttrUtil.AttributeDefinition(
965
989
  arg_type=AttrUtil.AttrArgType.BOOLEAN,
966
990
  help_msg="Assume the recursion limit is never reached in cases of "
@@ -1076,30 +1100,39 @@ class EvmAttributes(AttrUtil.Attributes):
1076
1100
  },
1077
1101
  affects_build_cache_key=True,
1078
1102
  disables_build_cache=False,
1079
- help_msg="Verify all foundry fuzz test in the current project",
1103
+ help_msg="Verify all Foundry fuzz tests in the current project",
1080
1104
  default_desc="",
1081
1105
  )
1082
1106
 
1083
- BMC = AttrUtil.AttributeDefinition(
1107
+ RANGE = AttrUtil.AttributeDefinition(
1084
1108
  attr_validation_func=Vf.validate_non_negative_integer,
1085
1109
  argparse_args={
1086
1110
  'action': AttrUtil.UniqueStore
1087
1111
  },
1112
+ help_msg="The maximal length of function call sequences Ranger checks",
1113
+ default_desc=f"The default value ('{Util.DEFAULT_RANGER_RANGE}') is used",
1088
1114
  jar_flag="-boundedModelChecking",
1089
1115
  affects_build_cache_key=False,
1090
1116
  disables_build_cache=False,
1091
1117
  )
1092
1118
 
1093
- BMC_FAILURE_LIMIT = AttrUtil.AttributeDefinition(
1119
+ RANGER_FAILURE_LIMIT = AttrUtil.AttributeDefinition(
1094
1120
  attr_validation_func=Vf.validate_non_negative_integer,
1095
1121
  argparse_args={
1096
1122
  'action': AttrUtil.UniqueStore
1097
1123
  },
1124
+ help_msg="Once this number of violations are found, no new Ranger call sequence checks will be started. Checks already in progress will continue.",
1125
+ default_desc=f"Once {Util.DEFAULT_RANGER_FAILURE_LIMIT} violations are found, no new Ranger call sequence checks will be started.",
1098
1126
  jar_flag="-boundedModelCheckingFailureLimit",
1099
1127
  affects_build_cache_key=False,
1100
1128
  disables_build_cache=False,
1101
1129
  )
1102
1130
 
1131
+ @classmethod
1132
+ def hide_attributes(cls) -> List[str]:
1133
+ # do not show these attributes in the help message
1134
+ return [cls.RANGER_FAILURE_LIMIT.name, cls.RANGE.name]
1135
+
1103
1136
 
1104
1137
  class InternalUseAttributes(AttrUtil.Attributes):
1105
1138
  '''
@@ -1451,6 +1484,16 @@ class BackendAttributes(AttrUtil.Attributes):
1451
1484
  disables_build_cache=False
1452
1485
  )
1453
1486
 
1487
+ ENFORCE_REQUIRE_REASON = AttrUtil.AttributeDefinition(
1488
+ arg_type=AttrUtil.AttrArgType.BOOLEAN,
1489
+ jar_flag='-enforceRequireReasonInCVL',
1490
+ argparse_args={
1491
+ 'action': AttrUtil.STORE_TRUE
1492
+ },
1493
+ affects_build_cache_key=False,
1494
+ disables_build_cache=False
1495
+ )
1496
+
1454
1497
  # resource files are string of the form <label>:<path> the client will add the file to .certora_sources
1455
1498
  # and will change the path from relative/absolute path to
1456
1499
  PROVER_RESOURCE_FILES = AttrUtil.AttributeDefinition(
@@ -1611,6 +1654,15 @@ class RustAttributes(AttrUtil.Attributes):
1611
1654
  disables_build_cache=False
1612
1655
  )
1613
1656
 
1657
+ CARGO_TOOLS_VERSION = AttrUtil.AttributeDefinition(
1658
+ help_msg="Platform tools version to use",
1659
+ default_desc="Platform tools version is chosen automatically",
1660
+ argparse_args={
1661
+ 'action': AttrUtil.UniqueStore
1662
+ },
1663
+ affects_build_cache_key=False,
1664
+ disables_build_cache=False
1665
+ )
1614
1666
 
1615
1667
  class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes, InternalUseAttributes,
1616
1668
  BackendAttributes):
@@ -1625,11 +1677,27 @@ class EvmProverAttributes(CommonAttributes, DeprecatedAttributes, EvmAttributes,
1625
1677
  affects_build_cache_key=True,
1626
1678
  disables_build_cache=False,
1627
1679
  config_data=AttributeJobConfigData(
1628
- main_section=MainSection.FILES
1680
+ main_section=MainSection.NEW_SECTION
1629
1681
  )
1630
1682
  )
1631
1683
 
1632
1684
 
1685
+ class RangerAttributes(EvmProverAttributes):
1686
+ @classmethod
1687
+ def ranger_unsupported_attributes(cls) -> List[AttrUtil.AttributeDefinition]:
1688
+ return [cls.PROJECT_SANITY, cls.RULE_SANITY, cls.COVERAGE_INFO, cls.FOUNDRY, cls.INDEPENDENT_SATISFY,
1689
+ cls.MULTI_ASSERT_CHECK, cls.MULTI_EXAMPLE]
1690
+
1691
+ @classmethod
1692
+ def ranger_true_by_default_attributes(cls) -> List[AttrUtil.AttributeDefinition]:
1693
+ return [cls.OPTIMISTIC_LOOP, cls.OPTIMISTIC_FALLBACK, cls.AUTO_DISPATCHER, cls.OPTIMISTIC_HASHING]
1694
+
1695
+ @classmethod
1696
+ def hide_attributes(cls) -> List[str]:
1697
+ # do not show these attributes in the help message
1698
+ combined_list = cls.ranger_unsupported_attributes() + cls.ranger_true_by_default_attributes()
1699
+ return [attr.name for attr in combined_list] + [cls.LOOP_ITER.name, cls.RANGER_FAILURE_LIMIT.name]
1700
+
1633
1701
  class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, RustAttributes):
1634
1702
  FILES = AttrUtil.AttributeDefinition(
1635
1703
  attr_validation_func=Vf.validate_soroban_extension,
@@ -1642,7 +1710,7 @@ class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAt
1642
1710
  affects_build_cache_key=True,
1643
1711
  disables_build_cache=False,
1644
1712
  config_data=AttributeJobConfigData(
1645
- main_section=MainSection.FILES
1713
+ main_section=MainSection.NEW_SECTION
1646
1714
  )
1647
1715
  )
1648
1716
 
@@ -1660,14 +1728,13 @@ class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAtt
1660
1728
  affects_build_cache_key=True,
1661
1729
  disables_build_cache=False,
1662
1730
  config_data=AttributeJobConfigData(
1663
- main_section=MainSection.FILES
1731
+ main_section=MainSection.NEW_SECTION
1664
1732
  )
1665
1733
  )
1666
1734
 
1667
1735
  SOLANA_INLINING = AttrUtil.AttributeDefinition(
1668
1736
  attr_validation_func=Vf.validate_readable_file,
1669
1737
  arg_type=AttrUtil.AttrArgType.LIST,
1670
- jar_flag='-solanaInlining',
1671
1738
  help_msg="a list of paths for the inlining files of Solana contracts",
1672
1739
  argparse_args={
1673
1740
  'nargs': AttrUtil.ONE_OR_MORE_OCCURRENCES,
@@ -1680,7 +1747,6 @@ class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAtt
1680
1747
  SOLANA_SUMMARIES = AttrUtil.AttributeDefinition(
1681
1748
  attr_validation_func=Vf.validate_readable_file,
1682
1749
  arg_type=AttrUtil.AttrArgType.LIST,
1683
- jar_flag='-solanaSummaries',
1684
1750
  help_msg="a list of paths for the summaries files of Solana contracts",
1685
1751
  argparse_args={
1686
1752
  'nargs': AttrUtil.ONE_OR_MORE_OCCURRENCES,
@@ -1782,6 +1848,9 @@ def is_soroban_app() -> bool:
1782
1848
  def is_rust_app() -> bool:
1783
1849
  return is_soroban_app() or is_solana_app()
1784
1850
 
1785
-
1851
+ # Ranger will also return true for this function
1786
1852
  def is_evm_app() -> bool:
1787
- return get_attribute_class() == EvmProverAttributes
1853
+ return issubclass(get_attribute_class(), EvmProverAttributes)
1854
+
1855
+ def is_ranger_app() -> bool:
1856
+ return get_attribute_class() == RangerAttributes
@@ -43,6 +43,39 @@ class CertoraContextValidator:
43
43
  def __init__(self, context: CertoraContext):
44
44
  self.context = context
45
45
 
46
+ def handle_ranger_attrs(self) -> None:
47
+ # unset unsupported attributes
48
+ if Attrs.is_ranger_app():
49
+ for attr in Attrs.RangerAttributes.ranger_unsupported_attributes():
50
+ attr_name = attr.get_conf_key()
51
+ if getattr(self.context, attr_name):
52
+ if attr.arg_type == AttrUtil.AttrArgType.BOOLEAN:
53
+ setattr(self.context, attr_name, False)
54
+ else:
55
+ setattr(self.context, attr_name, None)
56
+ validation_logger.info(f"Ranger does not support {attr_name}, ignoring this attribute")
57
+
58
+ # setting the default Ranger attributes
59
+
60
+ self.context.range = self.context.range or Util.DEFAULT_RANGER_RANGE
61
+ self.context.ranger_failure_limit = self.context.ranger_failure_limit or Util.DEFAULT_RANGER_FAILURE_LIMIT
62
+ if self.context.loop_iter and self.context.loop_iter != Util.DEFAULT_RANGER_LOOP_ITER:
63
+ validation_logger.info(f"While running Ranger, loop iter is {Util.DEFAULT_RANGER_LOOP_ITER} "
64
+ f"ignoring the set value of {self.context.loop_iter}")
65
+ self.context.loop_iter = self.context.loop_iter or Util.DEFAULT_RANGER_LOOP_ITER
66
+
67
+ for attr in Attrs.RangerAttributes.ranger_true_by_default_attributes():
68
+ attr_name = attr.get_conf_key()
69
+ setattr(self.context, attr_name, True)
70
+
71
+ else:
72
+ if self.context.range:
73
+ # self.context.range = None
74
+ validation_logger.info("the 'range' attribute is ignored when not running from the Ranger App")
75
+ if self.context.ranger_failure_limit:
76
+ # self.context.ranger_failure_limit = None
77
+ validation_logger.info("the 'ranger_failure_limit' is ignored when not running from the Ranger App")
78
+
46
79
  def validate(self) -> None:
47
80
 
48
81
  for attr_def in Attrs.get_attribute_class().attribute_list():
@@ -549,15 +582,16 @@ def check_mode_of_operation(context: CertoraContext) -> None:
549
582
  context.is_verify = context.verify is not None and len(context.verify) > 0
550
583
  context.is_assert = context.assert_contracts is not None and len(context.assert_contracts) > 0
551
584
  context.is_bytecode = context.bytecode_jsons is not None and len(context.bytecode_jsons) > 0
585
+ context.is_equivalence = context.equivalence_contracts is not None
552
586
 
553
- if (context.project_sanity or context.foundry) and (context.is_verify or context.is_assert or context.is_bytecode):
587
+ if (context.project_sanity or context.foundry) and (context.is_verify or context.is_assert or context.is_bytecode or context.is_equivalence):
554
588
  raise Util.CertoraUserInputError("The 'project_sanity' and 'foundry' options cannot coexist with the 'verify', 'assert_contract' or 'bytecode_jsons' options")
555
589
 
556
590
  if context.project_sanity and context.foundry:
557
591
  raise Util.CertoraUserInputError("The 'project_sanity' and 'foundry' options cannot coexist")
558
592
 
559
- if context.is_verify and context.is_assert:
560
- raise Util.CertoraUserInputError("only one option of 'assert_contracts' and 'verify' can be used")
593
+ if len(list(filter(None, [context.is_verify, context.is_assert, context.is_equivalence]))) > 1:
594
+ raise Util.CertoraUserInputError("only one option of 'assert_contracts', 'verify', 'equivalence' can be used")
561
595
 
562
596
  has_bytecode_spec = context.bytecode_spec is not None
563
597
  if has_bytecode_spec != context.is_bytecode:
@@ -624,7 +658,7 @@ def check_mode_of_operation(context: CertoraContext) -> None:
624
658
  raise Util.CertoraUserInputError(
625
659
  f"Option 'assert_contracts' cannot be used with a {special_file_type} file {input_file}")
626
660
 
627
- if not any([context.is_assert, context.is_verify, context.is_bytecode,
661
+ if not any([context.is_assert, context.is_verify, context.is_bytecode, context.equivalence_contracts,
628
662
  special_file_type]) and not context.build_only:
629
663
  raise Util.CertoraUserInputError("You must use 'verify' when running the Certora Prover")
630
664
 
@@ -872,7 +906,7 @@ def set_wait_for_results_default(context: CertoraContext) -> None:
872
906
 
873
907
 
874
908
  def mode_has_spec_file(context: CertoraContext) -> bool:
875
- return not context.is_assert and not context.is_tac
909
+ return not context.is_assert and not context.is_tac and not context.is_equivalence
876
910
 
877
911
 
878
912
  def to_relative_paths(paths: Union[str, List[str]]) -> Union[str, List[str]]:
@@ -17,6 +17,7 @@ import subprocess
17
17
  import json
18
18
  import logging
19
19
  import os
20
+ from typing import List
20
21
 
21
22
  from CertoraProver.certoraContextClass import CertoraContext
22
23
  from Shared import certoraUtils as Util
@@ -56,17 +57,11 @@ def add_solana_files_to_context(context: CertoraContext, json_obj: dict) -> None
56
57
  update_metadata(context, solana_files_attr)
57
58
 
58
59
 
59
- def run_script_and_parse_json(context: CertoraContext) -> None:
60
- if not context.build_script:
61
- return
60
+ def run_rust_build(context: CertoraContext, build_cmd: List[str]) -> None:
61
+
62
62
  try:
63
- build_script_logger.info(f"Building from script {context.build_script}")
64
- run_cmd = [context.build_script, '--json']
65
- if context.cargo_features is not None:
66
- run_cmd.append('--cargo_features')
67
- for feature in context.cargo_features:
68
- run_cmd.append(feature)
69
- result = subprocess.run(run_cmd, capture_output=True, text=True)
63
+ build_script_logger.info(f"Building by calling {build_cmd}")
64
+ result = subprocess.run(build_cmd, capture_output=True, text=True)
70
65
 
71
66
  # Check if the script executed successfully
72
67
  if result.returncode != 0:
@@ -97,6 +92,8 @@ def run_script_and_parse_json(context: CertoraContext) -> None:
97
92
 
98
93
  if context.test == str(Util.TestValue.AFTER_BUILD_RUST):
99
94
  raise Util.TestResultsReady(context)
95
+ assert not context.files, f"run_rust_build: expecting files to be empty, got: {context.files}"
96
+ context.files = [os.path.join(context.rust_project_directory, context.rust_executables)]
100
97
 
101
98
  except Util.TestResultsReady as e:
102
99
  raise e
@@ -51,6 +51,18 @@ class CertoraVerifyGenerator:
51
51
  contract_to_check_asserts_for = self.context.assert_contracts
52
52
  self.certora_verify_struct = {"type": "assertion",
53
53
  "primaryContracts": contract_to_check_asserts_for}
54
+ elif self.context.equivalence_contracts is not None:
55
+ if self.context.method is None:
56
+ raise Util.CertoraUserInputError("Argument `method` is required for equivalence checks")
57
+ if len(self.context.method) != 1:
58
+ raise Util.CertoraUserInputError("Can only check equivalence on one method")
59
+ equivalence_query = context.equivalence_contracts
60
+ equiv_contracts = equivalence_query.split("=")
61
+ self.certora_verify_struct = {
62
+ "type": "equivalence",
63
+ "primary_contract": equiv_contracts[0],
64
+ "secondary_contract": equiv_contracts[1]
65
+ }
54
66
 
55
67
  def update_certora_verify_struct(self, in_certora_sources: bool) -> None:
56
68
  """
@@ -96,6 +96,8 @@ class SplitRulesHandler():
96
96
  rule_flag = Attrs.EvmProverAttributes.RULE.get_flag()
97
97
  split_rules_flag = Attrs.EvmProverAttributes.SPLIT_RULES.get_flag()
98
98
  msg_flag = Attrs.CommonAttributes.MSG.get_flag()
99
+ # it is important to use the cache, when the difference between the runs is only the rules that apply
100
+ build_cache_flag = Attrs.EvmProverAttributes.BUILD_CACHE.get_flag()
99
101
  group_id_flag = Attrs.EvmProverAttributes.GROUP_ID.get_flag()
100
102
  disable_local_typechecking_flag = Attrs.EvmProverAttributes.DISABLE_LOCAL_TYPECHECKING.get_flag()
101
103
 
@@ -137,7 +139,7 @@ class SplitRulesHandler():
137
139
  self.context.msg = ''
138
140
 
139
141
  cmd = [get_cmd()] + args + [group_id_flag, self.context.group_id, disable_local_typechecking_flag,
140
- split_rules_flag]
142
+ build_cache_flag, split_rules_flag]
141
143
 
142
144
  if self.split_rules:
143
145
  for rule in self.split_rules:
@@ -496,7 +496,7 @@ class WebUtils:
496
496
  mutation_test_domain = MConstants.MUTATION_TEST_REPORT_DEV
497
497
  else:
498
498
  raise Util.CertoraUserInputError(f"Invalid server name {args.server}")
499
- self.mutation_test_id_url = f"https://{domain}/mutationTesting/initiate/"
499
+ self.mutation_test_id_url = f"https://{domain}/v1/domain/mutation-tests/initiate/"
500
500
  self.mutation_test_submit_final_result_url = f"https://{domain}/mutationTesting/getUploadInfo/"
501
501
  self.mutation_test_final_result_url = f"https://{mutation_test_domain}"
502
502
  mutation_logger.debug(f"Using server {args.server} with mutation_test_id_url {self.mutation_test_id_url}")
@@ -542,8 +542,8 @@ class WebUtils:
542
542
  try:
543
543
  return requests.put(url, json=body, timeout=self.request_timeout,
544
544
  headers=headers)
545
- except Exception:
546
- mutation_logger.debug(f"attempt {i} failed to put url {url}.")
545
+ except Exception as e:
546
+ mutation_logger.debug(f"attempt {i} failed to put url {url}. {e}")
547
547
  return None
548
548
 
549
549
  def get_response_with_timeout(self, url: str,
@@ -168,6 +168,8 @@ class Attributes:
168
168
  table.add_column(Text("Default"), width=default_col_width)
169
169
 
170
170
  for name in dir(cls):
171
+ if name in cls.hide_attributes():
172
+ continue
171
173
  if name.isupper():
172
174
  attr = getattr(cls, name, None)
173
175
  assert isinstance(attr, AttributeDefinition), "print_attr_help: type(attr) == Attribute"
@@ -193,3 +195,11 @@ class Attributes:
193
195
  cls._all_conf_names = [attr.name.lower() for attr in cls.attribute_list()]
194
196
  # 'compiler_map' does not have a matching 'compiler' attribute
195
197
  cls._all_map_attrs = [attr for attr in cls._all_conf_names if attr.endswith(Util.MAP_SUFFIX)]
198
+
199
+ @classmethod
200
+ def hide_attributes(cls) -> List[str]:
201
+ """
202
+ This function is used to hide attributes from the help message.
203
+ :return: A list of attribute names to be hidden.
204
+ """
205
+ return []
@@ -95,7 +95,6 @@ RECENT_JOBS_FILE = Path(".certora_recent_jobs.json")
95
95
  LAST_CONF_FILE = Path("run.conf")
96
96
  EMV_JAR = Path("emv.jar")
97
97
  CERTORA_SOURCES = Path(".certora_sources")
98
- SOLANA_DEFAULT_COMMAND = "cargo +solana build-sbf"
99
98
  SOLANA_INLINING = "solana_inlining"
100
99
  SOLANA_SUMMARIES = "solana_summaries"
101
100
 
@@ -122,6 +121,9 @@ MAP_SUFFIX = '_map'
122
121
  SUPPRESS_HELP_MSG = "==SUPPRESS=="
123
122
  MAX_FLAG_LENGTH = 31
124
123
  HELP_TABLE_WIDTH = 97
124
+ DEFAULT_RANGER_RANGE = '5'
125
+ DEFAULT_RANGER_LOOP_ITER = '3'
126
+ DEFAULT_RANGER_FAILURE_LIMIT = '1'
125
127
 
126
128
  T = TypeVar('T')
127
129
 
@@ -296,6 +298,10 @@ class ImplementationError(Exception):
296
298
  class BadMutationError(Exception):
297
299
  pass
298
300
 
301
+ class ExitException(Exception):
302
+ def __init__(self, message: str, exit_code: int):
303
+ super().__init__(message)
304
+ self.exit_code = exit_code # Store the integer data
299
305
 
300
306
  MIN_JAVA_VERSION = 11 # minimal java version to run the local type checker jar
301
307
 
@@ -1269,6 +1275,8 @@ class TestValue(NoValEnum):
1269
1275
  AFTER_GENERATE_COLLECT_REPORT = auto()
1270
1276
  AFTER_BUILD_RUST = auto()
1271
1277
  AFTER_RULE_SPLIT = auto()
1278
+ SOLANA_BUILD_CMD = auto()
1279
+ CHECK_ZIP = auto()
1272
1280
 
1273
1281
  class FeValue(NoValEnum):
1274
1282
  PRODUCTION = auto()
@@ -550,6 +550,13 @@ def validate_assert_contracts(contract: str) -> str:
550
550
  return contract
551
551
 
552
552
 
553
+ def validate_equivalence_contracts(equiv_string: str) -> str:
554
+ if not re.match(f'^{Util.SOLIDITY_ID_SUBSTRING_RE}={Util.SOLIDITY_ID_SUBSTRING_RE}$', equiv_string):
555
+ raise Util.CertoraUserInputError(
556
+ f"Equivalence check must be ContractA=ContractB, got {equiv_string}"
557
+ )
558
+ return equiv_string
559
+
553
560
  def validate_packages(package: str) -> str:
554
561
  if not re.search("^[^=]+=[^=]+$", package):
555
562
  raise Util.CertoraUserInputError("a package must have the form name=path")
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env python3
2
+ # The Certora Prover
3
+ # Copyright (C) 2025 Certora Ltd.
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, version 3 of the License.
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program. If not, see <https://www.gnu.org/licenses/>.
16
+
17
+
18
+ import sys
19
+ from pathlib import Path
20
+ from rich.console import Console
21
+
22
+
23
+ scripts_dir_path = Path(__file__).parent.resolve() # containing directory
24
+ sys.path.insert(0, str(scripts_dir_path))
25
+
26
+ import CertoraProver.certoraContextAttributes as Attrs
27
+ from Shared import certoraUtils as Util
28
+ from certoraRun import run_certora, CertoraRunResult, CertoraFoundViolations
29
+
30
+ from typing import List, Optional
31
+
32
+
33
+ def run_ranger(args: List[str]) -> Optional[CertoraRunResult]:
34
+ return run_certora(args, Attrs.RangerAttributes, prover_cmd=sys.argv[0])
35
+
36
+ def entry_point() -> None:
37
+ try:
38
+ run_ranger(sys.argv[1:])
39
+ sys.exit(0)
40
+ except KeyboardInterrupt:
41
+ Console().print("[bold red]\nInterrupted by user")
42
+ sys.exit(1)
43
+ except Util.TestResultsReady:
44
+ print("reached checkpoint")
45
+ sys.exit(0)
46
+ except CertoraFoundViolations as e:
47
+ try:
48
+ assert e.results
49
+ print(f"report url: {e.results.rule_report_link}")
50
+ except Exception:
51
+ pass
52
+ Console().print("[bold red]\nViolations were found\n")
53
+ sys.exit(1)
54
+ except Util.CertoraUserInputError as e:
55
+ if e.orig:
56
+ print(f"\n{str(e.orig).strip()}")
57
+ if e.more_info:
58
+ print(f"\n{e.more_info.strip()}")
59
+ Console().print(f"[bold red]\n{e}\n")
60
+ sys.exit(1)
61
+
62
+ except Util.ExitException as e:
63
+ Console().print(f"[bold red]{e}")
64
+ sys.exit(e.exit_code)
65
+
66
+ except Exception as e:
67
+ Console().print(f"[bold red]{e}")
68
+ sys.exit(1)
69
+
70
+ if __name__ == '__main__':
71
+ entry_point()