certora-cli-beta-mirror 7.28.0__py3-none-any.whl → 7.29.1__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 -55
- certora_cli/CertoraProver/certoraCloudIO.py +52 -63
- 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 +17 -5
- certora_cli/CertoraProver/certoraContextAttributes.py +98 -26
- certora_cli/CertoraProver/certoraContextValidator.py +47 -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 +13 -15
- certora_cli/certoraSolanaProver.py +9 -2
- certora_cli/certoraSorobanProver.py +253 -4
- certora_cli_beta_mirror-7.29.1.dist-info/LICENSE +15 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.1.dist-info}/METADATA +18 -4
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.1.dist-info}/RECORD +30 -29
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.1.dist-info}/WHEEL +1 -1
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-7.29.1.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.1.dist-info}/top_level.txt +0 -0
|
@@ -120,9 +120,11 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
|
|
|
120
120
|
"""
|
|
121
121
|
run_args = []
|
|
122
122
|
|
|
123
|
-
if
|
|
124
|
-
|
|
125
|
-
|
|
123
|
+
if Attrs.is_rust_app():
|
|
124
|
+
# For local runs, we want path to be relative to cwd instead of zip root.
|
|
125
|
+
rust_rel_path = os.path.relpath(Path(context.files[0]), os.getcwd())
|
|
126
|
+
run_args.append(rust_rel_path)
|
|
127
|
+
elif context.is_tac:
|
|
126
128
|
# For Rust app we assume the files holds the executable for the prover, currently we support a single file
|
|
127
129
|
try:
|
|
128
130
|
run_args.append(context.files[0])
|
|
@@ -159,10 +161,16 @@ class ProverParser(AttrUtil.ContextAttributeParser):
|
|
|
159
161
|
|
|
160
162
|
def format_help(self) -> str:
|
|
161
163
|
console = Console()
|
|
162
|
-
|
|
164
|
+
if Attrs.is_ranger_app():
|
|
165
|
+
console.print("\n\nRanger - Certora’s bounded model checker for smart contracts")
|
|
166
|
+
else:
|
|
167
|
+
console.print("\n\nThe Certora Prover - A formal verification tool for smart contracts")
|
|
163
168
|
# Using sys.stdout.write() as print() would color some of the strings here
|
|
164
169
|
sys.stdout.write(f"\n\nUsage: {sys.argv[0]} <Files> <Flags>\n\n")
|
|
165
|
-
if Attrs.
|
|
170
|
+
if Attrs.is_ranger_app():
|
|
171
|
+
sys.stdout.write("Ranger supports only Solidity (.sol) and configuration (.conf) files.\n"
|
|
172
|
+
"Rust and Vyper contracts are not currently supported.\n\n")
|
|
173
|
+
elif Attrs.is_evm_app():
|
|
166
174
|
sys.stdout.write("Acceptable files for EVM projects are Solidity files (.sol suffix), "
|
|
167
175
|
"Vyper files (.vy suffix), or conf files (.conf suffix)\n\n")
|
|
168
176
|
elif Attrs.is_solana_app():
|
|
@@ -252,6 +260,8 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
|
|
|
252
260
|
Cv.check_mode_of_operation(context) # Here boolean run characteristics are set
|
|
253
261
|
|
|
254
262
|
validator = Cv.CertoraContextValidator(context)
|
|
263
|
+
if Attrs.is_evm_app():
|
|
264
|
+
validator.handle_ranger_attrs()
|
|
255
265
|
validator.validate()
|
|
256
266
|
if Attrs.is_evm_app() or Attrs.is_rust_app():
|
|
257
267
|
current_build_directory = Util.get_build_dir()
|
|
@@ -268,6 +278,8 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
|
|
|
268
278
|
if Attrs.is_evm_app():
|
|
269
279
|
validator.check_args_post_argparse()
|
|
270
280
|
setup_cache(context) # Here context.cache, context.user_defined_cache are set
|
|
281
|
+
if Attrs.is_rust_app():
|
|
282
|
+
validator.check_rust_args_post_argparse()
|
|
271
283
|
|
|
272
284
|
attrs_to_relative(context)
|
|
273
285
|
# Setup defaults (defaults are not recorded in conf file)
|
|
@@ -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,12 @@ 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
|
|
1857
|
+
|
|
1858
|
+
def is_sophy_app() -> bool:
|
|
1859
|
+
return False # wait for the tool to be added
|
|
@@ -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():
|
|
@@ -121,6 +154,14 @@ class CertoraContextValidator:
|
|
|
121
154
|
elif value not in [True, False]:
|
|
122
155
|
raise Util.CertoraUserInputError(f"value of {conf_key} {value} is not a boolean (true/false)")
|
|
123
156
|
|
|
157
|
+
def check_rust_args_post_argparse(self) -> None:
|
|
158
|
+
context = self.context
|
|
159
|
+
if context.files:
|
|
160
|
+
if context.build_script:
|
|
161
|
+
raise Util.CertoraUserInputError("'files' and 'build_script' cannot be both set for Rust projects")
|
|
162
|
+
if len(context.files) > 1:
|
|
163
|
+
raise Util.CertoraUserInputError("Rust projects must specify exactly one executable in 'files'.")
|
|
164
|
+
|
|
124
165
|
def check_args_post_argparse(self) -> None:
|
|
125
166
|
"""
|
|
126
167
|
Performs checks over the arguments after basic argparse parsing
|
|
@@ -549,15 +590,16 @@ def check_mode_of_operation(context: CertoraContext) -> None:
|
|
|
549
590
|
context.is_verify = context.verify is not None and len(context.verify) > 0
|
|
550
591
|
context.is_assert = context.assert_contracts is not None and len(context.assert_contracts) > 0
|
|
551
592
|
context.is_bytecode = context.bytecode_jsons is not None and len(context.bytecode_jsons) > 0
|
|
593
|
+
context.is_equivalence = context.equivalence_contracts is not None
|
|
552
594
|
|
|
553
|
-
if (context.project_sanity or context.foundry) and (context.is_verify or context.is_assert or context.is_bytecode):
|
|
595
|
+
if (context.project_sanity or context.foundry) and (context.is_verify or context.is_assert or context.is_bytecode or context.is_equivalence):
|
|
554
596
|
raise Util.CertoraUserInputError("The 'project_sanity' and 'foundry' options cannot coexist with the 'verify', 'assert_contract' or 'bytecode_jsons' options")
|
|
555
597
|
|
|
556
598
|
if context.project_sanity and context.foundry:
|
|
557
599
|
raise Util.CertoraUserInputError("The 'project_sanity' and 'foundry' options cannot coexist")
|
|
558
600
|
|
|
559
|
-
if context.is_verify
|
|
560
|
-
raise Util.CertoraUserInputError("only one option of 'assert_contracts'
|
|
601
|
+
if len(list(filter(None, [context.is_verify, context.is_assert, context.is_equivalence]))) > 1:
|
|
602
|
+
raise Util.CertoraUserInputError("only one option of 'assert_contracts', 'verify', 'equivalence' can be used")
|
|
561
603
|
|
|
562
604
|
has_bytecode_spec = context.bytecode_spec is not None
|
|
563
605
|
if has_bytecode_spec != context.is_bytecode:
|
|
@@ -624,7 +666,7 @@ def check_mode_of_operation(context: CertoraContext) -> None:
|
|
|
624
666
|
raise Util.CertoraUserInputError(
|
|
625
667
|
f"Option 'assert_contracts' cannot be used with a {special_file_type} file {input_file}")
|
|
626
668
|
|
|
627
|
-
if not any([context.is_assert, context.is_verify, context.is_bytecode,
|
|
669
|
+
if not any([context.is_assert, context.is_verify, context.is_bytecode, context.equivalence_contracts,
|
|
628
670
|
special_file_type]) and not context.build_only:
|
|
629
671
|
raise Util.CertoraUserInputError("You must use 'verify' when running the Certora Prover")
|
|
630
672
|
|
|
@@ -872,7 +914,7 @@ def set_wait_for_results_default(context: CertoraContext) -> None:
|
|
|
872
914
|
|
|
873
915
|
|
|
874
916
|
def mode_has_spec_file(context: CertoraContext) -> bool:
|
|
875
|
-
return not context.is_assert and not context.is_tac
|
|
917
|
+
return not context.is_assert and not context.is_tac and not context.is_equivalence
|
|
876
918
|
|
|
877
919
|
|
|
878
920
|
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")
|