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.
Files changed (54) hide show
  1. certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +10 -3
  2. certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +51 -16
  3. certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
  4. certora_cli/CertoraProver/castingInstrumenter.py +192 -0
  5. certora_cli/CertoraProver/certoraApp.py +52 -0
  6. certora_cli/CertoraProver/certoraBuild.py +694 -207
  7. certora_cli/CertoraProver/certoraBuildCacheManager.py +21 -17
  8. certora_cli/CertoraProver/certoraBuildDataClasses.py +8 -2
  9. certora_cli/CertoraProver/certoraBuildRust.py +88 -54
  10. certora_cli/CertoraProver/certoraBuildSui.py +112 -0
  11. certora_cli/CertoraProver/certoraCloudIO.py +97 -96
  12. certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +230 -84
  13. certora_cli/CertoraProver/certoraCollectRunMetadata.py +52 -6
  14. certora_cli/CertoraProver/certoraCompilerParameters.py +11 -0
  15. certora_cli/CertoraProver/certoraConfigIO.py +43 -35
  16. certora_cli/CertoraProver/certoraContext.py +128 -54
  17. certora_cli/CertoraProver/certoraContextAttributes.py +415 -234
  18. certora_cli/CertoraProver/certoraContextValidator.py +152 -105
  19. certora_cli/CertoraProver/certoraContractFuncs.py +34 -1
  20. certora_cli/CertoraProver/certoraParseBuildScript.py +8 -10
  21. certora_cli/CertoraProver/certoraType.py +10 -1
  22. certora_cli/CertoraProver/certoraVerifyGenerator.py +22 -4
  23. certora_cli/CertoraProver/erc7201.py +45 -0
  24. certora_cli/CertoraProver/splitRules.py +23 -18
  25. certora_cli/CertoraProver/storageExtension.py +351 -0
  26. certora_cli/EquivalenceCheck/Eq_default.conf +0 -1
  27. certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -1
  28. certora_cli/EquivalenceCheck/equivCheck.py +2 -1
  29. certora_cli/Mutate/mutateApp.py +41 -22
  30. certora_cli/Mutate/mutateAttributes.py +11 -0
  31. certora_cli/Mutate/mutateValidate.py +42 -2
  32. certora_cli/Shared/certoraAttrUtil.py +21 -5
  33. certora_cli/Shared/certoraUtils.py +180 -60
  34. certora_cli/Shared/certoraValidateFuncs.py +68 -26
  35. certora_cli/Shared/proverCommon.py +308 -0
  36. certora_cli/certoraCVLFormatter.py +76 -0
  37. certora_cli/certoraConcord.py +39 -0
  38. certora_cli/certoraEVMProver.py +4 -3
  39. certora_cli/certoraRanger.py +39 -0
  40. certora_cli/certoraRun.py +83 -223
  41. certora_cli/certoraSolanaProver.py +40 -128
  42. certora_cli/certoraSorobanProver.py +59 -4
  43. certora_cli/certoraSuiProver.py +93 -0
  44. certora_cli_beta_mirror-8.5.0.dist-info/LICENSE +15 -0
  45. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/METADATA +21 -5
  46. certora_cli_beta_mirror-8.5.0.dist-info/RECORD +81 -0
  47. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/WHEEL +1 -1
  48. {certora_cli_beta_mirror-7.28.0.dist-info → certora_cli_beta_mirror-8.5.0.dist-info}/entry_points.txt +3 -0
  49. certora_jars/ASTExtraction.jar +0 -0
  50. certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
  51. certora_jars/Typechecker.jar +0 -0
  52. certora_cli_beta_mirror-7.28.0.dist-info/LICENSE +0 -22
  53. certora_cli_beta_mirror-7.28.0.dist-info/RECORD +0 -70
  54. {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, validate_version_and_branch
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
- import CertoraProver.certoraContextAttributes as Attrs
40
- from Shared import certoraAttrUtil as AttrUtil
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
- metadata = (
117
- collect_run_metadata(wd=Path.cwd(), raw_args=sys.argv, context=context))
118
-
119
- if context.test == str(Util.TestValue.CHECK_METADATA):
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 Attrs.is_evm_app() and context.split_rules:
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).print_group_id_url()
136
- raise ExitException(f"Split Rules {'succeeded' if exit_code == 0 else 'failed'}", exit_code)
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
- if Attrs.is_rust_app():
139
- build_rust_app(context)
97
+ # Version validation
98
+ ensure_version_compatibility(context)
140
99
 
141
- if context.local:
142
- check_cmd = Ctx.get_local_run_cmd(context)
143
- print(f"Verifier run command:\n {check_cmd}", flush=True)
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
- compare_with_tool_output = False
146
- run_result = Util.run_jar_cmd(check_cmd, compare_with_tool_output, logger_topic="verification",
147
- print_output=True)
148
- # For solana and wasm, we don't check types so build time is zero.
149
- timings["buildTime"] = 0.0
150
- if run_result != 0:
151
- exit_code = 1
152
- else:
153
- Util.print_completion_message("Finished running verifier:")
154
- print(f"\t{check_cmd}")
155
- else:
156
- validate_version_and_branch(context)
157
- context.key = Cv.validate_certora_key()
158
- cloud_verifier = CloudVerification(context, timings)
159
- # Wrap strings with space with ' so it can be copied and pasted to shell
160
- pretty_args = [f"'{arg}'" if ' ' in arg else arg for arg in args]
161
- cl_args = ' '.join(pretty_args)
162
- logging_manager.remove_debug_logger()
163
- result = cloud_verifier.cli_verify_and_report(cl_args, context.wait_for_results)
164
- if cloud_verifier.statusUrl:
165
- return_value = CertoraRunResult(cloud_verifier.statusUrl, False,
166
- Util.get_certora_sources_dir(), cloud_verifier.reportUrl)
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 not context.local and not context.build_only and not context.compilation_steps_only:
172
- """
173
- Before running the local type checker, we see if the current package version is compatible with
174
- the latest. We check it before running the local type checker, because local type checking
175
- errors could be simply a result of syntax introduced in the newest version.
176
- The line below will raise an exception if the local version is incompatible.
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
- if not context.build_only and exit_code == 0:
194
- # either we skipped building (TAC MODE) or build succeeded
195
- if context.local:
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
- check_cmd = Ctx.get_local_run_cmd(context)
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
- try:
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
- from CertoraProver.certoraCloudIO import CloudVerification, validate_version_and_branch
32
- from CertoraProver.certoraCollectRunMetadata import collect_run_metadata
33
- from CertoraProver.certoraCollectConfigurationLayout import collect_configuration_layout
34
- from CertoraProver import certoraContextValidator as Cv
35
-
36
- import CertoraProver.certoraContext as Ctx
37
- import CertoraProver.certoraContextAttributes as Attrs
38
- from CertoraProver.certoraBuildRust import build_rust_app
39
-
40
- from certoraRun import CertoraRunResult, VIOLATIONS_EXIT_CODE, CertoraFoundViolations
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
- Attrs.set_attribute_class(Attrs.SolanaProverAttributes)
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
- metadata = (
85
- collect_run_metadata(wd=Path.cwd(), raw_args=sys.argv, context=context))
59
+ # Collect and validate metadata
60
+ collect_and_dump_metadata(context)
61
+ collect_and_dump_config_layout(context)
86
62
 
87
- if context.test == str(Util.TestValue.CHECK_METADATA):
88
- raise Util.TestResultsReady(metadata)
89
- metadata.dump()
63
+ # Version validation
64
+ ensure_version_compatibility(context)
90
65
 
91
- configuration_layout = collect_configuration_layout()
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.test == str(Util.TestValue.CHECK_CONFIG_LAYOUT):
94
- raise Util.TestResultsReady(configuration_layout)
95
- configuration_layout.dump()
69
+ if context.build_only:
70
+ return return_value
96
71
 
97
- if not context.local and not context.build_only and not context.compilation_steps_only:
98
- """
99
- The line below will raise an exception if the local version is incompatible.
100
- """
101
- validate_version_and_branch(context)
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
- # Build Solana - If input file is .so or .o file, we skip building part
104
- run_logger.debug("Build Solana target")
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
- try:
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__':