certora-cli-beta-mirror 7.30.1__py3-none-any.whl → 7.31.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/CompilerCollectorFactory.py +11 -2
- certora_cli/CertoraProver/certoraBuild.py +50 -45
- certora_cli/CertoraProver/certoraBuildCacheManager.py +15 -16
- certora_cli/CertoraProver/certoraBuildRust.py +2 -1
- certora_cli/CertoraProver/certoraCloudIO.py +7 -27
- certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +62 -51
- certora_cli/CertoraProver/certoraConfigIO.py +2 -1
- certora_cli/CertoraProver/certoraContext.py +29 -2
- certora_cli/CertoraProver/certoraContextAttributes.py +20 -9
- certora_cli/CertoraProver/certoraContextValidator.py +39 -61
- certora_cli/CertoraProver/certoraParseBuildScript.py +4 -3
- certora_cli/Shared/certoraUtils.py +21 -19
- certora_cli/Shared/certoraValidateFuncs.py +5 -3
- certora_cli/Shared/proverCommon.py +2 -0
- certora_cli/certoraRun.py +2 -0
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/METADATA +3 -2
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/RECORD +23 -23
- certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
- certora_jars/Typechecker.jar +0 -0
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/LICENSE +0 -0
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/WHEEL +0 -0
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/entry_points.txt +0 -0
- {certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/top_level.txt +0 -0
|
@@ -25,8 +25,9 @@ from CertoraProver.Compiler.CompilerCollector import CompilerLang, CompilerColle
|
|
|
25
25
|
from CertoraProver.Compiler.CompilerCollectorSol import CompilerCollectorSol, CompilerLangSol
|
|
26
26
|
from CertoraProver.Compiler.CompilerCollectorYul import CompilerLangYul, CompilerCollectorYul
|
|
27
27
|
from CertoraProver.Compiler.CompilerCollectorVy import CompilerCollectorVy, CompilerLangVy
|
|
28
|
-
from Shared.certoraUtils import
|
|
28
|
+
from Shared.certoraUtils import remove_file, get_certora_config_dir
|
|
29
29
|
from CertoraProver.certoraContextClass import CertoraContext
|
|
30
|
+
import CertoraProver.certoraContext as Ctx
|
|
30
31
|
|
|
31
32
|
# logger for running the Solidity compiler and reporting any errors it emits
|
|
32
33
|
compiler_logger = logging.getLogger("compiler")
|
|
@@ -42,8 +43,16 @@ def get_relevant_compiler(contract_file_path: Path, context: CertoraContext) ->
|
|
|
42
43
|
|
|
43
44
|
if contract_file_path.is_absolute():
|
|
44
45
|
contract_file_path = Path(os.path.relpath(contract_file_path, Path.cwd()))
|
|
46
|
+
|
|
47
|
+
# If the contract file is in the sources directory, we want to use the relative path from the "cwd" in the source tree.
|
|
48
|
+
if Util.get_certora_sources_dir() in contract_file_path.parents:
|
|
49
|
+
cwd_in_source = Util.get_certora_sources_dir() / context.cwd_rel_in_sources
|
|
50
|
+
contract_file_path = Path(os.path.relpath(contract_file_path, cwd_in_source))
|
|
51
|
+
|
|
45
52
|
if context.compiler_map:
|
|
46
|
-
match =
|
|
53
|
+
match = Ctx.get_map_attribute_value(context, contract_file_path, 'compiler')
|
|
54
|
+
assert isinstance(match, str), (f"In the attribute compiler_map, {contract_file_path} expected to be matched "
|
|
55
|
+
f"to a string, {match} is of type {type(match)} not a string")
|
|
47
56
|
if match:
|
|
48
57
|
return match
|
|
49
58
|
else:
|
|
@@ -450,8 +450,12 @@ def convert_pathname_to_posix(json_dict: Dict[str, Any], entry: str, smart_contr
|
|
|
450
450
|
if path_obj.is_file():
|
|
451
451
|
json_dict_posix_paths[path_obj.as_posix()] = json_dict[entry][file_path]
|
|
452
452
|
else:
|
|
453
|
+
json_dict_str = str(json_dict)
|
|
454
|
+
# protecting against long strings
|
|
455
|
+
if len(json_dict_str) > 200:
|
|
456
|
+
json_dict_str = json_dict_str[:200] + '...'
|
|
453
457
|
fatal_error(compiler_logger, f"The path of the source file {file_path}"
|
|
454
|
-
f"in the standard json file {
|
|
458
|
+
f"in the standard json file {json_dict_str} does not exist")
|
|
455
459
|
json_dict[entry] = json_dict_posix_paths
|
|
456
460
|
|
|
457
461
|
|
|
@@ -1361,46 +1365,48 @@ class CertoraBuildGenerator:
|
|
|
1361
1365
|
|
|
1362
1366
|
return bytecode
|
|
1363
1367
|
|
|
1364
|
-
def
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1368
|
+
def get_solc_via_ir_value(self, contract_file_path: Path) -> bool:
|
|
1369
|
+
match = Ctx.get_map_attribute_value(self.context, contract_file_path, 'solc_via_ir')
|
|
1370
|
+
assert isinstance(match, (bool, type(None))), f"Expected solc_via_ir to be bool or None, got {type(match)}"
|
|
1371
|
+
return bool(match)
|
|
1372
|
+
|
|
1373
|
+
def get_solc_evm_version_value(self, contract_file_path: Path) -> Optional[str]:
|
|
1374
|
+
match = Ctx.get_map_attribute_value(self.context, contract_file_path, 'solc_evm_version')
|
|
1375
|
+
assert isinstance(match, (str, type(None))), f"Expected solc_evm_version to be string or None, got {type(match)}"
|
|
1376
|
+
return match
|
|
1377
|
+
|
|
1378
|
+
def get_solc_optimize_value(self, contract_file_path: Path) -> Optional[str]:
|
|
1379
|
+
match = Ctx.get_map_attribute_value(self.context, contract_file_path, 'solc_optimize')
|
|
1380
|
+
assert isinstance(match, (str, type(None))), f"Expected solc_optimize to be string or None, got {type(match)}"
|
|
1381
|
+
return match
|
|
1382
|
+
|
|
1383
|
+
def _handle_via_ir(self, contract_file_path: Path, settings_dict: Dict[str, Any]) -> None:
|
|
1384
|
+
if self.get_solc_via_ir_value(contract_file_path):
|
|
1372
1385
|
settings_dict["viaIR"] = True
|
|
1373
1386
|
|
|
1374
|
-
def _handle_evm_version(self, contract_file_path:
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
settings_dict["evmVersion"] = match
|
|
1379
|
-
elif self.context.solc_evm_version:
|
|
1380
|
-
settings_dict["evmVersion"] = self.context.solc_evm_version
|
|
1387
|
+
def _handle_evm_version(self, contract_file_path: Path, settings_dict: Dict[str, Any]) -> None:
|
|
1388
|
+
match = self.get_solc_evm_version_value(contract_file_path)
|
|
1389
|
+
if match:
|
|
1390
|
+
settings_dict["evmVersion"] = match
|
|
1381
1391
|
|
|
1382
|
-
def _handle_optimize(self, contract_file_path:
|
|
1392
|
+
def _handle_optimize(self, contract_file_path: Path, settings_dict: Dict[str, Any],
|
|
1383
1393
|
compiler_collector: CompilerCollector) -> None:
|
|
1384
1394
|
"""
|
|
1385
1395
|
@param contract_file_path: the contract that we are working on
|
|
1386
1396
|
@param settings_dict: data structure for sending to the solc compiler
|
|
1387
1397
|
"""
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
if match and int(match) > 0:
|
|
1391
|
-
settings_dict["optimizer"] = {"enabled": True}
|
|
1392
|
-
settings_dict["optimizer"]['runs'] = int(match)
|
|
1393
|
-
elif self.context.solc_optimize:
|
|
1398
|
+
match = self.get_solc_optimize_value(contract_file_path)
|
|
1399
|
+
if match:
|
|
1394
1400
|
settings_dict["optimizer"] = {"enabled": True}
|
|
1395
|
-
if int(
|
|
1396
|
-
settings_dict["optimizer"]['runs'] = int(
|
|
1401
|
+
if int(match) > 0:
|
|
1402
|
+
settings_dict["optimizer"]['runs'] = int(match)
|
|
1397
1403
|
|
|
1398
1404
|
# if optimizer is true, we should also define settings_dict["optimizer"]["details"]
|
|
1399
1405
|
# for both optimize map and optimize
|
|
1400
1406
|
optimizer = settings_dict.get("optimizer")
|
|
1401
1407
|
if optimizer and isinstance(optimizer, dict) and optimizer.get('enabled'):
|
|
1402
1408
|
# if we are not disabling finder friendly optimizer specifically, enable it whenever viaIR is also enabled
|
|
1403
|
-
if not self.context.strict_solc_optimizer and self.
|
|
1409
|
+
if not self.context.strict_solc_optimizer and self.get_solc_via_ir_value(contract_file_path):
|
|
1404
1410
|
# The default optimizer steps (taken from libsolidity/interface/OptimiserSettings.h) but with the
|
|
1405
1411
|
# full inliner step removed
|
|
1406
1412
|
solc0_8_26_to_0_8_30 = ("dhfoDgvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLCTUca[r]LSsTFOtfDnca[r]" +
|
|
@@ -1433,6 +1439,8 @@ class CertoraBuildGenerator:
|
|
|
1433
1439
|
raise Util.CertoraUserInputError(err_msg)
|
|
1434
1440
|
elif minor < 6 or (minor == 6 and patch < 7):
|
|
1435
1441
|
raise Util.CertoraUserInputError(err_msg)
|
|
1442
|
+
elif self.context.yul_optimizer_steps:
|
|
1443
|
+
yul_optimizer_steps = self.context.yul_optimizer_steps
|
|
1436
1444
|
elif (minor == 6 and patch >= 7) or (minor == 7 and 0 <= patch <= 1):
|
|
1437
1445
|
yul_optimizer_steps = solc0_6_7_to_0_7_1
|
|
1438
1446
|
elif minor == 7 and 2 <= patch <= 5:
|
|
@@ -1470,7 +1478,7 @@ class CertoraBuildGenerator:
|
|
|
1470
1478
|
for opt_pass in self.context.disable_solc_optimizers:
|
|
1471
1479
|
settings_dict["optimizer"]["details"][opt_pass] = False
|
|
1472
1480
|
|
|
1473
|
-
def _fill_codegen_related_options(self, contract_file_path:
|
|
1481
|
+
def _fill_codegen_related_options(self, contract_file_path: Path, settings_dict: Dict[str, Any],
|
|
1474
1482
|
compiler_collector: CompilerCollector) -> None:
|
|
1475
1483
|
"""
|
|
1476
1484
|
Fills options that control how we call solc and affect the bytecode in some way
|
|
@@ -1551,7 +1559,7 @@ class CertoraBuildGenerator:
|
|
|
1551
1559
|
}
|
|
1552
1560
|
}
|
|
1553
1561
|
|
|
1554
|
-
self._fill_codegen_related_options(contract_file_as_provided, settings_dict, compiler_collector)
|
|
1562
|
+
self._fill_codegen_related_options(Path(contract_file_as_provided), settings_dict, compiler_collector)
|
|
1555
1563
|
|
|
1556
1564
|
result_dict = {"language": compiler_collector_lang.name, "sources": sources_dict, "settings": settings_dict}
|
|
1557
1565
|
# debug_print("Standard json input")
|
|
@@ -2286,7 +2294,7 @@ class CertoraBuildGenerator:
|
|
|
2286
2294
|
|
|
2287
2295
|
if compiler_lang == CompilerLangSol():
|
|
2288
2296
|
settings_dict: Dict[str, Any] = {}
|
|
2289
|
-
self._fill_codegen_related_options(build_arg_contract_file, settings_dict,
|
|
2297
|
+
self._fill_codegen_related_options(Path(build_arg_contract_file), settings_dict,
|
|
2290
2298
|
compiler_collector_for_contract_file)
|
|
2291
2299
|
solc_optimizer_on, solc_optimizer_runs = self.solc_setting_optimizer_runs(settings_dict)
|
|
2292
2300
|
solc_via_ir = self.solc_setting_via_ir(settings_dict)
|
|
@@ -2416,7 +2424,7 @@ class CertoraBuildGenerator:
|
|
|
2416
2424
|
# if no function finder mode set, determine based on viaIR enabled or not:
|
|
2417
2425
|
if self.context.function_finder_mode is None:
|
|
2418
2426
|
# in via-ir, should not compress
|
|
2419
|
-
if self.
|
|
2427
|
+
if self.get_solc_via_ir_value(Path(contract_file)):
|
|
2420
2428
|
should_compress = False
|
|
2421
2429
|
else:
|
|
2422
2430
|
should_compress = True
|
|
@@ -3614,7 +3622,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3614
3622
|
|
|
3615
3623
|
try:
|
|
3616
3624
|
if overwrite:
|
|
3617
|
-
# expecting target path to exist.
|
|
3625
|
+
# expecting the target path to exist.
|
|
3618
3626
|
if target_path.exists():
|
|
3619
3627
|
build_logger.debug(f"Overwriting {target_path} by copying from {source_path}")
|
|
3620
3628
|
else:
|
|
@@ -3632,7 +3640,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3632
3640
|
cwd_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
3633
3641
|
cwd_file_path.touch()
|
|
3634
3642
|
|
|
3635
|
-
# the empty file .project_directory is written in the source tree to denote the
|
|
3643
|
+
# the empty file .project_directory is written in the source tree to denote the project directory
|
|
3636
3644
|
rust_proj_dir = getattr(context, 'rust_project_directory', None)
|
|
3637
3645
|
if rust_proj_dir:
|
|
3638
3646
|
proj_dir_parent_relative = os.path.relpath(rust_proj_dir, os.getcwd())
|
|
@@ -3683,8 +3691,9 @@ def build_from_scratch(context: CertoraContext,
|
|
|
3683
3691
|
|
|
3684
3692
|
# add to cache also source files that were found in the SDCs (e.g., storage extensions)
|
|
3685
3693
|
paths_set = sdc.all_contract_files
|
|
3686
|
-
for
|
|
3687
|
-
|
|
3694
|
+
for f in context.files:
|
|
3695
|
+
path = f.split(':')[0] # `f` is either 'path/to/file.sol' or 'path/to/file.sol:ContractName'
|
|
3696
|
+
paths_set.add(Path(path).absolute())
|
|
3688
3697
|
|
|
3689
3698
|
# the contract files in SDCs are relative to .certora_sources. Which isn't good for us here.
|
|
3690
3699
|
# Need to be relative to original paths
|
|
@@ -3724,8 +3733,7 @@ def build_from_scratch(context: CertoraContext,
|
|
|
3724
3733
|
|
|
3725
3734
|
def build_from_cache_or_scratch(context: CertoraContext,
|
|
3726
3735
|
certora_build_generator: CertoraBuildGenerator,
|
|
3727
|
-
certora_verify_generator: CertoraVerifyGenerator
|
|
3728
|
-
certora_build_cache_manager: CertoraBuildCacheManager) \
|
|
3736
|
+
certora_verify_generator: CertoraVerifyGenerator) \
|
|
3729
3737
|
-> Tuple[bool, bool, CachedFiles]:
|
|
3730
3738
|
"""
|
|
3731
3739
|
Builds either from cache (fast path) or from scratch (slow path)
|
|
@@ -3742,10 +3750,10 @@ def build_from_cache_or_scratch(context: CertoraContext,
|
|
|
3742
3750
|
False)
|
|
3743
3751
|
return cache_hit, False, cached_files
|
|
3744
3752
|
|
|
3745
|
-
build_cache_applicable =
|
|
3753
|
+
build_cache_applicable = CertoraBuildCacheManager.cache_is_applicable(context)
|
|
3746
3754
|
|
|
3747
3755
|
if not build_cache_applicable:
|
|
3748
|
-
build_cache_disabling_options =
|
|
3756
|
+
build_cache_disabling_options = CertoraBuildCacheManager.cache_disabling_options(context)
|
|
3749
3757
|
build_logger.warning("Requested to enable the build cache, but the build cache is not applicable "
|
|
3750
3758
|
f"to this run because of the given options: {build_cache_disabling_options}")
|
|
3751
3759
|
cached_files = build_from_scratch(context, certora_build_generator,
|
|
@@ -3753,7 +3761,7 @@ def build_from_cache_or_scratch(context: CertoraContext,
|
|
|
3753
3761
|
False)
|
|
3754
3762
|
return cache_hit, False, cached_files
|
|
3755
3763
|
|
|
3756
|
-
cached_files =
|
|
3764
|
+
cached_files = CertoraBuildCacheManager.build_from_cache(context)
|
|
3757
3765
|
# if no match, will rebuild from scratch
|
|
3758
3766
|
if cached_files is not None:
|
|
3759
3767
|
# write to .certora_build.json
|
|
@@ -3792,7 +3800,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3792
3800
|
|
|
3793
3801
|
try:
|
|
3794
3802
|
input_config = InputConfig(context)
|
|
3795
|
-
|
|
3803
|
+
context.main_cache_key = CertoraBuildCacheManager.get_main_cache_key(context)
|
|
3796
3804
|
# Create generators
|
|
3797
3805
|
certora_build_generator = CertoraBuildGenerator(input_config, context)
|
|
3798
3806
|
|
|
@@ -3808,12 +3816,9 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3808
3816
|
else:
|
|
3809
3817
|
Ctx.run_local_spec_check(False, context)
|
|
3810
3818
|
|
|
3811
|
-
certora_build_cache_manager = CertoraBuildCacheManager()
|
|
3812
|
-
|
|
3813
3819
|
cache_hit, build_cache_enabled, cached_files = build_from_cache_or_scratch(context,
|
|
3814
3820
|
certora_build_generator,
|
|
3815
|
-
certora_verify_generator
|
|
3816
|
-
certora_build_cache_manager)
|
|
3821
|
+
certora_verify_generator)
|
|
3817
3822
|
|
|
3818
3823
|
# avoid running the same test over and over again for each split run, context.split_rules is true only for
|
|
3819
3824
|
# the first run and is set to [] for split runs
|
|
@@ -3833,7 +3838,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3833
3838
|
|
|
3834
3839
|
# save in build cache
|
|
3835
3840
|
if not cache_hit and build_cache_enabled and cached_files.may_store_in_build_cache:
|
|
3836
|
-
|
|
3841
|
+
CertoraBuildCacheManager.save_build_cache(context, cached_files)
|
|
3837
3842
|
|
|
3838
3843
|
certora_verify_generator.update_certora_verify_struct(True)
|
|
3839
3844
|
certora_verify_generator.dump() # second dump with properly rooted specs
|
|
@@ -66,10 +66,9 @@ class CertoraBuildCacheManager:
|
|
|
66
66
|
@returns None if no cache hit, otherwise - the matching `.certora_build.json` file, and a set of source files
|
|
67
67
|
"""
|
|
68
68
|
build_cache_dir = Util.get_certora_build_cache_dir()
|
|
69
|
-
|
|
70
|
-
main_cache_entry_dir = build_cache_dir / main_cache_key
|
|
69
|
+
main_cache_entry_dir = build_cache_dir / context.main_cache_key
|
|
71
70
|
if not main_cache_entry_dir.exists():
|
|
72
|
-
build_cache_logger.info(f"cache miss on build cache key {main_cache_key}")
|
|
71
|
+
build_cache_logger.info(f"cache miss on build cache key {context.main_cache_key}")
|
|
73
72
|
return None
|
|
74
73
|
|
|
75
74
|
# here's the tricky matching part:
|
|
@@ -92,7 +91,7 @@ class CertoraBuildCacheManager:
|
|
|
92
91
|
build_cache_logger.debug(f"Current sub build cache key computed for {file_list_file} is invalid")
|
|
93
92
|
continue
|
|
94
93
|
elif sub_cache_key_current_for_list == sub_cache_key_from_saved_entry:
|
|
95
|
-
build_cache_logger.info(f"We have a match on build cache key {main_cache_key} and "
|
|
94
|
+
build_cache_logger.info(f"We have a match on build cache key {context.main_cache_key} and "
|
|
96
95
|
f"{sub_cache_key_current_for_list}")
|
|
97
96
|
sub_cache_key = sub_cache_key_current_for_list
|
|
98
97
|
all_contract_files = set([Path(f) for f in file_list])
|
|
@@ -103,24 +102,24 @@ class CertoraBuildCacheManager:
|
|
|
103
102
|
|
|
104
103
|
if sub_cache_key is None:
|
|
105
104
|
build_cache_logger.info("All sub-cache-key file list files missed, cache miss on build cache key "
|
|
106
|
-
f"{main_cache_key}")
|
|
105
|
+
f"{context.main_cache_key}")
|
|
107
106
|
return None
|
|
108
107
|
|
|
109
108
|
# cache hit
|
|
110
109
|
certora_build_file = main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.certora_build_suffix}"
|
|
111
110
|
if not certora_build_file.exists():
|
|
112
|
-
build_cache_logger.warning(f"Got a cache-hit on build cache key {main_cache_key} and {sub_cache_key} "
|
|
111
|
+
build_cache_logger.warning(f"Got a cache-hit on build cache key {context.main_cache_key} and {sub_cache_key} "
|
|
113
112
|
"but .certora_build.json file does not exist")
|
|
114
113
|
return None
|
|
115
114
|
|
|
116
115
|
if all_contract_files is None: # should not be feasible
|
|
117
|
-
build_cache_logger.warning(f"Got a cache-hit on build cache key {main_cache_key} and
|
|
118
|
-
"but file list file does not exist")
|
|
116
|
+
build_cache_logger.warning(f"Got a cache-hit on build cache key {context.main_cache_key} and "
|
|
117
|
+
f"{sub_cache_key} but file list file does not exist")
|
|
119
118
|
return None
|
|
120
119
|
|
|
121
120
|
build_output_props_file = main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.build_output_props_suffix}"
|
|
122
121
|
if not build_output_props_file.exists():
|
|
123
|
-
build_cache_logger.warning(f"Got a cache-hit on build cache key {main_cache_key} and {sub_cache_key} "
|
|
122
|
+
build_cache_logger.warning(f"Got a cache-hit on build cache key {context.main_cache_key} and {sub_cache_key} "
|
|
124
123
|
f"but {CachedFiles.build_output_props_suffix} file does not exist")
|
|
125
124
|
return None
|
|
126
125
|
|
|
@@ -131,26 +130,26 @@ class CertoraBuildCacheManager:
|
|
|
131
130
|
@staticmethod
|
|
132
131
|
def save_build_cache(context: CertoraContext, cached_files: CachedFiles) -> None:
|
|
133
132
|
build_cache_dir = Util.get_certora_build_cache_dir()
|
|
134
|
-
|
|
135
|
-
main_cache_entry_dir = build_cache_dir / main_cache_key
|
|
133
|
+
main_cache_entry_dir = build_cache_dir / context.main_cache_key
|
|
136
134
|
sub_cache_key = CertoraBuildCacheManager.get_sub_cache_key(cached_files.all_contract_files)
|
|
137
135
|
if sub_cache_key is None:
|
|
138
|
-
build_cache_logger.warning(f"Cannot save cache for main build cache key {main_cache_key} "
|
|
136
|
+
build_cache_logger.warning(f"Cannot save cache for main build cache key {context.main_cache_key} "
|
|
139
137
|
"as sub-cache-key could not be computed")
|
|
140
138
|
return
|
|
141
139
|
|
|
142
140
|
if main_cache_entry_dir.exists():
|
|
143
|
-
build_cache_logger.info(f"main build cache key already exists {main_cache_key}, "
|
|
141
|
+
build_cache_logger.info(f"main build cache key already exists {context.main_cache_key}, "
|
|
144
142
|
f"saving sub build cache key {sub_cache_key}")
|
|
145
143
|
if cached_files.all_exist(main_cache_entry_dir, sub_cache_key):
|
|
146
144
|
build_cache_logger.debug("cache already saved under this build cache key, override")
|
|
147
145
|
else:
|
|
148
|
-
build_cache_logger.debug(f"cache was corrupted, need to re-save build cache key
|
|
149
|
-
f"and sub cache key {sub_cache_key}")
|
|
146
|
+
build_cache_logger.debug(f"cache was corrupted, need to re-save build cache key "
|
|
147
|
+
f"{context.main_cache_key} and sub cache key {sub_cache_key}")
|
|
150
148
|
CertoraBuildCacheManager.save_files(cached_files, main_cache_entry_dir,
|
|
151
149
|
sub_cache_key)
|
|
152
150
|
else:
|
|
153
|
-
build_cache_logger.info(f"saving main build cache key {main_cache_key} and sub cache key
|
|
151
|
+
build_cache_logger.info(f"saving main build cache key {context.main_cache_key} and sub cache key "
|
|
152
|
+
f"{sub_cache_key}")
|
|
154
153
|
safe_create_dir(main_cache_entry_dir)
|
|
155
154
|
CertoraBuildCacheManager.save_files(cached_files, main_cache_entry_dir,
|
|
156
155
|
sub_cache_key)
|
|
@@ -51,6 +51,7 @@ def build_rust_app(context: CertoraContext) -> None:
|
|
|
51
51
|
feature_flag = '--features'
|
|
52
52
|
if context.cargo_tools_version:
|
|
53
53
|
build_command.extend(["--tools-version", context.cargo_tools_version])
|
|
54
|
+
context.rust_project_directory = Util.find_nearest_cargo_toml()
|
|
54
55
|
|
|
55
56
|
if context.cargo_features is not None:
|
|
56
57
|
build_command.append(feature_flag)
|
|
@@ -102,7 +103,7 @@ def add_solana_files_to_sources(context: CertoraContext, sources: Set[Path]) ->
|
|
|
102
103
|
|
|
103
104
|
|
|
104
105
|
def collect_files_from_rust_sources(context: CertoraContext, sources: Set[Path]) -> None:
|
|
105
|
-
patterns = ["*.rs", "*.so", "*.wasm",
|
|
106
|
+
patterns = ["*.rs", "*.so", "*.wasm", Util.CARGO_TOML_FILE, "Cargo.lock", "justfile"]
|
|
106
107
|
exclude_dirs = [".certora_internal"]
|
|
107
108
|
|
|
108
109
|
if hasattr(context, 'rust_project_directory'):
|
|
@@ -760,42 +760,20 @@ class CloudVerification:
|
|
|
760
760
|
Util.get_configuration_layout_data_file(),
|
|
761
761
|
Util.get_build_dir() / Path(self.context.files[0]).name]
|
|
762
762
|
|
|
763
|
+
if Util.get_debug_log_file().exists():
|
|
764
|
+
files_list.append(Util.get_debug_log_file())
|
|
765
|
+
|
|
763
766
|
if Util.get_certora_sources_dir().exists():
|
|
764
767
|
files_list.append(Util.get_certora_sources_dir())
|
|
765
768
|
|
|
766
769
|
if hasattr(self.context, 'build_script') and self.context.build_script:
|
|
767
|
-
result = compress_files(self.logZipFilePath, Util.get_debug_log_file(),
|
|
768
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
769
|
-
|
|
770
|
-
if not result:
|
|
771
|
-
return False
|
|
772
|
-
files_list.append(self.logZipFilePath)
|
|
773
|
-
|
|
774
|
-
# Create a .RustExecution file to classify zipInput as a rust source code
|
|
775
|
-
rust_execution_file = Util.get_build_dir() / ".RustExecution"
|
|
776
|
-
rust_execution_file.touch(exist_ok=True)
|
|
777
|
-
files_list.append(rust_execution_file)
|
|
778
|
-
|
|
779
770
|
if attr_file := getattr(self.context, 'rust_logs_stdout', None):
|
|
780
771
|
files_list.append(Util.get_build_dir() / Path(attr_file).name)
|
|
781
772
|
if attr_file := getattr(self.context, 'rust_logs_stderr', None):
|
|
782
773
|
files_list.append(Util.get_build_dir() / Path(attr_file).name)
|
|
783
774
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
elif Attrs.is_solana_app() or Attrs.is_soroban_app():
|
|
788
|
-
for file in self.context.files:
|
|
789
|
-
files_list.append(Path(file))
|
|
790
|
-
|
|
791
|
-
result = compress_files(self.ZipFilePath, *files_list,
|
|
792
|
-
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
793
|
-
else:
|
|
794
|
-
raise Util.CertoraUserInputError(
|
|
795
|
-
'When running rust application, context should either have attribute "rust_executables" '
|
|
796
|
-
'provided by build_script execution, '
|
|
797
|
-
'or either is_solana_app(), is_soroban_app() should be set to True'
|
|
798
|
-
)
|
|
775
|
+
result = compress_files(self.ZipFilePath, *files_list,
|
|
776
|
+
short_output=Ctx.is_minimal_cli_output(self.context))
|
|
799
777
|
|
|
800
778
|
else:
|
|
801
779
|
# Zip the log file first separately and again with the rest of the files, so it will not be decompressed
|
|
@@ -953,6 +931,8 @@ class CloudVerification:
|
|
|
953
931
|
for i in range(self.verification_request_retries):
|
|
954
932
|
try:
|
|
955
933
|
response = requests.post(verify_url, json=auth_data, headers=headers, timeout=60)
|
|
934
|
+
cloud_logger.debug(f"\n\n=================\n\nresponse - Status Code: {response.status_code}\n\n"
|
|
935
|
+
f"Headers:\n {response.headers}\n\nText:\n {response.text}\n\n=================\n\n")
|
|
956
936
|
if response is None:
|
|
957
937
|
continue
|
|
958
938
|
status = response.status_code
|
|
@@ -25,12 +25,13 @@ sys.path.insert(0, str(scripts_dir_path))
|
|
|
25
25
|
import CertoraProver.certoraContextAttributes as Attrs
|
|
26
26
|
from CertoraProver.certoraCollectRunMetadata import RunMetaData, MetadataEncoder
|
|
27
27
|
import Shared.certoraUtils as Utils
|
|
28
|
+
from typing import List
|
|
28
29
|
|
|
29
30
|
|
|
30
31
|
class MainSection(Enum):
|
|
31
32
|
GENERAL = "GENERAL"
|
|
33
|
+
OPTIONS = "OPTIONS"
|
|
32
34
|
SOLIDITY_COMPILER = "SOLIDITY_COMPILER"
|
|
33
|
-
GIT = "GIT"
|
|
34
35
|
NEW_SECTION = "NEW_SECTION"
|
|
35
36
|
|
|
36
37
|
|
|
@@ -47,13 +48,11 @@ class InnerContent:
|
|
|
47
48
|
content: Any
|
|
48
49
|
doc_link: str = ''
|
|
49
50
|
tooltip: str = ''
|
|
50
|
-
unsound:
|
|
51
|
+
unsound: bool = False
|
|
51
52
|
|
|
52
53
|
def __post_init__(self) -> None:
|
|
53
54
|
if isinstance(self.content, bool):
|
|
54
55
|
self.content = 'true' if self.content else 'false'
|
|
55
|
-
if isinstance(self.unsound, bool):
|
|
56
|
-
self.unsound = 'true' if self.unsound else 'false'
|
|
57
56
|
|
|
58
57
|
|
|
59
58
|
@dataclasses.dataclass
|
|
@@ -65,6 +64,7 @@ class CardContent:
|
|
|
65
64
|
|
|
66
65
|
DOC_LINK_PREFIX = 'https://docs.certora.com/en/latest/docs/'
|
|
67
66
|
GIT_ATTRIBUTES = ['origin', 'revision', 'branch', 'dirty']
|
|
67
|
+
ARG_LIST_ATTRIBUTES = ['prover_args', 'java_args']
|
|
68
68
|
|
|
69
69
|
|
|
70
70
|
class AttributeJobConfigData:
|
|
@@ -73,13 +73,13 @@ class AttributeJobConfigData:
|
|
|
73
73
|
This should be added to the AttributeDefinition and configured for every new attribute
|
|
74
74
|
presented in the Rule report.
|
|
75
75
|
|
|
76
|
-
Note: Attributes
|
|
76
|
+
Note: Attributes that do not contain specific information will be presented in the OPTIONS main section!
|
|
77
77
|
|
|
78
78
|
arguments:
|
|
79
79
|
- main_section : MainSection -- the main section inside the config tab
|
|
80
|
-
default: MainSection.
|
|
81
|
-
- subsection : str -- the subsection within the main_section
|
|
82
|
-
default:
|
|
80
|
+
default: MainSection.OPTIONS
|
|
81
|
+
- subsection : str -- the subsection within the main_section
|
|
82
|
+
default: None - they will be presented inside the OPTIONS card
|
|
83
83
|
- doc_link : Optional[str] -- a link to the Documentation page of this attribute (if exists)
|
|
84
84
|
default: 'https://docs.certora.com/en/latest/docs/' + Solana/EVM path + #<attribute_name>
|
|
85
85
|
- tooltip : Optional[str] -- a description of this attribute to present in the config tab
|
|
@@ -88,7 +88,7 @@ class AttributeJobConfigData:
|
|
|
88
88
|
default: False
|
|
89
89
|
"""
|
|
90
90
|
|
|
91
|
-
def __init__(self, main_section: MainSection = MainSection.
|
|
91
|
+
def __init__(self, main_section: MainSection = MainSection.OPTIONS, subsection: str = '',
|
|
92
92
|
doc_link: Optional[str] = '', tooltip: Optional[str] = '', unsound: bool = False):
|
|
93
93
|
self.main_section = main_section
|
|
94
94
|
self.subsection = subsection
|
|
@@ -201,6 +201,40 @@ def create_or_get_card_content(output: list[CardContent], name: str) -> CardCont
|
|
|
201
201
|
return main_section
|
|
202
202
|
|
|
203
203
|
|
|
204
|
+
def split_and_sort_arg_list_value(args_list: List[str]) -> List[str]:
|
|
205
|
+
"""
|
|
206
|
+
Splits a unified CLI argument list of strings into a sorted list of flag+value groups.
|
|
207
|
+
This is useful mainly for --prover_args and --java_args.
|
|
208
|
+
|
|
209
|
+
For example:
|
|
210
|
+
"-depth 15 -adaptiveSolverConfig false" → ["-adaptiveSolverConfig false", "-depth 15"]
|
|
211
|
+
|
|
212
|
+
Assumes each flag starts with '-' and its value follows immediately, if exists.
|
|
213
|
+
Lines are sorted alphabetically.
|
|
214
|
+
"""
|
|
215
|
+
unified_args = ''.join(args_list)
|
|
216
|
+
|
|
217
|
+
if not unified_args.strip():
|
|
218
|
+
return []
|
|
219
|
+
|
|
220
|
+
lines: List[str] = []
|
|
221
|
+
tokens = unified_args.split()
|
|
222
|
+
curr_line = ""
|
|
223
|
+
|
|
224
|
+
for token in tokens:
|
|
225
|
+
if token.startswith('-'):
|
|
226
|
+
if curr_line:
|
|
227
|
+
lines.append(curr_line)
|
|
228
|
+
curr_line = token
|
|
229
|
+
else:
|
|
230
|
+
curr_line += f" {token}"
|
|
231
|
+
|
|
232
|
+
if curr_line:
|
|
233
|
+
lines.append(curr_line)
|
|
234
|
+
|
|
235
|
+
return sorted(lines)
|
|
236
|
+
|
|
237
|
+
|
|
204
238
|
def create_inner_content(name: str, content_type: ContentType, value: Any, doc_link: str,
|
|
205
239
|
config_data: AttributeJobConfigData) -> InnerContent:
|
|
206
240
|
return InnerContent(
|
|
@@ -209,7 +243,7 @@ def create_inner_content(name: str, content_type: ContentType, value: Any, doc_l
|
|
|
209
243
|
content=value,
|
|
210
244
|
doc_link=doc_link,
|
|
211
245
|
tooltip=config_data.tooltip or '',
|
|
212
|
-
unsound=
|
|
246
|
+
unsound=config_data.unsound
|
|
213
247
|
)
|
|
214
248
|
|
|
215
249
|
|
|
@@ -260,35 +294,23 @@ def collect_attribute_configs(metadata: dict) -> list[CardContent]:
|
|
|
260
294
|
)
|
|
261
295
|
continue
|
|
262
296
|
|
|
263
|
-
# Find or create the subsection (if it
|
|
297
|
+
# Find or create the subsection (if it doesn't exist)
|
|
264
298
|
if isinstance(attr_value, list):
|
|
265
|
-
current_section: Any = main_section
|
|
266
299
|
content_type = ContentType.SIMPLE
|
|
300
|
+
if attr_name in ARG_LIST_ATTRIBUTES:
|
|
301
|
+
attr_value = split_and_sort_arg_list_value(attr_value)
|
|
267
302
|
|
|
268
303
|
elif isinstance(attr_value, dict):
|
|
269
|
-
current_section = main_section
|
|
270
304
|
content_type = ContentType.COMPLEX
|
|
271
305
|
attr_value = [
|
|
272
306
|
create_inner_content(key, ContentType.FLAG, value, doc_link, config_data)
|
|
273
307
|
for key, value in attr_value.items()
|
|
274
308
|
]
|
|
275
309
|
else:
|
|
276
|
-
# this attribute is a value attribute without a subsection, it will be placed in flags.
|
|
277
|
-
subsection_key = config_data.subsection.lower() if config_data.subsection else 'flags'
|
|
278
|
-
current_section = next((section for section in main_section.content
|
|
279
|
-
if section.inner_title == subsection_key), None)
|
|
280
|
-
if current_section is None:
|
|
281
|
-
current_section = InnerContent(
|
|
282
|
-
inner_title=subsection_key,
|
|
283
|
-
content_type=ContentType.COMPLEX.value,
|
|
284
|
-
content=[]
|
|
285
|
-
)
|
|
286
|
-
main_section.content.append(current_section)
|
|
287
|
-
|
|
288
310
|
content_type = ContentType.FLAG
|
|
289
311
|
|
|
290
312
|
# Update the current section with attribute details
|
|
291
|
-
|
|
313
|
+
main_section.content.append(
|
|
292
314
|
create_inner_content(attr_name, content_type, attr_value, doc_link, config_data)
|
|
293
315
|
)
|
|
294
316
|
|
|
@@ -300,37 +322,23 @@ def collect_run_config_from_metadata(attributes_configs: list[CardContent], meta
|
|
|
300
322
|
Adding CLI and Git configuration from metadata
|
|
301
323
|
"""
|
|
302
324
|
|
|
303
|
-
# Define a mapping of metadata attributes to their keys in general_section
|
|
304
|
-
metadata_mappings = {
|
|
305
|
-
'CLI Version': metadata.get('CLI_version'),
|
|
306
|
-
'Verify': metadata.get('conf', {}).get('verify'),
|
|
307
|
-
}
|
|
308
|
-
|
|
309
325
|
general_section = create_or_get_card_content(attributes_configs, MainSection.GENERAL.value.lower())
|
|
310
326
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
content=value,
|
|
318
|
-
))
|
|
327
|
+
if cli_version := metadata.get('CLI_version'):
|
|
328
|
+
general_section.content.append(InnerContent(
|
|
329
|
+
inner_title='CLI Version',
|
|
330
|
+
content_type=ContentType.FLAG.value,
|
|
331
|
+
content=cli_version,
|
|
332
|
+
))
|
|
319
333
|
|
|
320
|
-
# Adding GIT configuration from metadata only if attributes are found
|
|
321
|
-
git_content = []
|
|
322
334
|
for attr in GIT_ATTRIBUTES:
|
|
323
335
|
if attr_value := metadata.get(attr):
|
|
324
|
-
|
|
336
|
+
general_section.content.append(InnerContent(
|
|
325
337
|
inner_title=attr,
|
|
326
338
|
content_type=ContentType.FLAG.value,
|
|
327
339
|
content=attr_value,
|
|
328
340
|
))
|
|
329
341
|
|
|
330
|
-
if git_content:
|
|
331
|
-
git_section = create_or_get_card_content(attributes_configs, MainSection.GIT.value.lower())
|
|
332
|
-
git_section.content = git_content
|
|
333
|
-
|
|
334
342
|
return attributes_configs
|
|
335
343
|
|
|
336
344
|
|
|
@@ -338,14 +346,17 @@ def sort_configuration_layout(data: list[CardContent]) -> list[CardContent]:
|
|
|
338
346
|
"""
|
|
339
347
|
Sorts a configuration layout:
|
|
340
348
|
- Top-level sorted by 'card_title'
|
|
341
|
-
- Nested content sorted by 'inner_title', with '
|
|
349
|
+
- Nested content sorted by 'inner_title', with 'verify' first
|
|
342
350
|
"""
|
|
343
351
|
priority = {
|
|
344
|
-
|
|
352
|
+
# Priorities for top-level cards
|
|
345
353
|
"general": 0,
|
|
354
|
+
"files": 1,
|
|
355
|
+
"options": 2,
|
|
356
|
+
# Top level items inside their respective cards
|
|
357
|
+
"verify": 0,
|
|
346
358
|
"solc": 0,
|
|
347
|
-
"CLI Version":
|
|
348
|
-
"flags": 2
|
|
359
|
+
"CLI Version": 0
|
|
349
360
|
}
|
|
350
361
|
|
|
351
362
|
def inner_sort_key(item: Any) -> Any:
|
|
@@ -17,6 +17,7 @@ import json5
|
|
|
17
17
|
import logging
|
|
18
18
|
from pathlib import Path
|
|
19
19
|
from typing import Dict, Any
|
|
20
|
+
from collections import OrderedDict
|
|
20
21
|
|
|
21
22
|
import CertoraProver.certoraContext as Ctx
|
|
22
23
|
import CertoraProver.certoraContextAttributes as Attrs
|
|
@@ -75,7 +76,7 @@ def read_from_conf_file(context: CertoraContext) -> None:
|
|
|
75
76
|
|
|
76
77
|
try:
|
|
77
78
|
with conf_file_path.open() as conf_file:
|
|
78
|
-
context.conf_file_attr = json5.load(conf_file, allow_duplicate_keys=False)
|
|
79
|
+
context.conf_file_attr = json5.load(conf_file, allow_duplicate_keys=False, object_pairs_hook=OrderedDict)
|
|
79
80
|
try:
|
|
80
81
|
check_conf_content(context)
|
|
81
82
|
except Util.CertoraUserInputError as e:
|
|
@@ -20,6 +20,8 @@ import os
|
|
|
20
20
|
import re
|
|
21
21
|
import sys
|
|
22
22
|
import logging
|
|
23
|
+
import fnmatch
|
|
24
|
+
from wcmatch import glob
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
from pathlib import Path
|
|
@@ -150,8 +152,6 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
|
|
|
150
152
|
java_cmd.extend(context.java_args.strip().split(' '))
|
|
151
153
|
|
|
152
154
|
cmd = java_cmd + ["-jar", jar_path] + run_args
|
|
153
|
-
if context.test == str(Util.TestValue.LOCAL_JAR):
|
|
154
|
-
raise Util.TestResultsReady(' '.join(cmd))
|
|
155
155
|
return cmd
|
|
156
156
|
|
|
157
157
|
|
|
@@ -615,3 +615,30 @@ def attrs_to_relative(context: CertoraContext) -> None:
|
|
|
615
615
|
packages_to_relative()
|
|
616
616
|
prover_resource_file_to_relative()
|
|
617
617
|
verify_to_relative()
|
|
618
|
+
|
|
619
|
+
def get_map_attribute_value(context: CertoraContext, path: Path, attr_name: str) -> Optional[Union[str, bool]]:
|
|
620
|
+
|
|
621
|
+
value = getattr(context, attr_name, None)
|
|
622
|
+
if value:
|
|
623
|
+
return value
|
|
624
|
+
|
|
625
|
+
map_value = getattr(context, f"{attr_name}_map", None)
|
|
626
|
+
if not map_value:
|
|
627
|
+
return None # No map value defined
|
|
628
|
+
for key, entry_value in map_value.items():
|
|
629
|
+
# Split key to handle contract:field syntax
|
|
630
|
+
key_parts = key.split(':')
|
|
631
|
+
pattern = key_parts[0]
|
|
632
|
+
|
|
633
|
+
if Path(pattern).suffix == "": # This is a contract pattern
|
|
634
|
+
# Find contracts that match the pattern
|
|
635
|
+
for contract_name, contract_file_path in context.contract_to_file.items():
|
|
636
|
+
if fnmatch.fnmatch(contract_name, pattern):
|
|
637
|
+
# Check if this contract's file matches our target path
|
|
638
|
+
if Path(contract_file_path) == path:
|
|
639
|
+
return entry_value
|
|
640
|
+
else: # This is a file pattern
|
|
641
|
+
# Match the file pattern against the path
|
|
642
|
+
if glob.globmatch(str(path), pattern, flags=glob.GLOBSTAR):
|
|
643
|
+
return entry_value
|
|
644
|
+
return None # No match
|
|
@@ -156,7 +156,9 @@ class CommonAttributes(AttrUtil.Attributes):
|
|
|
156
156
|
'action': AttrUtil.NotAllowed
|
|
157
157
|
},
|
|
158
158
|
affects_build_cache_key=False,
|
|
159
|
-
disables_build_cache=False
|
|
159
|
+
disables_build_cache=False,
|
|
160
|
+
# Avoiding presentation of this attribute in Config Tab
|
|
161
|
+
config_data=None
|
|
160
162
|
)
|
|
161
163
|
|
|
162
164
|
RUN_SOURCE = AttrUtil.AttributeDefinition(
|
|
@@ -340,7 +342,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
340
342
|
default_desc="do not set via_ir during compilation unless solc_via_ir is set",
|
|
341
343
|
argparse_args={
|
|
342
344
|
'action': AttrUtil.UniqueStore,
|
|
343
|
-
'type': lambda value: Vf.
|
|
345
|
+
'type': lambda value: Vf.parse_ordered_dict('solc_via_ir_map', value, bool)
|
|
344
346
|
},
|
|
345
347
|
affects_build_cache_key=True,
|
|
346
348
|
disables_build_cache=False,
|
|
@@ -382,7 +384,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
382
384
|
default_desc="Uses the same Solidity EVM version for all contracts",
|
|
383
385
|
argparse_args={
|
|
384
386
|
'action': AttrUtil.UniqueStore,
|
|
385
|
-
'type': lambda value: Vf.
|
|
387
|
+
'type': lambda value: Vf.parse_ordered_dict('solc_evm_version_map', value)
|
|
386
388
|
},
|
|
387
389
|
affects_build_cache_key=True,
|
|
388
390
|
disables_build_cache=False,
|
|
@@ -405,7 +407,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
405
407
|
default_desc="Uses the same Solidity compiler version for all contracts",
|
|
406
408
|
argparse_args={
|
|
407
409
|
'action': AttrUtil.UniqueStore,
|
|
408
|
-
'type': lambda value: Vf.
|
|
410
|
+
'type': lambda value: Vf.parse_ordered_dict('solc_map', value)
|
|
409
411
|
},
|
|
410
412
|
affects_build_cache_key=True,
|
|
411
413
|
disables_build_cache=False,
|
|
@@ -428,7 +430,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
428
430
|
default_desc="Uses the same compiler version for all contracts",
|
|
429
431
|
argparse_args={
|
|
430
432
|
'action': AttrUtil.UniqueStore,
|
|
431
|
-
'type': lambda value: Vf.
|
|
433
|
+
'type': lambda value: Vf.parse_ordered_dict('compiler_map', value)
|
|
432
434
|
},
|
|
433
435
|
affects_build_cache_key=True,
|
|
434
436
|
disables_build_cache=False,
|
|
@@ -481,7 +483,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
481
483
|
default_desc="Compiles all contracts with the same optimization settings",
|
|
482
484
|
argparse_args={
|
|
483
485
|
'action': AttrUtil.UniqueStore,
|
|
484
|
-
'type': lambda value: Vf.
|
|
486
|
+
'type': lambda value: Vf.parse_ordered_dict('solc_optimize_map', value)
|
|
485
487
|
},
|
|
486
488
|
affects_build_cache_key=True,
|
|
487
489
|
disables_build_cache=False,
|
|
@@ -582,6 +584,16 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
582
584
|
affects_build_cache_key=True,
|
|
583
585
|
disables_build_cache=True
|
|
584
586
|
)
|
|
587
|
+
|
|
588
|
+
YUL_OPTIMIZER_STEPS = AttrUtil.AttributeDefinition(
|
|
589
|
+
# overrides the hardcoded yul optimizer steps, set in certoraBuild.py
|
|
590
|
+
argparse_args={
|
|
591
|
+
'action': AttrUtil.UniqueStore
|
|
592
|
+
},
|
|
593
|
+
affects_build_cache_key=True,
|
|
594
|
+
disables_build_cache=False
|
|
595
|
+
)
|
|
596
|
+
|
|
585
597
|
CACHE = AttrUtil.AttributeDefinition(
|
|
586
598
|
argparse_args={
|
|
587
599
|
'action': AttrUtil.UniqueStore
|
|
@@ -740,8 +752,7 @@ class EvmAttributes(AttrUtil.Attributes):
|
|
|
740
752
|
'action': AttrUtil.UniqueStore
|
|
741
753
|
},
|
|
742
754
|
affects_build_cache_key=False,
|
|
743
|
-
disables_build_cache=False
|
|
744
|
-
config_data=None
|
|
755
|
+
disables_build_cache=False
|
|
745
756
|
)
|
|
746
757
|
|
|
747
758
|
BUILD_CACHE = AttrUtil.AttributeDefinition(
|
|
@@ -1719,7 +1730,7 @@ class RangerAttributes(EvmProverAttributes):
|
|
|
1719
1730
|
@classmethod
|
|
1720
1731
|
def ranger_unsupported_attributes(cls) -> List[AttrUtil.AttributeDefinition]:
|
|
1721
1732
|
return [cls.PROJECT_SANITY, cls.RULE_SANITY, cls.COVERAGE_INFO, cls.FOUNDRY, cls.INDEPENDENT_SATISFY,
|
|
1722
|
-
cls.MULTI_ASSERT_CHECK, cls.MULTI_EXAMPLE]
|
|
1733
|
+
cls.MULTI_ASSERT_CHECK, cls.MULTI_EXAMPLE, cls.VYPER]
|
|
1723
1734
|
|
|
1724
1735
|
@classmethod
|
|
1725
1736
|
def ranger_true_by_default_attributes(cls) -> List[AttrUtil.AttributeDefinition]:
|
|
@@ -21,7 +21,8 @@ import itertools
|
|
|
21
21
|
import tempfile
|
|
22
22
|
import fnmatch
|
|
23
23
|
from pathlib import Path
|
|
24
|
-
from
|
|
24
|
+
from wcmatch import glob
|
|
25
|
+
from typing import Dict, List, Tuple, Set, Any, Union, OrderedDict
|
|
25
26
|
|
|
26
27
|
import CertoraProver.certoraContext as Ctx
|
|
27
28
|
import CertoraProver.certoraContextAttributes as Attrs
|
|
@@ -31,6 +32,7 @@ from Shared import certoraUtils as Util
|
|
|
31
32
|
from Shared import certoraAttrUtil as AttrUtil
|
|
32
33
|
from CertoraProver.certoraProjectScanner import scan_project
|
|
33
34
|
|
|
35
|
+
|
|
34
36
|
scripts_dir_path = Path(__file__).parent.resolve() # containing directory
|
|
35
37
|
sys.path.insert(0, str(scripts_dir_path))
|
|
36
38
|
|
|
@@ -70,10 +72,10 @@ class CertoraContextValidator:
|
|
|
70
72
|
|
|
71
73
|
else:
|
|
72
74
|
if self.context.range:
|
|
73
|
-
|
|
75
|
+
self.context.range = None
|
|
74
76
|
validation_logger.info("the 'range' attribute is ignored when not running from the Ranger App")
|
|
75
77
|
if self.context.ranger_failure_limit:
|
|
76
|
-
|
|
78
|
+
self.context.ranger_failure_limit = None
|
|
77
79
|
validation_logger.info("the 'ranger_failure_limit' is ignored when not running from the Ranger App")
|
|
78
80
|
|
|
79
81
|
def validate(self) -> None:
|
|
@@ -375,19 +377,15 @@ def convert_to_compiler_map(context: CertoraContext) -> None:
|
|
|
375
377
|
if context.solc_map:
|
|
376
378
|
context.compiler_map = context.solc_map
|
|
377
379
|
context.solc_map = None
|
|
378
|
-
|
|
379
|
-
context.compiler_map = {'*.sol': f'{context.solc}'}
|
|
380
|
-
if context.vyper:
|
|
381
|
-
context.compiler_map = {'*.vy': f'{context.vyper}'}
|
|
380
|
+
|
|
382
381
|
|
|
383
382
|
def check_vyper_flag(context: CertoraContext) -> None:
|
|
384
383
|
if context.vyper:
|
|
385
|
-
|
|
386
|
-
if
|
|
387
|
-
|
|
384
|
+
vy_paths = [path for path in context.files if path.endswith(".vy")]
|
|
385
|
+
if not vy_paths:
|
|
386
|
+
validation_logger.warning("vyper attribute was set but no Vyper files were set")
|
|
388
387
|
if context.solc:
|
|
389
388
|
raise Util.CertoraUserInputError("cannot set both vyper attribute and solc attribute")
|
|
390
|
-
context.solc = context.vyper
|
|
391
389
|
|
|
392
390
|
def check_contract_name_arg_inputs(context: CertoraContext) -> None:
|
|
393
391
|
"""
|
|
@@ -670,37 +668,20 @@ def check_mode_of_operation(context: CertoraContext) -> None:
|
|
|
670
668
|
special_file_type]) and not context.build_only:
|
|
671
669
|
raise Util.CertoraUserInputError("You must use 'verify' when running the Certora Prover")
|
|
672
670
|
|
|
671
|
+
def find_matching_contracts(context: CertoraContext, pattern: str) -> List[str]:
|
|
672
|
+
result = []
|
|
673
|
+
for contract in context.contract_to_file:
|
|
674
|
+
if fnmatch.fnmatch(contract, pattern):
|
|
675
|
+
result.append(context.contract_to_file[contract])
|
|
676
|
+
return result
|
|
673
677
|
|
|
674
|
-
def
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
:param context:
|
|
678
|
-
:param map_attr_name: name of the attribute e.g. solc_optimize_map
|
|
679
|
-
:param map_attr: the value of the map attribute, a dictionary mapping contract/file to a value
|
|
680
|
-
:return:
|
|
681
|
-
|
|
682
|
-
all solc_XXX_map attributes are used to set attributes for the Solidity compiler. The value is based on the
|
|
683
|
-
Solidity file to be compiled, therefore it translates all keys to a relative path to a file
|
|
684
|
-
"""
|
|
685
|
-
|
|
686
|
-
def find_matching_files(context: CertoraContext, pattern: str) -> List[str]:
|
|
687
|
-
file_part = pattern.split(':')[0]
|
|
688
|
-
if Path(file_part).suffix == "": # no suffix means the key is a contract
|
|
689
|
-
matching_contracts = fnmatch.filter(context.contracts, pattern) # find matching contracts
|
|
690
|
-
return [context.contract_to_file[contract] for contract in matching_contracts]
|
|
691
|
-
else:
|
|
692
|
-
return [file_part]
|
|
693
|
-
|
|
694
|
-
new_map_attr: Dict[str, str] = {}
|
|
695
|
-
for (pattern, value) in map_attr.copy().items():
|
|
696
|
-
matching_files = find_matching_files(context, pattern)
|
|
697
|
-
for file in matching_files:
|
|
698
|
-
file = str(Path(file).resolve(strict=False).relative_to(Path.cwd()))
|
|
699
|
-
attr_value = new_map_attr.get(file)
|
|
700
|
-
if attr_value is None: # key in file paths but no mapping yet
|
|
701
|
-
new_map_attr[file] = value
|
|
702
|
-
return new_map_attr
|
|
678
|
+
def find_matching_files(context: CertoraContext, pattern: str) -> List[str]:
|
|
679
|
+
result = []
|
|
703
680
|
|
|
681
|
+
for path in context.file_paths:
|
|
682
|
+
if glob.globmatch(path, pattern, flags=glob.GLOBSTAR):
|
|
683
|
+
result.append(path)
|
|
684
|
+
return result
|
|
704
685
|
|
|
705
686
|
def check_map_attributes(context: CertoraContext) -> None:
|
|
706
687
|
|
|
@@ -718,27 +699,24 @@ def check_map_attributes(context: CertoraContext) -> None:
|
|
|
718
699
|
# we also check the map value was not set to False explicitly in the conf file
|
|
719
700
|
if base_attr and map_attr and not (base_attr is False and context.conf_options.get(base_attr) is not None):
|
|
720
701
|
raise Util.CertoraUserInputError(f"You cannot use both '{attr_prefix}' and '{map_attr_name}' arguments")
|
|
721
|
-
if not isinstance(map_attr,
|
|
722
|
-
raise RuntimeError(f"map_attr is not dictionary, got {map_attr}")
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
for
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
paths_not_set = [path for path, value in sources_mappings.items() if value is None]
|
|
740
|
-
if paths_not_set:
|
|
741
|
-
raise Util.CertoraUserInputError(f"{' '.join(paths_not_set)} was not set in {map_attr_name}")
|
|
702
|
+
if not isinstance(map_attr, OrderedDict):
|
|
703
|
+
raise RuntimeError(f"`map_attr` is not an ordered dictionary, got {map_attr}")
|
|
704
|
+
|
|
705
|
+
# will check that all the contract files are matched
|
|
706
|
+
file_list: Dict[str, bool] = {path: False for path in context.file_paths}
|
|
707
|
+
|
|
708
|
+
for key, value in map_attr.items():
|
|
709
|
+
pattern = key.split(':')[0] # ignore the contract part
|
|
710
|
+
if Path(pattern).suffix == "":
|
|
711
|
+
for path in find_matching_contracts(context, pattern):
|
|
712
|
+
file_list[path] = True
|
|
713
|
+
else:
|
|
714
|
+
for path in find_matching_files(context, pattern):
|
|
715
|
+
file_list[path] = True
|
|
716
|
+
|
|
717
|
+
none_keys = [k for k, v in file_list.items() if v is False]
|
|
718
|
+
if none_keys:
|
|
719
|
+
raise Util.CertoraUserInputError(f"The following files are not matched in {map_attr_name}: {none_keys}")
|
|
742
720
|
|
|
743
721
|
|
|
744
722
|
def check_parametric_contracts(context: CertoraContext) -> None:
|
|
@@ -60,7 +60,7 @@ def add_solana_files_to_context(context: CertoraContext, json_obj: dict) -> None
|
|
|
60
60
|
def run_rust_build(context: CertoraContext, build_cmd: List[str]) -> None:
|
|
61
61
|
|
|
62
62
|
try:
|
|
63
|
-
build_script_logger.info(f"Building by calling {build_cmd}")
|
|
63
|
+
build_script_logger.info(f"Building by calling `{' '.join(build_cmd)}`")
|
|
64
64
|
result = subprocess.run(build_cmd, capture_output=True, text=True)
|
|
65
65
|
|
|
66
66
|
# Check if the script executed successfully
|
|
@@ -90,11 +90,12 @@ def run_rust_build(context: CertoraContext, build_cmd: List[str]) -> None:
|
|
|
90
90
|
|
|
91
91
|
add_solana_files_to_context(context, json_obj)
|
|
92
92
|
|
|
93
|
-
if context.test == str(Util.TestValue.AFTER_BUILD_RUST):
|
|
94
|
-
raise Util.TestResultsReady(context)
|
|
95
93
|
assert not context.files, f"run_rust_build: expecting files to be empty, got: {context.files}"
|
|
96
94
|
context.files = [os.path.join(context.rust_project_directory, context.rust_executables)]
|
|
97
95
|
|
|
96
|
+
if context.test == str(Util.TestValue.AFTER_BUILD_RUST):
|
|
97
|
+
raise Util.TestResultsReady(context)
|
|
98
|
+
|
|
98
99
|
except Util.TestResultsReady as e:
|
|
99
100
|
raise e
|
|
100
101
|
except FileNotFoundError as e:
|
|
@@ -14,7 +14,6 @@
|
|
|
14
14
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
15
|
|
|
16
16
|
import csv
|
|
17
|
-
import fnmatch
|
|
18
17
|
import json
|
|
19
18
|
import os
|
|
20
19
|
import subprocess
|
|
@@ -97,6 +96,7 @@ EMV_JAR = Path("emv.jar")
|
|
|
97
96
|
CERTORA_SOURCES = Path(".certora_sources")
|
|
98
97
|
SOLANA_INLINING = "solana_inlining"
|
|
99
98
|
SOLANA_SUMMARIES = "solana_summaries"
|
|
99
|
+
CARGO_TOML_FILE = "cargo.toml"
|
|
100
100
|
|
|
101
101
|
ALPHA_PACKAGE_NAME = 'certora-cli-alpha'
|
|
102
102
|
ALPHA_PACKAGE_MASTER_NAME = ALPHA_PACKAGE_NAME + '-master'
|
|
@@ -1171,26 +1171,9 @@ class Singleton(type):
|
|
|
1171
1171
|
cls.__instancesinstances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
|
|
1172
1172
|
return cls.__instancesinstances[cls]
|
|
1173
1173
|
|
|
1174
|
-
|
|
1175
1174
|
class AbstractAndSingleton(Singleton, ABCMeta):
|
|
1176
1175
|
pass
|
|
1177
1176
|
|
|
1178
|
-
|
|
1179
|
-
def match_path_to_mapping_key(path: Path, m: Dict[str, str]) -> Optional[str]:
|
|
1180
|
-
"""
|
|
1181
|
-
Matches the path to the best match in the dictionary's keys.
|
|
1182
|
-
For example, given an absolute path `/Users/JohnDoe/Path/ToSolc/a.sol`, if the map contains
|
|
1183
|
-
`b/a.sol` and `ToSolc/a.sol`, it will match on `ToSolc/a.sol`.
|
|
1184
|
-
@param path: the path to match against
|
|
1185
|
-
@param m: the map whose keys we're searching
|
|
1186
|
-
@return: the value from the map that best matches the path, None if not found.
|
|
1187
|
-
"""
|
|
1188
|
-
for k, v in m.items():
|
|
1189
|
-
if fnmatch.fnmatch(str(path), k):
|
|
1190
|
-
return v
|
|
1191
|
-
return None
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
1177
|
def find_in(dir_path: Path, file_to_find: Path) -> Optional[Path]:
|
|
1195
1178
|
"""
|
|
1196
1179
|
Given a directory dir_path and a file we wish to find within that directory,
|
|
@@ -1262,7 +1245,7 @@ class TestValue(NoValEnum):
|
|
|
1262
1245
|
determines the chekpoint where the execution will halt. The exception TestResultsReady will be thrown. The value
|
|
1263
1246
|
will also determine what object will be attached to the exception for inspection by the caller
|
|
1264
1247
|
"""
|
|
1265
|
-
|
|
1248
|
+
BEFORE_LOCAL_PROVER_CALL = auto()
|
|
1266
1249
|
CHECK_ARGS = auto()
|
|
1267
1250
|
AFTER_BUILD = auto()
|
|
1268
1251
|
CHECK_SOLC_OPTIONS = auto()
|
|
@@ -1452,3 +1435,22 @@ def eq_by(f: Callable[[T, T], bool], a: Sequence[T], b: Sequence[T]) -> bool:
|
|
|
1452
1435
|
check if Sequences a and b are equal according to function f.
|
|
1453
1436
|
"""
|
|
1454
1437
|
return len(a) == len(b) and all(map(f, a, b))
|
|
1438
|
+
|
|
1439
|
+
def find_nearest_cargo_toml() -> Optional[Path]:
|
|
1440
|
+
current = Path.cwd()
|
|
1441
|
+
for parent in [current] + list(current.parents):
|
|
1442
|
+
candidate = parent / CARGO_TOML_FILE
|
|
1443
|
+
if candidate.is_file():
|
|
1444
|
+
return candidate
|
|
1445
|
+
return None
|
|
1446
|
+
|
|
1447
|
+
def file_in_source_tree(file_path: Path) -> bool:
|
|
1448
|
+
# if the file is under .certora_source, return True
|
|
1449
|
+
file_path = Path(file_path).absolute()
|
|
1450
|
+
parent_dir = get_certora_sources_dir().absolute()
|
|
1451
|
+
|
|
1452
|
+
try:
|
|
1453
|
+
file_path.relative_to(parent_dir)
|
|
1454
|
+
return True
|
|
1455
|
+
except ValueError:
|
|
1456
|
+
return False
|
|
@@ -18,6 +18,8 @@ import sys
|
|
|
18
18
|
import argparse
|
|
19
19
|
import json
|
|
20
20
|
import logging
|
|
21
|
+
from collections import OrderedDict
|
|
22
|
+
|
|
21
23
|
import json5
|
|
22
24
|
import re
|
|
23
25
|
import urllib3.util
|
|
@@ -684,7 +686,7 @@ def validate_solc_via_ir_map(args: Dict[str, bool]) -> None:
|
|
|
684
686
|
if first:
|
|
685
687
|
validation_logger.warning("all via_ir values are set to True '--solc_via_ir' can be used instead")
|
|
686
688
|
else:
|
|
687
|
-
validation_logger.warning("all via_ir values are set to False, this flag/attribute
|
|
689
|
+
validation_logger.warning("all via_ir values are set to False, this flag/attribute can be omitted")
|
|
688
690
|
|
|
689
691
|
def validate_solc_evm_version_map(args: Dict[str, str]) -> None:
|
|
690
692
|
if not isinstance(args, dict):
|
|
@@ -938,7 +940,7 @@ def validate_on_off(value: str) -> str:
|
|
|
938
940
|
return __validate_enum_value(value, OnOffValue)
|
|
939
941
|
|
|
940
942
|
|
|
941
|
-
def
|
|
943
|
+
def parse_ordered_dict(conf_key: str, input_string: str, value_type: Type = str) -> OrderedDict[str, Union[str, bool]]:
|
|
942
944
|
"""
|
|
943
945
|
convert CLI flag value string of the form <key>=<value>,<key>=<value>,.. to a Dict.
|
|
944
946
|
Keys with different values raise an exception
|
|
@@ -971,7 +973,7 @@ def parse_dict(conf_key: str, input_string: str, value_type: Type = str) -> Dict
|
|
|
971
973
|
raise argparse.ArgumentTypeError(f"{conf_key} argument {input_string} is of wrong format. Must be of format:"
|
|
972
974
|
f"<key>=<value>[,..]")
|
|
973
975
|
|
|
974
|
-
return_dict =
|
|
976
|
+
return_dict = OrderedDict() # type: OrderedDict[str, Union[str, bool]]
|
|
975
977
|
|
|
976
978
|
for match in input_string.split(','):
|
|
977
979
|
key, value = match.split('=')
|
|
@@ -176,6 +176,8 @@ def run_local(context: CertoraContext, timings: Dict, additional_commands: Optio
|
|
|
176
176
|
cmd.extend(additional_commands)
|
|
177
177
|
|
|
178
178
|
print(f'Verifier run command:\n {" ".join(cmd)}')
|
|
179
|
+
if context.test == str(Util.TestValue.BEFORE_LOCAL_PROVER_CALL):
|
|
180
|
+
raise Util.TestResultsReady(' '.join(cmd))
|
|
179
181
|
rc = Util.run_jar_cmd(
|
|
180
182
|
cmd,
|
|
181
183
|
override_exit_code=compare_with_expected_file,
|
certora_cli/certoraRun.py
CHANGED
|
@@ -99,6 +99,8 @@ def run_certora(args: List[str], attrs_class: Optional[Type[AttrUtil.Attributes]
|
|
|
99
99
|
print(f"Verifier run command:\n {check_cmd_string}", flush=True)
|
|
100
100
|
|
|
101
101
|
compare_with_tool_output = False
|
|
102
|
+
if context.test == str(Util.TestValue.BEFORE_LOCAL_PROVER_CALL):
|
|
103
|
+
raise Util.TestResultsReady(' '.join(check_cmd))
|
|
102
104
|
run_result = Util.run_jar_cmd(check_cmd, compare_with_tool_output, logger_topic="verification",
|
|
103
105
|
print_output=True)
|
|
104
106
|
# For solana and wasm, we don't check types so build time is zero.
|
{certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: certora-cli-beta-mirror
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.31.0
|
|
4
4
|
Summary: Runner for the Certora Prover
|
|
5
5
|
Home-page: https://pypi.org/project/certora-cli-beta-mirror
|
|
6
6
|
Author: Certora
|
|
@@ -25,6 +25,7 @@ Requires-Dist: tqdm
|
|
|
25
25
|
Requires-Dist: StrEnum
|
|
26
26
|
Requires-Dist: universalmutator
|
|
27
27
|
Requires-Dist: jinja2
|
|
28
|
+
Requires-Dist: wcmatch
|
|
28
29
|
Dynamic: author
|
|
29
30
|
Dynamic: author-email
|
|
30
31
|
Dynamic: classifier
|
|
@@ -37,4 +38,4 @@ Dynamic: requires-dist
|
|
|
37
38
|
Dynamic: requires-python
|
|
38
39
|
Dynamic: summary
|
|
39
40
|
|
|
40
|
-
Commit
|
|
41
|
+
Commit 89159ec. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
{certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/RECORD
RENAMED
|
@@ -4,30 +4,30 @@ certora_cli/certoraEVMProver.py,sha256=gLxqPXG9jKlCdLdgfo0aNjvp09vbHGSs8wghY6RH0
|
|
|
4
4
|
certora_cli/certoraEqCheck.py,sha256=qfZq7bpU1kbAIezC66W61VfKNZz7Uywg2Ygup62qYeo,1069
|
|
5
5
|
certora_cli/certoraMutate.py,sha256=XhFHyNVP_sk-3XkY6AAV5fVliEFAVRq-JeDGsqE5IQQ,3333
|
|
6
6
|
certora_cli/certoraRanger.py,sha256=cwejxWTNlHsbwtu6Lew0SNsynSeq_ZKJu1Cr9uu0DhE,1314
|
|
7
|
-
certora_cli/certoraRun.py,sha256=
|
|
7
|
+
certora_cli/certoraRun.py,sha256=mTBAi-SVCApy8BvfvKAL8Z4PdGcaBV3G5vNXPrFdgTI,8817
|
|
8
8
|
certora_cli/certoraSolanaProver.py,sha256=7hu-YJJNA_P5eAJq_jYh6IGjiUf0PegGUBRCJ5AhE7s,3274
|
|
9
9
|
certora_cli/certoraSorobanProver.py,sha256=qE6b_vicC8KgOvUz7UTOaDuXT3UW0MMhq3keQgUVvzs,2865
|
|
10
10
|
certora_cli/rustMutator.py,sha256=6AvOGU8Ijz89zW_ZJCWlfXkeobJsk7EsqZhK7Eqwn-Y,14544
|
|
11
11
|
certora_cli/CertoraProver/__init__.py,sha256=QHNr-PJQAoyuPgTkO7gg23GRchiWSXglWNG7yLSQZvs,849
|
|
12
|
-
certora_cli/CertoraProver/certoraBuild.py,sha256=
|
|
13
|
-
certora_cli/CertoraProver/certoraBuildCacheManager.py,sha256=
|
|
12
|
+
certora_cli/CertoraProver/certoraBuild.py,sha256=eAAaRcyF16XNjr9Es54cQPutErqjW6j8VUefrGAxumc,212517
|
|
13
|
+
certora_cli/CertoraProver/certoraBuildCacheManager.py,sha256=I60x0ykMFPzciD193cPXihsHh0fdV--UOmNKbIZW6Rc,13238
|
|
14
14
|
certora_cli/CertoraProver/certoraBuildDataClasses.py,sha256=8tPny9-pasC7CCRKQclaVQ3qcEDNa6EdOUu1ZWh0MZY,14704
|
|
15
|
-
certora_cli/CertoraProver/certoraBuildRust.py,sha256=
|
|
16
|
-
certora_cli/CertoraProver/certoraCloudIO.py,sha256=
|
|
17
|
-
certora_cli/CertoraProver/certoraCollectConfigurationLayout.py,sha256=
|
|
15
|
+
certora_cli/CertoraProver/certoraBuildRust.py,sha256=ofKvmtqzUGTrgVm5crcybV7gbElbjiUc6Z4FphPEjz0,6016
|
|
16
|
+
certora_cli/CertoraProver/certoraCloudIO.py,sha256=w3mqA5ANgIX6dsb6Nxg4jl9zBRdAX5kw9xLeYmA-iHc,53062
|
|
17
|
+
certora_cli/CertoraProver/certoraCollectConfigurationLayout.py,sha256=6aHEGrhT_Y9aYfM5n_Mk--awgcQfdtc-chBPRl7FU4E,14095
|
|
18
18
|
certora_cli/CertoraProver/certoraCollectRunMetadata.py,sha256=n67E7hjVdPlBXMh1FMzcWSgu3v5SfFM_HOO2JpbCeY0,11787
|
|
19
19
|
certora_cli/CertoraProver/certoraCompilerParameters.py,sha256=r35y03IRwWIoz1GCNC7PuW3n8JPz9J1NGwhwUYKdYtI,1452
|
|
20
|
-
certora_cli/CertoraProver/certoraConfigIO.py,sha256=
|
|
21
|
-
certora_cli/CertoraProver/certoraContext.py,sha256=
|
|
22
|
-
certora_cli/CertoraProver/certoraContextAttributes.py,sha256=
|
|
20
|
+
certora_cli/CertoraProver/certoraConfigIO.py,sha256=uq-uNnjVBzg9Kh41fDqn-lnwSJXe4k2_iy5GTnQIDa8,7560
|
|
21
|
+
certora_cli/CertoraProver/certoraContext.py,sha256=HyYQlzIEk3gzzEH2ilTC_Qxw1zXvsKU3IJuCLiV2Sro,26916
|
|
22
|
+
certora_cli/CertoraProver/certoraContextAttributes.py,sha256=d8ywqZrWfhzwS8w3VSduwIqwgSASML7k_guXzsoxIdU,69463
|
|
23
23
|
certora_cli/CertoraProver/certoraContextClass.py,sha256=d7HDqM72K7YnswR7kEcAHGwkFNrTqRz5-_0m7cl2Mso,900
|
|
24
|
-
certora_cli/CertoraProver/certoraContextValidator.py,sha256=
|
|
24
|
+
certora_cli/CertoraProver/certoraContextValidator.py,sha256=SgdtQJFimBi51c9SUnpgEYow9FBEYU_7LUdZhISBxpo,45064
|
|
25
25
|
certora_cli/CertoraProver/certoraContractFuncs.py,sha256=ipSwge5QQzp8qhUavY44bZ-eCR6szK_HWwSIWqQyuR0,6921
|
|
26
26
|
certora_cli/CertoraProver/certoraExtensionInfo.py,sha256=YlShzdoqJQgXXj3r0TJ3fir1KntIR99Rk8JN5qii2lk,2026
|
|
27
27
|
certora_cli/CertoraProver/certoraJobList.py,sha256=FBIYgJ60I0Ok7vchfTbcuJJbiXgnfAhrONoVeZoHti4,11464
|
|
28
28
|
certora_cli/CertoraProver/certoraMiniSpecParser.py,sha256=NjjMwf5Rav3YWpoOJh4PZ-QOS8exC2cg4yIBSbZA6l0,9660
|
|
29
29
|
certora_cli/CertoraProver/certoraNodeFilters.py,sha256=5Uk2mixZKeis_JVd3HkLgoEVklkAYBXAZiNHRlXOIfY,2830
|
|
30
|
-
certora_cli/CertoraProver/certoraParseBuildScript.py,sha256=
|
|
30
|
+
certora_cli/CertoraProver/certoraParseBuildScript.py,sha256=l7KQA1poEjmbmuYbMskz0jOQg6cW0lM3vk5ruAGPjPI,4863
|
|
31
31
|
certora_cli/CertoraProver/certoraProjectScanner.py,sha256=jT7FeWzcy8o83LrZRwsg_L4x6im6Fm_0LZFKVbKr3Jk,6862
|
|
32
32
|
certora_cli/CertoraProver/certoraSourceFinders.py,sha256=qwJtwrQq3NUNYmdmn1UmANN4lmJFIUh4M-St2x1FJ2Y,19038
|
|
33
33
|
certora_cli/CertoraProver/certoraType.py,sha256=wD-Sr3xk_dJGtbvw33oIGu_lf15NCZuKWjUb4HlVcUM,29318
|
|
@@ -36,7 +36,7 @@ certora_cli/CertoraProver/erc7201.py,sha256=BME5kBZsDx6lgqLn7EE91I1cEOZtsnZ8BlRV
|
|
|
36
36
|
certora_cli/CertoraProver/splitRules.py,sha256=HfSqsKeeLZDeOnv8TGgpPDHoaXgdVc0HOrLcGk-cU1Q,7681
|
|
37
37
|
certora_cli/CertoraProver/storageExtension.py,sha256=BZC9HJygeLxqS5TmhNxbIrVNfH3kLEPjN1VjsWQi8s8,15922
|
|
38
38
|
certora_cli/CertoraProver/Compiler/CompilerCollector.py,sha256=cr-PIl7LY9VfNs4s4H3-EnSnomPiCgXudfwP9-KenMk,6740
|
|
39
|
-
certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py,sha256=
|
|
39
|
+
certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py,sha256=TOpHMSYGhfSmVQwJYZMVOI_Ws03k6cTffzaQUmhnNUo,8761
|
|
40
40
|
certora_cli/CertoraProver/Compiler/CompilerCollectorSol.py,sha256=7nAY2FLMUlGJn4f_YoZMqpa3rf7THqhJVjLwTaChcBc,5027
|
|
41
41
|
certora_cli/CertoraProver/Compiler/CompilerCollectorSolBased.py,sha256=UasYWyu8Of6R84vXsqRNGpscYcFQghmSIY_dyaAWDYA,1350
|
|
42
42
|
certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py,sha256=e95xOHK5Bz8BbzjbCVLCrGSutVs8ejqOImh5wH9o3Jk,69918
|
|
@@ -60,16 +60,16 @@ certora_cli/Shared/ExpectedComparator.py,sha256=eyRR-jni4WJoa6j2TK2lnZ89Tyb8U99w
|
|
|
60
60
|
certora_cli/Shared/__init__.py,sha256=s0dhvolFtsS4sRNzPVhC_rlw8mm194rCZ0WhOxInY40,1025
|
|
61
61
|
certora_cli/Shared/certoraAttrUtil.py,sha256=ZsoS6xbSZnAjEoPEcfiJi6CvHU-1ySBKubvVKh78ohs,8373
|
|
62
62
|
certora_cli/Shared/certoraLogging.py,sha256=cV2UQMhQ5j8crGXgeq9CEamI-Lk4HgdiA3HCrP-kSR4,14013
|
|
63
|
-
certora_cli/Shared/certoraUtils.py,sha256=
|
|
64
|
-
certora_cli/Shared/certoraValidateFuncs.py,sha256=
|
|
65
|
-
certora_cli/Shared/proverCommon.py,sha256
|
|
63
|
+
certora_cli/Shared/certoraUtils.py,sha256=5uxgeGyfq8jw4w9l7fxiyMsgw74GpEtS8Wy8u5MNBHs,55178
|
|
64
|
+
certora_cli/Shared/certoraValidateFuncs.py,sha256=Fn6GN_LEwlMjBdTiVO6WzCg8P5F6DhwkvP9Xl-XiQ6o,41921
|
|
65
|
+
certora_cli/Shared/proverCommon.py,sha256=PqkjycZ3TdZr0RNWoPuA_VZ5b7EAAsu9ewymNH6kIm4,11291
|
|
66
66
|
certora_cli/Shared/rustProverCommon.py,sha256=NIZ5ECbhuiMegyRAl07CV3r68MFG2tBNKgUAQoV4uLI,2049
|
|
67
|
-
certora_jars/CERTORA-CLI-VERSION-METADATA.json,sha256=
|
|
68
|
-
certora_jars/Typechecker.jar,sha256=
|
|
67
|
+
certora_jars/CERTORA-CLI-VERSION-METADATA.json,sha256=YT2XfCbYZ3cwuV-9FyvRVu5GrruMtCHqT0n1kvOSlGY,145
|
|
68
|
+
certora_jars/Typechecker.jar,sha256=NmnUZaxhNvRthGr1tEh9FVlT0wEO8A-jj9J22gOtngY,17143207
|
|
69
69
|
certora_jars/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
70
|
-
certora_cli_beta_mirror-7.
|
|
71
|
-
certora_cli_beta_mirror-7.
|
|
72
|
-
certora_cli_beta_mirror-7.
|
|
73
|
-
certora_cli_beta_mirror-7.
|
|
74
|
-
certora_cli_beta_mirror-7.
|
|
75
|
-
certora_cli_beta_mirror-7.
|
|
70
|
+
certora_cli_beta_mirror-7.31.0.dist-info/LICENSE,sha256=UGKSKIJSetF8m906JLKqNLkUS2CL60XfQdNvxBvpQXo,620
|
|
71
|
+
certora_cli_beta_mirror-7.31.0.dist-info/METADATA,sha256=OGfFfEjLrMpnJSD69pQjP_yH9-2Jfvh1GviqnGpZTN0,1254
|
|
72
|
+
certora_cli_beta_mirror-7.31.0.dist-info/WHEEL,sha256=jB7zZ3N9hIM9adW7qlTAyycLYW9npaWKLRzaoVcLKcM,91
|
|
73
|
+
certora_cli_beta_mirror-7.31.0.dist-info/entry_points.txt,sha256=_SQ5_uYOAJXtqEW992nIvq7blW9cWFSUVEdbMGuy--4,443
|
|
74
|
+
certora_cli_beta_mirror-7.31.0.dist-info/top_level.txt,sha256=8C77w3JLanY0-NW45vpJsjRssyCqVP-qmPiN9FjWiX4,38
|
|
75
|
+
certora_cli_beta_mirror-7.31.0.dist-info/RECORD,,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name": "certora-cli-beta-mirror", "tag": "7.
|
|
1
|
+
{"name": "certora-cli-beta-mirror", "tag": "7.31.0", "branch": "", "commit": "89159ec", "timestamp": "20250624.9.18.557504", "version": "7.31.0"}
|
certora_jars/Typechecker.jar
CHANGED
|
Binary file
|
{certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/LICENSE
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{certora_cli_beta_mirror-7.30.1.dist-info → certora_cli_beta_mirror-7.31.0.dist-info}/top_level.txt
RENAMED
|
File without changes
|