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
@@ -12,10 +12,10 @@
12
12
  #
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
-
15
+ import dataclasses
16
16
  import json
17
17
  from enum import Enum
18
- from typing import Optional, Dict, Any
18
+ from typing import Optional, Any
19
19
  from pathlib import Path
20
20
  import sys
21
21
 
@@ -25,27 +25,46 @@ sys.path.insert(0, str(scripts_dir_path))
25
25
  import CertoraProver.certoraContextAttributes as Attrs
26
26
  from CertoraProver.certoraCollectRunMetadata import RunMetaData, MetadataEncoder
27
27
  import Shared.certoraUtils as Utils
28
+ from typing import List
28
29
 
29
30
 
30
31
  class MainSection(Enum):
31
32
  GENERAL = "GENERAL"
33
+ OPTIONS = "OPTIONS"
32
34
  SOLIDITY_COMPILER = "SOLIDITY_COMPILER"
33
- GIT = "GIT"
34
- FILES = "FILES"
35
- LINKS = "LINKS"
36
- PACKAGES = "PACKAGES"
37
- METADATA = "METADATA"
35
+ NEW_SECTION = "NEW_SECTION"
36
+
37
+
38
+ class ContentType(Enum):
39
+ SIMPLE = "SIMPLE"
40
+ COMPLEX = "COMPLEX"
41
+ FLAG = "FLAG"
42
+
38
43
 
44
+ @dataclasses.dataclass
45
+ class InnerContent:
46
+ inner_title: str
47
+ content_type: str
48
+ content: Any
49
+ doc_link: str = ''
50
+ tooltip: str = ''
51
+ unsound: bool = False
39
52
 
40
- class FlagType(Enum):
41
- VALUE_FLAG = "VALUE"
42
- LIST_FLAG = "LIST"
43
- MAP_FLAG = "MAP"
53
+ def __post_init__(self) -> None:
54
+ if isinstance(self.content, bool):
55
+ self.content = 'true' if self.content else 'false'
56
+
57
+
58
+ @dataclasses.dataclass
59
+ class CardContent:
60
+ card_title: str
61
+ content_type: str
62
+ content: Any
44
63
 
45
64
 
46
65
  DOC_LINK_PREFIX = 'https://docs.certora.com/en/latest/docs/'
47
66
  GIT_ATTRIBUTES = ['origin', 'revision', 'branch', 'dirty']
48
- SPECIAL_MAIN_SECTIONS = ['files', 'links', 'packages']
67
+ ARG_LIST_ATTRIBUTES = ['prover_args', 'java_args']
49
68
 
50
69
 
51
70
  class AttributeJobConfigData:
@@ -54,13 +73,13 @@ class AttributeJobConfigData:
54
73
  This should be added to the AttributeDefinition and configured for every new attribute
55
74
  presented in the Rule report.
56
75
 
57
- Note: Attributes which do not contain specific information will be assigned as a Flag in the General main section!
76
+ Note: Attributes that do not contain specific information will be presented in the OPTIONS main section!
58
77
 
59
78
  arguments:
60
79
  - main_section : MainSection -- the main section inside the config tab
61
- default: MainSection.GENERAL
62
- - subsection : str -- the subsection within the main_section (e.g Flags)
63
- default: Flags
80
+ default: MainSection.OPTIONS
81
+ - subsection : str -- the subsection within the main_section
82
+ default: None - they will be presented inside the OPTIONS card
64
83
  - doc_link : Optional[str] -- a link to the Documentation page of this attribute (if exists)
65
84
  default: 'https://docs.certora.com/en/latest/docs/' + Solana/EVM path + #<attribute_name>
66
85
  - tooltip : Optional[str] -- a description of this attribute to present in the config tab
@@ -69,7 +88,7 @@ class AttributeJobConfigData:
69
88
  default: False
70
89
  """
71
90
 
72
- def __init__(self, main_section: MainSection = MainSection.GENERAL, subsection: str = '',
91
+ def __init__(self, main_section: MainSection = MainSection.OPTIONS, subsection: str = '',
73
92
  doc_link: Optional[str] = '', tooltip: Optional[str] = '', unsound: bool = False):
74
93
  self.main_section = main_section
75
94
  self.subsection = subsection
@@ -87,18 +106,25 @@ class RunConfigurationLayout:
87
106
  configuration_layout : Dict -- An aggregated configuration for a specific run, nested by main section, subsection.
88
107
  Each leaf contains data about attribute value, type, documentation link and UI data.
89
108
  """
90
- def __init__(self, configuration_layout: Dict[str, Any]):
109
+
110
+ configuration_layout: list[Any]
111
+
112
+ def __init__(self, configuration_layout: list[Any]):
91
113
  # Dynamically allocate class attributes from dict
92
- for key, value in configuration_layout.items():
93
- setattr(self, key, value)
114
+ self.configuration_layout = configuration_layout
94
115
 
95
116
  def __repr__(self) -> str:
96
- return "\n".join(f"{key}: {value}" for key, value in self.__dict__.items())
117
+ try:
118
+ return json.dumps(self.configuration_layout, indent=2, sort_keys=True)
119
+ except TypeError:
120
+ # Fallback if something isn't serializable
121
+ return str(self.configuration_layout)
97
122
 
98
123
  @classmethod
99
- def dump_file(cls, data: dict) -> None:
124
+ def dump_file(cls, data: list) -> None:
125
+ sorted_data = sort_configuration_layout(data)
100
126
  with Utils.get_configuration_layout_data_file().open("w+") as f:
101
- json.dump(data, f, indent=4, sort_keys=True, cls=MetadataEncoder)
127
+ json.dump(sorted_data, f, indent=4, cls=MetadataEncoder)
102
128
 
103
129
  @classmethod
104
130
  def load_file(cls) -> dict:
@@ -110,12 +136,11 @@ class RunConfigurationLayout:
110
136
  raise
111
137
 
112
138
  def dump(self) -> None:
113
- if self.__dict__: # dictionary containing all the attributes defined for GitInfo
114
- try:
115
- self.dump_file(self.__dict__)
116
- except Exception as e:
117
- print(f"failed to write configuration layout file {Utils.get_configuration_layout_data_file()}\n{e}")
118
- raise
139
+ try:
140
+ self.dump_file(self.configuration_layout)
141
+ except Exception as e:
142
+ print(f"Failed to write configuration layout file: {Utils.get_configuration_layout_data_file()}\n{e}")
143
+ raise
119
144
 
120
145
 
121
146
  def collect_configuration_layout() -> RunConfigurationLayout:
@@ -127,7 +152,7 @@ def collect_configuration_layout() -> RunConfigurationLayout:
127
152
  metadata = RunMetaData.load_file()
128
153
  except Exception as e:
129
154
  print(f"failed to load job metadata! cannot create a configuration layout file without metadata!\n{e}")
130
- return RunConfigurationLayout(configuration_layout={})
155
+ return RunConfigurationLayout(configuration_layout=[])
131
156
 
132
157
  attributes_configs = collect_attribute_configs(metadata)
133
158
  configuration_layout = collect_run_config_from_metadata(attributes_configs, metadata)
@@ -154,89 +179,210 @@ def get_doc_link(attr) -> str: # type: ignore
154
179
  return doc_link
155
180
 
156
181
 
157
- def collect_attribute_configs(metadata: dict) -> dict:
182
+ def create_or_get_card_content(output: list[CardContent], name: str) -> CardContent:
183
+ """
184
+ Returns an existing CardContent by name or creates and appends a new one if it doesn't exist.
185
+ Card content type will always be complex in this case.
186
+ Args:
187
+ output (list[CardContent]): List of CardContent objects.
188
+ name (str): Title of the card to find or create.
189
+
190
+ Returns:
191
+ CardContent: The found or newly created CardContent.
192
+ """
193
+ main_section = next((section for section in output if section.card_title == name), None)
194
+ if main_section is None:
195
+ main_section = CardContent(
196
+ card_title=name,
197
+ content_type=ContentType.COMPLEX.value,
198
+ content=[]
199
+ )
200
+ output.append(main_section)
201
+ return main_section
202
+
203
+
204
+ def split_and_sort_arg_list_value(args_list: List[str]) -> List[str]:
205
+ """
206
+ Splits a unified CLI argument list of strings into a sorted list of flag+value groups.
207
+ This is useful mainly for --prover_args and --java_args.
208
+
209
+ For example:
210
+ "-depth 15 -adaptiveSolverConfig false" → ["-adaptiveSolverConfig false", "-depth 15"]
211
+
212
+ Assumes each flag starts with '-' and its value follows immediately, if exists.
213
+ Lines are sorted alphabetically.
214
+ """
215
+ unified_args = ' '.join(str(arg) for arg in args_list)
216
+
217
+ if not unified_args.strip():
218
+ return []
219
+
220
+ lines: List[str] = []
221
+ tokens = unified_args.split()
222
+ curr_line = ""
223
+
224
+ for token in tokens:
225
+ if token.startswith('-'):
226
+ if curr_line:
227
+ lines.append(curr_line)
228
+ curr_line = token
229
+ else:
230
+ curr_line += f" {token}"
231
+
232
+ if curr_line:
233
+ lines.append(curr_line)
234
+
235
+ return sorted(lines)
236
+
237
+
238
+ def create_inner_content(name: str, content_type: ContentType, value: Any, doc_link: str,
239
+ config_data: AttributeJobConfigData) -> InnerContent:
240
+ return InnerContent(
241
+ inner_title=name,
242
+ content_type=content_type.value,
243
+ content=value,
244
+ doc_link=doc_link,
245
+ tooltip=config_data.tooltip or '',
246
+ unsound=config_data.unsound
247
+ )
248
+
249
+
250
+ def collect_attribute_configs(metadata: dict) -> list[CardContent]:
251
+ """
252
+ Collects and organizes attribute configurations into a structured list of CardContent objects.
253
+
254
+ This function iterates through all available attributes defined, checks if relevant metadata is provided
255
+ for each attribute, and organizes the data into sections and subsections based on configuration rules.
256
+
257
+ Attributes are grouped under their respective main sections, with special handling for:
258
+ - Simple value attributes
259
+ - List and dictionary attributes
260
+ - Attributes requiring new sections (e.g., Files, Links, Packages)
261
+
262
+ Args:
263
+ metadata (dict): Metadata dictionary containing attribute values.
264
+
265
+ Returns:
266
+ list: A list of CardContent objects representing the structured configuration view,
267
+ ready for rendering or further processing.
268
+ """
158
269
  attr_list = Attrs.get_attribute_class().attribute_list()
159
- output: Dict[str, Any] = {}
270
+ output: list[CardContent] = []
160
271
 
161
272
  for attr in attr_list:
162
273
  attr_name = attr.name.lower()
163
274
  if attr.config_data is None:
164
275
  continue
165
276
 
166
- if metadata.get(attr_name) is None and metadata.get('conf', {}).get(attr_name) is None:
277
+ attr_value = metadata.get(attr_name) or metadata.get('conf', {}).get(attr_name)
278
+ if attr_value is None:
167
279
  continue
168
280
 
169
- attr_value = metadata.get(attr_name) or metadata.get('conf', {}).get(attr_name)
170
281
  config_data: AttributeJobConfigData = attr.config_data
171
282
  doc_link = config_data.doc_link or get_doc_link(attr)
172
283
 
173
- # Get or create the main section
284
+ # Find or create the main section
174
285
  main_section_key = config_data.main_section.value.lower()
175
- main_section = output.setdefault(main_section_key, {})
286
+ main_section = create_or_get_card_content(output, main_section_key)
287
+
288
+ # Files, Links and Packages are special cases where the main section is the attribute itself
289
+ if main_section_key == MainSection.NEW_SECTION.value.lower():
290
+ main_section.card_title = attr_name
291
+ main_section.content_type = ContentType.SIMPLE.value
292
+ main_section.content.append(
293
+ create_inner_content(attr_name, ContentType.SIMPLE, attr_value, doc_link, config_data)
294
+ )
295
+ continue
176
296
 
177
- # Get or create the subsection (if it exists) and flag_type
297
+ # Find or create the subsection (if it doesn't exist)
178
298
  if isinstance(attr_value, list):
179
- # Files, Links and Packages are special cases where the main section is the attribute itself
180
- if main_section_key in SPECIAL_MAIN_SECTIONS:
181
- current_section = output
182
- attr_name = main_section_key
183
- else:
184
- current_section = main_section
185
-
186
- flag_type = FlagType.LIST_FLAG
299
+ content_type = ContentType.SIMPLE
300
+ if attr_name in ARG_LIST_ATTRIBUTES:
301
+ attr_value = split_and_sort_arg_list_value(attr_value)
302
+
187
303
  elif isinstance(attr_value, dict):
188
- current_section = main_section
189
- flag_type = FlagType.MAP_FLAG
304
+ content_type = ContentType.COMPLEX
305
+ attr_value = [
306
+ create_inner_content(key, ContentType.FLAG, value, doc_link, config_data)
307
+ for key, value in attr_value.items()
308
+ ]
190
309
  else:
191
- subsection_key = config_data.subsection.lower() if config_data.subsection else 'flags'
192
- current_section = main_section.setdefault(subsection_key, {})
193
- flag_type = FlagType.VALUE_FLAG
310
+ content_type = ContentType.FLAG
194
311
 
195
312
  # Update the current section with attribute details
196
- current_section[attr_name] = {
197
- 'value': attr_value,
198
- 'flag_type': flag_type.value.lower(),
199
- 'doc_link': doc_link,
200
- 'tooltip': config_data.tooltip,
201
- 'unsound': config_data.unsound
202
- }
313
+ main_section.content.append(
314
+ create_inner_content(attr_name, content_type, attr_value, doc_link, config_data)
315
+ )
203
316
 
204
317
  return output
205
318
 
206
319
 
207
- def collect_run_config_from_metadata(attributes_configs: dict, metadata: dict) -> dict:
320
+ def collect_run_config_from_metadata(attributes_configs: list[CardContent], metadata: dict) -> list[CardContent]:
208
321
  """
209
322
  Adding CLI and Git configuration from metadata
210
323
  """
211
- metadata_section = attributes_configs.setdefault(MainSection.METADATA.value.lower(), {})
212
324
 
213
- # Define a mapping of metadata attributes to their keys in general_section
214
- metadata_mappings = {
215
- 'cli_version': metadata.get('CLI_version'),
216
- 'main_spec': metadata.get('main_spec'),
217
- 'solc_version': metadata.get('conf', {}).get('solc'),
218
- 'verify': metadata.get('conf', {}).get('verify'),
219
- }
325
+ general_section = create_or_get_card_content(attributes_configs, MainSection.GENERAL.value.lower())
326
+
327
+ if cli_version := metadata.get('CLI_version'):
328
+ general_section.content.append(InnerContent(
329
+ inner_title='CLI Version',
330
+ content_type=ContentType.FLAG.value,
331
+ content=cli_version,
332
+ ))
220
333
 
221
- # Add metadata attributes dynamically if they exist
222
- for key, value in metadata_mappings.items():
223
- if value:
224
- metadata_section[key] = {
225
- 'value': value,
226
- 'flag_type': FlagType.VALUE_FLAG.value,
227
- 'doc_link': '',
228
- 'tooltip': '',
229
- }
230
-
231
- # Adding GIT configuration from metadata
232
- git_section = attributes_configs.setdefault(MainSection.GIT.value.lower(), {})
233
334
  for attr in GIT_ATTRIBUTES:
234
335
  if attr_value := metadata.get(attr):
235
- git_section[attr] = {
236
- 'value': attr_value,
237
- 'flag_type': FlagType.MAP_FLAG.value,
238
- 'doc_link': '',
239
- 'tooltip': ''
240
- }
336
+ general_section.content.append(InnerContent(
337
+ inner_title=attr,
338
+ content_type=ContentType.FLAG.value,
339
+ content=attr_value,
340
+ ))
241
341
 
242
342
  return attributes_configs
343
+
344
+
345
+ def sort_configuration_layout(data: list[CardContent]) -> list[CardContent]:
346
+ """
347
+ Sorts a configuration layout:
348
+ - Top-level sorted by 'card_title'
349
+ - Nested content sorted by 'inner_title', with 'verify' first
350
+ """
351
+ priority = {
352
+ # Priorities for top-level cards
353
+ "general": 0,
354
+ "files": 1,
355
+ "options": 2,
356
+ # Top level items inside their respective cards
357
+ "verify": 0,
358
+ "solc": 0,
359
+ "CLI Version": 0
360
+ }
361
+
362
+ def inner_sort_key(item: Any) -> Any:
363
+ if isinstance(item, CardContent):
364
+ title = item.card_title
365
+ return priority.get(title, 3), title.lower()
366
+ elif isinstance(item, InnerContent):
367
+ title = item.inner_title
368
+ return priority.get(title, 3), title.lower()
369
+ else:
370
+ return item
371
+
372
+ def sort_content(content: list[InnerContent]) -> list[InnerContent]:
373
+ sorted_content = []
374
+ for item in content:
375
+ if isinstance(item.content, list):
376
+ # Recurse into nested 'content'
377
+ item.content = sorted(item.content, key=inner_sort_key)
378
+ sorted_content.append(item)
379
+ return sorted(sorted_content, key=inner_sort_key)
380
+
381
+ # Sort top-level entries by 'card_title'
382
+ sorted_data = sorted(data, key=inner_sort_key)
383
+
384
+ # Sort nested 'content'
385
+ for section in sorted_data:
386
+ section.content = sort_content(section.content)
387
+
388
+ return sorted_data
@@ -12,8 +12,9 @@
12
12
  #
13
13
  # You should have received a copy of the GNU General Public License
14
14
  # along with this program. If not, see <https://www.gnu.org/licenses/>.
15
-
15
+ import dataclasses
16
16
  import json
17
+ import re
17
18
  from typing import Any, Dict, List, Optional
18
19
  import subprocess
19
20
  from datetime import datetime, timezone
@@ -31,6 +32,7 @@ import CertoraProver.certoraContextAttributes as Attrs
31
32
 
32
33
  metadata_logger = logging.getLogger("metadata")
33
34
 
35
+
34
36
  def collect_args_with_jar_flags() -> List[str]:
35
37
  return_array = []
36
38
  for attr in Attrs.get_attribute_class().attribute_list():
@@ -47,6 +49,8 @@ class MetadataEncoder(json.JSONEncoder):
47
49
  def default(self, obj: Any) -> Any:
48
50
  if isinstance(obj, set):
49
51
  return list(obj)
52
+ if dataclasses.is_dataclass(obj):
53
+ return dataclasses.asdict(obj)
50
54
  return json.JSONEncoder.default(self, obj)
51
55
 
52
56
 
@@ -68,10 +72,19 @@ class RunMetaData:
68
72
  dirty -- true iff the git repository has changes (git diff is not empty)
69
73
  main_spec -- the relative path to the main spec file that should be displayed by default at the web report
70
74
  conf_path -- the relative path form the cwd_relative to the configuration file
75
+ group_id -- optional identifier for grouping this run
76
+ java_version -- version of Java used during the run, if available
77
+ default_solc_version -- version of default solc version on current machine, if available
78
+ python_version -- version of Python running the process
79
+ certora_ci_client -- name of the CI client if available, derived from environment
80
+ timestamp -- UTC timestamp when the run metadata was generated
81
+ CLI_package_name -- name of the CLI package
82
+ CLI_version -- version of the CLI
83
+ jar_flag_info -- CLI attributes which are jarFlags
71
84
  """
72
85
  def __init__(self, raw_args: List[str], conf: Dict[str, Any], origin: str, revision: str,
73
86
  branch: str, cwd_relative: Path, dirty: bool, main_spec: Optional[str],
74
- conf_path: Optional[Path], group_id: Optional[str]):
87
+ conf_path: Optional[Path], group_id: Optional[str], java_version: str):
75
88
  self.raw_args = raw_args
76
89
  self.conf = conf
77
90
  self.origin = origin
@@ -83,6 +96,8 @@ class RunMetaData:
83
96
  self.conf_path = conf_path
84
97
  self.group_id = group_id
85
98
  self.python_version = ".".join(str(x) for x in sys.version_info[:3])
99
+ self.java_version = java_version
100
+ self.default_solc_version = get_solc_version(self.conf)
86
101
  self.certora_ci_client = Utils.get_certora_ci_name()
87
102
  self.timestamp = str(datetime.now(timezone.utc).timestamp())
88
103
  _, self.CLI_package_name, self.CLI_version = Utils.get_package_and_version()
@@ -103,6 +118,8 @@ class RunMetaData:
103
118
  f" conf_path: {self.conf_path}\n"
104
119
  f" group_id: {self.group_id}\n"
105
120
  f" python_version: {self.python_version}\n"
121
+ f" java_version: {self.java_version}\n"
122
+ f" default_solc_version: {self.default_solc_version}\n"
106
123
  f" CertoraCI client: {self.certora_ci_client}\n"
107
124
  f" jar_flag_info: {self.jar_flag_info}\n"
108
125
  )
@@ -180,7 +197,8 @@ def collect_run_metadata(wd: Path, raw_args: List[str], context: CertoraContext)
180
197
  dirty=True,
181
198
  main_spec=None,
182
199
  conf_path=None,
183
- group_id=None)
200
+ group_id=None,
201
+ java_version=context.java_version)
184
202
 
185
203
  # collect information about current git snapshot
186
204
  cwd_abs = wd.absolute()
@@ -208,7 +226,8 @@ def collect_run_metadata(wd: Path, raw_args: List[str], context: CertoraContext)
208
226
  dirty=True,
209
227
  main_spec=get_main_spec(context),
210
228
  conf_path=conf_path,
211
- group_id=context.group_id)
229
+ group_id=context.group_id,
230
+ java_version=context.java_version)
212
231
 
213
232
  try:
214
233
  sha_out = subprocess.run(['git', 'rev-parse', 'HEAD'], cwd=wd,
@@ -243,7 +262,8 @@ def collect_run_metadata(wd: Path, raw_args: List[str], context: CertoraContext)
243
262
  dirty=dirty,
244
263
  main_spec=get_main_spec(context),
245
264
  conf_path=conf_path,
246
- group_id=context.group_id)
265
+ group_id=context.group_id,
266
+ java_version=context.java_version)
247
267
 
248
268
  metadata_logger.debug(f' collected data:\n{str(data)}')
249
269
 
@@ -261,4 +281,30 @@ def collect_run_metadata(wd: Path, raw_args: List[str], context: CertoraContext)
261
281
  dirty=True,
262
282
  main_spec=get_main_spec(context),
263
283
  conf_path=conf_path,
264
- group_id=context.group_id)
284
+ group_id=context.group_id,
285
+ java_version=context.java_version)
286
+
287
+
288
+ def get_solc_version(conf: Dict[str, Any]) -> Optional[str]:
289
+ if conf.get('solc') or conf.get('solc_map') or conf.get('compiler_map'):
290
+ return None
291
+
292
+ try:
293
+ result = subprocess.run(
294
+ ["solc", "--version"],
295
+ capture_output=True,
296
+ text=True,
297
+ check=True
298
+ )
299
+ for line in result.stdout.splitlines():
300
+ if line.startswith("Version:"):
301
+ version_matches = re.findall(r'^Version: (\d+)\.(\d+)\.(\d+)', line, re.MULTILINE)
302
+ if len(version_matches) != 1:
303
+ return None
304
+ match = version_matches[0]
305
+ return f'solc{int(match[1])}.{int(match[2])}'
306
+
307
+ except Exception as e:
308
+ metadata_logger.debug(f'Error while trying to fetch default solc version: {e}')
309
+ return None
310
+ return None
@@ -35,3 +35,14 @@ class SolcParameters(CompilerParameters):
35
35
  as_dict.update({"optimizerOn": self.optimizer_on, "optimizerRuns": self.optimizer_runs, "viaIR": self.via_ir,
36
36
  "type": "SolcParameters"})
37
37
  return as_dict
38
+
39
+ class VyperParameters(CompilerParameters):
40
+
41
+ def __init__(self, is_venom: bool):
42
+ self.is_venom = is_venom
43
+ CompilerParameters.__init__(self)
44
+
45
+ def as_dict(self) -> Dict[str, Any]:
46
+ as_dict = CompilerParameters.as_dict(self)
47
+ as_dict.update({"is_venom": self.is_venom, "type": "VyperParameters"})
48
+ return as_dict