certora-cli 8.8.0__tar.gz → 8.11.3__tar.gz

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 (91) hide show
  1. {certora_cli-8.8.0/certora_cli.egg-info → certora_cli-8.11.3}/PKG-INFO +2 -2
  2. certora_cli-8.11.3/README.md +1 -0
  3. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraBuild.py +83 -28
  4. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraBuildCacheManager.py +16 -1
  5. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraBuildSui.py +42 -12
  6. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraCloudIO.py +6 -0
  7. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraContext.py +39 -8
  8. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraContextAttributes.py +77 -4
  9. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraContextValidator.py +25 -1
  10. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/certoraUtils.py +3 -1
  11. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/certoraValidateFuncs.py +7 -1
  12. {certora_cli-8.8.0 → certora_cli-8.11.3/certora_cli.egg-info}/PKG-INFO +2 -2
  13. certora_cli-8.8.0/certora_jars/Typechecker.jar → certora_cli-8.11.3/certora_jars/ASTExtraction.jar +0 -0
  14. certora_cli-8.11.3/certora_jars/CERTORA-CLI-VERSION-METADATA.json +1 -0
  15. certora_cli-8.8.0/certora_jars/ASTExtraction.jar → certora_cli-8.11.3/certora_jars/Typechecker.jar +0 -0
  16. {certora_cli-8.8.0 → certora_cli-8.11.3}/setup.py +2 -2
  17. certora_cli-8.8.0/README.md +0 -1
  18. certora_cli-8.8.0/certora_jars/CERTORA-CLI-VERSION-METADATA.json +0 -1
  19. {certora_cli-8.8.0 → certora_cli-8.11.3}/LICENSE +0 -0
  20. {certora_cli-8.8.0 → certora_cli-8.11.3}/MANIFEST.in +0 -0
  21. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_bins/__init__.py +0 -0
  22. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollector.py +0 -0
  23. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollectorFactory.py +0 -0
  24. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollectorSol.py +0 -0
  25. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollectorSolBased.py +0 -0
  26. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollectorVy.py +0 -0
  27. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/CompilerCollectorYul.py +0 -0
  28. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/Compiler/__init__.py +0 -0
  29. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/__init__.py +0 -0
  30. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/castingInstrumenter.py +0 -0
  31. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraApp.py +0 -0
  32. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraBuildDataClasses.py +0 -0
  33. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraBuildRust.py +0 -0
  34. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraCollectConfigurationLayout.py +0 -0
  35. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraCollectRunMetadata.py +0 -0
  36. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraCompilerParameters.py +0 -0
  37. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraConfigIO.py +0 -0
  38. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraContextClass.py +0 -0
  39. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraContractFuncs.py +0 -0
  40. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraExtensionInfo.py +0 -0
  41. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraJobList.py +0 -0
  42. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraMiniSpecParser.py +0 -0
  43. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraNodeFilters.py +0 -0
  44. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraOffsetConverter.py +0 -0
  45. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraParseBuildScript.py +0 -0
  46. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraProjectScanner.py +0 -0
  47. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraSourceFinders.py +0 -0
  48. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraType.py +0 -0
  49. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/certoraVerifyGenerator.py +0 -0
  50. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/erc7201.py +0 -0
  51. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/splitRules.py +0 -0
  52. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/storageExtension.py +0 -0
  53. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/CertoraProver/uncheckedOverflowInstrumenter.py +0 -0
  54. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/Eq_default.conf +0 -0
  55. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/Eq_mc_no_out_template.spec +0 -0
  56. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/Eq_mc_template.spec +0 -0
  57. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/Eq_sanity.conf +0 -0
  58. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/Eq_template.spec +0 -0
  59. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/__init__.py +0 -0
  60. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/equivCheck.py +0 -0
  61. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/EquivalenceCheck/sanity.spec +0 -0
  62. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/__init__.py +0 -0
  63. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/mutateApp.py +0 -0
  64. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/mutateAttributes.py +0 -0
  65. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/mutateConstants.py +0 -0
  66. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/mutateUtil.py +0 -0
  67. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Mutate/mutateValidate.py +0 -0
  68. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/ExpectedComparator.py +0 -0
  69. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/__init__.py +0 -0
  70. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/certoraAttrUtil.py +0 -0
  71. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/certoraLogging.py +0 -0
  72. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/Shared/proverCommon.py +0 -0
  73. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/__init__.py +0 -0
  74. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraCVLFormatter.py +0 -0
  75. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraConcord.py +0 -0
  76. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraEVMProver.py +0 -0
  77. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraEqCheck.py +0 -0
  78. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraMutate.py +0 -0
  79. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraRanger.py +0 -0
  80. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraRun.py +0 -0
  81. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraSolanaProver.py +0 -0
  82. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraSorobanProver.py +0 -0
  83. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/certoraSuiProver.py +0 -0
  84. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli/rustMutator.py +0 -0
  85. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli.egg-info/SOURCES.txt +0 -0
  86. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli.egg-info/dependency_links.txt +0 -0
  87. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli.egg-info/entry_points.txt +0 -0
  88. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli.egg-info/requires.txt +0 -0
  89. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_cli.egg-info/top_level.txt +0 -0
  90. {certora_cli-8.8.0 → certora_cli-8.11.3}/certora_jars/__init__.py +0 -0
  91. {certora_cli-8.8.0 → certora_cli-8.11.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: certora-cli
3
- Version: 8.8.0
3
+ Version: 8.11.3
4
4
  Summary: Runner for the Certora Prover
5
5
  Home-page: https://pypi.org/project/certora-cli
6
6
  Author: Certora
@@ -38,4 +38,4 @@ Dynamic: requires-dist
38
38
  Dynamic: requires-python
39
39
  Dynamic: summary
40
40
 
41
- Commit 2cf089d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
41
+ Commit d4f463a. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
@@ -0,0 +1 @@
1
+ Commit d4f463a. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
@@ -890,7 +890,7 @@ class CertoraBuildGenerator:
890
890
  # same name but used separately could exist right?
891
891
  # Add to the current contract all public/external functions, and internal/private ones if
892
892
  # this is the declaring contract.
893
- if func_visibility in ("public", "external") or (c_name == contract_name):
893
+ if func_visibility in ("public", "external") or (c_name == contract_name and c_file == contract_file):
894
894
  funcs.append(func)
895
895
  ast_logger.debug(f"Function {func.source_code_signature()} added")
896
896
 
@@ -1114,11 +1114,12 @@ class CertoraBuildGenerator:
1114
1114
  assert "baseName" in bc and "referencedDeclaration" in bc["baseName"]
1115
1115
  next_bc_ref = bc["baseName"]["referencedDeclaration"]
1116
1116
  next_bc = self.get_contract_file_of(build_arg_contract_file, next_bc_ref)
1117
- if next_bc not in base_contracts_lst:
1117
+ next_bc_name = self.asts[build_arg_contract_file][next_bc][next_bc_ref]["name"]
1118
+ if (next_bc, next_bc_name) not in [(e[0], e[1]) for e in base_contracts_lst]:
1118
1119
  base_contracts_lst.append(
1119
- (next_bc, self.asts[build_arg_contract_file][next_bc][next_bc_ref]["name"],
1120
+ (next_bc, next_bc_name,
1120
1121
  self.is_library_def_node(next_bc, next_bc_ref, build_arg_contract_file)))
1121
- base_contracts_queue.insert(0, (next_bc, bc["baseName"]["referencedDeclaration"]))
1122
+ base_contracts_queue.insert(0, (next_bc, next_bc_ref))
1122
1123
 
1123
1124
  if base_contracts_queue:
1124
1125
  retrieve_base_contracts_list_rec(base_contracts_queue, base_contracts_lst)
@@ -1447,7 +1448,9 @@ class CertoraBuildGenerator:
1447
1448
  if not self.context.strict_solc_optimizer and self.get_solc_via_ir_value(contract_file_path):
1448
1449
  # The default optimizer steps (taken from libsolidity/interface/OptimiserSettings.h) but with the
1449
1450
  # full inliner step removed
1450
- solc0_8_26_to_0_8_30 = ("dhfoDgvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLCTUca[r]LSsTFOtfDnca[r]" +
1451
+ solc0_8_34_to_0_8_34 = ("dfDvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLvifMCTUca[r]LSsTFOtfDnca[r]"
1452
+ "IulcscCTUtvifMx[scCTUt]TOntnfDIulvifMjmul[jul]VcTOculjmul")
1453
+ solc0_8_26_to_0_8_33 = ("dhfoDgvulfnTUtnIfxa[r]EscLMVcul[j]Trpeulxa[r]cLCTUca[r]LSsTFOtfDnca[r]" +
1451
1454
  "IulcscCTUtx[scCTUt]TOntnfDIuljmul[jul]VcTOculjmul")
1452
1455
  solc0_8_13_to_0_8_25 = "dhfoDgvulfnTUtnIf[xa[r]EscLMcCTUtTOntnfDIulLculVcul[j]T" + \
1453
1456
  "peulxa[rul]xa[r]cLgvifCTUca[r]LSsTFOtfDnca[r]Iulc]jmul[jul]VcTOculjmul"
@@ -1496,8 +1499,10 @@ class CertoraBuildGenerator:
1496
1499
  yul_optimizer_steps = solc0_8_12
1497
1500
  elif minor == 8 and 13 <= patch <= 25:
1498
1501
  yul_optimizer_steps = solc0_8_13_to_0_8_25
1499
- elif minor == 8 and 26 <= patch <= 30:
1500
- yul_optimizer_steps = solc0_8_26_to_0_8_30
1502
+ elif minor == 8 and 26 <= patch <= 33:
1503
+ yul_optimizer_steps = solc0_8_26_to_0_8_33
1504
+ elif minor == 8 and 34 <= patch <= 34:
1505
+ yul_optimizer_steps = solc0_8_34_to_0_8_34
1501
1506
  assert yul_optimizer_steps is not None, \
1502
1507
  'Yul Optimizer steps missing for requested Solidity version. Please contact Certora team.'
1503
1508
 
@@ -1591,10 +1596,12 @@ class CertoraBuildGenerator:
1591
1596
  "evm.bytecode.functionDebugData"]
1592
1597
  ast_selection = ["id", "ast"]
1593
1598
  elif compiler_collector_lang == CompilerLangVy():
1594
- main_contract_for_output_selection = "*"
1595
1599
  sources_dict = {}
1596
- with open(contract_file_posix_abs) as f:
1597
- if self.context.vyper_custom_std_json_in_map and contract_file_as_provided in self.context.vyper_custom_std_json_in_map:
1600
+ vyper_custom_std_json_in = None
1601
+
1602
+ if self.context.vyper_custom_std_json_in_map:
1603
+ main_contract_for_output_selection = contract_file_as_provided
1604
+ if contract_file_as_provided in self.context.vyper_custom_std_json_in_map:
1598
1605
  """
1599
1606
  If we're given a custom standard_json, we'll take from it the sources and
1600
1607
  the search paths.
@@ -1606,18 +1613,36 @@ class CertoraBuildGenerator:
1606
1613
  if we get more projects.
1607
1614
  """
1608
1615
  vyper_custom_std_json_in = self.context.vyper_custom_std_json_in_map[contract_file_as_provided]
1609
- with open(vyper_custom_std_json_in) as custom:
1610
- custom_json = json.load(custom)
1611
- sources_dict = custom_json.get("sources", None)
1612
- search_paths_arr = custom_json.get("settings", {}).get("search_paths", None)
1613
- additional_asts = [x for x, _ in sources_dict.items() if x.endswith(".vy")]
1614
- if not sources_dict:
1616
+ elif self.context.resolve_vyper_imports and compiler_collector.compiler_version >= (0, 4, 0):
1617
+ main_contract_for_output_selection = contract_file_as_provided
1618
+ """
1619
+ If resolve_vyper_imports is enabled, we ask the vyper compiler to generate a standard_json for us.
1620
+ """
1621
+ compiler_ver_to_run = get_relevant_compiler(Path(contract_file_as_provided), self.context)
1622
+ vyper_options = f"-f solc_json {contract_file_as_provided} --disable-sys-path"
1623
+ for path in ((self.context.vyper_system_path or []) + (self.context.vyper_import_path or [])):
1624
+ vyper_options += f" -p {path}"
1625
+ Util.run_compiler_cmd(f"{compiler_ver_to_run} {vyper_options}",
1626
+ f"{contract_file_posix_abs.name}.std_json_generated.json",
1627
+ wd=compile_wd)
1628
+ vyper_custom_std_json_in = compiler_collector_lang.compilation_output_path(
1629
+ f"{contract_file_posix_abs.name}.std_json_generated.stdout.json")
1630
+
1631
+ if vyper_custom_std_json_in:
1632
+ with open(vyper_custom_std_json_in) as custom:
1633
+ custom_json = json.load(custom)
1634
+ sources_dict = custom_json.get("sources", None)
1635
+ search_paths_arr = custom_json.get("settings", {}).get("search_paths", None)
1636
+ additional_asts = [x for x, _ in sources_dict.items() if x.endswith(".vy")]
1637
+
1638
+ if not sources_dict:
1639
+ with open(contract_file_posix_abs) as f:
1615
1640
  contents = f.read()
1616
1641
  sources_dict = {str(contract_file_posix_abs): {"content": contents}}
1617
- output_selection = ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers"]
1618
- if compiler_collector.compiler_version >= (0, 4, 4):
1619
- output_selection += ["metadata", "evm.deployedBytecode.symbolMap"]
1620
- ast_selection = ["ast"]
1642
+ output_selection = ["abi", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers"]
1643
+ if compiler_collector.compiler_version >= (0, 4, 4):
1644
+ output_selection += ["metadata", "evm.deployedBytecode.symbolMap"]
1645
+ ast_selection = ["ast"]
1621
1646
  else:
1622
1647
  # "non-compilable" language so no need to deal with it
1623
1648
  fatal_error(compiler_logger, "Expected only Solidity and Vyper as "
@@ -2483,8 +2508,8 @@ class CertoraBuildGenerator:
2483
2508
  return f"{contract}_{address}"
2484
2509
 
2485
2510
  @staticmethod
2486
- def get_primary_contract_from_sdc(contracts: List[ContractInSDC], primary: str) -> List[ContractInSDC]:
2487
- return [x for x in contracts if x.name == primary]
2511
+ def get_primary_contract_from_sdc(contracts: List[ContractInSDC], primary: str, primary_file: str) -> List[ContractInSDC]:
2512
+ return [x for x in contracts if x.name == primary and Util.abs_norm_path(x.original_file) == Util.abs_norm_path(primary_file)]
2488
2513
 
2489
2514
  @staticmethod
2490
2515
  def generate_library_import(file_absolute_path: str, library_name: str) -> str:
@@ -2945,7 +2970,7 @@ class CertoraBuildGenerator:
2945
2970
  sdc.original_srclist,
2946
2971
  sdc.report_srclist,
2947
2972
  f"{sdc.sdc_name}_{library_contract.name}",
2948
- self.get_primary_contract_from_sdc(sdc.contracts, library_contract.name),
2973
+ self.get_primary_contract_from_sdc(sdc.contracts, library_contract.name, library_contract.original_file),
2949
2974
  [],
2950
2975
  {},
2951
2976
  {},
@@ -2956,7 +2981,7 @@ class CertoraBuildGenerator:
2956
2981
  self.SDCs[self.get_sdc_key(sdc_lib.primary_contract, sdc_lib.primary_contract_address)] = sdc_lib
2957
2982
 
2958
2983
  # Filter out irrelevant contracts, now that we extracted the libraries, leave just the primary
2959
- sdc.contracts = self.get_primary_contract_from_sdc(sdc.contracts, sdc.primary_contract)
2984
+ sdc.contracts = self.get_primary_contract_from_sdc(sdc.contracts, sdc.primary_contract, sdc.sdc_origin_file)
2960
2985
  assert len(
2961
2986
  sdc.contracts) == 1, f"Found multiple primary contracts ({sdc.contracts}) in SDC {sdc.sdc_name}"
2962
2987
 
@@ -2977,8 +3002,13 @@ class CertoraBuildGenerator:
2977
3002
  corresponding to the namespaced types.
2978
3003
 
2979
3004
  Args:
2980
- original_file: Path to the Solidity file containing namespaced storage declarations
3005
+ original_file: Path to the Solidity file containing namespaced storage declarations.
3006
+ This may be a (transitivly) imported file rather than a user-specified target.
2981
3007
  ns_storage: Set of tuples (type_name, namespace) for each namespaced storage
3008
+ compiler_version: The compiler version to use, already resolved from target_file
3009
+ target_file: The user-specified file (from conf file) that imported original_file.
3010
+ Used to resolve compilation settings (solc_optimize_map, solc_via_ir_map, etc.)
3011
+ for the temporary harness file, since original_file may not have entries in those maps.
2982
3012
 
2983
3013
  Returns:
2984
3014
  NewStorageInfo: A tuple (fields, types) where:
@@ -2997,8 +3027,24 @@ class CertoraBuildGenerator:
2997
3027
  # directly can cause issues.
2998
3028
  tmp_file.write(f"import \"{original_file}\";\n\n")
2999
3029
  rel_path = os.path.relpath(tmp_file.name, Path.cwd())
3000
- if self.context.compiler_map:
3001
- self.context.compiler_map.update({rel_path: compiler_version}, last=False)
3030
+ tmp_abs_path = Util.abs_posix_path(tmp_file.name)
3031
+ # Add the temp file to all map attributes so that map lookups
3032
+ # (solc_optimize_map, solc_via_ir_map, etc.) succeed during compilation.
3033
+ # We resolve values from target_file (a user-specified file in context.file_paths)
3034
+ # rather than original_file (which may be a transitive dependency not in any map).
3035
+ # We store both relative and absolute path keys because different lookup sites
3036
+ # normalize paths differently: get_relevant_compiler uses relative paths,
3037
+ # while _handle_via_ir/_handle_optimize use absolute paths.
3038
+ for map_attr in self.context.app.attr_class.all_map_attrs():
3039
+ map_attr_value = getattr(self.context, map_attr, None)
3040
+ if not map_attr_value:
3041
+ continue
3042
+ attr_name = map_attr[:-len(Util.MAP_SUFFIX)]
3043
+ target_value = Ctx.get_map_attribute_value(
3044
+ self.context, Path(target_file), attr_name
3045
+ )
3046
+ if target_value is not None:
3047
+ map_attr_value.update({rel_path: target_value, tmp_abs_path: target_value}, last=False)
3002
3048
  # Write the harness contract with dummy fields for each namespaced storage
3003
3049
  var_to_slot = storageExtension.write_harness_contract(tmp_file, harness_name, ns_storage)
3004
3050
  tmp_file.flush()
@@ -4121,8 +4167,13 @@ def build_from_scratch(context: CertoraContext,
4121
4167
  indent=4,
4122
4168
  sort_keys=True)
4123
4169
 
4170
+ # check if asts file exists (only when --dump_asts is used)
4171
+ asts_file = Util.get_asts_file()
4172
+ asts_file_if_exists = asts_file if asts_file.exists() else None
4173
+
4124
4174
  return CachedFiles(certora_build_file, all_contract_files, build_output_props_file, may_store_in_build_cache,
4125
- path_with_additional_included_files=absolute_sources_dir)
4175
+ path_with_additional_included_files=absolute_sources_dir,
4176
+ asts_file=asts_file_if_exists)
4126
4177
 
4127
4178
 
4128
4179
  def build_from_cache_or_scratch(context: CertoraContext,
@@ -4204,6 +4255,10 @@ def build_from_cache_or_scratch(context: CertoraContext,
4204
4255
  else:
4205
4256
  shutil.copyfile(p, Util.get_certora_sources_dir() / p.name)
4206
4257
 
4258
+ # restore asts file from cache if present
4259
+ if cached_files.asts_file is not None and cached_files.asts_file.exists():
4260
+ shutil.copyfile(cached_files.asts_file, Util.get_asts_file())
4261
+
4207
4262
  return False, cached_files
4208
4263
 
4209
4264
 
@@ -41,6 +41,9 @@ class CachedFiles:
41
41
  # to keep .post_autofinders
42
42
  path_with_additional_included_files: Path
43
43
 
44
+ # optional asts file (only present when --dump_asts is used)
45
+ asts_file: Optional[Path] = None
46
+
44
47
  def all_exist(self, main_cache_entry_dir: Path, sub_cache_key: str) -> bool:
45
48
  exist = self.certora_build_file.exists() and \
46
49
  self.certora_build_file == main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.certora_build_suffix}"
@@ -55,6 +58,7 @@ class CachedFiles:
55
58
  file_list_suffix = "file_list.json"
56
59
  build_output_props_suffix = "build_output_props.json"
57
60
  additional_included_files = "additional_included_files"
61
+ asts_suffix = "asts.json"
58
62
 
59
63
 
60
64
  class CertoraBuildCacheManager:
@@ -124,8 +128,14 @@ class CertoraBuildCacheManager:
124
128
  return None
125
129
 
126
130
  additional_included_files = main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.additional_included_files}"
131
+
132
+ # check if asts file exists in cache
133
+ asts_file_in_cache = main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.asts_suffix}"
134
+ asts_file = asts_file_in_cache if asts_file_in_cache.exists() else None
135
+
127
136
  return CachedFiles(certora_build_file, all_contract_files, build_output_props_file,
128
- may_store_in_build_cache=True, path_with_additional_included_files=additional_included_files)
137
+ may_store_in_build_cache=True, path_with_additional_included_files=additional_included_files,
138
+ asts_file=asts_file)
129
139
 
130
140
  @staticmethod
131
141
  def save_build_cache(context: CertoraContext, cached_files: CachedFiles) -> None:
@@ -170,6 +180,11 @@ class CertoraBuildCacheManager:
170
180
  # save additional props file
171
181
  shutil.copyfile(cached_files.build_output_props_file,
172
182
  main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.build_output_props_suffix}")
183
+ # save asts file if present
184
+ if cached_files.asts_file is not None and cached_files.asts_file.exists():
185
+ shutil.copyfile(cached_files.asts_file,
186
+ main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.asts_suffix}")
187
+
173
188
  # save .post_autofinders from additional included files
174
189
  trg_path_with_additional_included_files = \
175
190
  main_cache_entry_dir / f"{sub_cache_key}.{CachedFiles.additional_included_files}"
@@ -55,13 +55,42 @@ def build_sui_project(context: CertoraContext, timings: Dict) -> None:
55
55
  def set_sui_build_directory(context: CertoraContext) -> None:
56
56
  sources: Set[Path] = set()
57
57
 
58
- # If no move_path was specified, try to build the package
59
- if not context.move_path:
60
- move_toml_file = Util.find_file_in_parents("Move.toml")
61
- if not move_toml_file:
62
- raise Util.CertoraUserInputError("Could not find Move.toml, and no move_path was specified.")
58
+ move_toml_file: Path | None = None
59
+
60
+ if context.move_path:
61
+ # If move_path is specified, we assume the user has already built the spec package separately. This is a legacy
62
+ # option that should not be used by new projects; they should use `spec_package_path` and/or `build_script`
63
+ # instead.
64
+ assert not context.build_script, "cannot have move_path and build_script together"
65
+ assert not context.spec_package_path, "cannot have move_path and spec_package_path together"
66
+ context.sui_package_summary_path = None
67
+ else:
68
+ if context.spec_package_path:
69
+ # Verify that there is a Move.toml at the specified spec_package_path
70
+ spec_package_dir = Path(context.spec_package_path)
71
+ move_toml_file = spec_package_dir / "Move.toml"
72
+ if not move_toml_file.exists():
73
+ raise Util.CertoraUserInputError(f"Could not find Move.toml at specified spec_package_path '{context.spec_package_path}'")
74
+ else:
75
+ # If spec_package_path is not specified, try to find the package that the current directory is in.
76
+ move_toml_file = Util.find_file_in_parents("Move.toml")
77
+ if not move_toml_file:
78
+ raise Util.CertoraUserInputError("Could not find Move.toml, and no spec_package_path was specified.")
79
+ spec_package_dir = move_toml_file.parent
80
+ context.spec_package_path = str(spec_package_dir)
81
+
63
82
  sources.add(move_toml_file.absolute())
64
- run_sui_build(context, move_toml_file.parent)
83
+ context.move_path = str(spec_package_dir / "build")
84
+ context.sui_package_summary_path = spec_package_dir / "package_summaries"
85
+
86
+ if context.build_script:
87
+ # Run the user-provided build script
88
+ script_path = Path(context.build_script).resolve()
89
+ sources.add(script_path)
90
+ run_sui_build([str(script_path), str(spec_package_dir)])
91
+ else:
92
+ # Build the package using `sui move summary`, which will also produce the package summaries.
93
+ run_sui_build(["sui", "move", "summary", "--test", "--path", str(move_toml_file.parent)])
65
94
 
66
95
  assert context.move_path, "expecting move_path to be set after build"
67
96
  move_dir = Path(context.move_path)
@@ -81,6 +110,12 @@ def set_sui_build_directory(context: CertoraContext) -> None:
81
110
  Util.get_build_dir() / move_dir.name,
82
111
  ignore=shutil.ignore_patterns('*.move'))
83
112
 
113
+ # Copy package summary directory if it exists. Projects built manually with "sui move build" may not have this.
114
+ if context.sui_package_summary_path and context.sui_package_summary_path.exists():
115
+ assert context.sui_package_summary_path.is_dir(), f"Package summary path '{context.sui_package_summary_path}' is not a directory"
116
+ shutil.copytree(context.sui_package_summary_path,
117
+ Util.get_build_dir() / context.sui_package_summary_path.name)
118
+
84
119
  try:
85
120
  # Create generators
86
121
  build_source_tree(sources, context)
@@ -88,11 +123,8 @@ def set_sui_build_directory(context: CertoraContext) -> None:
88
123
  except Exception as e:
89
124
  raise Util.CertoraUserInputError(f"Collecting build files failed with the exception: {e}")
90
125
 
91
- def run_sui_build(context: CertoraContext, package_dir: Path) -> None:
92
- assert not context.move_path, "run_sui_build: expecting move_path to be empty"
93
-
94
- build_cmd = ["sui", "move", "build", "--test", "--path", str(package_dir)]
95
126
 
127
+ def run_sui_build(build_cmd: list[str]) -> None:
96
128
  try:
97
129
  build_cmd_text = ' '.join(build_cmd)
98
130
  log.info(f"Building by calling `{build_cmd_text}`")
@@ -102,8 +134,6 @@ def run_sui_build(context: CertoraContext, package_dir: Path) -> None:
102
134
  if result.returncode != 0:
103
135
  raise Util.CertoraUserInputError(f"Error running `{build_cmd_text}`")
104
136
 
105
- context.move_path = str(package_dir / "build")
106
-
107
137
  except Util.TestResultsReady as e:
108
138
  raise e
109
139
  except Util.CertoraUserInputError as e:
@@ -615,6 +615,9 @@ class CloudVerification:
615
615
 
616
616
  elif Attrs.is_sui_app():
617
617
  sui_jar_settings = ['-movePath', Path(self.context.move_path).name]
618
+ if self.context.sui_package_summary_path and self.context.sui_package_summary_path.exists():
619
+ sui_jar_settings.append('-suiPackageSummaryPath')
620
+ sui_jar_settings.append(self.context.sui_package_summary_path.name)
618
621
  auth_data["jarSettings"] = sui_jar_settings + jar_settings
619
622
 
620
623
  elif Attrs.is_concord_app():
@@ -766,6 +769,9 @@ class CloudVerification:
766
769
  Util.get_configuration_layout_data_file(),
767
770
  Util.get_build_dir() / Path(self.context.move_path).name]
768
771
 
772
+ if self.context.sui_package_summary_path and self.context.sui_package_summary_path.exists():
773
+ files_list.append(Util.get_build_dir() / self.context.sui_package_summary_path.name)
774
+
769
775
  if Util.get_certora_sources_dir().exists():
770
776
  files_list.append(Util.get_certora_sources_dir())
771
777
 
@@ -63,6 +63,9 @@ def is_evm_app_class(context: CertoraContext) -> bool:
63
63
  def is_rust_app_class(context: CertoraContext) -> bool:
64
64
  return issubclass(context.app, App.RustAppClass)
65
65
 
66
+ def is_move_app_class(context: CertoraContext) -> bool:
67
+ return issubclass(context.app, App.MoveAppClass)
68
+
66
69
  def get_attr_value(context: CertoraContext, attr: AttrUtil.AttributeDefinition) -> Any:
67
70
  conf_key = attr.get_conf_key()
68
71
  return getattr(context, conf_key, None)
@@ -133,6 +136,9 @@ def get_local_run_cmd(context: CertoraContext) -> List[str]:
133
136
  # For local runs, we want path to be relative to cwd instead of zip root.
134
137
  move_rel_path = os.path.relpath(Path(context.move_path), os.getcwd())
135
138
  run_args.extend(['-movePath', move_rel_path])
139
+ if context.sui_package_summary_path and context.sui_package_summary_path.exists():
140
+ spec_package_summary_rel_path = os.path.relpath(context.sui_package_summary_path, os.getcwd())
141
+ run_args.extend(['-suiPackageSummaryPath', spec_package_summary_rel_path])
136
142
  elif is_rust_app_class(context):
137
143
  # For local runs, we want path to be relative to cwd instead of zip root.
138
144
  rust_rel_path = os.path.relpath(Path(context.files[0]), os.getcwd())
@@ -284,6 +290,9 @@ def get_args(args_list: List[str], app: Type[App.CertoraApp]) -> CertoraContext:
284
290
  Util.reset_certora_internal_dir(context.build_dir)
285
291
  os.rename(current_build_directory, context.build_dir)
286
292
 
293
+ if is_evm_app_class(context):
294
+ handle_vyper_system_path(context)
295
+
287
296
  # Store current options (including the ones read from .conf file)
288
297
  context.conf_options = current_conf_to_file(context)
289
298
 
@@ -297,6 +306,8 @@ def get_args(args_list: List[str], app: Type[App.CertoraApp]) -> CertoraContext:
297
306
  validator.handle_concord_attrs()
298
307
  if is_rust_app_class(context):
299
308
  validator.check_rust_args_post_argparse()
309
+ if is_move_app_class(context):
310
+ validator.check_move_args_post_argparse()
300
311
 
301
312
  attrs_to_relative(context)
302
313
  # Setup defaults (defaults are not recorded in conf file)
@@ -594,14 +605,14 @@ def run_local_spec_check(with_typechecking: bool, context: CertoraContext, extra
594
605
  raise Util.CertoraUserInputError("Cannot run local checks because of missing a suitable java installation. "
595
606
  "To skip local checks run with the --disable_local_typechecking flag")
596
607
 
597
- def attrs_to_relative(context: CertoraContext) -> None:
598
- def to_relative(input_path: Union[str, Path]) -> Union[str, Path]:
599
- path = Path(input_path) if isinstance(input_path, str) else input_path
600
- if path.is_absolute():
601
- relative_path = os.path.relpath(path, cwd) # Path.relative_to only works for subdirectories
602
- return str(relative_path) if isinstance(input_path, str) else relative_path
603
- return input_path
608
+ def to_relative(input_path: Union[str, Path]) -> Union[str, Path]:
609
+ path = Path(input_path) if isinstance(input_path, str) else input_path
610
+ if path.is_absolute():
611
+ relative_path = os.path.relpath(path, Path.cwd()) # Path.relative_to only works for subdirectories
612
+ return str(relative_path) if isinstance(input_path, str) else relative_path
613
+ return input_path
604
614
 
615
+ def attrs_to_relative(context: CertoraContext) -> None:
605
616
  def str_attr_to_relative(attr_name: str) -> None:
606
617
  attr_value = getattr(context, attr_name, None)
607
618
  if attr_value:
@@ -647,7 +658,6 @@ def attrs_to_relative(context: CertoraContext) -> None:
647
658
  if Path(spec_file).is_absolute():
648
659
  context.verify = ':'.join([contract, str(to_relative(spec_file))])
649
660
 
650
- cwd = Path.cwd()
651
661
  str_attr_to_relative('packages_path')
652
662
  str_attr_to_relative('bytecode_spec')
653
663
  str_attr_to_relative('yul_abi')
@@ -683,3 +693,24 @@ def get_map_attribute_value(context: CertoraContext, path: Path, attr_name: str)
683
693
  if glob.globmatch(str(path), pattern, flags=glob.GLOBSTAR):
684
694
  return entry_value
685
695
  raise RuntimeError(f"cannot match {attr_name} to {path} from {attr_name}_map")
696
+
697
+ def handle_vyper_system_path(context: CertoraContext) -> None:
698
+ """
699
+ Just like the Vyper compiler, we add the sys.path to the search path for imports, which allows us to resolve imports
700
+ using a package manager.
701
+
702
+ Note that we do this here, rather than allowing the Vyper compiler to do it, because we want to persist these paths
703
+ in the generated run.conf file, to make it easy to reproduce in a different environment.
704
+ """
705
+ if context.resolve_vyper_imports:
706
+ if not context.vyper_system_path:
707
+ # Pass the directories from sys.path in reversed order (Vyper treats later paths as higher precedence)
708
+ context.vyper_system_path = [
709
+ to_relative(p) for p in reversed(sys.path) if Path(p).is_dir()
710
+ ]
711
+ else:
712
+ # Filter out any directories that do not exist, to make the generated run.conf file more portable to
713
+ # different environments.
714
+ context.vyper_system_path = [
715
+ p for p in context.vyper_system_path if Path(p).is_dir()
716
+ ]
@@ -269,6 +269,22 @@ class DeprecatedAttributes(AttrUtil.Attributes):
269
269
  main_section=MainSection.SOLIDITY_COMPILER
270
270
  )
271
271
  )
272
+ MOVE_PATH = AttrUtil.AttributeDefinition(
273
+ attr_validation_func=Vf.validate_dir,
274
+ arg_type=AttrUtil.AttrArgType.STRING,
275
+ help_msg="path to a directory which includes all binary .mv files for the Prover",
276
+ deprecation_msg="`move_path` is deprecated and will be removed in a future release. "
277
+ "Please use `spec_package_path` instead.",
278
+ default_desc="",
279
+ argparse_args={
280
+ 'action': AttrUtil.UniqueStore
281
+ },
282
+ affects_build_cache_key=True,
283
+ disables_build_cache=False,
284
+ config_data=AttributeJobConfigData(
285
+ main_section=MainSection.NEW_SECTION
286
+ )
287
+ )
272
288
 
273
289
 
274
290
  class EvmAttributes(AttrUtil.Attributes):
@@ -326,6 +342,51 @@ class EvmAttributes(AttrUtil.Attributes):
326
342
  )
327
343
  )
328
344
 
345
+ RESOLVE_VYPER_IMPORTS = AttrUtil.AttributeDefinition(
346
+ arg_type=AttrUtil.AttrArgType.BOOLEAN,
347
+ help_msg="Whether to resolve Vyper imports (Vyper >= 4 only)",
348
+ default_desc="Vyper contracts are assumed not to use the import system",
349
+ argparse_args={
350
+ "action": AttrUtil.STORE_TRUE
351
+ },
352
+ affects_build_cache_key=True,
353
+ disables_build_cache=False,
354
+ config_data=AttributeJobConfigData(
355
+ main_section=MainSection.SOLIDITY_COMPILER
356
+ )
357
+ )
358
+
359
+ VYPER_IMPORT_PATH = AttrUtil.AttributeDefinition(
360
+ attr_validation_func=Vf.validate_dir,
361
+ arg_type=AttrUtil.AttrArgType.LIST,
362
+ help_msg="Additional paths to search for Vyper imports (Vyper >= 4 only)",
363
+ default_desc="Only the Python system path will be searched",
364
+ argparse_args={
365
+ 'nargs': AttrUtil.MULTIPLE_OCCURRENCES,
366
+ 'action': AttrUtil.APPEND
367
+ },
368
+ affects_build_cache_key=True,
369
+ disables_build_cache=False,
370
+ config_data=AttributeJobConfigData(
371
+ main_section=MainSection.NEW_SECTION
372
+ )
373
+ )
374
+
375
+ VYPER_SYSTEM_PATH = AttrUtil.AttributeDefinition(
376
+ arg_type=AttrUtil.AttrArgType.LIST,
377
+ help_msg="The system path to pass to Vyper (Vyper >= 4 only); typically automatically populated",
378
+ default_desc="Use the current Python system path",
379
+ argparse_args={
380
+ 'nargs': AttrUtil.MULTIPLE_OCCURRENCES,
381
+ 'action': AttrUtil.APPEND
382
+ },
383
+ affects_build_cache_key=True,
384
+ disables_build_cache=False,
385
+ config_data=AttributeJobConfigData(
386
+ main_section=MainSection.NEW_SECTION
387
+ )
388
+ )
389
+
329
390
  VYPER_CUSTOM_STD_JSON_IN_MAP = AttrUtil.AttributeDefinition(
330
391
  arg_type=AttrUtil.AttrArgType.MAP,
331
392
  attr_validation_func=Vf.validate_vyper_custom_std_json_in_map,
@@ -1215,7 +1276,7 @@ class EvmAttributes(AttrUtil.Attributes):
1215
1276
  argparse_args={
1216
1277
  'action': AttrUtil.STORE_TRUE
1217
1278
  },
1218
- affects_build_cache_key=False,
1279
+ affects_build_cache_key=True,
1219
1280
  disables_build_cache=False,
1220
1281
  )
1221
1282
 
@@ -1874,7 +1935,7 @@ class SorobanProverAttributes(CommonAttributes, InternalUseAttributes, BackendAt
1874
1935
  )
1875
1936
 
1876
1937
 
1877
- class SuiProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes):
1938
+ class SuiProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttributes, DeprecatedAttributes):
1878
1939
  FILES = AttrUtil.AttributeDefinition(
1879
1940
  attr_validation_func=Vf.validate_dir,
1880
1941
  arg_type=AttrUtil.AttrArgType.LIST,
@@ -1888,10 +1949,10 @@ class SuiProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttrib
1888
1949
  )
1889
1950
  )
1890
1951
 
1891
- MOVE_PATH = AttrUtil.AttributeDefinition(
1952
+ SPEC_PACKAGE_PATH = AttrUtil.AttributeDefinition(
1892
1953
  attr_validation_func=Vf.validate_dir,
1893
1954
  arg_type=AttrUtil.AttrArgType.STRING,
1894
- help_msg="path to a directory which includes all binary .mv files for the Prover",
1955
+ help_msg="path to the Move package containing the specification to be verified",
1895
1956
  default_desc="",
1896
1957
  argparse_args={
1897
1958
  'action': AttrUtil.UniqueStore
@@ -1903,6 +1964,17 @@ class SuiProverAttributes(CommonAttributes, InternalUseAttributes, BackendAttrib
1903
1964
  )
1904
1965
  )
1905
1966
 
1967
+ BUILD_SCRIPT = AttrUtil.AttributeDefinition(
1968
+ attr_validation_func=Vf.validate_exec_file,
1969
+ help_msg="script to build a Move project",
1970
+ default_desc="Using default building command",
1971
+ argparse_args={
1972
+ 'action': AttrUtil.UniqueStore
1973
+ },
1974
+ affects_build_cache_key=False,
1975
+ disables_build_cache=False
1976
+ )
1977
+
1906
1978
  RULE = AttrUtil.AttributeDefinition(
1907
1979
  arg_type=AttrUtil.AttrArgType.LIST,
1908
1980
  attr_validation_func=Vf.validate_move_rule_name,
@@ -2006,6 +2078,7 @@ class SolanaProverAttributes(CommonAttributes, InternalUseAttributes, BackendAtt
2006
2078
  ATTRIBUTES_CLASS: Optional[Type[AttrUtil.Attributes]] = None
2007
2079
 
2008
2080
  ARG_FLAG_LIST_ATTRIBUTES = ['prover_args', 'java_args']
2081
+ DUPLICATES_ALLOWED_LIST_ATTRIBUTES = [*ARG_FLAG_LIST_ATTRIBUTES, 'vyper_system_path']
2009
2082
 
2010
2083
 
2011
2084
  def get_attribute_class() -> Type[AttrUtil.Attributes]:
@@ -146,7 +146,7 @@ class CertoraContextValidator:
146
146
  # Check for duplicates, we exclude ARG_FLAG_LIST_ATTRIBUTES as those can have duplicates e.g.
147
147
  # prover_args value of “-rule rule1 -rule rule2" is valid, although the -rule string appears more than once.
148
148
 
149
- if conf_key not in Attrs.ARG_FLAG_LIST_ATTRIBUTES:
149
+ if conf_key not in Attrs.DUPLICATES_ALLOWED_LIST_ATTRIBUTES:
150
150
  if len(value) != len(set(value)):
151
151
  raise Util.CertoraUserInputError(f"The value of attribute '{conf_key}' contains duplicate entries: {value}")
152
152
 
@@ -196,6 +196,20 @@ class CertoraContextValidator:
196
196
  ci_value=str(Vf.UrlVisibilityOptions.PUBLIC),
197
197
  default_value=str(Vf.UrlVisibilityOptions.PRIVATE))
198
198
 
199
+ def check_move_args_post_argparse(self) -> None:
200
+ context = self.context
201
+ if context.move_path:
202
+ # Old-style move_path specification. We don't support build scripts or package paths in this case
203
+ if context.build_script:
204
+ raise Util.CertoraUserInputError(
205
+ "'move_path' and 'build_script' cannot be used together. To target a specific Move package with a "
206
+ "build script, specify `spec_package_path`."
207
+ )
208
+ if context.spec_package_path:
209
+ raise Util.CertoraUserInputError(
210
+ "'move_path' and 'spec_package_path' cannot be used together. `spec_package_path` is preferred."
211
+ )
212
+
199
213
  def check_args_post_argparse(self) -> None:
200
214
  """
201
215
  Performs checks over the arguments after basic argparse parsing
@@ -229,6 +243,7 @@ class CertoraContextValidator:
229
243
  set_bytecode_relative_paths(context)
230
244
  check_files_input(context.files)
231
245
  check_vyper_flag(context)
246
+ check_vyper_imports(context)
232
247
  check_via_ir_attr(context)
233
248
  check_contract_name_arg_inputs(context) # Here context.contracts is set
234
249
  Util.check_packages_arguments(context)
@@ -426,6 +441,15 @@ def check_vyper_flag(context: CertoraContext) -> None:
426
441
  if not vy_paths:
427
442
  validation_logger.warning("vyper attribute was set but no Vyper files were set")
428
443
 
444
+ def check_vyper_imports(context: CertoraContext) -> None:
445
+ if not context.resolve_vyper_imports:
446
+ if context.vyper_import_path:
447
+ raise Util.CertoraUserInputError("cannot set 'vyper_import_path' without setting 'resolve_vyper_imports' "
448
+ "to true")
449
+ if context.vyper_system_path:
450
+ raise Util.CertoraUserInputError("cannot set 'vyper_system_path' without setting 'resolve_vyper_imports' "
451
+ "to true")
452
+
429
453
  def check_contract_name_arg_inputs(context: CertoraContext) -> None:
430
454
  """
431
455
  This function verifies that all options that expect to get contract names get valid contract names.
@@ -265,8 +265,10 @@ def get_debug_log_file() -> Path:
265
265
  def get_extension_info_file() -> Path:
266
266
  return path_in_build_directory(Path(".vscode_extension_info.json"))
267
267
 
268
+ ASTS_FILE_NAME = ".asts.json"
269
+
268
270
  def get_asts_file() -> Path:
269
- return path_in_build_directory(Path(".asts.json"))
271
+ return path_in_build_directory(Path(ASTS_FILE_NAME))
270
272
 
271
273
  def get_zip_output_url_file() -> Path:
272
274
  return CERTORA_INTERNAL_ROOT / '.zip-output-url.txt'
@@ -874,6 +874,12 @@ def validate_evm_rule_name(rule_str: str) -> str:
874
874
  else:
875
875
  return __validate_solidity_id(rule_str, "rule")
876
876
 
877
+ def validate_move_rule_pattern_string(rule_str: str) -> str:
878
+ if not re.match(r"^([a-zA-Z0-9_$*]|::)+$", rule_str):
879
+ raise Util.CertoraUserInputError(f"invalid rule pattern \"{rule_str}\": rule patterns must contain only "
880
+ "letters, digits, dollar signs, underscores, asterisks, or double colons")
881
+ return rule_str
882
+
877
883
  def validate_move_function_name(name: str) -> str:
878
884
  if not re.match(r"^(0x[0-9a-fA-F]+|([a-zA-Z_][a-zA-Z0-9_]*))::[a-zA-Z_][a-zA-Z0-9_]*::[a-zA-Z_][a-zA-Z0-9_]*$", name):
879
885
  raise Util.CertoraUserInputError(f"invalid Move function name \"{name}\": must be a fully-qualified Move "
@@ -882,7 +888,7 @@ def validate_move_function_name(name: str) -> str:
882
888
 
883
889
  def validate_move_rule_name(rule_str: str) -> str:
884
890
  if ("*" in rule_str):
885
- return validate_rule_pattern_string(rule_str)
891
+ return validate_move_rule_pattern_string(rule_str)
886
892
  else:
887
893
  return validate_move_function_name(rule_str)
888
894
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: certora-cli
3
- Version: 8.8.0
3
+ Version: 8.11.3
4
4
  Summary: Runner for the Certora Prover
5
5
  Home-page: https://pypi.org/project/certora-cli
6
6
  Author: Certora
@@ -38,4 +38,4 @@ Dynamic: requires-dist
38
38
  Dynamic: requires-python
39
39
  Dynamic: summary
40
40
 
41
- Commit 2cf089d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
41
+ Commit d4f463a. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
@@ -0,0 +1 @@
1
+ {"name": "certora-cli", "tag": "8.11.3", "branch": "", "commit": "d4f463a", "timestamp": "20260421.18.49.434064", "version": "8.11.3"}
@@ -3,11 +3,11 @@ import setuptools
3
3
 
4
4
  setuptools.setup(
5
5
  name="certora-cli",
6
- version="8.8.0",
6
+ version="8.11.3",
7
7
  author="Certora",
8
8
  author_email="support@certora.com",
9
9
  description="Runner for the Certora Prover",
10
- long_description="Commit 2cf089d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.",
10
+ long_description="Commit d4f463a. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.",
11
11
  long_description_content_type="text/markdown",
12
12
  url="https://pypi.org/project/certora-cli",
13
13
  packages=setuptools.find_packages(),
@@ -1 +0,0 @@
1
- Commit 2cf089d. Build and Run scripts for executing the Certora Prover on Solidity smart contracts.
@@ -1 +0,0 @@
1
- {"name": "certora-cli", "tag": "8.8.0", "branch": "", "commit": "2cf089d", "timestamp": "20260209.18.33.322934", "version": "8.8.0"}
File without changes
File without changes
File without changes