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.
- certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +48 -13
- certora_cli/CertoraProver/certoraBuild.py +61 -30
- certora_cli/CertoraProver/certoraBuildDataClasses.py +5 -2
- certora_cli/CertoraProver/certoraBuildRust.py +77 -41
- certora_cli/CertoraProver/certoraCloudIO.py +29 -64
- certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +205 -70
- certora_cli/CertoraProver/certoraCollectRunMetadata.py +3 -1
- certora_cli/CertoraProver/certoraConfigIO.py +14 -15
- certora_cli/CertoraProver/certoraContext.py +13 -5
- certora_cli/CertoraProver/certoraContextAttributes.py +95 -26
- certora_cli/CertoraProver/certoraContextValidator.py +39 -5
- certora_cli/CertoraProver/certoraParseBuildScript.py +7 -10
- certora_cli/CertoraProver/certoraVerifyGenerator.py +12 -0
- certora_cli/CertoraProver/splitRules.py +3 -1
- certora_cli/Mutate/mutateApp.py +3 -3
- certora_cli/Shared/certoraAttrUtil.py +10 -0
- certora_cli/Shared/certoraUtils.py +9 -1
- certora_cli/Shared/certoraValidateFuncs.py +7 -0
- certora_cli/certoraRanger.py +71 -0
- certora_cli/certoraRun.py +11 -13
- certora_cli/certoraSolanaProver.py +7 -0
- certora_cli/certoraSorobanProver.py +253 -4
- certora_cli_beta_mirror-7.29.0.dist-info/LICENSE +15 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/METADATA +18 -4
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/RECORD +30 -29
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/WHEEL +1 -1
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.0.dist-info}/entry_points.txt +1 -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 → 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.
|
|
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
|
-
|
|
549
|
-
|
|
550
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
|
1103
|
+
help_msg="Verify all Foundry fuzz tests in the current project",
|
|
1080
1104
|
default_desc="",
|
|
1081
1105
|
)
|
|
1082
1106
|
|
|
1083
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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()
|
|
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
|
|
560
|
-
raise Util.CertoraUserInputError("only one option of 'assert_contracts'
|
|
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
|
|
60
|
-
|
|
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
|
|
64
|
-
|
|
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:
|
certora_cli/Mutate/mutateApp.py
CHANGED
|
@@ -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}/
|
|
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()
|