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.
- certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +1 -3
- certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +3 -0
- certora_cli/CertoraProver/certoraApp.py +49 -0
- certora_cli/CertoraProver/certoraBuild.py +197 -44
- certora_cli/CertoraProver/certoraBuildCacheManager.py +2 -0
- certora_cli/CertoraProver/certoraBuildDataClasses.py +3 -1
- certora_cli/CertoraProver/certoraBuildRust.py +32 -21
- certora_cli/{Shared/rustProverCommon.py → CertoraProver/certoraBuildSui.py} +24 -18
- certora_cli/CertoraProver/certoraCloudIO.py +37 -8
- certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +1 -1
- certora_cli/CertoraProver/certoraCollectRunMetadata.py +20 -5
- certora_cli/CertoraProver/certoraConfigIO.py +23 -22
- certora_cli/CertoraProver/certoraContext.py +77 -45
- certora_cli/CertoraProver/certoraContextAttributes.py +122 -195
- certora_cli/CertoraProver/certoraContextValidator.py +78 -49
- certora_cli/CertoraProver/certoraContractFuncs.py +6 -0
- certora_cli/CertoraProver/certoraType.py +10 -1
- certora_cli/CertoraProver/certoraVerifyGenerator.py +10 -4
- certora_cli/CertoraProver/splitRules.py +20 -17
- certora_cli/CertoraProver/storageExtension.py +0 -35
- certora_cli/EquivalenceCheck/equivCheck.py +2 -1
- certora_cli/Mutate/mutateApp.py +28 -16
- certora_cli/Mutate/mutateAttributes.py +11 -0
- certora_cli/Mutate/mutateValidate.py +2 -2
- certora_cli/Shared/certoraAttrUtil.py +11 -5
- certora_cli/Shared/certoraUtils.py +99 -35
- certora_cli/Shared/certoraValidateFuncs.py +24 -12
- certora_cli/Shared/proverCommon.py +10 -8
- certora_cli/certoraCVLFormatter.py +76 -0
- certora_cli/certoraConcord.py +39 -0
- certora_cli/certoraEVMProver.py +2 -2
- certora_cli/certoraRanger.py +2 -2
- certora_cli/certoraRun.py +58 -98
- certora_cli/certoraSolanaProver.py +3 -3
- certora_cli/certoraSorobanProver.py +3 -4
- {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/METADATA +4 -3
- certora_cli_beta_mirror-8.1.0.dist-info/RECORD +79 -0
- {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/entry_points.txt +1 -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.31.0.dist-info/RECORD +0 -75
- {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/LICENSE +0 -0
- {certora_cli_beta_mirror-7.31.0.dist-info → certora_cli_beta_mirror-8.1.0.dist-info}/WHEEL +0 -0
- {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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
264
|
-
validator.handle_ranger_attrs()
|
|
279
|
+
|
|
265
280
|
validator.validate()
|
|
266
|
-
if
|
|
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
|
|
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
|
-
|
|
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
|
|
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.
|
|
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(),
|
|
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
|
|
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
|
-
|
|
511
|
-
@param
|
|
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
|
|
544
|
-
|
|
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")
|