certora-cli 7.26.0__tar.gz → 7.29.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.1/LICENSE +15 -0
- {certora_cli-7.26.0/certora_cli.egg-info → certora_cli-7.29.1}/PKG-INFO +8 -5
- certora_cli-7.29.1/README.md +1 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +6 -3
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +48 -13
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraBuild.py +227 -51
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraBuildDataClasses.py +19 -4
- certora_cli-7.29.1/certora_cli/CertoraProver/certoraBuildRust.py +139 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraCloudIO.py +57 -67
- certora_cli-7.29.1/certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +377 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraCollectRunMetadata.py +13 -1
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraConfigIO.py +55 -20
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraContext.py +18 -6
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraContextAttributes.py +235 -67
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraContextValidator.py +114 -50
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraParseBuildScript.py +15 -12
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraVerifyGenerator.py +12 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/splitRules.py +3 -1
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/equivCheck.py +5 -4
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/mutateApp.py +10 -10
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/mutateConstants.py +0 -1
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/certoraAttrUtil.py +14 -2
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/certoraUtils.py +32 -8
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/certoraValidateFuncs.py +38 -14
- certora_cli-7.29.1/certora_cli/certoraRanger.py +71 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/certoraRun.py +21 -16
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/certoraSolanaProver.py +17 -3
- certora_cli-7.29.1/certora_cli/certoraSorobanProver.py +285 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1/certora_cli.egg-info}/PKG-INFO +8 -5
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli.egg-info/SOURCES.txt +2 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli.egg-info/entry_points.txt +1 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli.egg-info/requires.txt +0 -2
- certora_cli-7.29.1/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_jars/Typechecker.jar +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/setup.py +11 -5
- certora_cli-7.26.0/LICENSE +0 -22
- certora_cli-7.26.0/README.md +0 -1
- certora_cli-7.26.0/certora_cli/CertoraProver/certoraBuildRust.py +0 -99
- certora_cli-7.26.0/certora_cli/certoraSorobanProver.py +0 -36
- certora_cli-7.26.0/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
- {certora_cli-7.26.0 → certora_cli-7.29.1}/MANIFEST.in +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_bins/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollector.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorSol.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorSolBased.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraBuildCacheManager.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraCompilerParameters.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraContextClass.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraContractFuncs.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraExtensionInfo.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraJobList.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraMiniSpecParser.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraNodeFilters.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraProjectScanner.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraSourceFinders.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/certoraType.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/mutateAttributes.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/mutateUtil.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Mutate/mutateValidate.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/ExpectedComparator.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/Shared/certoraLogging.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/certoraEVMProver.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/certoraEqCheck.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/certoraMutate.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/rustMutator.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli.egg-info/dependency_links.txt +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli.egg-info/top_level.txt +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/certora_jars/__init__.py +0 -0
- {certora_cli-7.26.0 → certora_cli-7.29.1}/setup.cfg +0 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
The Certora Prover
|
|
3
|
+
Copyright (C) 2025 Certora Ltd.
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU General Public License as published by
|
|
7
|
+
the Free Software Foundation, version 3 of the License.
|
|
8
|
+
|
|
9
|
+
This program is distributed in the hope that it will be useful,
|
|
10
|
+
but WITHOUT ANY WARRANTY, without even the implied warranty of
|
|
11
|
+
MERCHANTABILITY or FITNESS FOR a PARTICULAR PURPOSE. See the
|
|
12
|
+
GNU General Public License for more details.
|
|
13
|
+
|
|
14
|
+
You should have received a copy of the GNU General Public License
|
|
15
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: certora-cli
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.29.1
|
|
4
4
|
Summary: Runner for the Certora Prover
|
|
5
5
|
Home-page: https://pypi.org/project/certora-cli
|
|
6
6
|
Author: Certora
|
|
7
7
|
Author-email: support@certora.com
|
|
8
|
+
License: GPL-3.0-only
|
|
9
|
+
Project-URL: Documentation, https://docs.certora.com/en/latest/
|
|
10
|
+
Project-URL: Source, https://github.com/Certora/CertoraProver
|
|
8
11
|
Classifier: Programming Language :: Python :: 3
|
|
9
|
-
Classifier: License :: OSI Approved ::
|
|
12
|
+
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
|
|
10
13
|
Classifier: Operating System :: OS Independent
|
|
11
14
|
Requires-Python: >=3.8
|
|
12
15
|
Description-Content-Type: text/markdown
|
|
@@ -20,18 +23,18 @@ Requires-Dist: sly
|
|
|
20
23
|
Requires-Dist: tabulate
|
|
21
24
|
Requires-Dist: tqdm
|
|
22
25
|
Requires-Dist: StrEnum
|
|
23
|
-
Requires-Dist: tomli
|
|
24
26
|
Requires-Dist: universalmutator
|
|
25
27
|
Requires-Dist: jinja2
|
|
26
|
-
Requires-Dist: setuptools==75.8.2
|
|
27
28
|
Dynamic: author
|
|
28
29
|
Dynamic: author-email
|
|
29
30
|
Dynamic: classifier
|
|
30
31
|
Dynamic: description
|
|
31
32
|
Dynamic: description-content-type
|
|
32
33
|
Dynamic: home-page
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: project-url
|
|
33
36
|
Dynamic: requires-dist
|
|
34
37
|
Dynamic: requires-python
|
|
35
38
|
Dynamic: summary
|
|
36
39
|
|
|
37
|
-
Commit
|
|
40
|
+
Commit b8a319d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Commit b8a319d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -39,12 +39,15 @@ def get_relevant_compiler(contract_file_path: Path, context: CertoraContext) ->
|
|
|
39
39
|
@return: the name of the compiler executable we want to run on this file (as a string, could be a path
|
|
40
40
|
or a resolvable executable name)
|
|
41
41
|
"""
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
|
|
43
|
+
if contract_file_path.is_absolute():
|
|
44
|
+
contract_file_path = Path(os.path.relpath(contract_file_path, Path.cwd()))
|
|
45
|
+
if context.compiler_map:
|
|
46
|
+
match = match_path_to_mapping_key(contract_file_path, context.compiler_map)
|
|
44
47
|
if match:
|
|
45
48
|
return match
|
|
46
49
|
else:
|
|
47
|
-
raise RuntimeError(f'cannot match compiler to {contract_file_path} from
|
|
50
|
+
raise RuntimeError(f'cannot match compiler to {contract_file_path} from compiler_map')
|
|
48
51
|
|
|
49
52
|
if Util.is_vyper_file(str(contract_file_path)):
|
|
50
53
|
if context.vyper:
|
{certora_cli-7.26.0 → certora_cli-7.29.1}/certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py
RENAMED
|
@@ -556,43 +556,78 @@ class CompilerLangVy(CompilerLang, metaclass=Singleton):
|
|
|
556
556
|
else:
|
|
557
557
|
raise Exception(f"Unexpected ast_node {ast_node}, cannot evaluate constant")
|
|
558
558
|
|
|
559
|
+
@staticmethod
|
|
560
|
+
def subscript_node(ast_node: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
561
|
+
ty = ast_node.get("ast_type")
|
|
562
|
+
# pre-vyper 0.4.0, look deeper within
|
|
563
|
+
if ty == "Index":
|
|
564
|
+
nested = ast_node.get("value")
|
|
565
|
+
if nested is None or not isinstance(nested, dict):
|
|
566
|
+
return None
|
|
567
|
+
return nested
|
|
568
|
+
else:
|
|
569
|
+
return ast_node
|
|
570
|
+
|
|
571
|
+
@staticmethod
|
|
572
|
+
def int_subscript(ast_node: Dict[str, Any], named_constants: Dict[str, int]) -> Optional[int]:
|
|
573
|
+
node = CompilerLangVy.subscript_node(ast_node)
|
|
574
|
+
if node is None:
|
|
575
|
+
return None
|
|
576
|
+
|
|
577
|
+
if "id" in node and node["id"] in named_constants:
|
|
578
|
+
return named_constants[node["id"]]
|
|
579
|
+
elif node.get("ast_type") == "Int":
|
|
580
|
+
return node.get("value")
|
|
581
|
+
else:
|
|
582
|
+
return None
|
|
583
|
+
|
|
584
|
+
@staticmethod
|
|
585
|
+
def get_tuple_elements(ast_node: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
586
|
+
node = CompilerLangVy.subscript_node(ast_node)
|
|
587
|
+
if node is None or node.get("ast_type") != "Tuple":
|
|
588
|
+
raise Exception("Couldn't get tuple elements from ast node")
|
|
589
|
+
return node["elements"]
|
|
590
|
+
|
|
559
591
|
@staticmethod
|
|
560
592
|
def extract_type_from_subscript_node(ast_subscript_node: Dict[str, Any],
|
|
561
593
|
named_constants: Dict[str, int]) -> VyperType:
|
|
562
594
|
value_id = ast_subscript_node['value'].get('id', None)
|
|
563
595
|
if value_id == 'String':
|
|
564
|
-
max_bytes = ast_subscript_node['slice']
|
|
596
|
+
max_bytes = CompilerLangVy.int_subscript(ast_subscript_node['slice'], named_constants)
|
|
597
|
+
if max_bytes is None:
|
|
598
|
+
raise Exception("Failed to find max length for string type declaration")
|
|
565
599
|
return CompilerLangVy.VyperTypeString(max_bytes)
|
|
566
600
|
elif value_id == 'Bytes':
|
|
567
|
-
max_bytes = ast_subscript_node['slice']
|
|
601
|
+
max_bytes = CompilerLangVy.int_subscript(ast_subscript_node['slice'], named_constants)
|
|
602
|
+
if max_bytes is None:
|
|
603
|
+
raise Exception("Failed to find max length for bytes type declaration")
|
|
568
604
|
return CompilerLangVy.VyperTypeBytes(max_bytes)
|
|
569
605
|
elif value_id == 'DynArray':
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
max_elements = CompilerLangVy.extract_constant(
|
|
573
|
-
named_constants)
|
|
606
|
+
tup_elems = CompilerLangVy.get_tuple_elements(ast_subscript_node["slice"])
|
|
607
|
+
elem_type = CompilerLangVy.extract_type_from_type_annotation_node(tup_elems[0], named_constants)
|
|
608
|
+
max_elements = CompilerLangVy.extract_constant(tup_elems[1], named_constants)
|
|
574
609
|
return CompilerLangVy.VyperTypeDynArray(elem_type, max_elements)
|
|
575
610
|
elif value_id == 'HashMap':
|
|
576
|
-
elements_node = ast_subscript_node['slice']
|
|
611
|
+
elements_node = CompilerLangVy.get_tuple_elements(ast_subscript_node['slice'])
|
|
577
612
|
key_type = CompilerLangVy.extract_type_from_type_annotation_node(elements_node[0], named_constants)
|
|
578
613
|
value_type = CompilerLangVy.extract_type_from_type_annotation_node(elements_node[1], named_constants)
|
|
579
614
|
return CompilerLangVy.VyperTypeHashMap(key_type, value_type)
|
|
580
615
|
else: # StaticArray key_type[size]
|
|
581
616
|
key_type = CompilerLangVy.extract_type_from_type_annotation_node(ast_subscript_node['value'],
|
|
582
617
|
named_constants)
|
|
583
|
-
|
|
584
|
-
if
|
|
585
|
-
return CompilerLangVy.VyperTypeStaticArray(key_type,
|
|
618
|
+
max_elem_value = CompilerLangVy.int_subscript(ast_subscript_node['slice'], named_constants)
|
|
619
|
+
if max_elem_value is not None:
|
|
620
|
+
return CompilerLangVy.VyperTypeStaticArray(key_type, max_elem_value)
|
|
586
621
|
else:
|
|
587
622
|
# this is very specific to curve code which has uint256[CONST/2] static array declaration.
|
|
623
|
+
max_elements_node = CompilerLangVy.subscript_node(ast_subscript_node["slice"])
|
|
624
|
+
if max_elements_node is None:
|
|
625
|
+
raise Exception("Couldn't find subscript node for array type")
|
|
588
626
|
if 'ast_type' in max_elements_node:
|
|
589
627
|
if max_elements_node['ast_type'] == 'BinOp' or max_elements_node['ast_type'] in ('Int', 'Name'):
|
|
590
628
|
# good chance this will succeed
|
|
591
629
|
static_array_len = CompilerLangVy.extract_constant(max_elements_node, named_constants)
|
|
592
630
|
return CompilerLangVy.VyperTypeStaticArray(key_type, static_array_len)
|
|
593
|
-
elif 'value' in max_elements_node:
|
|
594
|
-
return CompilerLangVy.VyperTypeStaticArray(key_type, max_elements_node['value'])
|
|
595
|
-
|
|
596
631
|
raise Exception(
|
|
597
632
|
f"Don't know how to deal with vyper static array declaration with length {max_elements_node}")
|
|
598
633
|
|
|
@@ -21,7 +21,7 @@ import re
|
|
|
21
21
|
import shutil
|
|
22
22
|
import sys
|
|
23
23
|
import typing
|
|
24
|
-
from collections import OrderedDict
|
|
24
|
+
from collections import OrderedDict, defaultdict
|
|
25
25
|
from enum import Enum
|
|
26
26
|
from functools import lru_cache
|
|
27
27
|
from pathlib import Path
|
|
@@ -411,6 +411,8 @@ def generate_modifier_finder(f: Func, internal_id: int, sym: int,
|
|
|
411
411
|
formal_strings = []
|
|
412
412
|
arg_strings = []
|
|
413
413
|
for (logged_ty, logged_name) in zip(loggable_types, loggable_names):
|
|
414
|
+
if logged_name == "":
|
|
415
|
+
continue
|
|
414
416
|
arg_strings.append(logged_name)
|
|
415
417
|
formal_strings.append(f"{logged_ty} {logged_name}")
|
|
416
418
|
modifier_body = f"modifier {modifier_name}"
|
|
@@ -825,7 +827,7 @@ class CertoraBuildGenerator:
|
|
|
825
827
|
ast_logger.debug(f"No body for {func_def} but ast claims it is implemented")
|
|
826
828
|
|
|
827
829
|
if original_contract is not None:
|
|
828
|
-
if method := original_contract.find_method(func_name):
|
|
830
|
+
if method := original_contract.find_method(func_name, solidity_type_args):
|
|
829
831
|
source_bytes = method.source_bytes
|
|
830
832
|
original_file = method.original_file
|
|
831
833
|
else:
|
|
@@ -1198,10 +1200,15 @@ class CertoraBuildGenerator:
|
|
|
1198
1200
|
return x[TYPE] == FUNCTION or x[TYPE] == CertoraBuildGenerator.CONSTRUCTOR_STRING
|
|
1199
1201
|
|
|
1200
1202
|
@staticmethod
|
|
1201
|
-
def collect_srcmap(data: Dict[str, Any]) ->
|
|
1203
|
+
def collect_srcmap(data: Dict[str, Any]) -> Tuple[str, str]:
|
|
1202
1204
|
# no source map object in vyper
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
+
deployed = data["evm"]["deployedBytecode"].get("sourceMap", "")
|
|
1206
|
+
if isinstance(deployed, dict):
|
|
1207
|
+
deployed = deployed.get("pc_pos_map_compressed", "")
|
|
1208
|
+
regular = data["evm"]["bytecode"].get("sourceMap", "")
|
|
1209
|
+
if isinstance(regular, dict):
|
|
1210
|
+
regular = regular.get("pc_pos_map_compressed", "")
|
|
1211
|
+
return deployed, regular
|
|
1205
1212
|
|
|
1206
1213
|
@staticmethod
|
|
1207
1214
|
def collect_varmap(contract: str, data: Dict[str, Any]) -> Any:
|
|
@@ -1389,7 +1396,7 @@ class CertoraBuildGenerator:
|
|
|
1389
1396
|
if not self.context.strict_solc_optimizer and self.context.solc_via_ir:
|
|
1390
1397
|
# The default optimizer steps (taken from libsolidity/interface/OptimiserSettings.h) but with the
|
|
1391
1398
|
# full inliner step removed
|
|
1392
|
-
|
|
1399
|
+
solc0_8_26_to_0_8_29 = ("dhfoDgvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLCTUca[r]LSsTFOtfDnca[r]" +
|
|
1393
1400
|
"IulcscCTUtx[scCTUt]TOntnfDIuljmul[jul]VcTOculjmul")
|
|
1394
1401
|
solc0_8_13_to_0_8_25 = "dhfoDgvulfnTUtnIf[xa[r]EscLMcCTUtTOntnfDIulLculVcul[j]T" + \
|
|
1395
1402
|
"peulxa[rul]xa[r]cLgvifCTUca[r]LSsTFOtfDnca[r]Iulc]jmul[jul]VcTOculjmul"
|
|
@@ -1433,8 +1440,8 @@ class CertoraBuildGenerator:
|
|
|
1433
1440
|
yul_optimizer_steps = solc0_8_12
|
|
1434
1441
|
elif minor == 8 and 13 <= patch <= 25:
|
|
1435
1442
|
yul_optimizer_steps = solc0_8_13_to_0_8_25
|
|
1436
|
-
elif minor == 8 and 26 <= patch <=
|
|
1437
|
-
yul_optimizer_steps =
|
|
1443
|
+
elif minor == 8 and 26 <= patch <= 29:
|
|
1444
|
+
yul_optimizer_steps = solc0_8_26_to_0_8_29
|
|
1438
1445
|
assert yul_optimizer_steps is not None, \
|
|
1439
1446
|
'Yul Optimizer steps missing for requested Solidity version. Please contact Certora team.'
|
|
1440
1447
|
|
|
@@ -1516,7 +1523,8 @@ class CertoraBuildGenerator:
|
|
|
1516
1523
|
sources_dict = {str(contract_file_posix_abs): {
|
|
1517
1524
|
"urls": [str(contract_file_posix_abs)]}} # type: Dict[str, Dict[str, Any]]
|
|
1518
1525
|
output_selection = ["transientStorageLayout", "storageLayout", "abi", "evm.bytecode",
|
|
1519
|
-
"evm.deployedBytecode", "evm.methodIdentifiers", "evm.assembly"
|
|
1526
|
+
"evm.deployedBytecode", "evm.methodIdentifiers", "evm.assembly",
|
|
1527
|
+
"evm.bytecode.functionDebugData"]
|
|
1520
1528
|
ast_selection = ["id", "ast"]
|
|
1521
1529
|
elif compiler_collector_lang == CompilerLangVy():
|
|
1522
1530
|
with open(contract_file_posix_abs) as f:
|
|
@@ -1739,6 +1747,10 @@ class CertoraBuildGenerator:
|
|
|
1739
1747
|
sdc_name = f"{Path(build_arg_contract_file).name}_{file_index}"
|
|
1740
1748
|
compilation_path = self.get_compilation_path(sdc_name)
|
|
1741
1749
|
self.file_to_sdc_name[Util.abs_norm_path(build_arg_contract_file)] = sdc_name
|
|
1750
|
+
|
|
1751
|
+
compiler_collector = self.compiler_coll_factory \
|
|
1752
|
+
.get_compiler_collector(Path(path_for_compiler_collector_file))
|
|
1753
|
+
|
|
1742
1754
|
# update remappings and collect_cmd:
|
|
1743
1755
|
if not is_vyper:
|
|
1744
1756
|
Util.safe_create_dir(compilation_path)
|
|
@@ -1786,8 +1798,10 @@ class CertoraBuildGenerator:
|
|
|
1786
1798
|
compiler_logger.debug(f"collect_cmd: {collect_cmd}\n")
|
|
1787
1799
|
else:
|
|
1788
1800
|
compiler_ver_to_run = get_relevant_compiler(Path(build_arg_contract_file), self.context)
|
|
1789
|
-
|
|
1790
|
-
|
|
1801
|
+
path_string = ""
|
|
1802
|
+
if compiler_collector.compiler_version[1] < 4:
|
|
1803
|
+
path_string = f' -p "{self.context.solc_allow_path}"'
|
|
1804
|
+
collect_cmd = f'{compiler_ver_to_run}{path_string} -o "{compilation_path}" ' \
|
|
1791
1805
|
f'--standard-json'
|
|
1792
1806
|
|
|
1793
1807
|
# Make sure compilation artifacts are always deleted
|
|
@@ -1800,9 +1814,6 @@ class CertoraBuildGenerator:
|
|
|
1800
1814
|
# (we do not try to save a big chain history of changes, just a previous and current)
|
|
1801
1815
|
self.backup_compiler_outputs(sdc_name, smart_contract_lang, "prev")
|
|
1802
1816
|
|
|
1803
|
-
compiler_collector = self.compiler_coll_factory \
|
|
1804
|
-
.get_compiler_collector(Path(path_for_compiler_collector_file))
|
|
1805
|
-
|
|
1806
1817
|
# Standard JSON
|
|
1807
1818
|
remappings = [] if isinstance(compiler_collector, CompilerCollectorYul) else self.context.remappings
|
|
1808
1819
|
input_for_solc = self.standard_json(Path(file_abs_path), build_arg_contract_file, remappings,
|
|
@@ -2246,6 +2257,14 @@ class CertoraBuildGenerator:
|
|
|
2246
2257
|
build_arg_contract_file)
|
|
2247
2258
|
immutables = self.collect_immutables(contract_data, build_arg_contract_file, compiler_lang)
|
|
2248
2259
|
|
|
2260
|
+
internal_function_entrypoints = set([])
|
|
2261
|
+
|
|
2262
|
+
if compiler_lang == CompilerLangSol() and "functionDebugData" in contract_data["evm"]["deployedBytecode"]:
|
|
2263
|
+
debug = contract_data["evm"]["deployedBytecode"]["functionDebugData"]
|
|
2264
|
+
for (_, v) in debug.items():
|
|
2265
|
+
if "entryPoint" in v and v["entryPoint"] is not None:
|
|
2266
|
+
internal_function_entrypoints.add(v["entryPoint"])
|
|
2267
|
+
|
|
2249
2268
|
if self.context.internal_funcs is not None:
|
|
2250
2269
|
all_internal_functions: Dict[str, Any] = \
|
|
2251
2270
|
Util.read_json_file(self.context.internal_funcs)
|
|
@@ -2296,7 +2315,8 @@ class CertoraBuildGenerator:
|
|
|
2296
2315
|
extension_contracts=list(),
|
|
2297
2316
|
local_assignments={},
|
|
2298
2317
|
branches={},
|
|
2299
|
-
requires={}
|
|
2318
|
+
requires={},
|
|
2319
|
+
internal_starts=list(internal_function_entrypoints)
|
|
2300
2320
|
)
|
|
2301
2321
|
|
|
2302
2322
|
@staticmethod
|
|
@@ -2527,7 +2547,7 @@ class CertoraBuildGenerator:
|
|
|
2527
2547
|
sources_from_pre_finder_SDCs |= sdc.all_contract_files
|
|
2528
2548
|
sources = self.collect_sources(context, certora_verify_generator, sources_from_pre_finder_SDCs)
|
|
2529
2549
|
try:
|
|
2530
|
-
|
|
2550
|
+
build_source_tree(sources, context)
|
|
2531
2551
|
except Exception as e:
|
|
2532
2552
|
build_logger.debug(f"build_source_tree failed. Sources: {sources}", exc_info=e)
|
|
2533
2553
|
raise
|
|
@@ -2652,6 +2672,169 @@ class CertoraBuildGenerator:
|
|
|
2652
2672
|
self.handle_links()
|
|
2653
2673
|
self.handle_struct_links()
|
|
2654
2674
|
self.handle_contract_extensions()
|
|
2675
|
+
self.handle_storage_extension_harnesses()
|
|
2676
|
+
|
|
2677
|
+
def handle_storage_extension_harnesses(self) -> None:
|
|
2678
|
+
def new_field_of_node(ext_instance: Any, node: Dict[str, Any]) -> Optional[Dict[str, Any]]:
|
|
2679
|
+
"""
|
|
2680
|
+
If this node is a storage variable declaration like the following:
|
|
2681
|
+
|
|
2682
|
+
/** @custom:certoralink 0x12345 */
|
|
2683
|
+
T x;
|
|
2684
|
+
|
|
2685
|
+
and if so, return a storage field matching the type of x but using 0x12345 as the slot
|
|
2686
|
+
"""
|
|
2687
|
+
|
|
2688
|
+
if node.get("nodeType") != "VariableDeclaration":
|
|
2689
|
+
return None
|
|
2690
|
+
if not node.get("stateVariable"):
|
|
2691
|
+
return None
|
|
2692
|
+
if "documentation" not in node:
|
|
2693
|
+
return None
|
|
2694
|
+
if node["documentation"].get("nodeType") != "StructuredDocumentation":
|
|
2695
|
+
return None
|
|
2696
|
+
annot_link = node["documentation"].get("text")
|
|
2697
|
+
var_name = node.get("name")
|
|
2698
|
+
if var_name is None or not isinstance(annot_link, str):
|
|
2699
|
+
return None
|
|
2700
|
+
|
|
2701
|
+
link_regex = r'@custom:certoralink\s+(0x[0-9a-fA-F]+)\s*'
|
|
2702
|
+
link_match = re.search(link_regex, annot_link)
|
|
2703
|
+
|
|
2704
|
+
if link_match is None:
|
|
2705
|
+
raise Util.CertoraUserInputError(f"Couldn't parse annotation in on "
|
|
2706
|
+
f"{ext_instance.original_file_name}.{var_name}: {annot_link}")
|
|
2707
|
+
try:
|
|
2708
|
+
link_slot = int(link_match.group(1), 16)
|
|
2709
|
+
except ValueError:
|
|
2710
|
+
raise Util.CertoraUserInputError(f"Invalid certoralink slot value in annotation on"
|
|
2711
|
+
f"{ext_instance.original_file_name}.{var_name}: {annot_link}")
|
|
2712
|
+
storage_field_info = None
|
|
2713
|
+
for field in ext_instance.storage_layout["storage"]:
|
|
2714
|
+
if field["label"] == var_name:
|
|
2715
|
+
storage_field_info = field
|
|
2716
|
+
break
|
|
2717
|
+
if storage_field_info is None:
|
|
2718
|
+
return None
|
|
2719
|
+
cloned_field = storage_field_info.copy()
|
|
2720
|
+
cloned_field["slot"] = str(link_slot)
|
|
2721
|
+
# Don't bother trying to uniquify the name
|
|
2722
|
+
cloned_field["label"] = var_name
|
|
2723
|
+
return cloned_field
|
|
2724
|
+
|
|
2725
|
+
def handle_one_extension(storage_ext: str) -> tuple[Any, str, List[Dict[str, Any]]] :
|
|
2726
|
+
"""
|
|
2727
|
+
Get the extension contract plus the new fields
|
|
2728
|
+
"""
|
|
2729
|
+
extension_sdc_cands = self.get_matching_sdc_names_from_SDCs(storage_ext)
|
|
2730
|
+
assert len(extension_sdc_cands) == 1, f"Zero or multiple possible contracts for {storage_ext}"
|
|
2731
|
+
extension_sdc_name = extension_sdc_cands[0]
|
|
2732
|
+
extension_sdc = self.SDCs.get(extension_sdc_name)
|
|
2733
|
+
assert extension_sdc and extension_sdc.primary_contract == storage_ext, f"Could not find SDC for {extension_sdc_name}"
|
|
2734
|
+
ext_instance = extension_sdc.find_contract(storage_ext)
|
|
2735
|
+
assert ext_instance is not None, f"Could not find extension contract {storage_ext}"
|
|
2736
|
+
|
|
2737
|
+
# let's try to find the AST now
|
|
2738
|
+
build_file_ast = None
|
|
2739
|
+
for (k, v) in self.asts.items():
|
|
2740
|
+
if ext_instance.original_file in v:
|
|
2741
|
+
build_file_ast = k
|
|
2742
|
+
break
|
|
2743
|
+
if build_file_ast is None:
|
|
2744
|
+
raise RuntimeError(f"Couldn't find file for storage extension file {storage_ext}")
|
|
2745
|
+
|
|
2746
|
+
contract_def_node = self.get_contract_def_node_ref(
|
|
2747
|
+
build_file_ast,
|
|
2748
|
+
ext_instance.original_file,
|
|
2749
|
+
storage_ext
|
|
2750
|
+
)
|
|
2751
|
+
def_node = self.asts[build_file_ast][ext_instance.original_file][contract_def_node]
|
|
2752
|
+
nodes = def_node.get("nodes")
|
|
2753
|
+
if not isinstance(nodes, list):
|
|
2754
|
+
raise RuntimeError(f"Couldn't find nodes for body of {storage_ext}")
|
|
2755
|
+
|
|
2756
|
+
new_fields = []
|
|
2757
|
+
for node in nodes:
|
|
2758
|
+
new_field = new_field_of_node(ext_instance, node)
|
|
2759
|
+
if new_field is not None:
|
|
2760
|
+
new_fields.append(new_field)
|
|
2761
|
+
|
|
2762
|
+
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
|
+
extension_contracts: Set[str] = set()
|
|
2810
|
+
storage_extensions: Dict[str, Set[str]] = defaultdict(set)
|
|
2811
|
+
storage_ext = self.context.storage_extension_harnesses
|
|
2812
|
+
|
|
2813
|
+
if storage_ext is None:
|
|
2814
|
+
return
|
|
2815
|
+
|
|
2816
|
+
for i in storage_ext:
|
|
2817
|
+
target_contract, extension_contract = i.split("=")
|
|
2818
|
+
extension_contracts.add(extension_contract)
|
|
2819
|
+
storage_extensions[target_contract].add(extension_contract)
|
|
2820
|
+
|
|
2821
|
+
# These are the new fields to add for each contract
|
|
2822
|
+
extension_to_fields_and_types: Dict[str, Tuple[List[Dict[str, Any]], Dict[str, Any]]] = {}
|
|
2823
|
+
|
|
2824
|
+
for storage_ext in extension_contracts:
|
|
2825
|
+
(ext_instance, extension_sdc_name, new_fields) = handle_one_extension(storage_ext)
|
|
2826
|
+
new_types = ext_instance.storage_layout["types"]
|
|
2827
|
+
extension_to_fields_and_types[storage_ext] = (new_fields, {} if new_types is None else new_types)
|
|
2828
|
+
del self.SDCs[extension_sdc_name]
|
|
2829
|
+
|
|
2830
|
+
for (target, extensions) in storage_extensions.items():
|
|
2831
|
+
target_sdc_names = self.get_matching_sdc_names_from_SDCs(target)
|
|
2832
|
+
assert len(target_sdc_names) == 1, f"no matching sdc for {target}"
|
|
2833
|
+
target_sdc = target_sdc_names[0]
|
|
2834
|
+
sdc = self.SDCs[target_sdc]
|
|
2835
|
+
target_contract = sdc.find_contract(target)
|
|
2836
|
+
assert target_contract is not None, f"could not find contract for {target}"
|
|
2837
|
+
apply_extensions(target_contract, extensions, extension_to_fields_and_types)
|
|
2655
2838
|
|
|
2656
2839
|
def finders_compilation_round(self,
|
|
2657
2840
|
build_arg_contract_file: str,
|
|
@@ -2851,7 +3034,7 @@ class CertoraBuildGenerator:
|
|
|
2851
3034
|
for k, v in autofinder_remappings.items():
|
|
2852
3035
|
self.function_finder_file_remappings[Util.abs_posix_path(k)] = Util.abs_posix_path(v)
|
|
2853
3036
|
new_sdcs = self.collect_for_file(new_file, i, get_compiler_lang(build_arg_contract_file),
|
|
2854
|
-
Util.get_certora_sources_dir() / self.cwd_rel_in_sources,
|
|
3037
|
+
Util.get_certora_sources_dir() / self.context.cwd_rel_in_sources,
|
|
2855
3038
|
path_for_compiler_collector_file,
|
|
2856
3039
|
sdc_pre_finder,
|
|
2857
3040
|
fail_on_compilation_error=False,
|
|
@@ -2879,7 +3062,7 @@ class CertoraBuildGenerator:
|
|
|
2879
3062
|
contract_path = Util.abs_posix_path_obj(contract_file)
|
|
2880
3063
|
rel_directory = Path(os.path.relpath(contract_file, '.')).parent
|
|
2881
3064
|
contract_filename = contract_path.name
|
|
2882
|
-
new_path = Util.get_certora_sources_dir() / self.cwd_rel_in_sources / rel_directory / contract_filename
|
|
3065
|
+
new_path = Util.get_certora_sources_dir() / self.context.cwd_rel_in_sources / rel_directory / contract_filename
|
|
2883
3066
|
new_path.parent.mkdir(parents=True, exist_ok=True)
|
|
2884
3067
|
return str(new_path)
|
|
2885
3068
|
|
|
@@ -2889,7 +3072,7 @@ class CertoraBuildGenerator:
|
|
|
2889
3072
|
This assumes those paths can be related to cwd.
|
|
2890
3073
|
"""
|
|
2891
3074
|
rel_to_cwd_path = Path(os.path.relpath(path, '.'))
|
|
2892
|
-
new_path = Util.get_certora_sources_dir() / self.cwd_rel_in_sources / rel_to_cwd_path
|
|
3075
|
+
new_path = Util.get_certora_sources_dir() / self.context.cwd_rel_in_sources / rel_to_cwd_path
|
|
2893
3076
|
return str(new_path.absolute())
|
|
2894
3077
|
|
|
2895
3078
|
def handle_links(self) -> None:
|
|
@@ -2985,7 +3168,7 @@ class CertoraBuildGenerator:
|
|
|
2985
3168
|
f"for contract extension")
|
|
2986
3169
|
extension_contract = contracts_by_name[extension]
|
|
2987
3170
|
for f in ext["exclude"]:
|
|
2988
|
-
if extension_contract.
|
|
3171
|
+
if not extension_contract.has_method_with_name(f):
|
|
2989
3172
|
raise Util.CertoraUserInputError(f"Can't find a method named {f} in contract "
|
|
2990
3173
|
f"{extension_contract.name}")
|
|
2991
3174
|
extended_contract.add_extension(ContractExtension(extension_contract, ext["exclude"]))
|
|
@@ -3267,6 +3450,8 @@ class CertoraBuildGenerator:
|
|
|
3267
3450
|
sources.add(Path(context.bytecode_spec))
|
|
3268
3451
|
if context.yul_abi:
|
|
3269
3452
|
sources.add(Path(context.yul_abi))
|
|
3453
|
+
if context.override_base_config:
|
|
3454
|
+
sources.add(Path(context.override_base_config))
|
|
3270
3455
|
|
|
3271
3456
|
if hasattr(context, Attrs.EvmProverAttributes.PROVER_RESOURCE_FILES.get_conf_key()) \
|
|
3272
3457
|
and context.prover_resource_files:
|
|
@@ -3295,20 +3480,19 @@ def sources_to_abs(sources: Set[Path]) -> Set[Path]:
|
|
|
3295
3480
|
return result
|
|
3296
3481
|
|
|
3297
3482
|
|
|
3298
|
-
def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bool = False) ->
|
|
3483
|
+
def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bool = False) -> None:
|
|
3299
3484
|
"""
|
|
3300
3485
|
Copies files to .certora_sources
|
|
3301
|
-
@returns the cwd relative in sources
|
|
3302
3486
|
"""
|
|
3303
3487
|
sources = sources_to_abs(sources)
|
|
3304
|
-
cwd_rel_in_sources, common_path = CertoraBuildGenerator.get_cwd_rel_in_sources(sources)
|
|
3488
|
+
context.cwd_rel_in_sources, context.common_path = CertoraBuildGenerator.get_cwd_rel_in_sources(sources)
|
|
3305
3489
|
|
|
3306
3490
|
for source_path in sources:
|
|
3307
3491
|
is_dir = source_path.is_dir()
|
|
3308
3492
|
# copy file to the path of the file from the common root under the sources directory
|
|
3309
3493
|
|
|
3310
3494
|
# make sure directory exists
|
|
3311
|
-
target_path = Util.get_certora_sources_dir() / source_path.relative_to(common_path)
|
|
3495
|
+
target_path = Util.get_certora_sources_dir() / source_path.relative_to(context.common_path)
|
|
3312
3496
|
target_directory = target_path if is_dir else target_path.parent
|
|
3313
3497
|
try:
|
|
3314
3498
|
target_directory.mkdir(parents=True, exist_ok=True)
|
|
@@ -3337,28 +3521,19 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3337
3521
|
raise
|
|
3338
3522
|
|
|
3339
3523
|
# the empty file .cwd is written in the source tree to denote the current working directory
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
new_value = []
|
|
3354
|
-
len_orig = len(context.prover_resource_files)
|
|
3355
|
-
for value in context.prover_resource_files:
|
|
3356
|
-
label, file_path = value.split(':')
|
|
3357
|
-
rel_path = Path(os.path.relpath(file_path, '.'))
|
|
3358
|
-
new_value.append(':'.join([label, os.path.normpath(rel_path)]))
|
|
3359
|
-
if len_orig != len(new_value):
|
|
3360
|
-
raise RuntimeError(f"fail to process prover_resource_files {len_orig} out of {len(new_value)}")
|
|
3361
|
-
context.prover_resource_files = new_value
|
|
3524
|
+
cwd_file_path = Util.get_certora_sources_dir() / context.cwd_rel_in_sources / Util.CWD_FILE
|
|
3525
|
+
cwd_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
3526
|
+
cwd_file_path.touch()
|
|
3527
|
+
|
|
3528
|
+
# the empty file .project_directory is written in the source tree to denote the projecct directory
|
|
3529
|
+
rust_proj_dir = getattr(context, 'rust_project_directory', None)
|
|
3530
|
+
if rust_proj_dir:
|
|
3531
|
+
proj_dir_parent_relative = os.path.relpath(rust_proj_dir, os.getcwd())
|
|
3532
|
+
assert Path(rust_proj_dir).is_dir(), f"build_source_tree: not a directory {rust_proj_dir}"
|
|
3533
|
+
proj_dir_parent_file = (Util.get_certora_sources_dir() / context.cwd_rel_in_sources / proj_dir_parent_relative /
|
|
3534
|
+
Util.PROJECT_DIR_FILE)
|
|
3535
|
+
proj_dir_parent_file.parent.mkdir(parents=True, exist_ok=True)
|
|
3536
|
+
proj_dir_parent_file.touch()
|
|
3362
3537
|
|
|
3363
3538
|
# Copy the repro conf file to the sources as the overall way to reproduce this run easily.
|
|
3364
3539
|
# The file is being copied in here and not added through collect_sources, because we want
|
|
@@ -3371,9 +3546,6 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3371
3546
|
build_logger.debug("Couldn't copy repro conf to certora sources.", exc_info=e)
|
|
3372
3547
|
raise
|
|
3373
3548
|
|
|
3374
|
-
return cwd_rel_in_sources
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
3549
|
def build_from_scratch(certora_build_generator: CertoraBuildGenerator,
|
|
3378
3550
|
certora_verify_generator: CertoraVerifyGenerator,
|
|
3379
3551
|
build_cache_enabled: bool) -> CachedFiles:
|
|
@@ -3516,8 +3688,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3516
3688
|
|
|
3517
3689
|
# Start by syntax checking, if we're in the right mode
|
|
3518
3690
|
if Cv.mode_has_spec_file(context) and not context.build_only and not ignore_spec_syntax_check:
|
|
3519
|
-
|
|
3520
|
-
if attr:
|
|
3691
|
+
if context.disable_local_typechecking:
|
|
3521
3692
|
build_logger.warning(
|
|
3522
3693
|
"Local checks of CVL specification files disabled. It is recommended to enable the checks.")
|
|
3523
3694
|
else:
|
|
@@ -3530,6 +3701,11 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3530
3701
|
certora_verify_generator,
|
|
3531
3702
|
certora_build_cache_manager)
|
|
3532
3703
|
|
|
3704
|
+
# avoid running the same test over and over again for each split run, context.split_rules is true only for
|
|
3705
|
+
# the first run and is set to [] for split runs
|
|
3706
|
+
if context.split_rules:
|
|
3707
|
+
Ctx.run_local_spec_check(True, context)
|
|
3708
|
+
|
|
3533
3709
|
# .certora_verify.json is always constructed even if build cache is enabled
|
|
3534
3710
|
# Sources construction should only happen when rebuilding
|
|
3535
3711
|
# Build sources tree
|