diff --git a/.github/scripts/check-ocaml-refs.sh b/.github/scripts/check-ocaml-refs.sh new file mode 100755 index 000000000..e6167c248 --- /dev/null +++ b/.github/scripts/check-ocaml-refs.sh @@ -0,0 +1,241 @@ +#!/usr/bin/env bash +# Script to validate OCaml reference comments in Rust code +# Usage: ./.github/scripts/check-ocaml-refs.sh [--repo REPO_URL] [--branch BRANCH] [--update] + +set -euo pipefail + +# Default configuration +OCAML_REPO="${OCAML_REPO:-https://github.com/MinaProtocol/mina.git}" +OCAML_BRANCH="${OCAML_BRANCH:-compatible}" +UPDATE_MODE="${UPDATE_MODE:-false}" +RUST_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" + +# Parse arguments +while [[ $# -gt 0 ]]; do + case $1 in + --repo) + OCAML_REPO="$2" + shift 2 + ;; + --branch) + OCAML_BRANCH="$2" + shift 2 + ;; + --update) + UPDATE_MODE="true" + shift + ;; + *) + echo "Unknown option: $1" + echo "Usage: ./.github/scripts/check-ocaml-refs.sh [--repo REPO_URL] [--branch BRANCH] [--update]" + exit 1 + ;; + esac +done + +echo "Checking OCaml references against ${OCAML_REPO} (branch: ${OCAML_BRANCH})" + +# Create temporary directory +TEMP_DIR=$(mktemp -d) +trap 'rm -rf "$TEMP_DIR"' EXIT + +# Extract GitHub owner and repo from URL (e.g., https://github.com/MinaProtocol/mina.git) +GITHUB_URL_PATTERN="https://github.com/([^/]+)/(.+)" +if [[ "$OCAML_REPO" =~ $GITHUB_URL_PATTERN ]]; then + GITHUB_OWNER="${BASH_REMATCH[1]}" + GITHUB_REPO="${BASH_REMATCH[2]%.git}" # Remove .git suffix if present +else + echo "Error: Repository URL must be a GitHub URL" + exit 1 +fi + +# Get current commit hash for the branch using GitHub API +echo "Fetching current commit from ${OCAML_BRANCH}..." +CURRENT_COMMIT=$(curl -s "https://api.github.com/repos/${GITHUB_OWNER}/${GITHUB_REPO}/commits/${OCAML_BRANCH}" | grep -o '"sha": "[^"]*"' | head -1 | cut -d'"' -f4) + +if [ -z "$CURRENT_COMMIT" ]; then + echo "Error: Could not fetch current commit for branch ${OCAML_BRANCH}" + exit 1 +fi + +echo "Current OCaml commit: ${CURRENT_COMMIT}" + +# Find all Rust files with OCaml references +cd "${RUST_ROOT}" +RUST_FILES=$(rg -l "^/// OCaml reference:" --type rust || true) + +if [ -z "$RUST_FILES" ]; then + echo "No OCaml references found in Rust code" + exit 0 +fi + +# Use temporary files to accumulate results +RESULTS_FILE="${TEMP_DIR}/results.txt" +touch "$RESULTS_FILE" + +echo "" +echo "Validating references..." +echo "========================" + +# Process each file +echo "$RUST_FILES" | while IFS= read -r rust_file; do + # Extract OCaml reference comments from the file + awk ' + /^\/\/\/ OCaml reference:/ { + ref = $0 + getline + if ($0 ~ /^\/\/\/ Commit:/) { + commit = $0 + getline + if ($0 ~ /^\/\/\/ Last verified:/) { + verified = $0 + print ref + print commit + print verified + print "---" + } + } + } + ' "$rust_file" | while IFS= read -r line; do + if [[ "$line" == "/// OCaml reference:"* ]]; then + # Extract file path and line range + # Format: src/lib/mina_base/transaction_status.ml L:9-113 + FULL_REF="${line#/// OCaml reference: }" + OCAML_PATH="${FULL_REF%% L:*}" + LINE_RANGE=$(echo "$FULL_REF" | grep -o 'L:[0-9-]*' | sed 's/L://' || echo "") + + # Read next two lines + read -r commit_line + read -r _verified_line + read -r _separator + + COMMIT="${commit_line#/// Commit: }" + # LAST_VERIFIED could be extracted from _verified_line if needed for future validation + + # Fetch the OCaml file from the current branch + CURRENT_FILE="${TEMP_DIR}/current_${rust_file//\//_}_${OCAML_PATH//\//_}" + CURRENT_URL="https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${OCAML_BRANCH}/${OCAML_PATH}" + + if ! curl -sf "$CURRENT_URL" -o "$CURRENT_FILE"; then + echo "INVALID|${rust_file}|${OCAML_PATH}|FILE_NOT_FOUND" >> "$RESULTS_FILE" + echo "❌ INVALID: ${rust_file}" + echo " OCaml file not found: ${OCAML_PATH}" + else + # Validate line range if specified + RANGE_VALID=true + if [ -n "$LINE_RANGE" ]; then + FILE_LINES=$(wc -l < "$CURRENT_FILE") + # START_LINE is not currently used but could be useful for validation + # START_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f1) + END_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f2) + + if [ "$END_LINE" -gt "$FILE_LINES" ]; then + echo "INVALID|${rust_file}|${OCAML_PATH}|LINE_RANGE_EXCEEDED|L:${LINE_RANGE}|${FILE_LINES}" >> "$RESULTS_FILE" + echo "❌ INVALID: ${rust_file}" + echo " Line range L:${LINE_RANGE} exceeds file length (${FILE_LINES} lines): ${OCAML_PATH}" + RANGE_VALID=false + fi + fi + + if [ "$RANGE_VALID" = "true" ]; then + # Verify that the code at the referenced commit matches the current branch + CODE_MATCHES=true + if [ -n "$LINE_RANGE" ]; then + START_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f1) + END_LINE=$(echo "$LINE_RANGE" | cut -d'-' -f2) + + # Fetch the file from the referenced commit + COMMIT_FILE="${TEMP_DIR}/commit_${rust_file//\//_}_${OCAML_PATH//\//_}" + COMMIT_URL="https://raw.githubusercontent.com/${GITHUB_OWNER}/${GITHUB_REPO}/${COMMIT}/${OCAML_PATH}" + + if ! curl -sf "$COMMIT_URL" -o "$COMMIT_FILE"; then + echo "INVALID|${rust_file}|${OCAML_PATH}|COMMIT_NOT_FOUND|${COMMIT}" >> "$RESULTS_FILE" + echo "❌ INVALID: ${rust_file}" + echo " Referenced commit does not exist: ${COMMIT}" + CODE_MATCHES=false + else + # Extract the specific line ranges from both files and compare + CURRENT_LINES=$(sed -n "${START_LINE},${END_LINE}p" "$CURRENT_FILE") + COMMIT_LINES=$(sed -n "${START_LINE},${END_LINE}p" "$COMMIT_FILE") + + if [ "$CURRENT_LINES" != "$COMMIT_LINES" ]; then + echo "INVALID|${rust_file}|${OCAML_PATH}|CODE_MISMATCH|${COMMIT}" >> "$RESULTS_FILE" + echo "❌ INVALID: ${rust_file}" + echo " Code at L:${LINE_RANGE} differs between commit ${COMMIT} and current branch" + echo " Referenced: https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/blob/${COMMIT}/${OCAML_PATH}#L${START_LINE}-L${END_LINE}" + echo " Current: https://github.com/${GITHUB_OWNER}/${GITHUB_REPO}/blob/${OCAML_BRANCH}/${OCAML_PATH}#L${START_LINE}-L${END_LINE}" + CODE_MATCHES=false + fi + fi + fi + + if [ "$CODE_MATCHES" = "true" ]; then + # Check if commit is stale + if [ "$COMMIT" != "$CURRENT_COMMIT" ]; then + echo "STALE|${rust_file}|${OCAML_PATH}|${COMMIT}|${LINE_RANGE}" >> "$RESULTS_FILE" + echo "✓ VALID: ${rust_file} -> ${OCAML_PATH} L:${LINE_RANGE}" + echo " ⚠ STALE COMMIT: ${COMMIT} (current: ${CURRENT_COMMIT})" + else + echo "VALID|${rust_file}|${OCAML_PATH}|${LINE_RANGE}" >> "$RESULTS_FILE" + echo "✓ VALID: ${rust_file} -> ${OCAML_PATH} L:${LINE_RANGE}" + fi + fi + fi + fi + fi + done +done + +# Count results +TOTAL_REFS=$(wc -l < "$RESULTS_FILE") +VALID_REFS=$(grep -c "^VALID|" "$RESULTS_FILE" || true) +INVALID_REFS=$(grep -c "^INVALID|" "$RESULTS_FILE" || true) +STALE_COMMITS=$(grep -c "^STALE|" "$RESULTS_FILE" || true) + +echo "" +echo "Summary" +echo "=======" +echo "Total references found: ${TOTAL_REFS}" +echo "Valid references: $((VALID_REFS + STALE_COMMITS))" +echo "Invalid references: ${INVALID_REFS}" +echo "Stale commits: ${STALE_COMMITS}" + +if [ "$UPDATE_MODE" = "true" ] && [ "${STALE_COMMITS}" -gt 0 ]; then + echo "" + echo "Updating stale commit hashes and verification dates..." + + CURRENT_DATE=$(date +%Y-%m-%d) + + # Update each file with stale commits + grep "^STALE|" "$RESULTS_FILE" | while IFS='|' read -r _status rust_file ocaml_path _old_commit _line_range; do + echo "Updating ${rust_file}..." + + # Find and replace the old commit with the new one + sed -i.bak \ + -e "/^\/\/\/ OCaml reference: ${ocaml_path//\//\\/}/,/^\/\/\/ Last verified:/ { + s/^\/\/\/ Commit: .*/\/\/\/ Commit: ${CURRENT_COMMIT}/ + s/^\/\/\/ Last verified: .*/\/\/\/ Last verified: ${CURRENT_DATE}/ + }" \ + "${RUST_ROOT}/${rust_file}" + rm -f "${RUST_ROOT}/${rust_file}.bak" + done + + echo "Updated ${STALE_COMMITS} reference(s)" +fi + +# Exit with error if there are invalid references +if [ "${INVALID_REFS}" -gt 0 ]; then + echo "" + echo "❌ Validation failed: ${INVALID_REFS} invalid reference(s) found" + exit 1 +fi + +if [ "${STALE_COMMITS}" -gt 0 ] && [ "$UPDATE_MODE" = "false" ]; then + echo "" + echo "⚠ Warning: ${STALE_COMMITS} reference(s) have stale commits" + echo "Run with --update to update them automatically" + exit 0 +fi + +echo "" +echo "✓ All OCaml references are valid!" diff --git a/.github/scripts/verify-code-references.sh b/.github/scripts/verify-code-references.sh index 92fcbe3be..8b86d20f0 100755 --- a/.github/scripts/verify-code-references.sh +++ b/.github/scripts/verify-code-references.sh @@ -221,7 +221,7 @@ Please follow this workflow: 2. Create a follow-up PR with the documentation updates that reference the merged code 3. The verification will pass once the code is available on \`develop\` -See the [documentation guidelines](https://o1-labs.github.io/mina-rust/developers/documentation-guidelines) for more information about the two-PR workflow. +See the [documentation guidelines](https://o1-labs.github.io/mina-rust/docs/developers/documentation-guidelines) for more information about the two-PR workflow. EOF echo "" echo "PR comment written to: ${COMMENT_FILE}" diff --git a/.github/workflows/check-ocaml-refs.yaml b/.github/workflows/check-ocaml-refs.yaml new file mode 100644 index 000000000..12184e24c --- /dev/null +++ b/.github/workflows/check-ocaml-refs.yaml @@ -0,0 +1,195 @@ +# Check OCaml References +# +# This workflow validates OCaml reference comments in the Rust codebase +# and automatically updates stale commit hashes. +# +# Run locally with: +# gh act schedule -W .github/workflows/check-ocaml-refs.yaml +# gh act workflow_dispatch -W .github/workflows/check-ocaml-refs.yaml +# gh act workflow_dispatch -W .github/workflows/check-ocaml-refs.yaml --input branch=develop + +name: Check OCaml References + +on: + pull_request: + branches: + - develop + - main + schedule: + # Run every Monday at 9:00 AM UTC + - cron: '0 9 * * 1' + workflow_dispatch: + inputs: + repo: + description: 'OCaml repository URL' + required: false + default: 'https://github.com/MinaProtocol/mina.git' + branch: + description: 'OCaml repository branch' + required: false + default: 'compatible' + +permissions: + contents: write + pull-requests: write + +jobs: + check-refs: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Install ripgrep + run: sudo apt-get update && sudo apt-get install -y ripgrep + + - name: Run OCaml reference validation + id: check + env: + OCAML_REPO: ${{ github.event.inputs.repo || 'https://github.com/MinaProtocol/mina.git' }} + OCAML_BRANCH: ${{ github.event.inputs.branch || 'compatible' }} + run: | + set +e + # Capture output to file + ./.github/scripts/check-ocaml-refs.sh \ + --repo "$OCAML_REPO" \ + --branch "$OCAML_BRANCH" 2>&1 | tee validation_output.txt + exit_code=$? + if [ $exit_code -ne 0 ]; then + echo "has_issues=true" >> $GITHUB_OUTPUT + else + echo "has_issues=false" >> $GITHUB_OUTPUT + fi + # Store output for PR comment + echo "output_file=validation_output.txt" >> $GITHUB_OUTPUT + exit 0 + + - name: Prepare PR comment + if: github.event_name == 'pull_request' + id: prepare-comment + env: + HAS_ISSUES: ${{ steps.check.outputs.has_issues }} + OCAML_REPO: ${{ github.event.inputs.repo || 'https://github.com/MinaProtocol/mina.git' }} + OCAML_BRANCH: ${{ github.event.inputs.branch || 'compatible' }} + run: | + # Determine status message + if [ "$HAS_ISSUES" = "true" ]; then + STATUS_MSG="❌ Validation failed" + else + STATUS_MSG="✓ Validation passed" + fi + + # Create comment body with hidden identifier + cat > comment.md < + ## OCaml Reference Validation Results + + **Repository**: ${OCAML_REPO} + **Branch**: ${OCAML_BRANCH} + **Status**: ${STATUS_MSG} + +
+ Click to see full validation output + + \`\`\` + COMMENT_EOF + + # Append validation output + cat validation_output.txt >> comment.md + + # Close the code block and details + cat >> comment.md <<'COMMENT_EOF' + ``` + +
+ COMMENT_EOF + + - name: Find existing OCaml validation comment + if: github.event_name == 'pull_request' + uses: peter-evans/find-comment@v4 + id: find-comment + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: '' + + - name: Post PR comment with validation results + if: github.event_name == 'pull_request' + uses: peter-evans/create-or-update-comment@v5 + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body-path: comment.md + edit-mode: replace + + - name: Update references if stale + if: steps.check.outputs.has_issues != 'true' && github.event_name != 'pull_request' + env: + OCAML_REPO: ${{ github.event.inputs.repo || 'https://github.com/MinaProtocol/mina.git' }} + OCAML_BRANCH: ${{ github.event.inputs.branch || 'compatible' }} + run: | + ./.github/scripts/check-ocaml-refs.sh \ + --repo "$OCAML_REPO" \ + --branch "$OCAML_BRANCH" \ + --update + + - name: Check for changes + if: github.event_name != 'pull_request' + id: changes + run: | + if git diff --quiet; then + echo "has_changes=false" >> $GITHUB_OUTPUT + else + echo "has_changes=true" >> $GITHUB_OUTPUT + fi + + - name: Create Pull Request + if: steps.changes.outputs.has_changes == 'true' && github.event_name != 'pull_request' + uses: peter-evans/create-pull-request@v6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: | + Update OCaml reference verification dates + + Automated update of OCaml reference commit hashes and verification + dates based on latest compatible branch. + branch: update-ocaml-refs-${{ github.run_number }} + delete-branch: true + title: 'Update OCaml reference verification dates' + body: | + ## Automated OCaml Reference Update + + This PR updates the OCaml reference comments in the Rust codebase to + reflect the latest commit from the OCaml repository. + + ### Changes + - Updated commit hashes to match latest OCaml compatible branch + - Updated verification dates to today + + ### Validation + All OCaml file references have been validated to ensure they still + exist at the specified paths. + + **Repository**: ${{ github.event.inputs.repo || 'https://github.com/MinaProtocol/mina.git' }} + **Branch**: ${{ github.event.inputs.branch || 'compatible' }} + + This PR was automatically generated by the `check-ocaml-refs` + workflow. + labels: | + automation + documentation + + - name: Post summary + if: always() + run: | + echo "## OCaml Reference Validation Summary" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + if [ "${{ steps.check.outputs.has_issues }}" == "true" ]; then + echo "❌ Validation failed - some OCaml references are invalid" >> $GITHUB_STEP_SUMMARY + elif [ "${{ github.event_name }}" == "pull_request" ]; then + echo "✓ Validation completed - results posted as PR comment" >> $GITHUB_STEP_SUMMARY + elif [ "${{ steps.changes.outputs.has_changes }}" == "true" ]; then + echo "✓ Validation passed - created PR to update stale references" >> $GITHUB_STEP_SUMMARY + else + echo "✓ All references are up to date" >> $GITHUB_STEP_SUMMARY + fi diff --git a/CHANGELOG.md b/CHANGELOG.md index f49da0820..5b70b904f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -38,6 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1493](https://github.com/o1-labs/mina-rust/pull/1509)) - **Ledger/ZkAppCommand**: show how to build a ZkAppCommand from scratch, with dummy values ([#1514](https://github.com/o1-labs/mina-rust/pull/1514)) +- **CI/Documentation**: add a script to check the references to the OCaml code + ([#1525](https://github.com/o1-labs/mina-rust/pull/1525)). ### Changed @@ -62,6 +64,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ([#1515](https://github.com/o1-labs/mina-rust/pull/1515)) - **CI/tests**: run the step `build-wasm` for each push and PR to `develop` ([#1497](https://github.com/o1-labs/mina-rust/pull/1497)) +- **ledger/scan_state/transaction_logic**: update OCaml references in `mod.rs` + ([#1525](https://github.com/o1-labs/mina-rust/pull/1525)) ## v0.17.0 diff --git a/CLAUDE.md b/CLAUDE.md index 0b59440f8..f8644f217 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -162,6 +162,40 @@ The website is available at http://localhost:3000 when running locally. The website supports versioning and will be automatically deployed when commits are made to `develop` or when tags are created. +### OCaml Reference Tracking + +The Rust codebase maintains references to the corresponding OCaml implementation +to track correspondence and detect when updates are needed. + +**Comment format:** + +```rust +/// OCaml reference: src/lib/mina_base/transaction_status.ml L:9-113 +/// Commit: 55582d249cdb225f722dbbb3b1420ce7570d501f +/// Last verified: 2025-10-08 +pub enum TransactionFailure { + // ... +} +``` + +**Validation:** + +```bash +# Check all OCaml references +./.github/scripts/check-ocaml-refs.sh + +# Update stale commit hashes +./.github/scripts/check-ocaml-refs.sh --update + +# Check against specific branch +./.github/scripts/check-ocaml-refs.sh --branch develop +``` + +The validation script verifies that referenced OCaml files exist, line ranges +are valid, code at the referenced commit matches the current branch, and tracks +commit staleness. A GitHub Actions workflow runs weekly to automatically update +references and create PRs. + ## Additional Resources - `docs/handover/` - Comprehensive architecture documentation diff --git a/ledger/src/scan_state/transaction_logic/mod.rs b/ledger/src/scan_state/transaction_logic/mod.rs index 7d486d3ca..3b844f4a0 100644 --- a/ledger/src/scan_state/transaction_logic/mod.rs +++ b/ledger/src/scan_state/transaction_logic/mod.rs @@ -60,7 +60,9 @@ pub use transaction_union_payload::{ ExistingOrNew, Tag, TimingValidation, TransactionUnion, TransactionUnionPayload, }; -/// +/// OCaml reference: src/lib/mina_base/transaction_status.ml L:9-51 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-08 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq, Eq)] pub enum TransactionFailure { Predicate, @@ -176,7 +178,9 @@ impl Display for TransactionFailure { } } -/// +/// OCaml reference: src/lib/mina_base/transaction_status.ml L:452-454 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-08 #[derive(SerdeYojsonEnum, Debug, Clone, PartialEq, Eq)] pub enum TransactionStatus { Applied, @@ -192,7 +196,9 @@ impl TransactionStatus { } } -/// +/// OCaml reference: src/lib/mina_base/with_status.ml L:6-10 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-08 #[derive(serde::Serialize, serde::Deserialize, Debug, Clone, PartialEq)] pub struct WithStatus { pub data: T, @@ -259,7 +265,9 @@ where } } -/// +/// OCaml reference: src/lib/mina_base/fee_transfer.ml L:76-80 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-10 #[derive(Debug, Clone, PartialEq)] pub struct SingleFeeTransfer { pub receiver_pk: CompressedPubKey, @@ -284,7 +292,9 @@ impl SingleFeeTransfer { } } -/// +/// OCaml reference: src/lib/mina_base/fee_transfer.ml L:68-69 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-10 #[derive(Debug, Clone, PartialEq)] pub struct FeeTransfer(pub(super) OneOrTwo); @@ -312,7 +322,9 @@ impl FeeTransfer { }) } - /// + /// OCaml reference: src/lib/mina_base/fee_transfer.ml L:110-114 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn fee_excess(&self) -> Result { let one_or_two = self.0.map(|SingleFeeTransfer { fee, fee_token, .. }| { (fee_token.clone(), Signed::::of_unsigned(*fee).negate()) @@ -320,7 +332,9 @@ impl FeeTransfer { FeeExcess::of_one_or_two(one_or_two) } - /// + /// OCaml reference: src/lib/mina_base/fee_transfer.ml L:85-97 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn of_singles(singles: OneOrTwo) -> Result { match singles { OneOrTwo::One(a) => Ok(Self(OneOrTwo::One(a))), @@ -359,7 +373,9 @@ impl CoinbaseFeeTransfer { } } -/// +/// OCaml reference: src/lib/mina_base/coinbase.ml L:17-21 +/// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 +/// Last verified: 2025-10-10 #[derive(Debug, Clone, PartialEq)] pub struct Coinbase { pub receiver: CompressedPubKey, @@ -401,7 +417,9 @@ impl Coinbase { } } - /// + /// OCaml reference: src/lib/mina_base/coinbase.ml L:92-100 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 fn expected_supply_increase(&self) -> Result { let Self { amount, @@ -423,12 +441,16 @@ impl Coinbase { self.expected_supply_increase().map(|_| FeeExcess::empty()) } - /// + /// OCaml reference: src/lib/mina_base/coinbase.ml L:39-39 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn receiver(&self) -> AccountId { AccountId::new(self.receiver.clone(), TokenId::default()) } - /// + /// OCaml reference: src/lib/mina_base/coinbase.ml L:51-65 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn account_access_statuses( &self, status: &TransactionStatus, @@ -449,7 +471,9 @@ impl Coinbase { ids } - /// + /// OCaml reference: src/lib/mina_base/coinbase.ml L:67-69 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn accounts_referenced(&self) -> Vec { self.account_access_statuses(&TransactionStatus::Applied) .into_iter() @@ -552,7 +576,9 @@ impl Memo { self.0.as_slice() } - /// + /// OCaml reference: src/lib/mina_base/signed_command_memo.ml L:156-156 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn dummy() -> Self { // TODO Self([0; 34]) @@ -579,7 +605,9 @@ impl Memo { Self(s.into_bytes().try_into().unwrap()) } - /// + /// OCaml reference: src/lib/mina_base/signed_command_memo.ml L:117-120 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 fn create_by_digesting_string_exn(s: &str) -> Self { if s.len() > Self::MAX_DIGESTIBLE_STRING_LENGTH { panic!("Too_long_digestible_string"); @@ -600,7 +628,9 @@ impl Memo { Self(memo) } - /// + /// OCaml reference: src/lib/mina_base/signed_command_memo.ml L:205-207 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn gen() -> Self { use rand::distributions::{Alphanumeric, DistString}; let random_string = Alphanumeric.sample_string(&mut rand::thread_rng(), 50); @@ -661,7 +691,9 @@ impl binprot::BinProtRead for UserCommand { } impl UserCommand { - /// + /// OCaml reference: src/lib/mina_base/user_command.ml L:239 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn account_access_statuses( &self, status: &TransactionStatus, @@ -672,7 +704,9 @@ impl UserCommand { } } - /// + /// OCaml reference: src/lib/mina_base/user_command.ml L:306-307 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn accounts_referenced(&self) -> Vec { self.account_access_statuses(&TransactionStatus::Applied) .into_iter() @@ -708,7 +742,9 @@ impl UserCommand { self.applicable_at_nonce().succ() } - /// + /// OCaml reference: src/lib/mina_base/user_command.ml L:283-287 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn fee(&self) -> Fee { match self { UserCommand::SignedCommand(cmd) => cmd.fee(), @@ -742,7 +778,9 @@ impl UserCommand { } } - /// + /// OCaml reference: src/lib/mina_base/user_command.ml L:388-401 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn to_valid_unsafe(self) -> valid::UserCommand { match self { UserCommand::SignedCommand(cmd) => valid::UserCommand::SignedCommand(cmd), @@ -754,7 +792,9 @@ impl UserCommand { } } - /// + /// OCaml reference: src/lib/mina_base/user_command.ml L:220-226 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn to_verifiable( &self, status: &TransactionStatus, @@ -977,7 +1017,9 @@ impl Transaction { } } - /// + /// OCaml reference: src/lib/transaction/transaction.ml L:98-110 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn public_keys(&self) -> Vec { use Transaction::*; use UserCommand::*; @@ -992,7 +1034,9 @@ impl Transaction { } } - /// + /// OCaml reference: src/lib/transaction/transaction.ml L:112-124 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn account_access_statuses( &self, status: &TransactionStatus, @@ -1011,7 +1055,9 @@ impl Transaction { } } - /// + /// OCaml reference: src/lib/transaction/transaction.ml L:126-128 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 pub fn accounts_referenced(&self) -> Vec { self.account_access_statuses(&TransactionStatus::Applied) .into_iter() @@ -1088,11 +1134,15 @@ pub mod for_tests { } } - /// + /// OCaml reference: src/lib/transaction_logic/mina_transaction_logic.ml L:2285-2285 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 #[derive(Debug)] pub struct InitLedger(pub Vec<(Keypair, u64)>); - /// + /// OCaml reference: src/lib/transaction_logic/mina_transaction_logic.ml L:2351-2356 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 #[derive(Debug)] pub struct TransactionSpec { pub fee: Fee, @@ -1101,7 +1151,9 @@ pub mod for_tests { pub amount: Amount, } - /// + /// OCaml reference: src/lib/transaction_logic/mina_transaction_logic.ml L:2407 + /// Commit: 5da42ccd72e791f164d4d200cf1ce300262873b3 + /// Last verified: 2025-10-10 #[derive(Debug)] pub struct TestSpec { pub init_ledger: InitLedger, diff --git a/website/docs/developers/ocaml-reference-tracking.md b/website/docs/developers/ocaml-reference-tracking.md new file mode 100644 index 000000000..8fd9612d6 --- /dev/null +++ b/website/docs/developers/ocaml-reference-tracking.md @@ -0,0 +1,135 @@ +--- +sidebar_position: 11 +title: OCaml reference tracking +description: + System for tracking correspondence between Rust and OCaml implementations +slug: /developers/ocaml-reference-tracking +--- + +# OCaml reference tracking + +This document describes the system for tracking correspondence between Rust code +in this repository and the original OCaml implementation in the +[Mina Protocol repository](https://github.com/MinaProtocol/mina). + +## Overview + +As mina-rust is a reimplementation of the Mina OCaml client, we maintain inline +comments that reference the corresponding OCaml code. This helps developers: + +1. Understand the original implementation context +2. Verify that the Rust implementation matches the OCaml behavior +3. Track changes in the OCaml codebase that may require updates in Rust + +## Comment format + +OCaml references are added as doc comments directly above the Rust type or +function: + +```rust +/// OCaml reference: src/lib/mina_base/transaction_status.ml L:9-113 +/// Commit: 55582d249cdb225f722dbbb3b1420ce7570d501f +/// Last verified: 2025-10-08 +pub enum TransactionFailure { + // ... +} +``` + +### Format specification + +- **Line 1**: `/// OCaml reference: L:-` + - ``: Path to the OCaml file relative to the Mina repository root + - `L:-`: Line range in the OCaml file (optional but recommended) +- **Line 2**: `/// Commit: ` + - Full commit hash from the Mina repository +- **Line 3**: `/// Last verified: ` + - Date when the reference was last verified to be accurate + +## Validation script + +The `.github/scripts/check-ocaml-refs.sh` script validates all OCaml references: + +```bash +# Validate against compatible branch (default) +./.github/scripts/check-ocaml-refs.sh + +# Validate against a specific branch +./.github/scripts/check-ocaml-refs.sh --branch develop + +# Validate against a specific repository +./.github/scripts/check-ocaml-refs.sh --repo https://github.com/MinaProtocol/mina.git --branch develop + +# Automatically update stale commit hashes +./.github/scripts/check-ocaml-refs.sh --update +``` + +### What the script checks + +1. **File existence**: Verifies the OCaml file exists at the specified path +2. **Line ranges**: Validates that line ranges don't exceed the file length +3. **Code consistency**: Verifies that the code at the referenced commit matches + the code on the current branch (ensures the reference is still accurate) +4. **Commit staleness**: Checks if the commit hash matches the current HEAD + +### Exit codes + +- `0`: All references are valid or only stale commits (warning) +- `1`: Invalid references found (missing files or invalid line ranges) + +## Automated verification + +A GitHub Actions workflow runs weekly to: + +1. Validate all OCaml references against the latest `compatible` branch +2. Automatically update stale commit hashes and verification dates +3. Create a pull request with the updates + +The workflow can also be triggered manually via the Actions tab. + +## Adding new references + +When implementing new features from the OCaml codebase: + +1. Add the OCaml reference comment above your Rust type/function +2. Use the current commit hash from the Mina repository +3. Set the verification date to today +4. Include line ranges to make it easy to find the exact code + +Example: + +```rust +/// OCaml reference: src/lib/mina_base/fee_transfer.ml L:19-45 +/// Commit: 55582d249cdb225f722dbbb3b1420ce7570d501f +/// Last verified: 2025-10-08 +#[derive(Debug, Clone, PartialEq)] +pub struct SingleFeeTransfer { + pub receiver_pk: CompressedPubKey, + pub fee: Fee, + pub fee_token: TokenId, +} +``` + +## Finding the correct line range + +To find the line range for an OCaml reference: + +1. Navigate to the file in the Mina repository +2. Find the relevant type or function definition +3. Note the starting and ending line numbers +4. Use format `L:-` + +For single-line references, use the same number: `L:42-42` + +## Best practices + +1. **Be specific**: Include line ranges to point to exact definitions +2. **Verify regularly**: Run the validation script before committing +3. **Update when needed**: If you update Rust code based on OCaml changes, + update the commit hash and date +4. **Document differences**: If the Rust implementation intentionally differs, + add a note explaining why + +## Example references + +See `ledger/src/scan_state/transaction_logic/mod.rs` for examples of properly +formatted OCaml references. diff --git a/website/docs/developers/documentation-guidelines.md b/website/docs/developers/referencing-code-in-documentation.md similarity index 96% rename from website/docs/developers/documentation-guidelines.md rename to website/docs/developers/referencing-code-in-documentation.md index e6d74a625..e525c55a1 100644 --- a/website/docs/developers/documentation-guidelines.md +++ b/website/docs/developers/referencing-code-in-documentation.md @@ -1,11 +1,11 @@ --- sidebar_position: 10 -title: Documentation Guidelines +title: Referencing code in documentation description: Best practices for writing and maintaining documentation -slug: /developers/documentation-guidelines +slug: /developers/referencing-code-in-documentation --- -# Documentation Guidelines +# Referencing code in documentation This guide explains how to write and maintain documentation for the Mina Rust project, including how to reference code from the codebase. Referencing code @@ -13,8 +13,6 @@ from codebases can be useful to check compatibility between implementations. For instance, we can have pages where the Rust code is compared to the OCaml code to discuss the differences or similarities. -## Referencing Code in Documentation - To keep documentation synchronized with the actual codebase, we use the [`docusaurus-theme-github-codeblock`](https://github.com/christian-bromann/docusaurus-theme-github-codeblock) plugin that automatically fetches code from GitHub. diff --git a/website/sidebars.ts b/website/sidebars.ts index 962b0621d..2b2411cd4 100644 --- a/website/sidebars.ts +++ b/website/sidebars.ts @@ -137,7 +137,8 @@ const sidebars: SidebarsConfig = { type: 'category', label: 'Documentation', items: [ - 'developers/documentation-guidelines', + 'developers/referencing-code-in-documentation', + 'developers/ocaml-reference-tracking', ], }, {