|
11 | 11 | 7) Error(string) selector constant sync between ContractSpec and Interpreter. |
12 | 12 | 8) Address mask constant sync between ContractSpec and Interpreter. |
13 | 13 | 9) Selector shift constant sync between ContractSpec, Codegen, and Builtins. |
| 14 | +10) Internal function prefix sync between ContractSpec and CI script. |
| 15 | +11) Special entrypoint names sync between ContractSpec and CI script. |
14 | 16 | """ |
15 | 17 |
|
16 | 18 | from __future__ import annotations |
@@ -597,6 +599,70 @@ def check_selector_shift_sync() -> List[str]: |
597 | 599 | return errors |
598 | 600 |
|
599 | 601 |
|
| 602 | +# --------------------------------------------------------------------------- |
| 603 | +# Internal function prefix sync |
| 604 | +# --------------------------------------------------------------------------- |
| 605 | + |
| 606 | +_INTERNAL_PREFIX_RE = re.compile( |
| 607 | + r'def\s+internalFunctionPrefix\s*:\s*String\s*:=\s*"([^"]*)"' |
| 608 | +) |
| 609 | + |
| 610 | + |
| 611 | +def check_internal_prefix_sync() -> List[str]: |
| 612 | + """Verify _INTERNAL_FUNCTION_PREFIX matches ContractSpec.internalFunctionPrefix.""" |
| 613 | + errors: List[str] = [] |
| 614 | + if not CONTRACT_SPEC_FILE.exists(): |
| 615 | + errors.append(f"Missing {CONTRACT_SPEC_FILE}") |
| 616 | + return errors |
| 617 | + text = CONTRACT_SPEC_FILE.read_text(encoding="utf-8") |
| 618 | + m = _INTERNAL_PREFIX_RE.search(text) |
| 619 | + if not m: |
| 620 | + errors.append( |
| 621 | + "ContractSpec.lean: missing internalFunctionPrefix definition" |
| 622 | + ) |
| 623 | + elif m.group(1) != _INTERNAL_FUNCTION_PREFIX: |
| 624 | + errors.append( |
| 625 | + f"ContractSpec.internalFunctionPrefix is {m.group(1)!r} " |
| 626 | + f"but check_selectors.py uses {_INTERNAL_FUNCTION_PREFIX!r}" |
| 627 | + ) |
| 628 | + return errors |
| 629 | + |
| 630 | + |
| 631 | +# --------------------------------------------------------------------------- |
| 632 | +# Special entrypoint names sync |
| 633 | +# --------------------------------------------------------------------------- |
| 634 | + |
| 635 | +_INTEROP_ENTRYPOINTS_RE = re.compile( |
| 636 | + r'def\s+isInteropEntrypointName\b.*?:=\s*\[([^\]]*)\]', |
| 637 | + re.DOTALL, |
| 638 | +) |
| 639 | + |
| 640 | + |
| 641 | +def check_special_entrypoints_sync() -> List[str]: |
| 642 | + """Verify _SPECIAL_ENTRYPOINTS matches ContractSpec.isInteropEntrypointName.""" |
| 643 | + errors: List[str] = [] |
| 644 | + if not CONTRACT_SPEC_FILE.exists(): |
| 645 | + errors.append(f"Missing {CONTRACT_SPEC_FILE}") |
| 646 | + return errors |
| 647 | + text = CONTRACT_SPEC_FILE.read_text(encoding="utf-8") |
| 648 | + m = _INTEROP_ENTRYPOINTS_RE.search(text) |
| 649 | + if not m: |
| 650 | + errors.append( |
| 651 | + "ContractSpec.lean: missing isInteropEntrypointName definition" |
| 652 | + ) |
| 653 | + return errors |
| 654 | + # Parse the Lean list literal: ["fallback", "receive"] |
| 655 | + lean_names = set( |
| 656 | + n.strip().strip('"') for n in m.group(1).split(",") if n.strip() |
| 657 | + ) |
| 658 | + if lean_names != _SPECIAL_ENTRYPOINTS: |
| 659 | + errors.append( |
| 660 | + f"ContractSpec.isInteropEntrypointName uses {sorted(lean_names)} " |
| 661 | + f"but check_selectors.py uses {sorted(_SPECIAL_ENTRYPOINTS)}" |
| 662 | + ) |
| 663 | + return errors |
| 664 | + |
| 665 | + |
600 | 666 | def main() -> None: |
601 | 667 | if not SPEC_FILE.exists(): |
602 | 668 | die(f"Missing specs file: {SPEC_FILE}") |
@@ -658,6 +724,12 @@ def main() -> None: |
658 | 724 | # Validate selector shift constant consistency. |
659 | 725 | errors.extend(check_selector_shift_sync()) |
660 | 726 |
|
| 727 | + # Validate internal function prefix consistency. |
| 728 | + errors.extend(check_internal_prefix_sync()) |
| 729 | + |
| 730 | + # Validate special entrypoint names consistency. |
| 731 | + errors.extend(check_special_entrypoints_sync()) |
| 732 | + |
661 | 733 | report_errors(errors, "Selector checks failed") |
662 | 734 | print("Selector checks passed.") |
663 | 735 |
|
|
0 commit comments