certora-cli-beta-mirror 7.28.0__py3-none-any.whl → 8.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +10 -3
- certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +51 -16
- certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
- certora_cli/CertoraProver/castingInstrumenter.py +192 -0
- certora_cli/CertoraProver/certoraApp.py +52 -0
- certora_cli/CertoraProver/certoraBuild.py +694 -207
- certora_cli/CertoraProver/certoraBuildCacheManager.py +21 -17
- certora_cli/CertoraProver/certoraBuildDataClasses.py +8 -2
- certora_cli/CertoraProver/certoraBuildRust.py +88 -54
- certora_cli/CertoraProver/certoraBuildSui.py +112 -0
- certora_cli/CertoraProver/certoraCloudIO.py +97 -96
- certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +230 -84
- certora_cli/CertoraProver/certoraCollectRunMetadata.py +52 -6
- certora_cli/CertoraProver/certoraCompilerParameters.py +11 -0
- certora_cli/CertoraProver/certoraConfigIO.py +43 -35
- certora_cli/CertoraProver/certoraContext.py +128 -54
- certora_cli/CertoraProver/certoraContextAttributes.py +415 -234
- certora_cli/CertoraProver/certoraContextValidator.py +152 -105
- certora_cli/CertoraProver/certoraContractFuncs.py +34 -1
- certora_cli/CertoraProver/certoraParseBuildScript.py +8 -10
- certora_cli/CertoraProver/certoraType.py +10 -1
- certora_cli/CertoraProver/certoraVerifyGenerator.py +22 -4
- certora_cli/CertoraProver/erc7201.py +45 -0
- certora_cli/CertoraProver/splitRules.py +23 -18
- certora_cli/CertoraProver/storageExtension.py +351 -0
- certora_cli/EquivalenceCheck/Eq_default.conf +0 -1
- certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -1
- certora_cli/EquivalenceCheck/equivCheck.py +2 -1
- certora_cli/Mutate/mutateApp.py +41 -22
- certora_cli/Mutate/mutateAttributes.py +11 -0
- certora_cli/Mutate/mutateValidate.py +42 -2
- certora_cli/Shared/certoraAttrUtil.py +21 -5
- certora_cli/Shared/certoraUtils.py +180 -60
- certora_cli/Shared/certoraValidateFuncs.py +68 -26
- certora_cli/Shared/proverCommon.py +308 -0
- certora_cli/certoraCVLFormatter.py +76 -0
- certora_cli/certoraConcord.py +39 -0
- certora_cli/certoraEVMProver.py +4 -3
- certora_cli/certoraRanger.py +39 -0
- certora_cli/certoraRun.py +83 -223
- certora_cli/certoraSolanaProver.py +40 -128
- certora_cli/certoraSorobanProver.py +59 -4
- certora_cli/certoraSuiProver.py +93 -0
- certora_cli_beta_mirror-8.5.0.dist-info/LICENSE +15 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/METADATA +21 -5
- certora_cli_beta_mirror-8.5.0.dist-info/RECORD +81 -0
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/WHEEL +1 -1
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/entry_points.txt +3 -0
- certora_jars/ASTExtraction.jar +0 -0
- certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
- certora_jars/Typechecker.jar +0 -0
- certora_cli_beta_mirror-7.28.0.dist-info/LICENSE +0 -22
- certora_cli_beta_mirror-7.28.0.dist-info/RECORD +0 -70
- {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
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/>.
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
import sys
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
|
|
21
|
+
scripts_dir_path = Path(__file__).parent.resolve() # containing directory
|
|
22
|
+
sys.path.insert(0, str(scripts_dir_path))
|
|
23
|
+
|
|
24
|
+
import CertoraProver.certoraApp as App
|
|
25
|
+
from certoraRun import run_certora
|
|
26
|
+
from Shared.proverCommon import CertoraRunResult, catch_exits
|
|
27
|
+
|
|
28
|
+
from typing import List, Optional
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def run_ranger(args: List[str]) -> Optional[CertoraRunResult]:
|
|
32
|
+
return run_certora(args, App.RangerApp, prover_cmd=sys.argv[0])
|
|
33
|
+
|
|
34
|
+
@catch_exits
|
|
35
|
+
def entry_point() -> None:
|
|
36
|
+
run_ranger(sys.argv[1:])
|
|
37
|
+
|
|
38
|
+
if __name__ == '__main__':
|
|
39
|
+
entry_point()
|
certora_cli/certoraRun.py
CHANGED
|
@@ -17,58 +17,41 @@
|
|
|
17
17
|
import sys
|
|
18
18
|
import time
|
|
19
19
|
import logging
|
|
20
|
-
from dataclasses import dataclass
|
|
21
20
|
from typing import List, Optional, Type
|
|
22
21
|
from pathlib import Path
|
|
23
|
-
from rich.console import Console
|
|
24
22
|
|
|
25
23
|
scripts_dir_path = Path(__file__).parent.resolve() # containing directory
|
|
26
24
|
sys.path.insert(0, str(scripts_dir_path))
|
|
27
25
|
from Shared import certoraUtils as Util
|
|
28
26
|
|
|
29
|
-
from CertoraProver.certoraCloudIO import CloudVerification
|
|
27
|
+
from CertoraProver.certoraCloudIO import CloudVerification
|
|
30
28
|
|
|
31
|
-
from CertoraProver.certoraCollectRunMetadata import collect_run_metadata
|
|
32
|
-
from CertoraProver.certoraCollectConfigurationLayout import collect_configuration_layout
|
|
33
|
-
from Shared.certoraLogging import LoggingManager
|
|
34
29
|
from CertoraProver.certoraBuild import build
|
|
35
|
-
from CertoraProver.certoraBuildRust import build_rust_app
|
|
36
30
|
import CertoraProver.certoraContext as Ctx
|
|
31
|
+
import CertoraProver.certoraApp as App
|
|
37
32
|
|
|
38
33
|
from CertoraProver import certoraContextValidator as Cv
|
|
39
|
-
|
|
40
|
-
from Shared import
|
|
34
|
+
|
|
35
|
+
from Shared.proverCommon import (
|
|
36
|
+
build_context,
|
|
37
|
+
collect_and_dump_metadata,
|
|
38
|
+
collect_and_dump_config_layout,
|
|
39
|
+
ensure_version_compatibility,
|
|
40
|
+
run_local,
|
|
41
|
+
run_remote,
|
|
42
|
+
CertoraRunResult,
|
|
43
|
+
handle_exit,
|
|
44
|
+
catch_exits
|
|
45
|
+
)
|
|
41
46
|
import CertoraProver.splitRules as splitRules
|
|
42
47
|
|
|
43
48
|
BUILD_SCRIPT_PATH = Path("CertoraProver/certoraBuild.py")
|
|
44
|
-
VIOLATIONS_EXIT_CODE = 100
|
|
45
49
|
|
|
46
50
|
# logger for issues regarding the general run flow.
|
|
47
51
|
# Also serves as the default logger for errors originating from unexpected places.
|
|
48
52
|
run_logger = logging.getLogger("run")
|
|
49
53
|
|
|
50
|
-
|
|
51
|
-
@dataclass
|
|
52
|
-
class CertoraRunResult:
|
|
53
|
-
link: Optional[str] # Path to emv_dir if running locally, or the link to the job status page
|
|
54
|
-
is_local_link: bool
|
|
55
|
-
src_dir: Path
|
|
56
|
-
rule_report_link: Optional[str]
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class CertoraFoundViolations(Exception):
|
|
60
|
-
def __init__(self, message: str, results: Optional[CertoraRunResult] = None) -> None:
|
|
61
|
-
super().__init__(message)
|
|
62
|
-
self.results = results
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class ExitException(Exception):
|
|
66
|
-
def __init__(self, message: str, exit_code: int):
|
|
67
|
-
super().__init__(message)
|
|
68
|
-
self.exit_code = exit_code # Store the integer data
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
def run_certora(args: List[str], attrs_class: Optional[Type[AttrUtil.Attributes]] = None,
|
|
54
|
+
def run_certora(args: List[str], app: Type[App.CertoraApp] = App.EvmApp,
|
|
72
55
|
prover_cmd: Optional[str] = None) -> Optional[CertoraRunResult]:
|
|
73
56
|
"""
|
|
74
57
|
The main function that is responsible for the general flow of the script.
|
|
@@ -77,186 +60,93 @@ def run_certora(args: List[str], attrs_class: Optional[Type[AttrUtil.Attributes]
|
|
|
77
60
|
2. Run the necessary steps (type checking/ build/ cloud verification/ local verification)
|
|
78
61
|
|
|
79
62
|
"""
|
|
63
|
+
context, logging_manager = build_context(args, app)
|
|
80
64
|
|
|
81
|
-
non_str_els = [x for x in args if not isinstance(x, str)]
|
|
82
|
-
if non_str_els:
|
|
83
|
-
print(f"args for run_certora that are not strings: {non_str_els}")
|
|
84
|
-
exit(1)
|
|
85
|
-
|
|
86
|
-
# If we are not in debug mode, we do not want to print the traceback in case of exceptions.
|
|
87
|
-
if '--debug' not in args: # We check manually, because we want no traceback in argument parsing exceptions
|
|
88
|
-
sys.tracebacklimit = 0
|
|
89
|
-
|
|
90
|
-
# creating the default internal dir, files may be copied to user defined build directory after
|
|
91
|
-
# parsing the input
|
|
92
|
-
|
|
93
|
-
if not ('--help' in args or '--version' in args):
|
|
94
|
-
Util.reset_certora_internal_dir()
|
|
95
|
-
Util.safe_create_dir(Util.get_build_dir())
|
|
96
|
-
logging_manager = LoggingManager()
|
|
97
|
-
|
|
98
|
-
if not attrs_class:
|
|
99
|
-
attrs_class = Attrs.detect_application_class(args)
|
|
100
|
-
Attrs.set_attribute_class(attrs_class)
|
|
101
|
-
|
|
102
|
-
Ctx.handle_flags_in_args(args)
|
|
103
|
-
context = Ctx.get_args(args) # Parse arguments
|
|
104
65
|
if prover_cmd:
|
|
105
66
|
context.prover_cmd = prover_cmd
|
|
106
|
-
assert logging_manager, "logging manager was not set"
|
|
107
|
-
logging_manager.set_log_level_and_format(is_quiet=Ctx.is_minimal_cli_output(context),
|
|
108
|
-
debug=context.debug,
|
|
109
|
-
debug_topics=context.debug_topics,
|
|
110
|
-
show_debug_topics=context.show_debug_topics)
|
|
111
67
|
|
|
112
68
|
timings = {}
|
|
113
69
|
exit_code = 0 # The exit code of the script. 0 means success, any other number is an error.
|
|
114
70
|
return_value = None
|
|
115
71
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
raise Util.TestResultsReady(metadata)
|
|
121
|
-
metadata.dump()
|
|
122
|
-
|
|
123
|
-
configuration_layout = collect_configuration_layout()
|
|
124
|
-
|
|
125
|
-
if context.test == str(Util.TestValue.CHECK_CONFIG_LAYOUT):
|
|
126
|
-
raise Util.TestResultsReady(configuration_layout)
|
|
127
|
-
configuration_layout.dump()
|
|
72
|
+
# Collect and validate metadata
|
|
73
|
+
collect_and_dump_metadata(context)
|
|
74
|
+
# Collect and dump configuration layout
|
|
75
|
+
collect_and_dump_config_layout(context)
|
|
128
76
|
|
|
129
|
-
if
|
|
77
|
+
if context.split_rules:
|
|
130
78
|
context.build_only = True
|
|
131
79
|
build(context)
|
|
132
80
|
context.build_only = False
|
|
133
81
|
rule_handler = splitRules.SplitRulesHandler(context)
|
|
134
82
|
exit_code = rule_handler.generate_runs()
|
|
135
|
-
CloudVerification(context)
|
|
136
|
-
|
|
83
|
+
cv = CloudVerification(context)
|
|
84
|
+
cv.print_group_id_url()
|
|
85
|
+
if exit_code == 0:
|
|
86
|
+
print("Split rules succeeded")
|
|
87
|
+
return_value = CertoraRunResult(
|
|
88
|
+
cv.get_group_id_url(),
|
|
89
|
+
False,
|
|
90
|
+
Util.get_certora_sources_dir(),
|
|
91
|
+
cv.get_group_id_url(),
|
|
92
|
+
)
|
|
93
|
+
return handle_exit(exit_code, return_value)
|
|
94
|
+
else:
|
|
95
|
+
raise Util.ExitException("Split rules failed", exit_code)
|
|
137
96
|
|
|
138
|
-
|
|
139
|
-
|
|
97
|
+
# Version validation
|
|
98
|
+
ensure_version_compatibility(context)
|
|
140
99
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
100
|
+
# When a TAC file is provided, no build arguments will be processed
|
|
101
|
+
if not context.is_tac:
|
|
102
|
+
run_logger.debug(f"There is no TAC file. Going to script {BUILD_SCRIPT_PATH} to main_with_args()")
|
|
103
|
+
build_start = time.perf_counter()
|
|
144
104
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
105
|
+
# If we are not in CI, we also check the spec for Syntax errors.
|
|
106
|
+
build(context)
|
|
107
|
+
build_end = time.perf_counter()
|
|
108
|
+
|
|
109
|
+
timings["buildTime"] = round(build_end - build_start, 4)
|
|
110
|
+
if context.test == str(Util.TestValue.AFTER_BUILD):
|
|
111
|
+
raise Util.TestResultsReady(context)
|
|
112
|
+
|
|
113
|
+
if context.build_only:
|
|
114
|
+
return return_value
|
|
115
|
+
|
|
116
|
+
# either we skipped building (TAC MODE) or build succeeded
|
|
117
|
+
if context.local:
|
|
118
|
+
compare_with_expected_file = Path(context.expected_file).exists()
|
|
119
|
+
|
|
120
|
+
run_result = run_local(context, timings, compare_with_expected_file=compare_with_expected_file)
|
|
121
|
+
emv_dir = latest_emv_dir()
|
|
122
|
+
return_value = CertoraRunResult(str(emv_dir) if emv_dir else None, True,
|
|
123
|
+
Util.get_certora_sources_dir(), None)
|
|
124
|
+
if run_result != 0:
|
|
125
|
+
exit_code = run_result
|
|
126
|
+
elif compare_with_expected_file:
|
|
127
|
+
print("Comparing tool output to the expected output:")
|
|
128
|
+
output_path = context.tool_output or (
|
|
129
|
+
'tmpOutput.json' if emv_dir is None else
|
|
130
|
+
str(emv_dir / 'Reports/output.json')
|
|
131
|
+
)
|
|
132
|
+
result = Util.check_results_from_file(output_path, context.expected_file)
|
|
167
133
|
if not result:
|
|
168
134
|
exit_code = 1
|
|
169
|
-
else:
|
|
170
|
-
|
|
171
|
-
if
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
"""
|
|
178
|
-
validate_version_and_branch(context)
|
|
179
|
-
|
|
180
|
-
# When a TAC file is provided, no build arguments will be processed
|
|
181
|
-
if not context.is_tac:
|
|
182
|
-
run_logger.debug(f"There is no TAC file. Going to script {BUILD_SCRIPT_PATH} to main_with_args()")
|
|
183
|
-
build_start = time.perf_counter()
|
|
184
|
-
|
|
185
|
-
# If we are not in CI, we also check the spec for Syntax errors.
|
|
186
|
-
build(context, ignore_spec_syntax_check=False)
|
|
187
|
-
build_end = time.perf_counter()
|
|
188
|
-
|
|
189
|
-
timings["buildTime"] = round(build_end - build_start, 4)
|
|
190
|
-
if context.test == str(Util.TestValue.AFTER_BUILD):
|
|
191
|
-
raise Util.TestResultsReady(context)
|
|
135
|
+
else: # Remote run
|
|
136
|
+
# Syntax checking and typechecking
|
|
137
|
+
if Cv.mode_has_spec_file(context):
|
|
138
|
+
if Ctx.should_run_local_speck_check(context):
|
|
139
|
+
typechecking_start = time.perf_counter()
|
|
140
|
+
Ctx.run_local_spec_check(True, context)
|
|
141
|
+
typechecking_end = time.perf_counter()
|
|
142
|
+
timings['typecheckingTime'] = round(typechecking_end - typechecking_start, 4)
|
|
192
143
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
compare_with_expected_file = Path(context.expected_file).exists()
|
|
144
|
+
# Remove debug logger and run remote verification
|
|
145
|
+
logging_manager.remove_debug_logger()
|
|
146
|
+
exit_code, return_value = run_remote(context, args, timings)
|
|
197
147
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
# In local mode, this is reserved for Certora devs, so let the script print it
|
|
201
|
-
print(f"Verifier run command:\n {' '.join(check_cmd)}", flush=True)
|
|
202
|
-
run_result = \
|
|
203
|
-
Util.run_jar_cmd(check_cmd, compare_with_expected_file,
|
|
204
|
-
logger_topic="verification", print_output=True)
|
|
205
|
-
emv_dir = latest_emv_dir()
|
|
206
|
-
return_value = CertoraRunResult(str(emv_dir) if emv_dir else None, True,
|
|
207
|
-
Util.get_certora_sources_dir(), None)
|
|
208
|
-
if run_result != 0:
|
|
209
|
-
exit_code = run_result
|
|
210
|
-
else:
|
|
211
|
-
Util.print_completion_message("Finished running verifier:")
|
|
212
|
-
print(f"\t{check_cmd}")
|
|
213
|
-
if compare_with_expected_file:
|
|
214
|
-
print("Comparing tool output to the expected output:")
|
|
215
|
-
output_path = (context.tool_output if context.tool_output else
|
|
216
|
-
('tmpOutput.json' if emv_dir is None
|
|
217
|
-
else str(emv_dir / 'Reports/output.json')))
|
|
218
|
-
result = Util.check_results_from_file(output_path, context.expected_file)
|
|
219
|
-
if not result:
|
|
220
|
-
exit_code = 1
|
|
221
|
-
else: # Remote run
|
|
222
|
-
# Syntax checking and typechecking
|
|
223
|
-
if Cv.mode_has_spec_file(context):
|
|
224
|
-
if context.disable_local_typechecking:
|
|
225
|
-
run_logger.warning(
|
|
226
|
-
"Local checks of CVL specification files disabled. It is recommended to enable "
|
|
227
|
-
"the checks.")
|
|
228
|
-
else:
|
|
229
|
-
typechecking_start = time.perf_counter()
|
|
230
|
-
Ctx.run_local_spec_check(True, context)
|
|
231
|
-
typechecking_end = time.perf_counter()
|
|
232
|
-
timings['typecheckingTime'] = round(typechecking_end - typechecking_start, 4)
|
|
233
|
-
|
|
234
|
-
if exit_code == 0:
|
|
235
|
-
if context.compilation_steps_only:
|
|
236
|
-
# Give a non-None value for the overall result, but with links set to None
|
|
237
|
-
return_value = CertoraRunResult(None, False, Util.get_certora_sources_dir(), None)
|
|
238
|
-
else:
|
|
239
|
-
# typechecking either succeeded or skipped
|
|
240
|
-
|
|
241
|
-
context.key = Cv.validate_certora_key()
|
|
242
|
-
cloud_verifier = CloudVerification(context, timings)
|
|
243
|
-
|
|
244
|
-
# Wrap strings with space with ' so it can be copied and pasted to shell
|
|
245
|
-
pretty_args = [f"'{arg}'" if ' ' in arg else arg for arg in args]
|
|
246
|
-
cl_args = ' '.join(pretty_args)
|
|
247
|
-
|
|
248
|
-
logging_manager.remove_debug_logger()
|
|
249
|
-
if not cloud_verifier.cli_verify_and_report(cl_args, context.wait_for_results):
|
|
250
|
-
exit_code = VIOLATIONS_EXIT_CODE
|
|
251
|
-
if cloud_verifier.statusUrl:
|
|
252
|
-
return_value = CertoraRunResult(cloud_verifier.statusUrl, False,
|
|
253
|
-
Util.get_certora_sources_dir(), cloud_verifier.reportUrl)
|
|
254
|
-
|
|
255
|
-
if exit_code == VIOLATIONS_EXIT_CODE:
|
|
256
|
-
raise CertoraFoundViolations("violations were found", return_value)
|
|
257
|
-
if exit_code != 0:
|
|
258
|
-
raise Util.CertoraUserInputError(f"run_certora failed (code {exit_code})")
|
|
259
|
-
return return_value
|
|
148
|
+
# Handle exit codes and return
|
|
149
|
+
return handle_exit(exit_code, return_value)
|
|
260
150
|
|
|
261
151
|
|
|
262
152
|
def latest_emv_dir() -> Optional[Path]:
|
|
@@ -279,43 +169,13 @@ def latest_emv_dir() -> Optional[Path]:
|
|
|
279
169
|
return max
|
|
280
170
|
|
|
281
171
|
|
|
172
|
+
@catch_exits
|
|
282
173
|
def entry_point() -> None:
|
|
283
174
|
"""
|
|
284
175
|
This function is the entry point of the certora_cli customer-facing package, as well as this script.
|
|
285
176
|
It is important this function gets no arguments!
|
|
286
177
|
"""
|
|
287
|
-
|
|
288
|
-
run_certora(sys.argv[1:], prover_cmd=sys.argv[0])
|
|
289
|
-
sys.exit(0)
|
|
290
|
-
except KeyboardInterrupt:
|
|
291
|
-
Console().print("[bold red]\nInterrupted by user")
|
|
292
|
-
sys.exit(1)
|
|
293
|
-
except Util.TestResultsReady:
|
|
294
|
-
print("reached checkpoint")
|
|
295
|
-
sys.exit(0)
|
|
296
|
-
except CertoraFoundViolations as e:
|
|
297
|
-
try:
|
|
298
|
-
assert e.results
|
|
299
|
-
print(f"report url: {e.results.rule_report_link}")
|
|
300
|
-
except Exception:
|
|
301
|
-
pass
|
|
302
|
-
Console().print("[bold red]\nViolations were found\n")
|
|
303
|
-
sys.exit(1)
|
|
304
|
-
except Util.CertoraUserInputError as e:
|
|
305
|
-
if e.orig:
|
|
306
|
-
print(f"\n{str(e.orig).strip()}")
|
|
307
|
-
if e.more_info:
|
|
308
|
-
print(f"\n{e.more_info.strip()}")
|
|
309
|
-
Console().print(f"[bold red]\n{e}\n")
|
|
310
|
-
sys.exit(1)
|
|
311
|
-
|
|
312
|
-
except ExitException as e:
|
|
313
|
-
Console().print(f"[bold red]{e}")
|
|
314
|
-
sys.exit(e.exit_code)
|
|
315
|
-
|
|
316
|
-
except Exception as e:
|
|
317
|
-
Console().print(f"[bold red]{e}")
|
|
318
|
-
sys.exit(1)
|
|
178
|
+
run_certora(sys.argv[1:], prover_cmd=sys.argv[0])
|
|
319
179
|
|
|
320
180
|
|
|
321
181
|
if __name__ == '__main__':
|
|
@@ -16,28 +16,27 @@
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
import sys
|
|
19
|
-
import time
|
|
20
19
|
import logging
|
|
21
|
-
from typing import List, Optional
|
|
20
|
+
from typing import List, Optional, Dict
|
|
22
21
|
from pathlib import Path
|
|
23
|
-
from rich.console import Console
|
|
24
22
|
|
|
25
23
|
scripts_dir_path = Path(__file__).parent.resolve() # containing directory
|
|
26
24
|
sys.path.insert(0, str(scripts_dir_path))
|
|
27
25
|
|
|
28
|
-
from Shared import certoraUtils as Util
|
|
29
|
-
from Shared.certoraLogging import LoggingManager
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
from CertoraProver.
|
|
33
|
-
from
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
27
|
+
import CertoraProver.certoraApp as App
|
|
28
|
+
from CertoraProver.certoraBuildRust import build_rust_project
|
|
29
|
+
from Shared.proverCommon import (
|
|
30
|
+
build_context,
|
|
31
|
+
collect_and_dump_metadata,
|
|
32
|
+
collect_and_dump_config_layout,
|
|
33
|
+
ensure_version_compatibility,
|
|
34
|
+
run_local,
|
|
35
|
+
run_remote,
|
|
36
|
+
CertoraRunResult,
|
|
37
|
+
handle_exit,
|
|
38
|
+
catch_exits,
|
|
39
|
+
)
|
|
41
40
|
|
|
42
41
|
# logger for issues regarding the general run flow.
|
|
43
42
|
# Also serves as the default logger for errors originating from unexpected places.
|
|
@@ -51,135 +50,48 @@ def run_solana_prover(args: List[str]) -> Optional[CertoraRunResult]:
|
|
|
51
50
|
1. Parse program arguments
|
|
52
51
|
2. Run the necessary steps (build/ cloud verification/ local verification)
|
|
53
52
|
"""
|
|
53
|
+
context, logging_manager = build_context(args, App.SolanaApp)
|
|
54
54
|
|
|
55
|
-
|
|
56
|
-
non_str_els = [x for x in args if not isinstance(x, str)]
|
|
57
|
-
if non_str_els:
|
|
58
|
-
print(f"args for run_certora that are not strings: {non_str_els}")
|
|
59
|
-
exit(1)
|
|
60
|
-
|
|
61
|
-
# If we are not in debug mode, we do not want to print the traceback in case of exceptions.
|
|
62
|
-
if '--debug' not in args: # We check manually, because we want no traceback in argument parsing exceptions
|
|
63
|
-
sys.tracebacklimit = 0
|
|
64
|
-
|
|
65
|
-
# creating the default internal dir, files may be copied to user defined build directory after
|
|
66
|
-
# parsing the input
|
|
67
|
-
|
|
68
|
-
if not ('--help' in args or '--version' in args):
|
|
69
|
-
Util.reset_certora_internal_dir()
|
|
70
|
-
Util.safe_create_dir(Util.get_build_dir())
|
|
71
|
-
logging_manager = LoggingManager()
|
|
72
|
-
|
|
73
|
-
Ctx.handle_flags_in_args(args)
|
|
74
|
-
context = Ctx.get_args(args) # Parse arguments
|
|
75
|
-
logging_manager.set_log_level_and_format(is_quiet=Ctx.is_minimal_cli_output(context),
|
|
76
|
-
debug=context.debug,
|
|
77
|
-
debug_topics=context.debug_topics,
|
|
78
|
-
show_debug_topics=context.show_debug_topics)
|
|
79
|
-
|
|
80
|
-
timings = {}
|
|
55
|
+
timings: Dict[str, float] = {}
|
|
81
56
|
exit_code = 0 # The exit code of the script. 0 means success, any other number is an error.
|
|
82
57
|
return_value = None
|
|
83
58
|
|
|
84
|
-
|
|
85
|
-
|
|
59
|
+
# Collect and validate metadata
|
|
60
|
+
collect_and_dump_metadata(context)
|
|
61
|
+
collect_and_dump_config_layout(context)
|
|
86
62
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
metadata.dump()
|
|
63
|
+
# Version validation
|
|
64
|
+
ensure_version_compatibility(context)
|
|
90
65
|
|
|
91
|
-
|
|
66
|
+
# Build Solana - If input file is .so or .o file, we skip building part
|
|
67
|
+
build_rust_project(context, timings)
|
|
92
68
|
|
|
93
|
-
if context.
|
|
94
|
-
|
|
95
|
-
configuration_layout.dump()
|
|
69
|
+
if context.build_only:
|
|
70
|
+
return return_value
|
|
96
71
|
|
|
97
|
-
if
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
72
|
+
if context.local:
|
|
73
|
+
additional_commands = []
|
|
74
|
+
if context.solana_summaries:
|
|
75
|
+
additional_commands += ["-solanaSummaries", ",".join(context.solana_summaries)]
|
|
76
|
+
if context.solana_inlining:
|
|
77
|
+
additional_commands += ["-solanaInlining", ",".join(context.solana_inlining)]
|
|
78
|
+
# Run local verification
|
|
79
|
+
exit_code = run_local(context, timings, additional_commands)
|
|
80
|
+
else:
|
|
81
|
+
logging_manager.remove_debug_logger()
|
|
82
|
+
exit_code, return_value = run_remote(context, args, timings)
|
|
102
83
|
|
|
103
|
-
#
|
|
104
|
-
|
|
105
|
-
build_start = time.perf_counter()
|
|
106
|
-
|
|
107
|
-
build_rust_app(context)
|
|
108
|
-
build_end = time.perf_counter()
|
|
109
|
-
timings["buildTime"] = round(build_end - build_start, 4)
|
|
110
|
-
if context.test == str(Util.TestValue.AFTER_BUILD):
|
|
111
|
-
raise Util.TestResultsReady(context)
|
|
112
|
-
|
|
113
|
-
if not context.build_only and exit_code == 0:
|
|
114
|
-
|
|
115
|
-
if context.local:
|
|
116
|
-
check_cmd = Ctx.get_local_run_cmd(context)
|
|
117
|
-
print(f"Verifier run command:\n {check_cmd}", flush=True)
|
|
118
|
-
|
|
119
|
-
compare_with_tool_output = False
|
|
120
|
-
run_result = Util.run_jar_cmd(check_cmd, compare_with_tool_output, logger_topic="verification",
|
|
121
|
-
print_output=True)
|
|
122
|
-
|
|
123
|
-
if run_result != 0:
|
|
124
|
-
exit_code = 1
|
|
125
|
-
else:
|
|
126
|
-
Util.print_completion_message("Finished running verifier:")
|
|
127
|
-
print(f"\t{check_cmd}")
|
|
128
|
-
else:
|
|
129
|
-
if context.compilation_steps_only:
|
|
130
|
-
# Give a non-None value for the overall result, but with links set to None
|
|
131
|
-
return_value = CertoraRunResult(None, False, Util.get_certora_sources_dir(), None)
|
|
132
|
-
else:
|
|
133
|
-
context.key = Cv.validate_certora_key()
|
|
134
|
-
cloud_verifier = CloudVerification(context, timings)
|
|
135
|
-
|
|
136
|
-
# Wrap strings with space with ' so it can be copied and pasted to shell
|
|
137
|
-
pretty_args = [f"'{arg}'" if ' ' in arg else arg for arg in args]
|
|
138
|
-
cl_args = ' '.join(pretty_args)
|
|
139
|
-
|
|
140
|
-
logging_manager.remove_debug_logger()
|
|
141
|
-
if not cloud_verifier.cli_verify_and_report(cl_args, context.wait_for_results):
|
|
142
|
-
exit_code = VIOLATIONS_EXIT_CODE
|
|
143
|
-
if cloud_verifier.statusUrl:
|
|
144
|
-
return_value = CertoraRunResult(cloud_verifier.statusUrl, False,
|
|
145
|
-
Util.get_certora_sources_dir(), cloud_verifier.reportUrl)
|
|
146
|
-
|
|
147
|
-
if exit_code == VIOLATIONS_EXIT_CODE:
|
|
148
|
-
raise CertoraFoundViolations("violations were found", return_value)
|
|
149
|
-
if exit_code != 0:
|
|
150
|
-
raise Util.CertoraUserInputError(f"run_certora failed (code {exit_code})")
|
|
151
|
-
return return_value
|
|
84
|
+
# Handle exit codes and return
|
|
85
|
+
return handle_exit(exit_code, return_value)
|
|
152
86
|
|
|
153
87
|
|
|
88
|
+
@catch_exits
|
|
154
89
|
def entry_point() -> None:
|
|
155
90
|
"""
|
|
156
91
|
This function is the entry point of the certora_cli customer-facing package, as well as this script.
|
|
157
92
|
It is important this function gets no arguments!
|
|
158
93
|
"""
|
|
159
|
-
|
|
160
|
-
run_solana_prover(sys.argv[1:])
|
|
161
|
-
sys.exit(0)
|
|
162
|
-
except KeyboardInterrupt:
|
|
163
|
-
Console().print("[bold red]\nInterrupted by user")
|
|
164
|
-
sys.exit(1)
|
|
165
|
-
except CertoraFoundViolations as e:
|
|
166
|
-
try:
|
|
167
|
-
if e.results and e.results.rule_report_link:
|
|
168
|
-
print(f"report url: {e.results.rule_report_link}")
|
|
169
|
-
except Exception:
|
|
170
|
-
pass
|
|
171
|
-
Console().print("[bold red]\nViolations were found\n")
|
|
172
|
-
sys.exit(1)
|
|
173
|
-
except Util.CertoraUserInputError as e:
|
|
174
|
-
if e.orig:
|
|
175
|
-
print(f"\n{str(e.orig).strip()}")
|
|
176
|
-
if e.more_info:
|
|
177
|
-
print(f"\n{e.more_info.strip()}")
|
|
178
|
-
Console().print(f"[bold red]\n{e}\n")
|
|
179
|
-
sys.exit(1)
|
|
180
|
-
except Exception as e:
|
|
181
|
-
Console().print(f"[bold red]{e}")
|
|
182
|
-
sys.exit(1)
|
|
94
|
+
run_solana_prover(sys.argv[1:])
|
|
183
95
|
|
|
184
96
|
|
|
185
97
|
if __name__ == '__main__':
|