certora-cli-beta-mirror 7.31.0__py3-none-any.whl → 8.1.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 (45) hide show
  1. certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +1 -3
  2. certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
  3. certora_cli/CertoraProver/certoraApp.py +49 -0
  4. certora_cli/CertoraProver/certoraBuild.py +197 -44
  5. certora_cli/CertoraProver/certoraBuildCacheManager.py +2 -0
  6. certora_cli/CertoraProver/certoraBuildDataClasses.py +3 -1
  7. certora_cli/CertoraProver/certoraBuildRust.py +32 -21
  8. certora_cli/{Shared/rustProverCommon.py → CertoraProver/certoraBuildSui.py} +24 -18
  9. certora_cli/CertoraProver/certoraCloudIO.py +37 -8
  10. certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +1 -1
  11. certora_cli/CertoraProver/certoraCollectRunMetadata.py +20 -5
  12. certora_cli/CertoraProver/certoraConfigIO.py +23 -22
  13. certora_cli/CertoraProver/certoraContext.py +77 -45
  14. certora_cli/CertoraProver/certoraContextAttributes.py +122 -195
  15. certora_cli/CertoraProver/certoraContextValidator.py +78 -49
  16. certora_cli/CertoraProver/certoraContractFuncs.py +6 -0
  17. certora_cli/CertoraProver/certoraType.py +10 -1
  18. certora_cli/CertoraProver/certoraVerifyGenerator.py +10 -4
  19. certora_cli/CertoraProver/splitRules.py +20 -17
  20. certora_cli/CertoraProver/storageExtension.py +0 -35
  21. certora_cli/EquivalenceCheck/equivCheck.py +2 -1
  22. certora_cli/Mutate/mutateApp.py +28 -16
  23. certora_cli/Mutate/mutateAttributes.py +11 -0
  24. certora_cli/Mutate/mutateValidate.py +2 -2
  25. certora_cli/Shared/certoraAttrUtil.py +11 -5
  26. certora_cli/Shared/certoraUtils.py +99 -35
  27. certora_cli/Shared/certoraValidateFuncs.py +24 -12
  28. certora_cli/Shared/proverCommon.py +10 -8
  29. certora_cli/certoraCVLFormatter.py +76 -0
  30. certora_cli/certoraConcord.py +39 -0
  31. certora_cli/certoraEVMProver.py +2 -2
  32. certora_cli/certoraRanger.py +2 -2
  33. certora_cli/certoraRun.py +58 -98
  34. certora_cli/certoraSolanaProver.py +3 -3
  35. certora_cli/certoraSorobanProver.py +3 -4
  36. {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/METADATA +4 -3
  37. certora_cli_beta_mirror-8.1.0.dist-info/RECORD +79 -0
  38. {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/entry_points.txt +1 -0
  39. certora_jars/ASTExtraction.jar +0 -0
  40. certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -1
  41. certora_jars/Typechecker.jar +0 -0
  42. certora_cli_beta_mirror-7.31.0.dist-info/RECORD +0 -75
  43. {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/LICENSE +0 -0
  44. {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/WHEEL +0 -0
  45. {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/top_level.txt +0 -0
@@ -25,7 +25,7 @@ from wcmatch import glob
25
25
 
26
26
 
27
27
  from pathlib import Path
28
- from typing import Dict, List, Optional, Any, Union
28
+ from typing import Dict, List, Optional, Any, Union, Type
29
29
  from rich.console import Console
30
30
 
31
31
  scripts_dir_path = Path(__file__).parent.resolve() # containing directory
@@ -39,6 +39,8 @@ import CertoraProver.certoraContextAttributes as Attrs
39
39
 
40
40
  from Shared import certoraValidateFuncs as Vf
41
41
  from Shared import certoraAttrUtil as AttrUtil
42
+ import CertoraProver.certoraApp as App
43
+
42
44
 
43
45
  context_logger = logging.getLogger("context")
44
46
 
@@ -55,6 +57,11 @@ def escape_string(string: str) -> str:
55
57
  else:
56
58
  return f"\"{string}\""
57
59
 
60
+ def is_evm_app_class(context: CertoraContext) -> bool:
61
+ return issubclass(context.app, App.EvmAppClass)
62
+
63
+ def is_rust_app_class(context: CertoraContext) -> bool:
64
+ return issubclass(context.app, App.RustAppClass)
58
65
 
59
66
  def get_attr_value(context: CertoraContext, attr: AttrUtil.AttributeDefinition) -> Any:
60
67
  conf_key = attr.get_conf_key()
@@ -62,18 +69,18 @@ def get_attr_value(context: CertoraContext, attr: AttrUtil.AttributeDefinition)
62
69
 
63
70
 
64
71
  def collect_args_with_jar_flags(context: CertoraContext) -> List[AttrUtil.AttributeDefinition]:
65
- attribute_list = Attrs.get_attribute_class().attribute_list()
72
+ attribute_list = context.app.attr_class.attribute_list()
66
73
  return [attr for attr in attribute_list if get_attr_value(context, attr) and attr.jar_flag]
67
74
 
68
75
 
69
76
  def collect_args_build_cache_affecting(context: CertoraContext) -> List[AttrUtil.AttributeDefinition]:
70
- attribute_list = Attrs.get_attribute_class().attribute_list()
77
+ attribute_list = context.app.attr_class.attribute_list()
71
78
  return [attr for attr in attribute_list if get_attr_value(context, attr) and
72
79
  attr.affects_build_cache_key]
73
80
 
74
81
 
75
82
  def collect_args_build_cache_disabling(context: CertoraContext) -> List[AttrUtil.AttributeDefinition]:
76
- attribute_list = Attrs.get_attribute_class().attribute_list()
83
+ attribute_list = context.app.attr_class.attribute_list()
77
84
  return [attr for attr in attribute_list if get_attr_value(context, attr) and
78
85
  attr.disables_build_cache]
79
86
 
@@ -122,7 +129,11 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
122
129
  """
123
130
  run_args = []
124
131
 
125
- if Attrs.is_rust_app():
132
+ if context.app == App.SuiApp:
133
+ # For local runs, we want path to be relative to cwd instead of zip root.
134
+ move_rel_path = os.path.relpath(Path(context.move_path), os.getcwd())
135
+ run_args.extend(['-movePath', move_rel_path])
136
+ elif is_rust_app_class(context):
126
137
  # For local runs, we want path to be relative to cwd instead of zip root.
127
138
  rust_rel_path = os.path.relpath(Path(context.files[0]), os.getcwd())
128
139
  run_args.append(rust_rel_path)
@@ -133,9 +144,10 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
133
144
  except Exception:
134
145
  raise RuntimeError("get_local_run_cmd: cannot find context.files[0]")
135
146
 
136
- if Attrs.is_evm_app() and context.cache is not None:
147
+ if is_evm_app_class(context) and context.cache is not None:
137
148
  run_args.extend(['-cache', context.cache])
138
-
149
+ if context.app == App.ConcordApp:
150
+ run_args.extend(['-equivalenceCheck', 'true'])
139
151
  jar_args = collect_jar_args(context)
140
152
  run_args.extend(jar_args)
141
153
 
@@ -156,27 +168,33 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
156
168
 
157
169
 
158
170
  class ProverParser(AttrUtil.ContextAttributeParser):
159
- def __init__(self, *args: Any, **kwargs: Any) -> None:
171
+ def __init__(self, app: Type[App.CertoraApp], *args: Any, **kwargs: Any) -> None:
160
172
  super().__init__(*args, **kwargs)
173
+ self.app = app
161
174
 
162
175
  def format_help(self) -> str:
163
176
  console = Console()
164
- if Attrs.is_ranger_app():
177
+ if self.app == App.ConcordApp:
178
+ console.print("\n\nConcord - Certora’s equivalence checker for smart contracts")
179
+ elif self.app == App.RangerApp:
165
180
  console.print("\n\nRanger - Certora’s bounded model checker for smart contracts")
166
181
  else:
167
182
  console.print("\n\nThe Certora Prover - A formal verification tool for smart contracts")
168
183
  # Using sys.stdout.write() as print() would color some of the strings here
169
184
  sys.stdout.write(f"\n\nUsage: {sys.argv[0]} <Files> <Flags>\n\n")
170
- if Attrs.is_ranger_app():
185
+ if self.app == App.ConcordApp:
186
+ sys.stdout.write("Concord supports only Solidity (.sol/.yul) and configuration (.conf) files.\n"
187
+ "Rust and Vyper contracts are not currently supported.\n\n")
188
+ if self.app == App.RangerApp:
171
189
  sys.stdout.write("Ranger supports only Solidity (.sol) and configuration (.conf) files.\n"
172
190
  "Rust and Vyper contracts are not currently supported.\n\n")
173
- elif Attrs.is_evm_app():
191
+ elif isinstance(self.app, App.EvmAppClass):
174
192
  sys.stdout.write("Acceptable files for EVM projects are Solidity files (.sol suffix), "
175
193
  "Vyper files (.vy suffix), or conf files (.conf suffix)\n\n")
176
- elif Attrs.is_solana_app():
194
+ elif self.app == App.SolanaApp:
177
195
  sys.stdout.write("Acceptable files for Solana projects are RUST executables ('.so' suffix) or conf "
178
196
  "files ('.conf' suffix')\n\n")
179
- elif Attrs.is_soroban_app():
197
+ elif self.app == App.SorobanApp:
180
198
  sys.stdout.write("Acceptable files for Soroban projects are WASM executables ('.wasm' suffix) or conf "
181
199
  "files ('.conf' suffix')\n\n")
182
200
  else:
@@ -195,24 +213,23 @@ class ProverParser(AttrUtil.ContextAttributeParser):
195
213
 
196
214
  return ''
197
215
 
198
- def __get_argparser() -> argparse.ArgumentParser:
216
+ def __get_argparser(app: Type[App.CertoraApp]) -> argparse.ArgumentParser:
199
217
  def formatter(prog: Any) -> argparse.HelpFormatter:
200
218
  return argparse.HelpFormatter(prog, max_help_position=100, width=200)
201
219
 
202
- parser = ProverParser(prog="certora-cli arguments and options", allow_abbrev=False,
220
+ parser = ProverParser(app, prog="certora-cli arguments and options", allow_abbrev=False,
203
221
  formatter_class=formatter,
204
222
  epilog=" -*-*-* You can find detailed documentation of the supported options in "
205
223
  f"{CLI_DOCUMENTATION_URL} -*-*-*")
206
224
 
207
- for arg in Attrs.get_attribute_class().attribute_list():
225
+ for arg in app.attr_class.attribute_list():
208
226
  flag = arg.get_flag()
209
227
  parser.add_argument(flag, help=arg.help_msg, **arg.argparse_args)
210
228
  return parser
211
229
 
212
-
213
- def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
230
+ def get_args(args_list: List[str], app: Type[App.CertoraApp]) -> CertoraContext:
214
231
  """
215
- Compiles an argparse.Namespace from the given list of command line arguments.
232
+ Compiles an CertoraContext object from the given list of command line arguments.
216
233
 
217
234
  Why do we handle --version before argparse?
218
235
  Because on some platforms, mainly CI tests, we cannot fetch the installed distribution package version of
@@ -220,15 +237,13 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
220
237
  We do it pre-argparse, because we do not care bout the input validity of anything else if we have a --version flag
221
238
  """
222
239
 
223
- if not Attrs.ATTRIBUTES_CLASS:
224
- Attrs.set_attribute_class(Attrs.EvmProverAttributes) # for scripts that call get_args directly
225
240
  if args_list is None:
226
241
  args_list = sys.argv
227
242
 
228
243
  handle_version_flag(args_list)
229
244
 
230
245
  pre_arg_fetching_checks(args_list)
231
- parser = __get_argparser()
246
+ parser = __get_argparser(app)
232
247
 
233
248
  # if there is a --help flag, we want to ignore all parsing errors, even those before it:
234
249
  if any(string in [arg.strip() for arg in args_list] for string in ['--help', '-h']):
@@ -243,6 +258,7 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
243
258
 
244
259
  args = parser.parse_args(args_list)
245
260
  context = CertoraContext(**vars(args))
261
+ context.app = app
246
262
  context.args_list = args_list
247
263
 
248
264
  __remove_parsing_whitespace(args_list)
@@ -251,19 +267,18 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
251
267
 
252
268
  if context.is_conf:
253
269
  read_from_conf_file(context)
254
-
270
+ context.process = None
255
271
  context.local = Util.is_local(context)
256
272
  context.is_tac = context.files and context.files[0].endswith('.tac')
257
273
  context.is_vyper = context.files and context.files[0].endswith('.vy')
258
274
 
259
- if Attrs.is_evm_app():
275
+ if is_evm_app_class(context):
260
276
  Cv.check_mode_of_operation(context) # Here boolean run characteristics are set
261
277
 
262
278
  validator = Cv.CertoraContextValidator(context)
263
- if Attrs.is_evm_app():
264
- validator.handle_ranger_attrs()
279
+
265
280
  validator.validate()
266
- if Attrs.is_evm_app() or Attrs.is_rust_app():
281
+ if is_evm_app_class(context) or is_rust_app_class(context):
267
282
  current_build_directory = Util.get_build_dir()
268
283
  if context.build_dir is not None and current_build_directory != context.build_dir:
269
284
  Util.reset_certora_internal_dir(context.build_dir)
@@ -275,16 +290,19 @@ def get_args(args_list: Optional[List[str]] = None) -> CertoraContext:
275
290
  if context.java_args is not None:
276
291
  context.java_args = ' '.join(context.java_args).replace('"', '').replace("'", '')
277
292
 
278
- if Attrs.is_evm_app():
293
+ if is_evm_app_class(context) or context.app == App.ConcordApp:
279
294
  validator.check_args_post_argparse()
280
295
  setup_cache(context) # Here context.cache, context.user_defined_cache are set
281
- if Attrs.is_rust_app():
296
+ validator.handle_ranger_attrs()
297
+ validator.handle_concord_attrs()
298
+ if is_rust_app_class(context):
282
299
  validator.check_rust_args_post_argparse()
283
300
 
284
301
  attrs_to_relative(context)
285
302
  # Setup defaults (defaults are not recorded in conf file)
286
303
  context.expected_file = context.expected_file or "expected.json"
287
304
  context.run_source = context.run_source or Vf.RunSources.COMMAND.name.upper()
305
+ context.java_version = Util.get_java_version()
288
306
 
289
307
  context_logger.debug("parsed args successfully.")
290
308
  context_logger.debug(f"args= {context}")
@@ -358,7 +376,7 @@ def format_input(context: CertoraContext) -> None:
358
376
  :param context: Namespace containing all command line arguments, generated by get_args()
359
377
  """
360
378
  flatten_arg_lists(context)
361
- if Attrs.is_evm_app():
379
+ if is_evm_app_class(context):
362
380
  __dedup_link(context)
363
381
 
364
382
 
@@ -403,7 +421,7 @@ def setup_cache(context: CertoraContext) -> None:
403
421
  # we have a user defined cache key if the user provided a cache key
404
422
  context.user_defined_cache = context.cache is not None
405
423
  if not context.disable_auto_cache_key_gen and not os.environ.get("CERTORA_DISABLE_AUTO_CACHE") is not None:
406
- if context.is_verify or context.is_assert or context.is_conf:
424
+ if context.is_verify or context.is_conf:
407
425
  # in local mode we don't want to create a cache key if not such is given
408
426
  if (context.cache is None) and (not context.local):
409
427
  optimistic_loop = context.optimistic_loop
@@ -437,7 +455,7 @@ def write_output_conf_to_path(json_content: Dict[str, Any], path: Path) -> None:
437
455
  json.dump(json_content, out_file, indent=4, sort_keys=True)
438
456
 
439
457
 
440
- def handle_flags_in_args(args: List[str]) -> None:
458
+ def handle_flags_in_args(args: List[str], app: Type[App.CertoraApp]) -> None:
441
459
  """
442
460
  For argparse flags are strings that start with a dash. Some arguments get flags as value.
443
461
  The problem is that argparse will not treat the string as a value but rather as a new flag. There are different ways
@@ -453,7 +471,7 @@ def handle_flags_in_args(args: List[str]) -> None:
453
471
  Will all be converted to " -d"
454
472
 
455
473
  """
456
- all_flags = list(map(lambda member: member.get_flag(), Attrs.get_attribute_class().attribute_list()))
474
+ all_flags = list(map(lambda member: member.get_flag(), app.attr_class.attribute_list()))
457
475
 
458
476
  def surrounded(string: str, char: str) -> bool:
459
477
  if len(string) < 2:
@@ -504,14 +522,19 @@ def __rename_key(context: CertoraContext, old_key: str, new_key: str) -> None:
504
522
  context.delete_key(old_key)
505
523
 
506
524
 
507
- def run_typechecker(typechecker_name: str, with_typechecking: bool, args: List[str]) -> None:
525
+ def should_run_local_speck_check(context: CertoraContext) -> bool:
526
+ return not (context.disable_local_typechecking or Util.is_ci_or_git_action())
527
+
528
+
529
+ def run_typechecker(typechecker_name: str, with_typechecking: bool, args: List[str], print_errors: bool) -> None:
508
530
  """
509
531
  Runs a spec typechecker or syntax checker
510
- @param typechecker_name - the name of the jar that we should run for running typechecking
511
- @param with_typechecking - True if we want full typechecking including build (Solidity outputs) file,
532
+
533
+ @param typechecker_name: the name of the jar that we should run for running typechecking
534
+ @param with_typechecking: True if we want full typechecking including build (Solidity outputs) file,
512
535
  False if we run only the leaner syntax checking.
513
536
  @param args: A list of strings of additional arguments to the typechecker jar.
514
-
537
+ @param print_errors: Toggles printing the typechecker's errors to stderr.
515
538
  """
516
539
  # Find path to typechecker jar
517
540
  path_to_typechecker = Util.find_jar(typechecker_name)
@@ -524,11 +547,14 @@ def run_typechecker(typechecker_name: str, with_typechecking: bool, args: List[s
524
547
  if with_typechecking:
525
548
  cmd_str_list.append('-typeCheck')
526
549
 
550
+ context_logger.debug(f"typechecking cmd: {' '.join(cmd_str_list)}")
551
+
527
552
  exit_code = Util.run_jar_cmd(cmd_str_list, False,
528
553
  custom_error_message="Failed to run Certora Prover locally. Please check the errors "
529
554
  "below for problems in the specifications (.spec files) or the "
530
555
  "prover_args defined in the .conf file.",
531
- logger_topic="type_check")
556
+ logger_topic="type_check",
557
+ print_err=print_errors)
532
558
  if exit_code != 0:
533
559
  raise Util.CertoraUserInputError(
534
560
  "CVL syntax or type check failed.\n Please fix the issue. "
@@ -538,17 +564,23 @@ def run_typechecker(typechecker_name: str, with_typechecking: bool, args: List[s
538
564
  "simple syntax failures will be visible only on the cloud run.")
539
565
 
540
566
 
541
- def run_local_spec_check(with_typechecking: bool, context: CertoraContext) -> None:
567
+ def run_local_spec_check(with_typechecking: bool, context: CertoraContext, extra_args: List[str] = list(), print_errors: bool = True) -> None:
542
568
  """
543
- Runs the local type checker in one of two modes: (1) syntax only,
544
- and (2) including full typechecking after building the contracts
569
+ Runs the local type checker
570
+
571
+ @param with_typechecking: If `True` will perform a full typecheck pass which requires Solidity build information.
572
+ Otherwise performs only a syntax check.
573
+
574
+ @param context: The `CertoraContext`.
575
+
576
+ @param extra_args: a list of additional arguments that should be sent to the typechecker.
577
+
578
+ @param print_errors: Toggles printing the typechecker's errors to stderr. Default: True
545
579
  """
546
580
 
547
- if context.disable_local_typechecking or Util.is_ci_or_git_action():
548
- return
549
581
  args = collect_jar_args(context)
550
- if Util.is_java_installed():
551
- run_typechecker("Typechecker.jar", with_typechecking, args)
582
+ if Util.is_java_installed(context.java_version):
583
+ run_typechecker("Typechecker.jar", with_typechecking, args + extra_args, print_errors)
552
584
  else:
553
585
  raise Util.CertoraUserInputError("Cannot run local checks because of missing a suitable java installation. "
554
586
  "To skip local checks run with the --disable_local_typechecking flag")