certora-cli-beta-mirror 8.1.1__py3-none-any.whl → 8.2.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/certoraApp.py +4 -1
- certora_cli/CertoraProver/certoraBuild.py +66 -42
- certora_cli/CertoraProver/concordance.py +939 -0
- certora_cli/Mutate/mutateValidate.py +32 -0
- certora_cli/Shared/certoraUtils.py +27 -4
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/METADATA +2 -2
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/RECORD +14 -13
- certora_jars/ASTExtraction.jar +0 -0
- certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
- certora_jars/Typechecker.jar +0 -0
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/LICENSE +0 -0
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/WHEEL +0 -0
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/entry_points.txt +0 -0
- {certora_cli_beta_mirror-8.1.1.dist-info → certora_cli_beta_mirror-8.2.0.dist-info}/top_level.txt +0 -0
|
@@ -33,6 +33,9 @@ class EvmApp(EvmAppClass):
|
|
|
33
33
|
class RustAppClass(CertoraApp):
|
|
34
34
|
pass
|
|
35
35
|
|
|
36
|
+
class MoveAppClass(CertoraApp):
|
|
37
|
+
pass
|
|
38
|
+
|
|
36
39
|
class SolanaApp(RustAppClass):
|
|
37
40
|
attr_class = Attrs.SolanaProverAttributes
|
|
38
41
|
|
|
@@ -45,5 +48,5 @@ class RangerApp(EvmAppClass):
|
|
|
45
48
|
class ConcordApp(EvmAppClass):
|
|
46
49
|
attr_class = Attrs.ConcordAttributes
|
|
47
50
|
|
|
48
|
-
class SuiApp(
|
|
51
|
+
class SuiApp(MoveAppClass):
|
|
49
52
|
attr_class = Attrs.SuiProverAttributes
|
|
@@ -2505,7 +2505,7 @@ class CertoraBuildGenerator:
|
|
|
2505
2505
|
mut=InsertAfter())
|
|
2506
2506
|
return function_finder_by_contract, function_finder_instrumentation
|
|
2507
2507
|
|
|
2508
|
-
def add_internal_func_harnesses(self, contract_file: str, sdc: SDC,
|
|
2508
|
+
def add_internal_func_harnesses(self, contract_file: str, sdc: SDC, spec_calls: List[str]) -> Optional[Tuple[Dict[str, str], Dict[str, Dict[int, Instrumentation]]]]:
|
|
2509
2509
|
# contract file -> byte offset -> to insert
|
|
2510
2510
|
harness_function_instrumentation: Dict[str, Dict[int, Instrumentation]] = defaultdict(dict)
|
|
2511
2511
|
# internal function name -> harness fuction name
|
|
@@ -2519,7 +2519,7 @@ class CertoraBuildGenerator:
|
|
|
2519
2519
|
|
|
2520
2520
|
for c in sdc.contracts:
|
|
2521
2521
|
for f in c.internal_funcs:
|
|
2522
|
-
if f"{sdc.primary_contract}.{f.name}" not in
|
|
2522
|
+
if f"{sdc.primary_contract}.{f.name}" not in spec_calls:
|
|
2523
2523
|
continue
|
|
2524
2524
|
|
|
2525
2525
|
if f.fromLib:
|
|
@@ -2669,12 +2669,12 @@ class CertoraBuildGenerator:
|
|
|
2669
2669
|
def build(self, certora_verify_generator: CertoraVerifyGenerator) -> None:
|
|
2670
2670
|
context = self.context
|
|
2671
2671
|
|
|
2672
|
-
|
|
2672
|
+
spec_calls: List[str] = []
|
|
2673
2673
|
if context.verify and not context.disallow_internal_function_calls:
|
|
2674
2674
|
with tempfile.NamedTemporaryFile("r", dir=Util.get_build_dir()) as tmp_file:
|
|
2675
2675
|
try:
|
|
2676
2676
|
Ctx.run_local_spec_check(False, context, ["-listCalls", tmp_file.name], print_errors=False)
|
|
2677
|
-
|
|
2677
|
+
spec_calls = tmp_file.read().split("\n")
|
|
2678
2678
|
except Exception as e:
|
|
2679
2679
|
instrumentation_logger.warning(f"Failed to get calls from spec\n{e}")
|
|
2680
2680
|
|
|
@@ -2729,7 +2729,7 @@ class CertoraBuildGenerator:
|
|
|
2729
2729
|
# We start by trying to instrument _all_ finders, both autofinders and source finders
|
|
2730
2730
|
added_finders, all_finders_success, src_finders_gen_success, post_backup_dir = self.finders_compilation_round(
|
|
2731
2731
|
build_arg_contract_file, i, ignore_patterns, path_for_compiler_collector_file, pre_backup_dir,
|
|
2732
|
-
sdc_pre_finders, not context.disable_source_finders,
|
|
2732
|
+
sdc_pre_finders, not context.disable_source_finders, spec_calls)
|
|
2733
2733
|
|
|
2734
2734
|
# we could have a case where source finders failed but regular finders succeeded.
|
|
2735
2735
|
# e.g. if we processed the AST wrong and skipped source finders generation
|
|
@@ -2741,7 +2741,7 @@ class CertoraBuildGenerator:
|
|
|
2741
2741
|
# let's try just the function autofinders
|
|
2742
2742
|
added_finders, function_autofinder_success, _, post_backup_dir = self.finders_compilation_round(
|
|
2743
2743
|
build_arg_contract_file, i, ignore_patterns, path_for_compiler_collector_file, pre_backup_dir,
|
|
2744
|
-
sdc_pre_finders, False,
|
|
2744
|
+
sdc_pre_finders, False, spec_calls)
|
|
2745
2745
|
|
|
2746
2746
|
if not function_autofinder_success:
|
|
2747
2747
|
self.auto_finders_failed = True
|
|
@@ -3089,12 +3089,12 @@ class CertoraBuildGenerator:
|
|
|
3089
3089
|
pre_backup_dir: Path,
|
|
3090
3090
|
sdc_pre_finders: List[SDC],
|
|
3091
3091
|
with_source_finders: bool,
|
|
3092
|
-
|
|
3092
|
+
spec_calls: List[str]) -> Tuple[
|
|
3093
3093
|
List[Tuple[Dict[str, InternalFunc], Dict[str, UnspecializedSourceFinder], Dict[str, str], SDC]], bool, bool, Path]:
|
|
3094
3094
|
added_finders_to_sdc, finders_compilation_success, source_finders_gen_success = \
|
|
3095
3095
|
self.instrument_auto_finders(
|
|
3096
3096
|
build_arg_contract_file, i, sdc_pre_finders,
|
|
3097
|
-
path_for_compiler_collector_file, with_source_finders,
|
|
3097
|
+
path_for_compiler_collector_file, with_source_finders, spec_calls)
|
|
3098
3098
|
# successful or not, we backup current .certora_sources for either debuggability, or for availability
|
|
3099
3099
|
# of sources.
|
|
3100
3100
|
post_backup_dir = self.get_fresh_backupdir(Util.POST_AUTOFINDER_BACKUP_DIR)
|
|
@@ -3167,7 +3167,7 @@ class CertoraBuildGenerator:
|
|
|
3167
3167
|
sdc_pre_finders: List[SDC],
|
|
3168
3168
|
path_for_compiler_collector_file: str,
|
|
3169
3169
|
instrument_source_finders: bool,
|
|
3170
|
-
|
|
3170
|
+
spec_calls: List[str]) -> Tuple[
|
|
3171
3171
|
List[Tuple[Dict[str, InternalFunc], Dict[str, UnspecializedSourceFinder], Dict[str, str], SDC]], bool, bool]:
|
|
3172
3172
|
|
|
3173
3173
|
# initialization
|
|
@@ -3188,7 +3188,7 @@ class CertoraBuildGenerator:
|
|
|
3188
3188
|
|
|
3189
3189
|
added_internal_function_harnesses: Dict[str, str] = {}
|
|
3190
3190
|
if not self.context.disallow_internal_function_calls:
|
|
3191
|
-
added_internal_func_harness_tuple = self.add_internal_func_harnesses(build_arg_contract_file, sdc_pre_finder,
|
|
3191
|
+
added_internal_func_harness_tuple = self.add_internal_func_harnesses(build_arg_contract_file, sdc_pre_finder, spec_calls)
|
|
3192
3192
|
if added_internal_func_harness_tuple:
|
|
3193
3193
|
instr = CertoraBuildGenerator.merge_dicts_instrumentation(function_instr, added_internal_func_harness_tuple[1])
|
|
3194
3194
|
added_internal_function_harnesses = added_internal_func_harness_tuple[0]
|
|
@@ -3887,21 +3887,19 @@ def build_from_scratch(context: CertoraContext,
|
|
|
3887
3887
|
def build_from_cache_or_scratch(context: CertoraContext,
|
|
3888
3888
|
certora_build_generator: CertoraBuildGenerator,
|
|
3889
3889
|
certora_verify_generator: CertoraVerifyGenerator) \
|
|
3890
|
-
-> Tuple[bool,
|
|
3890
|
+
-> Tuple[bool, CachedFiles]:
|
|
3891
3891
|
"""
|
|
3892
3892
|
Builds either from cache (fast path) or from scratch (slow path)
|
|
3893
|
-
@returns 1st tuple element whether
|
|
3894
|
-
@returns 2nd tuple element
|
|
3895
|
-
@returns 3rd tuple element the artifacts of the build to potentially be cached
|
|
3893
|
+
@returns 1st tuple element whether the cache should be saved
|
|
3894
|
+
@returns 2nd tuple element the artifacts of the build to potentially be cached
|
|
3896
3895
|
"""
|
|
3897
|
-
cache_hit = False
|
|
3898
3896
|
cached_files: Optional[CachedFiles] = None
|
|
3899
3897
|
|
|
3900
3898
|
if not context.build_cache:
|
|
3901
3899
|
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3902
3900
|
certora_verify_generator,
|
|
3903
3901
|
False)
|
|
3904
|
-
return
|
|
3902
|
+
return False, cached_files
|
|
3905
3903
|
|
|
3906
3904
|
build_cache_applicable = CertoraBuildCacheManager.cache_is_applicable(context)
|
|
3907
3905
|
|
|
@@ -3912,34 +3910,60 @@ def build_from_cache_or_scratch(context: CertoraContext,
|
|
|
3912
3910
|
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3913
3911
|
certora_verify_generator,
|
|
3914
3912
|
False)
|
|
3915
|
-
return
|
|
3913
|
+
return False, cached_files
|
|
3916
3914
|
|
|
3917
3915
|
cached_files = CertoraBuildCacheManager.build_from_cache(context)
|
|
3918
|
-
|
|
3919
|
-
if
|
|
3920
|
-
#
|
|
3921
|
-
shutil.copyfile(cached_files.certora_build_file, Util.get_certora_build_file())
|
|
3922
|
-
# write build_output_props file
|
|
3923
|
-
shutil.copyfile(cached_files.build_output_props_file, Util.get_built_output_props_file())
|
|
3924
|
-
# write build_cache indicator file
|
|
3925
|
-
with open(Util.get_build_cache_indicator_file(), "w+") as indicator_handle:
|
|
3926
|
-
json.dump({"build_cache_hit": True}, indicator_handle)
|
|
3927
|
-
# write in sources all the additional paths found
|
|
3928
|
-
for p in cached_files.path_with_additional_included_files.glob("*"):
|
|
3929
|
-
if p.is_dir():
|
|
3930
|
-
Util.safe_copy_folder(p,
|
|
3931
|
-
Util.get_certora_sources_dir() / p.name,
|
|
3932
|
-
shutil.ignore_patterns())
|
|
3933
|
-
else:
|
|
3934
|
-
shutil.copyfile(p, Util.get_certora_sources_dir() / p.name)
|
|
3935
|
-
cache_hit = True
|
|
3936
|
-
else:
|
|
3937
|
-
# rebuild
|
|
3916
|
+
|
|
3917
|
+
if not cached_files:
|
|
3918
|
+
# No match, rebuild
|
|
3938
3919
|
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3939
3920
|
certora_verify_generator,
|
|
3940
3921
|
True)
|
|
3922
|
+
return True, cached_files
|
|
3923
|
+
|
|
3924
|
+
# Cache hit!
|
|
3925
|
+
|
|
3926
|
+
# write to .certora_build.json
|
|
3927
|
+
# This must happen _before_ searching for new internal function calls - the typechecker needs this file.
|
|
3928
|
+
shutil.copyfile(cached_files.certora_build_file, Util.get_certora_build_file())
|
|
3929
|
+
|
|
3930
|
+
# Check whether there are any new internal function calls in the spec file - if there are then we need to build
|
|
3931
|
+
# from scratch in order to create the relevant harness function.
|
|
3932
|
+
if context.verify and not context.disallow_internal_function_calls:
|
|
3933
|
+
with tempfile.NamedTemporaryFile("r", dir=Util.get_build_dir()) as tmp_file:
|
|
3934
|
+
internal_calls = []
|
|
3935
|
+
try:
|
|
3936
|
+
Ctx.run_local_spec_check(True, context, ["-listCalls", tmp_file.name], print_errors=False)
|
|
3937
|
+
output = tmp_file.read().strip()
|
|
3938
|
+
if output:
|
|
3939
|
+
internal_calls = output.split("\n")
|
|
3940
|
+
except Exception as e:
|
|
3941
|
+
instrumentation_logger.warning(f"Failed to get calls from spec\n{e}")
|
|
3942
|
+
|
|
3943
|
+
if internal_calls:
|
|
3944
|
+
build_logger.info("Found new internal calls in the spec file, need to recompile anyway")
|
|
3945
|
+
# There are new internal calls in the spec, we need to rebuild in order to generate the
|
|
3946
|
+
# external harness functions for them.
|
|
3947
|
+
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3948
|
+
certora_verify_generator,
|
|
3949
|
+
True)
|
|
3950
|
+
return True, cached_files
|
|
3951
|
+
|
|
3952
|
+
# write build_output_props file
|
|
3953
|
+
shutil.copyfile(cached_files.build_output_props_file, Util.get_built_output_props_file())
|
|
3954
|
+
# write build_cache indicator file
|
|
3955
|
+
with open(Util.get_build_cache_indicator_file(), "w+") as indicator_handle:
|
|
3956
|
+
json.dump({"build_cache_hit": True}, indicator_handle)
|
|
3957
|
+
# write in sources all the additional paths found
|
|
3958
|
+
for p in cached_files.path_with_additional_included_files.glob("*"):
|
|
3959
|
+
if p.is_dir():
|
|
3960
|
+
Util.safe_copy_folder(p,
|
|
3961
|
+
Util.get_certora_sources_dir() / p.name,
|
|
3962
|
+
shutil.ignore_patterns())
|
|
3963
|
+
else:
|
|
3964
|
+
shutil.copyfile(p, Util.get_certora_sources_dir() / p.name)
|
|
3941
3965
|
|
|
3942
|
-
return
|
|
3966
|
+
return False, cached_files
|
|
3943
3967
|
|
|
3944
3968
|
|
|
3945
3969
|
def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> None:
|
|
@@ -3969,9 +3993,9 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3969
3993
|
build_logger.warning(
|
|
3970
3994
|
"Local checks of CVL specification files disabled. It is recommended to enable the checks.")
|
|
3971
3995
|
|
|
3972
|
-
|
|
3973
|
-
|
|
3974
|
-
|
|
3996
|
+
should_save_cache, cached_files = build_from_cache_or_scratch(context,
|
|
3997
|
+
certora_build_generator,
|
|
3998
|
+
certora_verify_generator)
|
|
3975
3999
|
|
|
3976
4000
|
# avoid running the same test over and over again for each split run, context.split_rules is true only for
|
|
3977
4001
|
# the first run and is set to [] for split runs
|
|
@@ -3990,7 +4014,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3990
4014
|
build_logger.debug("build_source_tree failed", exc_info=e)
|
|
3991
4015
|
|
|
3992
4016
|
# save in build cache
|
|
3993
|
-
if
|
|
4017
|
+
if should_save_cache and cached_files.may_store_in_build_cache:
|
|
3994
4018
|
CertoraBuildCacheManager.save_build_cache(context, cached_files)
|
|
3995
4019
|
|
|
3996
4020
|
certora_verify_generator.update_certora_verify_struct(True)
|