certora-cli 7.29.3__tar.gz → 7.31.1__tar.gz
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-7.29.3/certora_cli.egg-info → certora_cli-7.31.1}/PKG-INFO +3 -2
- certora_cli-7.31.1/README.md +1 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +11 -2
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraBuild.py +224 -105
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraBuildCacheManager.py +15 -16
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraBuildRust.py +2 -1
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraCloudIO.py +7 -27
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +62 -51
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraConfigIO.py +2 -1
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraContext.py +29 -2
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraContextAttributes.py +53 -9
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraContextValidator.py +39 -61
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraParseBuildScript.py +4 -3
- certora_cli-7.31.1/certora_cli/CertoraProver/erc7201.py +45 -0
- certora_cli-7.31.1/certora_cli/CertoraProver/storageExtension.py +386 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -1
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -1
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/mutateApp.py +10 -3
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/certoraUtils.py +22 -19
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/certoraValidateFuncs.py +5 -3
- certora_cli-7.31.1/certora_cli/Shared/proverCommon.py +302 -0
- certora_cli-7.31.1/certora_cli/Shared/rustProverCommon.py +62 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/certoraEVMProver.py +2 -1
- certora_cli-7.31.1/certora_cli/certoraRanger.py +39 -0
- certora_cli-7.31.1/certora_cli/certoraRun.py +218 -0
- certora_cli-7.31.1/certora_cli/certoraSolanaProver.py +98 -0
- certora_cli-7.31.1/certora_cli/certoraSorobanProver.py +92 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1/certora_cli.egg-info}/PKG-INFO +3 -2
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli.egg-info/SOURCES.txt +4 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli.egg-info/requires.txt +1 -0
- certora_cli-7.31.1/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_jars/Typechecker.jar +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/setup.py +3 -3
- certora_cli-7.29.3/README.md +0 -1
- certora_cli-7.29.3/certora_cli/certoraRanger.py +0 -71
- certora_cli-7.29.3/certora_cli/certoraRun.py +0 -320
- certora_cli-7.29.3/certora_cli/certoraSolanaProver.py +0 -193
- certora_cli-7.29.3/certora_cli/certoraSorobanProver.py +0 -285
- certora_cli-7.29.3/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
- {certora_cli-7.29.3 → certora_cli-7.31.1}/LICENSE +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/MANIFEST.in +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_bins/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollector.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorSol.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorSolBased.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/Compiler/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraBuildDataClasses.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraCollectRunMetadata.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraCompilerParameters.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraContextClass.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraContractFuncs.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraExtensionInfo.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraJobList.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraMiniSpecParser.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraNodeFilters.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraProjectScanner.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraSourceFinders.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraType.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/certoraVerifyGenerator.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/CertoraProver/splitRules.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/equivCheck.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/mutateAttributes.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/mutateConstants.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/mutateUtil.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Mutate/mutateValidate.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/ExpectedComparator.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/certoraAttrUtil.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/Shared/certoraLogging.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/certoraEqCheck.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/certoraMutate.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli/rustMutator.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli.egg-info/dependency_links.txt +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli.egg-info/entry_points.txt +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_cli.egg-info/top_level.txt +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/certora_jars/__init__.py +0 -0
- {certora_cli-7.29.3 → certora_cli-7.31.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: certora-cli
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.31.1
|
|
4
4
|
Summary: Runner for the Certora Prover
|
|
5
5
|
Home-page: https://pypi.org/project/certora-cli
|
|
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 9a7c8df. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Commit 9a7c8df. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -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:
|
|
@@ -25,8 +25,11 @@ from collections import OrderedDict, defaultdict
|
|
|
25
25
|
from enum import Enum
|
|
26
26
|
from functools import lru_cache
|
|
27
27
|
from pathlib import Path
|
|
28
|
-
from typing import Any, Dict, List, Tuple, Optional, Set, Iterator, NoReturn
|
|
29
28
|
from Crypto.Hash import keccak
|
|
29
|
+
import tempfile
|
|
30
|
+
|
|
31
|
+
from typing import Any, Dict, List, Tuple, Optional, Set, Iterator, NoReturn
|
|
32
|
+
|
|
30
33
|
|
|
31
34
|
from CertoraProver.certoraBuildCacheManager import CertoraBuildCacheManager, CachedFiles
|
|
32
35
|
from CertoraProver.certoraBuildDataClasses import CONTRACTS, ImmutableReference, ContractExtension, ContractInSDC, SDC, \
|
|
@@ -35,6 +38,7 @@ from CertoraProver.certoraCompilerParameters import SolcParameters
|
|
|
35
38
|
from CertoraProver.certoraSourceFinders import add_source_finders
|
|
36
39
|
from CertoraProver.certoraVerifyGenerator import CertoraVerifyGenerator
|
|
37
40
|
from CertoraProver.certoraContractFuncs import Func, InternalFunc, STATEMUT, SourceBytes
|
|
41
|
+
|
|
38
42
|
from Shared.certoraUtils import is_relative_to
|
|
39
43
|
|
|
40
44
|
scripts_dir_path = Path(__file__).parent.parent.resolve() # containing directory
|
|
@@ -54,7 +58,11 @@ from Shared import certoraValidateFuncs as Vf
|
|
|
54
58
|
from CertoraProver import certoraContextValidator as Cv
|
|
55
59
|
from Shared import certoraUtils as Util
|
|
56
60
|
import CertoraProver.certoraContext as Ctx
|
|
57
|
-
|
|
61
|
+
from CertoraProver import storageExtension
|
|
62
|
+
from CertoraProver.storageExtension import (
|
|
63
|
+
NameSpacedStorage,
|
|
64
|
+
NewStorageInfo,
|
|
65
|
+
)
|
|
58
66
|
|
|
59
67
|
BUILD_IS_LIBRARY = False
|
|
60
68
|
AUTO_FINDER_PREFIX = "autoFinder_"
|
|
@@ -72,6 +80,7 @@ MUTANTS_LOCATION = "mutants_location"
|
|
|
72
80
|
|
|
73
81
|
FunctionSig = Tuple[str, List[str], List[str], str]
|
|
74
82
|
|
|
83
|
+
|
|
75
84
|
# logger for building the abstract syntax tree
|
|
76
85
|
ast_logger = logging.getLogger("ast")
|
|
77
86
|
# logger for issues calling/shelling out to external functions
|
|
@@ -84,12 +93,10 @@ build_logger = logging.getLogger("build_conf")
|
|
|
84
93
|
# logger of the build cache
|
|
85
94
|
build_cache_logger = logging.getLogger("build_cache")
|
|
86
95
|
|
|
87
|
-
|
|
88
96
|
def fatal_error(logger: logging.Logger, msg: str) -> NoReturn:
|
|
89
97
|
logger.fatal(msg)
|
|
90
98
|
raise Exception(msg)
|
|
91
99
|
|
|
92
|
-
|
|
93
100
|
class InputConfig:
|
|
94
101
|
def __init__(self, context: CertoraContext) -> None:
|
|
95
102
|
"""
|
|
@@ -443,8 +450,12 @@ def convert_pathname_to_posix(json_dict: Dict[str, Any], entry: str, smart_contr
|
|
|
443
450
|
if path_obj.is_file():
|
|
444
451
|
json_dict_posix_paths[path_obj.as_posix()] = json_dict[entry][file_path]
|
|
445
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] + '...'
|
|
446
457
|
fatal_error(compiler_logger, f"The path of the source file {file_path}"
|
|
447
|
-
f"in the standard json file {
|
|
458
|
+
f"in the standard json file {json_dict_str} does not exist")
|
|
448
459
|
json_dict[entry] = json_dict_posix_paths
|
|
449
460
|
|
|
450
461
|
|
|
@@ -1354,49 +1365,51 @@ class CertoraBuildGenerator:
|
|
|
1354
1365
|
|
|
1355
1366
|
return bytecode
|
|
1356
1367
|
|
|
1357
|
-
def
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
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):
|
|
1365
1385
|
settings_dict["viaIR"] = True
|
|
1366
1386
|
|
|
1367
|
-
def _handle_evm_version(self, contract_file_path:
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
settings_dict["evmVersion"] = match
|
|
1372
|
-
elif self.context.solc_evm_version:
|
|
1373
|
-
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
|
|
1374
1391
|
|
|
1375
|
-
def _handle_optimize(self, contract_file_path:
|
|
1392
|
+
def _handle_optimize(self, contract_file_path: Path, settings_dict: Dict[str, Any],
|
|
1376
1393
|
compiler_collector: CompilerCollector) -> None:
|
|
1377
1394
|
"""
|
|
1378
1395
|
@param contract_file_path: the contract that we are working on
|
|
1379
1396
|
@param settings_dict: data structure for sending to the solc compiler
|
|
1380
1397
|
"""
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
if match and int(match) > 0:
|
|
1384
|
-
settings_dict["optimizer"] = {"enabled": True}
|
|
1385
|
-
settings_dict["optimizer"]['runs'] = int(match)
|
|
1386
|
-
elif self.context.solc_optimize:
|
|
1398
|
+
match = self.get_solc_optimize_value(contract_file_path)
|
|
1399
|
+
if match:
|
|
1387
1400
|
settings_dict["optimizer"] = {"enabled": True}
|
|
1388
|
-
if int(
|
|
1389
|
-
settings_dict["optimizer"]['runs'] = int(
|
|
1401
|
+
if int(match) > 0:
|
|
1402
|
+
settings_dict["optimizer"]['runs'] = int(match)
|
|
1390
1403
|
|
|
1391
1404
|
# if optimizer is true, we should also define settings_dict["optimizer"]["details"]
|
|
1392
1405
|
# for both optimize map and optimize
|
|
1393
1406
|
optimizer = settings_dict.get("optimizer")
|
|
1394
1407
|
if optimizer and isinstance(optimizer, dict) and optimizer.get('enabled'):
|
|
1395
1408
|
# if we are not disabling finder friendly optimizer specifically, enable it whenever viaIR is also enabled
|
|
1396
|
-
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):
|
|
1397
1410
|
# The default optimizer steps (taken from libsolidity/interface/OptimiserSettings.h) but with the
|
|
1398
1411
|
# full inliner step removed
|
|
1399
|
-
|
|
1412
|
+
solc0_8_26_to_0_8_30 = ("dhfoDgvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLCTUca[r]LSsTFOtfDnca[r]" +
|
|
1400
1413
|
"IulcscCTUtx[scCTUt]TOntnfDIuljmul[jul]VcTOculjmul")
|
|
1401
1414
|
solc0_8_13_to_0_8_25 = "dhfoDgvulfnTUtnIf[xa[r]EscLMcCTUtTOntnfDIulLculVcul[j]T" + \
|
|
1402
1415
|
"peulxa[rul]xa[r]cLgvifCTUca[r]LSsTFOtfDnca[r]Iulc]jmul[jul]VcTOculjmul"
|
|
@@ -1426,6 +1439,8 @@ class CertoraBuildGenerator:
|
|
|
1426
1439
|
raise Util.CertoraUserInputError(err_msg)
|
|
1427
1440
|
elif minor < 6 or (minor == 6 and patch < 7):
|
|
1428
1441
|
raise Util.CertoraUserInputError(err_msg)
|
|
1442
|
+
elif self.context.yul_optimizer_steps:
|
|
1443
|
+
yul_optimizer_steps = self.context.yul_optimizer_steps
|
|
1429
1444
|
elif (minor == 6 and patch >= 7) or (minor == 7 and 0 <= patch <= 1):
|
|
1430
1445
|
yul_optimizer_steps = solc0_6_7_to_0_7_1
|
|
1431
1446
|
elif minor == 7 and 2 <= patch <= 5:
|
|
@@ -1440,8 +1455,8 @@ class CertoraBuildGenerator:
|
|
|
1440
1455
|
yul_optimizer_steps = solc0_8_12
|
|
1441
1456
|
elif minor == 8 and 13 <= patch <= 25:
|
|
1442
1457
|
yul_optimizer_steps = solc0_8_13_to_0_8_25
|
|
1443
|
-
elif minor == 8 and 26 <= patch <=
|
|
1444
|
-
yul_optimizer_steps =
|
|
1458
|
+
elif minor == 8 and 26 <= patch <= 30:
|
|
1459
|
+
yul_optimizer_steps = solc0_8_26_to_0_8_30
|
|
1445
1460
|
assert yul_optimizer_steps is not None, \
|
|
1446
1461
|
'Yul Optimizer steps missing for requested Solidity version. Please contact Certora team.'
|
|
1447
1462
|
|
|
@@ -1463,7 +1478,7 @@ class CertoraBuildGenerator:
|
|
|
1463
1478
|
for opt_pass in self.context.disable_solc_optimizers:
|
|
1464
1479
|
settings_dict["optimizer"]["details"][opt_pass] = False
|
|
1465
1480
|
|
|
1466
|
-
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],
|
|
1467
1482
|
compiler_collector: CompilerCollector) -> None:
|
|
1468
1483
|
"""
|
|
1469
1484
|
Fills options that control how we call solc and affect the bytecode in some way
|
|
@@ -1544,7 +1559,7 @@ class CertoraBuildGenerator:
|
|
|
1544
1559
|
}
|
|
1545
1560
|
}
|
|
1546
1561
|
|
|
1547
|
-
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)
|
|
1548
1563
|
|
|
1549
1564
|
result_dict = {"language": compiler_collector_lang.name, "sources": sources_dict, "settings": settings_dict}
|
|
1550
1565
|
# debug_print("Standard json input")
|
|
@@ -2279,7 +2294,7 @@ class CertoraBuildGenerator:
|
|
|
2279
2294
|
|
|
2280
2295
|
if compiler_lang == CompilerLangSol():
|
|
2281
2296
|
settings_dict: Dict[str, Any] = {}
|
|
2282
|
-
self._fill_codegen_related_options(build_arg_contract_file, settings_dict,
|
|
2297
|
+
self._fill_codegen_related_options(Path(build_arg_contract_file), settings_dict,
|
|
2283
2298
|
compiler_collector_for_contract_file)
|
|
2284
2299
|
solc_optimizer_on, solc_optimizer_runs = self.solc_setting_optimizer_runs(settings_dict)
|
|
2285
2300
|
solc_via_ir = self.solc_setting_via_ir(settings_dict)
|
|
@@ -2409,7 +2424,7 @@ class CertoraBuildGenerator:
|
|
|
2409
2424
|
# if no function finder mode set, determine based on viaIR enabled or not:
|
|
2410
2425
|
if self.context.function_finder_mode is None:
|
|
2411
2426
|
# in via-ir, should not compress
|
|
2412
|
-
if self.
|
|
2427
|
+
if self.get_solc_via_ir_value(Path(contract_file)):
|
|
2413
2428
|
should_compress = False
|
|
2414
2429
|
else:
|
|
2415
2430
|
should_compress = True
|
|
@@ -2539,7 +2554,6 @@ class CertoraBuildGenerator:
|
|
|
2539
2554
|
Util.print_progress_message(f"Compiling {orig_file_name}...")
|
|
2540
2555
|
sdc_pre_finders = self.collect_for_file(build_arg_contract_file, i, compiler_lang, Path(os.getcwd()),
|
|
2541
2556
|
path_for_compiler_collector_file, original_sdc=None)
|
|
2542
|
-
|
|
2543
2557
|
# Build sources tree
|
|
2544
2558
|
build_logger.debug("Building source tree")
|
|
2545
2559
|
sources_from_pre_finder_SDCs = set()
|
|
@@ -2672,8 +2686,154 @@ class CertoraBuildGenerator:
|
|
|
2672
2686
|
self.handle_links()
|
|
2673
2687
|
self.handle_struct_links()
|
|
2674
2688
|
self.handle_contract_extensions()
|
|
2689
|
+
if self.context.storage_extension_annotation:
|
|
2690
|
+
self.handle_erc7201_annotations()
|
|
2675
2691
|
self.handle_storage_extension_harnesses()
|
|
2676
2692
|
|
|
2693
|
+
def extract_slayout(self, original_file: str, ns_storage: Set[NameSpacedStorage]) -> NewStorageInfo:
|
|
2694
|
+
"""
|
|
2695
|
+
Given a file containing a contract with namespaced storage, extract the storage information
|
|
2696
|
+
corresponding to the namespaced types.
|
|
2697
|
+
|
|
2698
|
+
Args:
|
|
2699
|
+
original_file: Path to the Solidity file containing namespaced storage declarations
|
|
2700
|
+
ns_storage: Set of tuples (type_name, namespace) for each namespaced storage
|
|
2701
|
+
|
|
2702
|
+
Returns:
|
|
2703
|
+
NewStorageInfo: A tuple (fields, types) where:
|
|
2704
|
+
- fields: List of new fields added by the namespaced storage
|
|
2705
|
+
- types: Dictionary of types referenced by the fields
|
|
2706
|
+
"""
|
|
2707
|
+
file_dir = Path(original_file).parent
|
|
2708
|
+
|
|
2709
|
+
# Generate a unique name for the harness contract based on the contract names in the file
|
|
2710
|
+
harness_name = storageExtension.generate_harness_name(original_file)
|
|
2711
|
+
|
|
2712
|
+
with tempfile.NamedTemporaryFile(mode="w+t", suffix=".sol", dir=file_dir, delete=True) as tmp_file:
|
|
2713
|
+
# Import the original file.
|
|
2714
|
+
# Note we import and don't inline the file's contents since that's how the
|
|
2715
|
+
# original file is accessed also in the actual code, and compiling it
|
|
2716
|
+
# directly can cause issues.
|
|
2717
|
+
tmp_file.write(f"import \"{original_file}\";\n\n")
|
|
2718
|
+
|
|
2719
|
+
# Write the harness contract with dummy fields for each namespaced storage
|
|
2720
|
+
var_to_slot = storageExtension.write_harness_contract(tmp_file, harness_name, ns_storage)
|
|
2721
|
+
tmp_file.flush()
|
|
2722
|
+
|
|
2723
|
+
if self.context.extract_storage_extension_annotation:
|
|
2724
|
+
# If the flag is set, save the storage extension contract
|
|
2725
|
+
build_dir = Util.get_build_dir()
|
|
2726
|
+
shutil.copyfile(
|
|
2727
|
+
Path(tmp_file.name),
|
|
2728
|
+
build_dir / f"{Path(original_file).stem}_storage_extension.sol"
|
|
2729
|
+
)
|
|
2730
|
+
|
|
2731
|
+
# Add harness to compiler map
|
|
2732
|
+
storageExtension.add_harness_to_compiler_map(
|
|
2733
|
+
original_file,
|
|
2734
|
+
tmp_file,
|
|
2735
|
+
self.context
|
|
2736
|
+
)
|
|
2737
|
+
|
|
2738
|
+
# normalize the path exactly the way collect_for_file expects it:
|
|
2739
|
+
abs_path = Util.abs_posix_path(tmp_file.name)
|
|
2740
|
+
self.context.file_to_contract[abs_path] = {harness_name}
|
|
2741
|
+
|
|
2742
|
+
try:
|
|
2743
|
+
# Compile & fetch the raw storage_layout
|
|
2744
|
+
compile_idx = storageExtension.get_next_file_index(self.file_to_sdc_name)
|
|
2745
|
+
sdcs = self.collect_for_file(tmp_file.name, compile_idx, CompilerLangSol(), Path.cwd(), Util.abs_posix_path(tmp_file.name), None)
|
|
2746
|
+
if not sdcs:
|
|
2747
|
+
raise RuntimeError(f"Failed to compile harness contract for {tmp_file}")
|
|
2748
|
+
layout = storageExtension.extract_harness_contract_layout(sdcs, harness_name)
|
|
2749
|
+
|
|
2750
|
+
# Remap each slot according to the ERC-7201 namespace
|
|
2751
|
+
remapped_fields = storageExtension.remapped_fields_from_layout(layout, var_to_slot)
|
|
2752
|
+
|
|
2753
|
+
return (remapped_fields, layout.get('types', {}))
|
|
2754
|
+
|
|
2755
|
+
except Exception as e:
|
|
2756
|
+
build_logger.error(f"Error extracting storage layout for {original_file}: {str(e)}")
|
|
2757
|
+
raise
|
|
2758
|
+
finally:
|
|
2759
|
+
# Delete the key from the context
|
|
2760
|
+
self.context.file_to_contract.pop(abs_path, None)
|
|
2761
|
+
|
|
2762
|
+
def handle_erc7201_annotations(self) -> None:
|
|
2763
|
+
"""
|
|
2764
|
+
Look for contracts that use erc-7201 namespaced storage layout
|
|
2765
|
+
(see https://eips.ethereum.org/EIPS/eip-7201).
|
|
2766
|
+
|
|
2767
|
+
Find contracts A s.t. A contain a type declaration with such an annotation, e.g.
|
|
2768
|
+
/** @custom:storage-location erc-7201:some.name.space */
|
|
2769
|
+
struct T { ... }
|
|
2770
|
+
|
|
2771
|
+
Then, for any contract C that has A as a base contract, _extend_ C's storage layout
|
|
2772
|
+
information such that it contains the information for a `T` at the slot
|
|
2773
|
+
erc-7201(some.name.space) as defined in the EIP.
|
|
2774
|
+
"""
|
|
2775
|
+
# Find all erc7201-like contracts, generate+compile a harness & extract layout information
|
|
2776
|
+
# maps (path,contract) -> new storage info added by (path,contract)
|
|
2777
|
+
slayouts: Dict[Tuple[str, str], NewStorageInfo] = {}
|
|
2778
|
+
|
|
2779
|
+
# Scan all of the contracts (including dependencies of targets) for namespaced storage
|
|
2780
|
+
# layout information
|
|
2781
|
+
for target_file in self.context.file_paths:
|
|
2782
|
+
if target_file not in self.asts:
|
|
2783
|
+
# No AST for this file, so we can't do anything
|
|
2784
|
+
continue
|
|
2785
|
+
for (imported_file, imported_file_ast) in self.asts[target_file].items():
|
|
2786
|
+
for def_node in imported_file_ast.values():
|
|
2787
|
+
if def_node.get("nodeType") != "ContractDefinition":
|
|
2788
|
+
continue
|
|
2789
|
+
|
|
2790
|
+
# Construct a key for the contract definition node
|
|
2791
|
+
contract_name = def_node.get("name")
|
|
2792
|
+
key = (imported_file, contract_name)
|
|
2793
|
+
if key in slayouts:
|
|
2794
|
+
# We already have this contract's storage layout information
|
|
2795
|
+
continue
|
|
2796
|
+
|
|
2797
|
+
# Collect any @custom:storage-location annotations
|
|
2798
|
+
ns_storage = storageExtension.get_namespace_storage_from_ast(def_node)
|
|
2799
|
+
|
|
2800
|
+
if not ns_storage:
|
|
2801
|
+
# No namespaced storage found in this contract
|
|
2802
|
+
continue
|
|
2803
|
+
|
|
2804
|
+
# Now that we have all the storage layout information, extract it once
|
|
2805
|
+
slayouts[key] = self.extract_slayout(imported_file, ns_storage)
|
|
2806
|
+
|
|
2807
|
+
if self.context.test == str(Util.TestValue.STORAGE_EXTENSION_LAYOUT):
|
|
2808
|
+
raise Util.TestResultsReady(slayouts)
|
|
2809
|
+
|
|
2810
|
+
if not slayouts:
|
|
2811
|
+
# No contracts with namespaced storage found
|
|
2812
|
+
return
|
|
2813
|
+
|
|
2814
|
+
# Finally, extend each target contract with the storage layout info from
|
|
2815
|
+
# all of its base contracts
|
|
2816
|
+
for target in self.get_primary_contracts_from_sdcs():
|
|
2817
|
+
if target.name not in self.context.contract_to_file:
|
|
2818
|
+
# This is a contract that was not compiled, so we don't have a file for it
|
|
2819
|
+
continue
|
|
2820
|
+
target_file = self.context.contract_to_file[target.name]
|
|
2821
|
+
base_contracts = self.retrieve_base_contracts_list(
|
|
2822
|
+
target_file,
|
|
2823
|
+
Util.abs_posix_path(target_file),
|
|
2824
|
+
target.name
|
|
2825
|
+
)
|
|
2826
|
+
extensions: Set[str] = set()
|
|
2827
|
+
harnesses: Dict[str, NewStorageInfo] = {}
|
|
2828
|
+
for base in base_contracts:
|
|
2829
|
+
layout = slayouts.get((base[0], base[1]))
|
|
2830
|
+
if layout is not None:
|
|
2831
|
+
extensions.add(base[1])
|
|
2832
|
+
harnesses[base[1]] = layout
|
|
2833
|
+
else:
|
|
2834
|
+
build_logger.warning(f"Could not find storage layout for {base[1]} in {base[0]}")
|
|
2835
|
+
storageExtension.apply_extensions(target, extensions, harnesses)
|
|
2836
|
+
|
|
2677
2837
|
def handle_storage_extension_harnesses(self) -> None:
|
|
2678
2838
|
def new_field_of_node(ext_instance: Any, node: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
2679
2839
|
"""
|
|
@@ -2760,52 +2920,6 @@ class CertoraBuildGenerator:
|
|
|
2760
2920
|
new_fields.append(new_field)
|
|
2761
2921
|
|
|
2762
2922
|
return (ext_instance, extension_sdc_name, new_fields)
|
|
2763
|
-
|
|
2764
|
-
def apply_extensions(target_contract: Any, extensions: Set[str], to_add: Dict[str, Tuple[List[Dict[str, Any]], Dict[str, Any]]]) -> None:
|
|
2765
|
-
"""
|
|
2766
|
-
Apply the fields from each extension to the target contract,
|
|
2767
|
-
"""
|
|
2768
|
-
if target_contract.storage_layout.get("storage") is None:
|
|
2769
|
-
target_contract.storage_layout["storage"] = []
|
|
2770
|
-
if target_contract.storage_layout.get("types") is None:
|
|
2771
|
-
target_contract.storage_layout["types"] = {}
|
|
2772
|
-
target_slots = {storage["slot"] for storage in target_contract.storage_layout["storage"]}
|
|
2773
|
-
target_vars = {storage["label"] for storage in target_contract.storage_layout["storage"]}
|
|
2774
|
-
# Keep track of slots we've added, and error if we
|
|
2775
|
-
# find two extensions extending the same slot
|
|
2776
|
-
added_slots: Dict[str, str] = {}
|
|
2777
|
-
added_vars: Dict[str, str] = {}
|
|
2778
|
-
for ext in extensions:
|
|
2779
|
-
(new_fields, new_types) = to_add[ext]
|
|
2780
|
-
|
|
2781
|
-
for f in new_fields:
|
|
2782
|
-
# See if any of the new fields is a slot or variable name we've already added
|
|
2783
|
-
slot = f["slot"]
|
|
2784
|
-
var = f["label"]
|
|
2785
|
-
if slot in added_slots:
|
|
2786
|
-
seen = added_slots[slot]
|
|
2787
|
-
raise Util.CertoraUserInputError(f"Slot {slot} added to {target_contract.name} by {ext} was already added by {seen}")
|
|
2788
|
-
|
|
2789
|
-
if var in added_vars:
|
|
2790
|
-
seen = added_vars[var]
|
|
2791
|
-
raise Util.CertoraUserInputError(f"Var '{var}' added to {target_contract.name} by {ext} was already added by {seen}")
|
|
2792
|
-
|
|
2793
|
-
if slot in target_slots:
|
|
2794
|
-
raise Util.CertoraUserInputError(f"Slot {slot} added to {target_contract.name} by {ext} is already mapped by {target_contract.name}")
|
|
2795
|
-
|
|
2796
|
-
if var in target_vars:
|
|
2797
|
-
raise Util.CertoraUserInputError(f"Var '{var}' added to {target_contract.name} by {ext} is already declared by {target_contract.name}")
|
|
2798
|
-
|
|
2799
|
-
added_slots[slot] = ext
|
|
2800
|
-
added_vars[var] = ext
|
|
2801
|
-
|
|
2802
|
-
target_contract.storage_layout["storage"].extend(new_fields)
|
|
2803
|
-
|
|
2804
|
-
for (new_id, new_ty) in new_types.items():
|
|
2805
|
-
if new_id in target_contract.storage_layout["types"]:
|
|
2806
|
-
continue
|
|
2807
|
-
target_contract.storage_layout["types"][new_id] = new_ty
|
|
2808
|
-
|
|
2809
2923
|
extension_contracts: Set[str] = set()
|
|
2810
2924
|
storage_extensions: Dict[str, Set[str]] = defaultdict(set)
|
|
2811
2925
|
storage_ext = self.context.storage_extension_harnesses
|
|
@@ -2834,7 +2948,7 @@ class CertoraBuildGenerator:
|
|
|
2834
2948
|
sdc = self.SDCs[target_sdc]
|
|
2835
2949
|
target_contract = sdc.find_contract(target)
|
|
2836
2950
|
assert target_contract is not None, f"could not find contract for {target}"
|
|
2837
|
-
apply_extensions(target_contract, extensions, extension_to_fields_and_types)
|
|
2951
|
+
storageExtension.apply_extensions(target_contract, extensions, extension_to_fields_and_types)
|
|
2838
2952
|
|
|
2839
2953
|
def finders_compilation_round(self,
|
|
2840
2954
|
build_arg_contract_file: str,
|
|
@@ -3436,8 +3550,9 @@ class CertoraBuildGenerator:
|
|
|
3436
3550
|
raise Util.CertoraUserInputError(f"collect_sources: {path_to_file} does not exist cwd - {Path.cwd()}."
|
|
3437
3551
|
f"abs - {os.path.normpath(Path.cwd() / path_to_file)}")
|
|
3438
3552
|
|
|
3439
|
-
sources = set()
|
|
3440
|
-
|
|
3553
|
+
sources = set(sources_from_SDCs)
|
|
3554
|
+
if context.files:
|
|
3555
|
+
sources.update(Path(p) for p in context.files) # all files in "files" attribute are uploaded
|
|
3441
3556
|
sources |= certora_verify_generator.get_spec_files()
|
|
3442
3557
|
if Util.PACKAGE_FILE.exists():
|
|
3443
3558
|
add_to_sources(Util.PACKAGE_FILE)
|
|
@@ -3507,7 +3622,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3507
3622
|
|
|
3508
3623
|
try:
|
|
3509
3624
|
if overwrite:
|
|
3510
|
-
# expecting target path to exist.
|
|
3625
|
+
# expecting the target path to exist.
|
|
3511
3626
|
if target_path.exists():
|
|
3512
3627
|
build_logger.debug(f"Overwriting {target_path} by copying from {source_path}")
|
|
3513
3628
|
else:
|
|
@@ -3525,7 +3640,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3525
3640
|
cwd_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
3526
3641
|
cwd_file_path.touch()
|
|
3527
3642
|
|
|
3528
|
-
# 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
|
|
3529
3644
|
rust_proj_dir = getattr(context, 'rust_project_directory', None)
|
|
3530
3645
|
if rust_proj_dir:
|
|
3531
3646
|
proj_dir_parent_relative = os.path.relpath(rust_proj_dir, os.getcwd())
|
|
@@ -3546,7 +3661,8 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3546
3661
|
build_logger.debug("Couldn't copy repro conf to certora sources.", exc_info=e)
|
|
3547
3662
|
raise
|
|
3548
3663
|
|
|
3549
|
-
def build_from_scratch(
|
|
3664
|
+
def build_from_scratch(context: CertoraContext,
|
|
3665
|
+
certora_build_generator: CertoraBuildGenerator,
|
|
3550
3666
|
certora_verify_generator: CertoraVerifyGenerator,
|
|
3551
3667
|
build_cache_enabled: bool) -> CachedFiles:
|
|
3552
3668
|
"""
|
|
@@ -3572,9 +3688,16 @@ def build_from_scratch(certora_build_generator: CertoraBuildGenerator,
|
|
|
3572
3688
|
may_store_in_build_cache = True
|
|
3573
3689
|
absolute_sources_dir = Util.get_certora_sources_dir().absolute()
|
|
3574
3690
|
for sdc in certora_build_generator.SDCs.values():
|
|
3691
|
+
|
|
3692
|
+
# add to cache also source files that were found in the SDCs (e.g., storage extensions)
|
|
3693
|
+
paths_set = sdc.all_contract_files
|
|
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())
|
|
3697
|
+
|
|
3575
3698
|
# the contract files in SDCs are relative to .certora_sources. Which isn't good for us here.
|
|
3576
3699
|
# Need to be relative to original paths
|
|
3577
|
-
for f in
|
|
3700
|
+
for f in paths_set:
|
|
3578
3701
|
if is_relative_to(f, absolute_sources_dir):
|
|
3579
3702
|
rel_f = f.relative_to(absolute_sources_dir)
|
|
3580
3703
|
else:
|
|
@@ -3610,8 +3733,7 @@ def build_from_scratch(certora_build_generator: CertoraBuildGenerator,
|
|
|
3610
3733
|
|
|
3611
3734
|
def build_from_cache_or_scratch(context: CertoraContext,
|
|
3612
3735
|
certora_build_generator: CertoraBuildGenerator,
|
|
3613
|
-
certora_verify_generator: CertoraVerifyGenerator
|
|
3614
|
-
certora_build_cache_manager: CertoraBuildCacheManager) \
|
|
3736
|
+
certora_verify_generator: CertoraVerifyGenerator) \
|
|
3615
3737
|
-> Tuple[bool, bool, CachedFiles]:
|
|
3616
3738
|
"""
|
|
3617
3739
|
Builds either from cache (fast path) or from scratch (slow path)
|
|
@@ -3623,23 +3745,23 @@ def build_from_cache_or_scratch(context: CertoraContext,
|
|
|
3623
3745
|
cached_files: Optional[CachedFiles] = None
|
|
3624
3746
|
|
|
3625
3747
|
if not context.build_cache:
|
|
3626
|
-
cached_files = build_from_scratch(certora_build_generator,
|
|
3748
|
+
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3627
3749
|
certora_verify_generator,
|
|
3628
3750
|
False)
|
|
3629
3751
|
return cache_hit, False, cached_files
|
|
3630
3752
|
|
|
3631
|
-
build_cache_applicable =
|
|
3753
|
+
build_cache_applicable = CertoraBuildCacheManager.cache_is_applicable(context)
|
|
3632
3754
|
|
|
3633
3755
|
if not build_cache_applicable:
|
|
3634
|
-
build_cache_disabling_options =
|
|
3756
|
+
build_cache_disabling_options = CertoraBuildCacheManager.cache_disabling_options(context)
|
|
3635
3757
|
build_logger.warning("Requested to enable the build cache, but the build cache is not applicable "
|
|
3636
3758
|
f"to this run because of the given options: {build_cache_disabling_options}")
|
|
3637
|
-
cached_files = build_from_scratch(certora_build_generator,
|
|
3759
|
+
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3638
3760
|
certora_verify_generator,
|
|
3639
3761
|
False)
|
|
3640
3762
|
return cache_hit, False, cached_files
|
|
3641
3763
|
|
|
3642
|
-
cached_files =
|
|
3764
|
+
cached_files = CertoraBuildCacheManager.build_from_cache(context)
|
|
3643
3765
|
# if no match, will rebuild from scratch
|
|
3644
3766
|
if cached_files is not None:
|
|
3645
3767
|
# write to .certora_build.json
|
|
@@ -3660,7 +3782,7 @@ def build_from_cache_or_scratch(context: CertoraContext,
|
|
|
3660
3782
|
cache_hit = True
|
|
3661
3783
|
else:
|
|
3662
3784
|
# rebuild
|
|
3663
|
-
cached_files = build_from_scratch(certora_build_generator,
|
|
3785
|
+
cached_files = build_from_scratch(context, certora_build_generator,
|
|
3664
3786
|
certora_verify_generator,
|
|
3665
3787
|
True)
|
|
3666
3788
|
|
|
@@ -3678,7 +3800,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3678
3800
|
|
|
3679
3801
|
try:
|
|
3680
3802
|
input_config = InputConfig(context)
|
|
3681
|
-
|
|
3803
|
+
context.main_cache_key = CertoraBuildCacheManager.get_main_cache_key(context)
|
|
3682
3804
|
# Create generators
|
|
3683
3805
|
certora_build_generator = CertoraBuildGenerator(input_config, context)
|
|
3684
3806
|
|
|
@@ -3694,12 +3816,9 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3694
3816
|
else:
|
|
3695
3817
|
Ctx.run_local_spec_check(False, context)
|
|
3696
3818
|
|
|
3697
|
-
certora_build_cache_manager = CertoraBuildCacheManager()
|
|
3698
|
-
|
|
3699
3819
|
cache_hit, build_cache_enabled, cached_files = build_from_cache_or_scratch(context,
|
|
3700
3820
|
certora_build_generator,
|
|
3701
|
-
certora_verify_generator
|
|
3702
|
-
certora_build_cache_manager)
|
|
3821
|
+
certora_verify_generator)
|
|
3703
3822
|
|
|
3704
3823
|
# avoid running the same test over and over again for each split run, context.split_rules is true only for
|
|
3705
3824
|
# the first run and is set to [] for split runs
|
|
@@ -3719,7 +3838,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3719
3838
|
|
|
3720
3839
|
# save in build cache
|
|
3721
3840
|
if not cache_hit and build_cache_enabled and cached_files.may_store_in_build_cache:
|
|
3722
|
-
|
|
3841
|
+
CertoraBuildCacheManager.save_build_cache(context, cached_files)
|
|
3723
3842
|
|
|
3724
3843
|
certora_verify_generator.update_certora_verify_struct(True)
|
|
3725
3844
|
certora_verify_generator.dump() # second dump with properly rooted specs
|