certora-cli-beta-mirror 7.27.1__tar.gz → 7.29.0__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_beta_mirror-7.29.0/LICENSE +15 -0
- {certora_cli_beta_mirror-7.27.1/certora_cli_beta_mirror.egg-info → certora_cli_beta_mirror-7.29.0}/PKG-INFO +8 -3
- certora_cli_beta_mirror-7.29.0/README.md +1 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +48 -13
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraBuild.py +65 -32
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraBuildDataClasses.py +19 -4
- certora_cli_beta_mirror-7.29.0/certora_cli/CertoraProver/certoraBuildRust.py +153 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraCloudIO.py +29 -64
- certora_cli_beta_mirror-7.29.0/certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +377 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraCollectRunMetadata.py +3 -1
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraConfigIO.py +55 -20
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraContext.py +14 -6
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraContextAttributes.py +106 -50
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraContextValidator.py +40 -7
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraParseBuildScript.py +7 -10
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraVerifyGenerator.py +12 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/splitRules.py +3 -1
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/mutateApp.py +3 -3
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/certoraAttrUtil.py +10 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/certoraUtils.py +18 -2
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/certoraValidateFuncs.py +17 -11
- certora_cli_beta_mirror-7.29.0/certora_cli/certoraRanger.py +71 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/certoraRun.py +12 -14
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/certoraSolanaProver.py +8 -1
- certora_cli_beta_mirror-7.29.0/certora_cli/certoraSorobanProver.py +285 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0/certora_cli_beta_mirror.egg-info}/PKG-INFO +8 -3
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli_beta_mirror.egg-info/SOURCES.txt +1 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli_beta_mirror.egg-info/entry_points.txt +1 -0
- certora_cli_beta_mirror-7.29.0/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_jars/Typechecker.jar +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/setup.py +10 -4
- certora_cli_beta_mirror-7.27.1/LICENSE +0 -22
- certora_cli_beta_mirror-7.27.1/README.md +0 -1
- certora_cli_beta_mirror-7.27.1/certora_cli/CertoraProver/certoraBuildRust.py +0 -117
- certora_cli_beta_mirror-7.27.1/certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +0 -242
- certora_cli_beta_mirror-7.27.1/certora_cli/certoraSorobanProver.py +0 -36
- certora_cli_beta_mirror-7.27.1/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/MANIFEST.in +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_bins/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollector.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollectorSol.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollectorSolBased.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/Compiler/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraBuildCacheManager.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraCompilerParameters.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraContextClass.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraContractFuncs.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraExtensionInfo.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraJobList.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraMiniSpecParser.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraNodeFilters.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraProjectScanner.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraSourceFinders.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/CertoraProver/certoraType.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/equivCheck.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/mutateAttributes.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/mutateConstants.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/mutateUtil.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Mutate/mutateValidate.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/ExpectedComparator.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/Shared/certoraLogging.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/certoraEVMProver.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/certoraEqCheck.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/certoraMutate.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli/rustMutator.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli_beta_mirror.egg-info/dependency_links.txt +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli_beta_mirror.egg-info/requires.txt +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_cli_beta_mirror.egg-info/top_level.txt +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/certora_jars/__init__.py +0 -0
- {certora_cli_beta_mirror-7.27.1 → certora_cli_beta_mirror-7.29.0}/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-beta-mirror
|
|
3
|
-
Version: 7.
|
|
3
|
+
Version: 7.29.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
|
|
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
|
|
@@ -28,8 +31,10 @@ Dynamic: classifier
|
|
|
28
31
|
Dynamic: description
|
|
29
32
|
Dynamic: description-content-type
|
|
30
33
|
Dynamic: home-page
|
|
34
|
+
Dynamic: license
|
|
35
|
+
Dynamic: project-url
|
|
31
36
|
Dynamic: requires-dist
|
|
32
37
|
Dynamic: requires-python
|
|
33
38
|
Dynamic: summary
|
|
34
39
|
|
|
35
|
-
Commit
|
|
40
|
+
Commit 3f35845. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Commit 3f35845. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
|
|
@@ -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
|
|
|
@@ -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:
|
|
@@ -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
|
|
@@ -2698,8 +2718,8 @@ class CertoraBuildGenerator:
|
|
|
2698
2718
|
return None
|
|
2699
2719
|
cloned_field = storage_field_info.copy()
|
|
2700
2720
|
cloned_field["slot"] = str(link_slot)
|
|
2701
|
-
#
|
|
2702
|
-
cloned_field["label"] =
|
|
2721
|
+
# Don't bother trying to uniquify the name
|
|
2722
|
+
cloned_field["label"] = var_name
|
|
2703
2723
|
return cloned_field
|
|
2704
2724
|
|
|
2705
2725
|
def handle_one_extension(storage_ext: str) -> tuple[Any, str, List[Dict[str, Any]]] :
|
|
@@ -2750,23 +2770,34 @@ class CertoraBuildGenerator:
|
|
|
2750
2770
|
if target_contract.storage_layout.get("types") is None:
|
|
2751
2771
|
target_contract.storage_layout["types"] = {}
|
|
2752
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"]}
|
|
2753
2774
|
# Keep track of slots we've added, and error if we
|
|
2754
2775
|
# find two extensions extending the same slot
|
|
2755
2776
|
added_slots: Dict[str, str] = {}
|
|
2777
|
+
added_vars: Dict[str, str] = {}
|
|
2756
2778
|
for ext in extensions:
|
|
2757
2779
|
(new_fields, new_types) = to_add[ext]
|
|
2758
2780
|
|
|
2759
2781
|
for f in new_fields:
|
|
2760
|
-
# See if any of the new fields is a slot we've already added
|
|
2782
|
+
# See if any of the new fields is a slot or variable name we've already added
|
|
2761
2783
|
slot = f["slot"]
|
|
2784
|
+
var = f["label"]
|
|
2762
2785
|
if slot in added_slots:
|
|
2763
2786
|
seen = added_slots[slot]
|
|
2764
|
-
raise Util.CertoraUserInputError(f"Slot {slot} added to {target_contract.name} by {ext} already added by {seen}")
|
|
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}")
|
|
2765
2792
|
|
|
2766
2793
|
if slot in target_slots:
|
|
2767
|
-
raise Util.CertoraUserInputError(f"Slot {slot} added to {target_contract.name} by {ext} already mapped by {target_contract.name}")
|
|
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}")
|
|
2768
2798
|
|
|
2769
2799
|
added_slots[slot] = ext
|
|
2800
|
+
added_vars[var] = ext
|
|
2770
2801
|
|
|
2771
2802
|
target_contract.storage_layout["storage"].extend(new_fields)
|
|
2772
2803
|
|
|
@@ -3003,7 +3034,7 @@ class CertoraBuildGenerator:
|
|
|
3003
3034
|
for k, v in autofinder_remappings.items():
|
|
3004
3035
|
self.function_finder_file_remappings[Util.abs_posix_path(k)] = Util.abs_posix_path(v)
|
|
3005
3036
|
new_sdcs = self.collect_for_file(new_file, i, get_compiler_lang(build_arg_contract_file),
|
|
3006
|
-
Util.get_certora_sources_dir() / self.cwd_rel_in_sources,
|
|
3037
|
+
Util.get_certora_sources_dir() / self.context.cwd_rel_in_sources,
|
|
3007
3038
|
path_for_compiler_collector_file,
|
|
3008
3039
|
sdc_pre_finder,
|
|
3009
3040
|
fail_on_compilation_error=False,
|
|
@@ -3031,7 +3062,7 @@ class CertoraBuildGenerator:
|
|
|
3031
3062
|
contract_path = Util.abs_posix_path_obj(contract_file)
|
|
3032
3063
|
rel_directory = Path(os.path.relpath(contract_file, '.')).parent
|
|
3033
3064
|
contract_filename = contract_path.name
|
|
3034
|
-
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
|
|
3035
3066
|
new_path.parent.mkdir(parents=True, exist_ok=True)
|
|
3036
3067
|
return str(new_path)
|
|
3037
3068
|
|
|
@@ -3041,7 +3072,7 @@ class CertoraBuildGenerator:
|
|
|
3041
3072
|
This assumes those paths can be related to cwd.
|
|
3042
3073
|
"""
|
|
3043
3074
|
rel_to_cwd_path = Path(os.path.relpath(path, '.'))
|
|
3044
|
-
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
|
|
3045
3076
|
return str(new_path.absolute())
|
|
3046
3077
|
|
|
3047
3078
|
def handle_links(self) -> None:
|
|
@@ -3137,7 +3168,7 @@ class CertoraBuildGenerator:
|
|
|
3137
3168
|
f"for contract extension")
|
|
3138
3169
|
extension_contract = contracts_by_name[extension]
|
|
3139
3170
|
for f in ext["exclude"]:
|
|
3140
|
-
if extension_contract.
|
|
3171
|
+
if not extension_contract.has_method_with_name(f):
|
|
3141
3172
|
raise Util.CertoraUserInputError(f"Can't find a method named {f} in contract "
|
|
3142
3173
|
f"{extension_contract.name}")
|
|
3143
3174
|
extended_contract.add_extension(ContractExtension(extension_contract, ext["exclude"]))
|
|
@@ -3419,6 +3450,8 @@ class CertoraBuildGenerator:
|
|
|
3419
3450
|
sources.add(Path(context.bytecode_spec))
|
|
3420
3451
|
if context.yul_abi:
|
|
3421
3452
|
sources.add(Path(context.yul_abi))
|
|
3453
|
+
if context.override_base_config:
|
|
3454
|
+
sources.add(Path(context.override_base_config))
|
|
3422
3455
|
|
|
3423
3456
|
if hasattr(context, Attrs.EvmProverAttributes.PROVER_RESOURCE_FILES.get_conf_key()) \
|
|
3424
3457
|
and context.prover_resource_files:
|
|
@@ -3447,20 +3480,19 @@ def sources_to_abs(sources: Set[Path]) -> Set[Path]:
|
|
|
3447
3480
|
return result
|
|
3448
3481
|
|
|
3449
3482
|
|
|
3450
|
-
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:
|
|
3451
3484
|
"""
|
|
3452
3485
|
Copies files to .certora_sources
|
|
3453
|
-
@returns the cwd relative in sources
|
|
3454
3486
|
"""
|
|
3455
3487
|
sources = sources_to_abs(sources)
|
|
3456
|
-
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)
|
|
3457
3489
|
|
|
3458
3490
|
for source_path in sources:
|
|
3459
3491
|
is_dir = source_path.is_dir()
|
|
3460
3492
|
# copy file to the path of the file from the common root under the sources directory
|
|
3461
3493
|
|
|
3462
3494
|
# make sure directory exists
|
|
3463
|
-
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)
|
|
3464
3496
|
target_directory = target_path if is_dir else target_path.parent
|
|
3465
3497
|
try:
|
|
3466
3498
|
target_directory.mkdir(parents=True, exist_ok=True)
|
|
@@ -3489,7 +3521,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3489
3521
|
raise
|
|
3490
3522
|
|
|
3491
3523
|
# the empty file .cwd is written in the source tree to denote the current working directory
|
|
3492
|
-
cwd_file_path = Util.get_certora_sources_dir() / cwd_rel_in_sources / Util.CWD_FILE
|
|
3524
|
+
cwd_file_path = Util.get_certora_sources_dir() / context.cwd_rel_in_sources / Util.CWD_FILE
|
|
3493
3525
|
cwd_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
3494
3526
|
cwd_file_path.touch()
|
|
3495
3527
|
|
|
@@ -3498,7 +3530,7 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3498
3530
|
if rust_proj_dir:
|
|
3499
3531
|
proj_dir_parent_relative = os.path.relpath(rust_proj_dir, os.getcwd())
|
|
3500
3532
|
assert Path(rust_proj_dir).is_dir(), f"build_source_tree: not a directory {rust_proj_dir}"
|
|
3501
|
-
proj_dir_parent_file = (Util.get_certora_sources_dir() / cwd_rel_in_sources / proj_dir_parent_relative /
|
|
3533
|
+
proj_dir_parent_file = (Util.get_certora_sources_dir() / context.cwd_rel_in_sources / proj_dir_parent_relative /
|
|
3502
3534
|
Util.PROJECT_DIR_FILE)
|
|
3503
3535
|
proj_dir_parent_file.parent.mkdir(parents=True, exist_ok=True)
|
|
3504
3536
|
proj_dir_parent_file.touch()
|
|
@@ -3514,9 +3546,6 @@ def build_source_tree(sources: Set[Path], context: CertoraContext, overwrite: bo
|
|
|
3514
3546
|
build_logger.debug("Couldn't copy repro conf to certora sources.", exc_info=e)
|
|
3515
3547
|
raise
|
|
3516
3548
|
|
|
3517
|
-
return cwd_rel_in_sources
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
3549
|
def build_from_scratch(certora_build_generator: CertoraBuildGenerator,
|
|
3521
3550
|
certora_verify_generator: CertoraVerifyGenerator,
|
|
3522
3551
|
build_cache_enabled: bool) -> CachedFiles:
|
|
@@ -3659,8 +3688,7 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3659
3688
|
|
|
3660
3689
|
# Start by syntax checking, if we're in the right mode
|
|
3661
3690
|
if Cv.mode_has_spec_file(context) and not context.build_only and not ignore_spec_syntax_check:
|
|
3662
|
-
|
|
3663
|
-
if attr:
|
|
3691
|
+
if context.disable_local_typechecking:
|
|
3664
3692
|
build_logger.warning(
|
|
3665
3693
|
"Local checks of CVL specification files disabled. It is recommended to enable the checks.")
|
|
3666
3694
|
else:
|
|
@@ -3673,6 +3701,11 @@ def build(context: CertoraContext, ignore_spec_syntax_check: bool = False) -> No
|
|
|
3673
3701
|
certora_verify_generator,
|
|
3674
3702
|
certora_build_cache_manager)
|
|
3675
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
|
+
|
|
3676
3709
|
# .certora_verify.json is always constructed even if build cache is enabled
|
|
3677
3710
|
# Sources construction should only happen when rebuilding
|
|
3678
3711
|
# Build sources tree
|
|
@@ -107,7 +107,8 @@ class ContractInSDC:
|
|
|
107
107
|
extension_contracts: List[ContractExtension],
|
|
108
108
|
local_assignments: Dict[str, UnspecializedSourceFinder],
|
|
109
109
|
branches: Dict[str, UnspecializedSourceFinder],
|
|
110
|
-
requires: Dict[str, UnspecializedSourceFinder]
|
|
110
|
+
requires: Dict[str, UnspecializedSourceFinder],
|
|
111
|
+
internal_starts: List[int]
|
|
111
112
|
):
|
|
112
113
|
self.name = name
|
|
113
114
|
self.original_file = source_file
|
|
@@ -139,6 +140,7 @@ class ContractInSDC:
|
|
|
139
140
|
self.original_file_name = Path(source_file).name
|
|
140
141
|
self.compiler_collector = compiler_collector
|
|
141
142
|
self.compiler_parameters = compiler_parameters
|
|
143
|
+
self.internal_starts = internal_starts
|
|
142
144
|
|
|
143
145
|
if not self.compiler_collector:
|
|
144
146
|
compiler_version = ""
|
|
@@ -193,7 +195,8 @@ class ContractInSDC:
|
|
|
193
195
|
"compilerParameters": None if not self.compiler_parameters else self.compiler_parameters.as_dict(),
|
|
194
196
|
"sourceBytes": None if self.source_bytes is None else self.source_bytes.as_dict(),
|
|
195
197
|
"extensionContracts": [e.as_dict() for e in self.extension_contracts],
|
|
196
|
-
"localAssignments": {k: v.as_dict() for k, v in self.local_assignments.items()}
|
|
198
|
+
"localAssignments": {k: v.as_dict() for k, v in self.local_assignments.items()},
|
|
199
|
+
"internalFunctionStarts": self.internal_starts
|
|
197
200
|
}
|
|
198
201
|
# "sourceHints": {"localAssignments": {k: v.as_dict() for k, v in self.local_assignments.items()},
|
|
199
202
|
# "branches": {k: v.as_dict() for k, v in self.branches.items()},
|
|
@@ -218,12 +221,24 @@ class ContractInSDC:
|
|
|
218
221
|
"localAssignments": {k: v.as_dict() for k, v in self.local_assignments.items()}
|
|
219
222
|
}
|
|
220
223
|
|
|
221
|
-
def find_method(self, name: str) -> Optional[Func]:
|
|
224
|
+
def find_method(self, name: str, fullArgs: List[CT.TypeInstance]) -> Optional[Func]:
|
|
225
|
+
"""
|
|
226
|
+
attempts to find and return a matching method. from Solidity documentation,
|
|
227
|
+
the combination of the method name and (ordered) parameter types
|
|
228
|
+
is sufficient to disambiguate method overloading.
|
|
229
|
+
"""
|
|
222
230
|
for method in self.methods:
|
|
223
231
|
if method.name == name:
|
|
224
|
-
|
|
232
|
+
if Util.eq_by(CT.TypeInstance.matches, method.fullArgs, fullArgs):
|
|
233
|
+
return method
|
|
225
234
|
return None
|
|
226
235
|
|
|
236
|
+
def has_method_with_name(self, name: str) -> bool:
|
|
237
|
+
for method in self.methods:
|
|
238
|
+
if method.name == name:
|
|
239
|
+
return True
|
|
240
|
+
return False
|
|
241
|
+
|
|
227
242
|
def __repr__(self) -> str:
|
|
228
243
|
return repr(self.as_printable_dict())
|
|
229
244
|
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# The Certora Prover
|
|
2
|
+
# Copyright (C) 2025 Certora Ltd.
|
|
3
|
+
#
|
|
4
|
+
# This program is free software: you can redistribute it and/or modify
|
|
5
|
+
# it under the terms of the GNU General Public License as published by
|
|
6
|
+
# the Free Software Foundation, version 3 of the License.
|
|
7
|
+
#
|
|
8
|
+
# This program is distributed in the hope that it will be useful,
|
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
11
|
+
# GNU General Public License for more details.
|
|
12
|
+
#
|
|
13
|
+
# You should have received a copy of the GNU General Public License
|
|
14
|
+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
15
|
+
|
|
16
|
+
import glob
|
|
17
|
+
import shutil
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
from typing import Set, List
|
|
20
|
+
|
|
21
|
+
from CertoraProver.certoraBuild import build_source_tree
|
|
22
|
+
from CertoraProver.certoraContextClass import CertoraContext
|
|
23
|
+
from CertoraProver.certoraParseBuildScript import run_rust_build
|
|
24
|
+
import CertoraProver.certoraContextAttributes as Attrs
|
|
25
|
+
from Shared import certoraUtils as Util
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def build_rust_app(context: CertoraContext) -> None:
|
|
29
|
+
build_command: List[str] = []
|
|
30
|
+
feature_flag = None
|
|
31
|
+
if context.build_script:
|
|
32
|
+
build_command = [context.build_script]
|
|
33
|
+
feature_flag = '--cargo_features'
|
|
34
|
+
|
|
35
|
+
elif not context.files:
|
|
36
|
+
build_command = ["cargo", "certora-sbf"]
|
|
37
|
+
feature_flag = '--features'
|
|
38
|
+
if context.cargo_tools_version:
|
|
39
|
+
build_command.append("--tools-version")
|
|
40
|
+
build_command.append(context.cargo_tools_version)
|
|
41
|
+
|
|
42
|
+
if build_command:
|
|
43
|
+
if context.cargo_features is not None:
|
|
44
|
+
build_command.extend([feature_flag] + context.cargo_features)
|
|
45
|
+
|
|
46
|
+
build_command.extend(['--json', '-l'])
|
|
47
|
+
|
|
48
|
+
if context.test == str(Util.TestValue.SOLANA_BUILD_CMD):
|
|
49
|
+
raise Util.TestResultsReady(build_command)
|
|
50
|
+
|
|
51
|
+
run_rust_build(context, build_command)
|
|
52
|
+
|
|
53
|
+
else:
|
|
54
|
+
if not context.files:
|
|
55
|
+
raise Util.CertoraUserInputError("'files' or 'build_script' must be set for Rust projects")
|
|
56
|
+
if len(context.files) > 1:
|
|
57
|
+
raise Util.CertoraUserInputError("Rust projects must specify exactly one executable in 'files'.")
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
Util.get_certora_sources_dir().mkdir(parents=True, exist_ok=True)
|
|
61
|
+
shutil.copy(Util.get_last_conf_file(), Util.get_certora_sources_dir() / Util.LAST_CONF_FILE)
|
|
62
|
+
except Exception as e:
|
|
63
|
+
raise Util.CertoraUserInputError(f"Collecting build files failed with the exception: {e}")
|
|
64
|
+
|
|
65
|
+
copy_files_to_build_dir(context)
|
|
66
|
+
|
|
67
|
+
sources: Set[Path] = set()
|
|
68
|
+
collect_files_from_rust_sources(context, sources)
|
|
69
|
+
|
|
70
|
+
try:
|
|
71
|
+
# Create generators
|
|
72
|
+
build_source_tree(sources, context)
|
|
73
|
+
|
|
74
|
+
except Exception as e:
|
|
75
|
+
raise Util.CertoraUserInputError(f"Collecting build files failed with the exception: {e}")
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def add_solana_files_from_prover_args(context: CertoraContext) -> None:
|
|
79
|
+
if context.prover_args:
|
|
80
|
+
inlining_file = False
|
|
81
|
+
summaries_file = False
|
|
82
|
+
for prover_arg in context.prover_args:
|
|
83
|
+
for arg in prover_arg.split(' '):
|
|
84
|
+
if inlining_file:
|
|
85
|
+
context.solana_inlining = context.solana_inlining or [Path(arg)]
|
|
86
|
+
inlining_file = False
|
|
87
|
+
if summaries_file:
|
|
88
|
+
context.solana_summaries = context.solana_summaries or [Path(arg)]
|
|
89
|
+
summaries_file = False
|
|
90
|
+
|
|
91
|
+
if arg == '-solanaInlining':
|
|
92
|
+
inlining_file = True
|
|
93
|
+
elif arg == '-solanaSummaries':
|
|
94
|
+
summaries_file = True
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def add_solana_files_to_sources(context: CertoraContext, sources: Set[Path]) -> None:
|
|
98
|
+
for attr in [Attrs.SolanaProverAttributes.SOLANA_INLINING,
|
|
99
|
+
Attrs.SolanaProverAttributes.SOLANA_SUMMARIES,
|
|
100
|
+
Attrs.SolanaProverAttributes.BUILD_SCRIPT,
|
|
101
|
+
Attrs.SolanaProverAttributes.FILES]:
|
|
102
|
+
attr_name = attr.get_conf_key()
|
|
103
|
+
attr_value = getattr(context, attr_name, None)
|
|
104
|
+
if not attr_value:
|
|
105
|
+
continue
|
|
106
|
+
if isinstance(attr_value, str):
|
|
107
|
+
attr_value = [attr_value]
|
|
108
|
+
if not isinstance(attr_value, list):
|
|
109
|
+
raise Util.CertoraUserInputError(f"{attr_value} is not a valid value for {attr_name} {attr_value}. Value "
|
|
110
|
+
f"must be a string or a llist ")
|
|
111
|
+
file_paths = [Path(s) for s in attr_value]
|
|
112
|
+
for file_path in file_paths:
|
|
113
|
+
if not file_path.exists():
|
|
114
|
+
raise Util.CertoraUserInputError(f"in {attr_name} file {file_path} does not exist")
|
|
115
|
+
sources.add(file_path.absolute().resolve())
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def collect_files_from_rust_sources(context: CertoraContext, sources: Set[Path]) -> None:
|
|
119
|
+
patterns = ["*.rs", "*.so", "*.wasm", "Cargo.toml", "Cargo.lock", "justfile"]
|
|
120
|
+
exclude_dirs = [".certora_internal"]
|
|
121
|
+
|
|
122
|
+
if hasattr(context, 'rust_project_directory'):
|
|
123
|
+
project_directory = Path(context.rust_project_directory)
|
|
124
|
+
|
|
125
|
+
if not project_directory.is_dir():
|
|
126
|
+
raise ValueError(f"The given directory '{project_directory}' is not valid.")
|
|
127
|
+
|
|
128
|
+
for source in context.rust_sources:
|
|
129
|
+
for file in glob.glob(f'{project_directory.joinpath(source)}', recursive=True):
|
|
130
|
+
file_path = Path(file)
|
|
131
|
+
if any(excluded in file_path.parts for excluded in exclude_dirs):
|
|
132
|
+
continue
|
|
133
|
+
if file_path.is_file() and any(file_path.match(pattern) for pattern in patterns):
|
|
134
|
+
sources.add(file_path)
|
|
135
|
+
|
|
136
|
+
sources.add(project_directory.absolute())
|
|
137
|
+
if Path(context.build_script).exists():
|
|
138
|
+
sources.add(Path(context.build_script).resolve())
|
|
139
|
+
if getattr(context, 'conf_file', None) and Path(context.conf_file).exists():
|
|
140
|
+
sources.add(Path(context.conf_file).absolute())
|
|
141
|
+
|
|
142
|
+
add_solana_files_from_prover_args(context)
|
|
143
|
+
add_solana_files_to_sources(context, sources)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def copy_files_to_build_dir(context: CertoraContext) -> None:
|
|
147
|
+
assert context.files, "copy_files_to_build_dir: expecting files to be non-empty"
|
|
148
|
+
shutil.copyfile(context.files[0], Util.get_build_dir() / Path(context.files[0]).name)
|
|
149
|
+
|
|
150
|
+
if rust_logs := getattr(context, 'rust_logs_stdout', None):
|
|
151
|
+
shutil.copy(Path(rust_logs), Util.get_build_dir() / Path(rust_logs).name)
|
|
152
|
+
if rust_logs := getattr(context, 'rust_logs_stderr', None):
|
|
153
|
+
shutil.copy(Path(rust_logs), Util.get_build_dir() / Path(rust_logs).name)
|