diff --git a/.github/actions/avalanchego-setup-action/README.md b/.github/actions/avalanchego-setup-action/README.md new file mode 100644 index 000000000000..a561cf1b8d4a --- /dev/null +++ b/.github/actions/avalanchego-setup-action/README.md @@ -0,0 +1,44 @@ +# AvalancheGo Setup Action + +## Overview +This action provides composable CI capabilities for setting up AvalancheGo with custom dependency versions. + +### Why this exists? +Solves CI composability problems by enabling repositories to setup and build AvalancheGo with specific dependency versions without complex setup or cross-repository coordination. + +### Why is it needed? +Dependencies need AvalancheGo as their integration context for realistic testing. +Without this action, setting up AvalancheGo with custom dependency versions requires build knowledge and manual `go mod` manipulation. +Teams either skip proper testing or dump tests in AvalancheGo (wrong ownership). +This action makes AvalancheGo composable - any repository can pull it in as integration context with one line. + +## Security Model +- Repository Restriction: Only allows dependencies from `github.com/ava-labs/*` repositories +- No Custom Forks: Prevents supply chain attacks from malicious forks +- Commit Validation: Validates dependency versions reference ava-labs repositories only + +## Inputs + +| Input | Description | Required | Default | +|-------|-------------|----------|-----------------------| +| `checkout-path` | Directory path where AvalancheGo will be checked out | No | `'.'` | +| `avalanchego` | AvalancheGo version (commit SHA, branch, tag) | No | `'${{ github.sha }}'` | +| `firewood` | Firewood version. Consumer should run Firewood shared workflow first | No | `''` | +| `coreth` | Coreth version (commit SHA, branch, tag) | No | `''` | +| `libevm` | LibEVM version (commit SHA, branch, tag) | No | `''` | + +## Usage Examples + +```yaml +- name: Setup AvalancheGo with Firewood # This will setup go.mod + uses: ./.github/actions/avalanchego-setup-action + with: + checkout-path: "build/avalanchego" + coreth: "my-feature-branch" + libevm: "experimental-branch" + firewood: "ffi/v0.0.12" +- name: Load test # This will compile and run the load test + uses: ./.github/actions/run-monitored-tmpnet-cmd + with: + run: ./scripts/run_task.sh test-load -- --load-timeout=30m --firewood +``` diff --git a/.github/actions/avalanchego-setup-action/action.yml b/.github/actions/avalanchego-setup-action/action.yml new file mode 100644 index 000000000000..0807e822505c --- /dev/null +++ b/.github/actions/avalanchego-setup-action/action.yml @@ -0,0 +1,69 @@ +name: 'Setup AvalancheGo' +description: 'Setup AvalancheGo with custom dependencies (Firewood, Coreth, LibEVM)' + +inputs: + avalanchego: + description: 'AvalancheGo version (commit SHA, branch name, or tag)' + required: false + default: ${{ github.sha }} + checkout-path: + description: 'Path where AvalancheGo will be checked out' + required: false + default: '.' + firewood: + description: 'Firewood version (commit SHA, branch, tag, or ffi/vX.Y.Z for pre-built)' + required: false + default: '' + firewood-path: + description: 'Directory path where Firewood will be cloned/built (preferably NVMe storage)' + required: false + default: '' + coreth: + description: 'Coreth version (commit SHA, branch name, or tag)' + required: false + default: '' + libevm: + description: 'LibEVM version (commit SHA, branch name, or tag)' + required: false + default: '' + +runs: + using: 'composite' + steps: + - name: Checkout AvalancheGo + uses: actions/checkout@v4 + with: + repository: 'ava-labs/avalanchego' + ref: ${{ inputs.avalanchego }} + path: ${{ inputs.checkout-path }} + - name: Update Coreth dependency + if: inputs.coreth != '' + shell: bash + working-directory: ${{ inputs.checkout-path }} + run: | + echo "Updating Coreth to version: ${{ inputs.coreth }}" + go get github.com/ava-labs/coreth@${{ inputs.coreth }} + - name: Update LibEVM dependency + if: inputs.libevm != '' + shell: bash + working-directory: ${{ inputs.checkout-path }} + run: | + echo "Updating LibEVM to version: ${{ inputs.libevm }}" + go get github.com/ava-labs/libevm@${{ inputs.libevm }} + - name: Setup Firewood FFI + if: inputs.firewood != '' + id: setup-firewood + uses: ava-labs/firewood/.github/actions/build-action@composable-ci-action + with: + version: ${{ inputs.firewood }} + workspace-path: ${{ inputs.firewood-path }} + - name: Configure Go modules with Firewood FFI + if: inputs.firewood != '' + shell: bash + working-directory: ${{ inputs.checkout-path }} + run: | + FFI_PATH="${{ steps.setup-firewood.outputs.ffi-path }}" + echo "Updating go.mod with FFI path: ${FFI_PATH}" + go mod edit -replace github.com/ava-labs/firewood-go-ethhash/ffi="${FFI_PATH}" + go mod tidy + go mod download diff --git a/.github/actions/c-chain-reexecution-benchmark/action.yml b/.github/actions/c-chain-reexecution-benchmark/action.yml index 3385ff50a0c1..35d3452bb133 100644 --- a/.github/actions/c-chain-reexecution-benchmark/action.yml +++ b/.github/actions/c-chain-reexecution-benchmark/action.yml @@ -2,30 +2,34 @@ name: 'C-Chain Re-Execution Benchmark' description: 'Run C-Chain re-execution benchmark' inputs: - runner_name: - description: 'The name of the runner to use and include in the Golang Benchmark name.' - required: true + task: + description: 'Task name to execute from Taskfile.yml. Leave empty to use custom inputs below.' + default: '' + # Custom inputs (alternative to task-based approach) config: description: 'The config to pass to the VM for the benchmark. See BenchmarkReexecuteRange for details.' default: '' start-block: description: 'The start block for the benchmark.' - default: '101' + default: '' end-block: description: 'The end block for the benchmark.' - default: '250000' + default: '' block-dir-src: description: 'The source block directory. Supports S3 directory/zip and local directories.' - default: 's3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-1m-ldb/**' + default: '' current-state-dir-src: description: 'The current state directory. Supports S3 directory/zip and local directories.' - default: 's3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/**' + default: '' + runner_name: + description: 'The name of the runner to use and include in the Golang Benchmark name.' + required: true aws-role: description: 'AWS role to assume for S3 access.' required: true aws-region: description: 'AWS region to use for S3 access.' - required: true + default: 'us-east-2' aws-role-duration-seconds: description: 'The duration of the AWS role to assume for S3 access.' required: true @@ -56,54 +60,145 @@ inputs: push-github-action-benchmark: description: 'Whether to push the benchmark result to GitHub.' required: true - default: false push-post-state: description: 'S3 destination to copy the current-state directory after completing re-execution. If empty, this will be skipped.' default: '' + # The following inputs need never be provided by the caller. They + # default to context values that the action's steps are unable to + # access directly. + repository-owner: + default: ${{ github.repository_owner }} + repository-name: + default: ${{ github.event.repository.name }} + workflow: + default: ${{ github.workflow }} + run-id: + default: ${{ github.run_id }} + run-number: + default: ${{ github.run_number }} + run-attempt: + default: ${{ github.run_attempt }} + job: + default: ${{ github.job }} + +outputs: + metrics-from-timestamp: + description: 'Start timestamp for metrics monitoring (in seconds)' + value: ${{ steps.export-metrics-timestamps.outputs.from-timestamp }} + metrics-to-timestamp: + description: 'End timestamp for metrics monitoring (in seconds)' + value: ${{ steps.export-metrics-timestamps.outputs.to-timestamp }} runs: using: composite steps: - - name: Set task env + - uses: cachix/install-nix-action@02a151ada4993995686f9ed4f1be7cfbb229e56f #v31 + with: + github_access_token: ${{ inputs.github-token }} + - run: echo "dependencies installed" + shell: nix develop --command bash {0} + # Cache Go modules (architecture-independent) + - uses: actions/cache@v4 + id: go-mod-cache + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-mod-${{ hashFiles('go.sum') }} + restore-keys: ${{ runner.os }}-go-mod- + # Cache Go build cache (architecture-specific) + - uses: actions/cache@v4 + with: + path: ~/.cache/go-build + key: ${{ runner.os }}-${{ runner.arch }}-go-build-${{ hashFiles('go.sum') }} + restore-keys: ${{ runner.os }}-${{ runner.arch }}-go-build- + # Download modules only on cache miss + - run: go mod download + if: steps.go-mod-cache.outputs.cache-hit != 'true' + shell: nix develop --command bash -x {0} + - name: Notify of metrics availability + if: inputs.prometheus-username != '' shell: bash run: | - { - echo "EXECUTION_DATA_DIR=${{ inputs.workspace }}/reexecution-data" - echo "BENCHMARK_OUTPUT_FILE=output.txt" - echo "START_BLOCK=${{ inputs.start-block }}" - echo "END_BLOCK=${{ inputs.end-block }}" - echo "BLOCK_DIR_SRC=${{ inputs.block-dir-src }}" - echo "CURRENT_STATE_DIR_SRC=${{ inputs.current-state-dir-src }}" - } >> $GITHUB_ENV + metrics_url=$($GITHUB_ACTION_PATH/output-metrics-url.sh) + echo "Grafana: ${metrics_url}" + echo "🔗 [View Grafana Dashboard](${metrics_url})" >> "$GITHUB_STEP_SUMMARY" + env: + GRAFANA_URL: https://grafana-poc.avax-dev.network/d/Gl1I20mnk/c-chain?orgId=1&refresh=10s&var-filter=is_ephemeral_node%7C%3D%7Cfalse&var-filter=gh_repo%7C%3D%7C${{ inputs.repository_owner }}%2F${{ inputs.repository_name }}&var-filter=gh_run_id%7C%3D%7C${{ inputs.run_id }}&var-filter=gh_run_attempt%7C%3D%7C${{ inputs.run_attempt }} + GH_JOB_ID: ${{ inputs.job }} + - name: Export metrics timestamps + id: export-metrics-timestamps + if: inputs.prometheus-username != '' + shell: bash + run: | + echo "from-timestamp=${METRICS_FROM_TIMESTAMP}" >> "$GITHUB_OUTPUT" + echo "to-timestamp=${METRICS_TO_TIMESTAMP}" >> "$GITHUB_OUTPUT" + - name: Warn that collection of metrics and logs will not be performed + if: inputs.prometheus-username == '' + shell: bash + run: echo "::warning::Monitoring credentials not found. Skipping collector start. Is the PR from a fork branch?" - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ inputs.aws-role }} aws-region: ${{ inputs.aws-region }} role-duration-seconds: ${{ inputs.aws-role-duration-seconds }} - - name: Run C-Chain Re-Execution - uses: ./.github/actions/run-monitored-tmpnet-cmd - with: - run: | + - name: Validate inputs + shell: bash + run: | + if [[ -z "${{ inputs.task }}" ]]; then + # Granular mode - validate required inputs + missing=() + [[ -z "${{ inputs.block-dir-src }}" ]] && missing+=("block-dir-src") + [[ -z "${{ inputs.current-state-dir-src }}" ]] && missing+=("current-state-dir-src") + [[ -z "${{ inputs.start-block }}" ]] && missing+=("start-block") + [[ -z "${{ inputs.end-block }}" ]] && missing+=("end-block") + + if [[ ${#missing[@]} -gt 0 ]]; then + echo "::error::When 'task' is empty, the following inputs are required: ${missing[*]}" + exit 1 + fi + fi + - name: Set task env + shell: bash + run: | + TIMESTAMP=$(date '+%Y%m%d-%H%M%S') + echo "EXECUTION_DATA_DIR=/tmp/reexecution-data-${TIMESTAMP}" >> "$GITHUB_ENV" + echo "BENCHMARK_OUTPUT_FILE=${GITHUB_WORKSPACE}/benchmark-output.txt" >> "$GITHUB_ENV" + - name: Run C-Chain Re-execution Benchmark + shell: nix develop --impure --command bash -x {0} + run: | + if [[ -n "${{ inputs.task }}" ]]; then + # Task-based approach + ./scripts/run_task.sh ${{ inputs.task }} \ + BENCHMARK_OUTPUT_FILE="${{ env.BENCHMARK_OUTPUT_FILE }}" \ + EXECUTION_DATA_DIR="${{ env.EXECUTION_DATA_DIR }}" + else + # Granular approach ./scripts/run_task.sh reexecute-cchain-range-with-copied-data \ CONFIG=${{ inputs.config }} \ EXECUTION_DATA_DIR=${{ env.EXECUTION_DATA_DIR }} \ - BLOCK_DIR_SRC=${{ env.BLOCK_DIR_SRC }} \ - CURRENT_STATE_DIR_SRC=${{ env.CURRENT_STATE_DIR_SRC }} \ - START_BLOCK=${{ env.START_BLOCK }} \ - END_BLOCK=${{ env.END_BLOCK }} \ - LABELS=${{ env.LABELS }} \ - BENCHMARK_OUTPUT_FILE=${{ env.BENCHMARK_OUTPUT_FILE }} \ - RUNNER_NAME=${{ inputs.runner_name }} \ - METRICS_SERVER_ENABLED=true \ - METRICS_COLLECTOR_ENABLED=true - prometheus_url: ${{ inputs.prometheus-url }} - prometheus_push_url: ${{ inputs.prometheus-push-url }} - prometheus_username: ${{ inputs.prometheus-username }} - prometheus_password: ${{ inputs.prometheus-password }} - grafana_dashboard_id: 'Gl1I20mnk/c-chain' - runtime: "" # Set runtime input to empty string to disable log collection - + BLOCK_DIR_SRC=${{ inputs.block-dir-src }} \ + CURRENT_STATE_DIR_SRC=${{ inputs.current-state-dir-src }} \ + START_BLOCK=${{ inputs.start-block }} \ + END_BLOCK=${{ inputs.end-block }} \ + BENCHMARK_OUTPUT_FILE="${{ env.BENCHMARK_OUTPUT_FILE }}" + fi + env: + RUNNER_NAME: ${{ inputs.runner_name }} + METRICS_COLLECTOR_ENABLED: ${{ inputs.prometheus-username != '' }} + PROMETHEUS_URL: ${{ inputs.prometheus-url }} + PROMETHEUS_PUSH_URL: ${{ inputs.prometheus-push-url }} + PROMETHEUS_USERNAME: ${{ inputs.prometheus-username }} + PROMETHEUS_PASSWORD: ${{ inputs.prometheus-password }} + GH_REPO: ${{ inputs.repository_owner }}/${{ inputs.repository_name }} + GH_WORKFLOW: ${{ inputs.workflow }} + GH_RUN_ID: ${{ inputs.run_id }} + GH_RUN_NUMBER: ${{ inputs.run_number }} + GH_RUN_ATTEMPT: ${{ inputs.run_attempt }} + GH_JOB_ID: ${{ inputs.job }} + - name: Stash local changes before benchmark comparison + shell: bash + run: | + git stash --include-untracked || true - name: Compare Benchmark Results uses: benchmark-action/github-action-benchmark@v1 with: @@ -112,8 +207,10 @@ runs: summary-always: true github-token: ${{ inputs.github-token }} auto-push: ${{ inputs.push-github-action-benchmark }} - - - name: Push Post-State to S3 (if not exists) - if: ${{ inputs.push-post-state != '' }} - shell: nix develop --command bash -x {0} - run: ./scripts/run_task.sh export-dir-to-s3 SRC=${{ env.EXECUTION_DATA_DIR }}/current-state/ DST=${{ inputs.push-post-state }} + - name: Push Post-State to S3 + if: inputs.push-post-state != '' + shell: nix develop --impure --command bash -x {0} + run: | + ./scripts/run_task.sh export-dir-to-s3 \ + SRC=${{ env.EXECUTION_DATA_DIR }}/current-state/ \ + DST=${{ inputs.push-post-state }} diff --git a/.github/actions/c-chain-reexecution-benchmark/output-metrics-url.sh b/.github/actions/c-chain-reexecution-benchmark/output-metrics-url.sh new file mode 100755 index 000000000000..e08d2507c2e1 --- /dev/null +++ b/.github/actions/c-chain-reexecution-benchmark/output-metrics-url.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# WARNING: This file is a duplication of: +# - .github/actions/run-monitored-tmpnet-cmd/output-metrics-url.sh (source of truth) +# Changes must be made to BOTH files. + +set -euo pipefail + +# Timestamps are in seconds +from_timestamp="$(date '+%s')" +monitoring_period=900 # 15 minutes +to_timestamp="$((from_timestamp + monitoring_period))" + +# Export timestamps to GitHub environment +if [ -n "${GITHUB_ENV:-}" ]; then + echo "METRICS_FROM_TIMESTAMP=${from_timestamp}" >> "$GITHUB_ENV" + echo "METRICS_TO_TIMESTAMP=${to_timestamp}" >> "$GITHUB_ENV" +fi + +# Grafana expects microseconds, so pad timestamps with 3 zeros +metrics_url="${GRAFANA_URL}&var-filter=gh_job_id%7C%3D%7C${GH_JOB_ID}&from=${from_timestamp}000&to=${to_timestamp}000" + +# Optionally ensure that the link displays metrics only for the shared +# network rather than mixing it with the results for private networks. +if [[ -n "${FILTER_BY_OWNER:-}" ]]; then + metrics_url="${metrics_url}&var-filter=network_owner%7C%3D%7C${FILTER_BY_OWNER}" +fi + +echo "${metrics_url}" diff --git a/.github/actions/run-monitored-tmpnet-cmd/output-metrics-url.sh b/.github/actions/run-monitored-tmpnet-cmd/output-metrics-url.sh index ccecc34ac09c..5d2e8d59e8d1 100755 --- a/.github/actions/run-monitored-tmpnet-cmd/output-metrics-url.sh +++ b/.github/actions/run-monitored-tmpnet-cmd/output-metrics-url.sh @@ -1,5 +1,9 @@ #!/usr/bin/env bash +# WARNING: This file is duplicated at: +# - .github/actions/c-chain-reexecution-benchmark/output-metrics-url.sh (copy) +# Changes must be made to BOTH files. + set -euo pipefail # Timestamps are in seconds diff --git a/.github/workflows/c-chain-reexecution-benchmark-container.json b/.github/workflows/c-chain-reexecution-benchmark-container.json index aa8edb0aac70..2ccfac027111 100644 --- a/.github/workflows/c-chain-reexecution-benchmark-container.json +++ b/.github/workflows/c-chain-reexecution-benchmark-container.json @@ -3,20 +3,12 @@ "include": [ { "runner": "ubuntu-latest", - "config": "default", - "start-block": 101, - "end-block": 250000, - "block-dir-src": "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-1m-ldb/**", - "current-state-dir-src": "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/**", + "task": "c-chain-reexecution-hashdb-101-250k", "timeout-minutes": 30 }, { "runner": "avalanche-avalanchego-runner-2ti", - "config": "default", - "start-block": 101, - "end-block": 250000, - "block-dir-src": "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-1m-ldb/**", - "current-state-dir-src": "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/**", + "task": "c-chain-reexecution-hashdb-101-250k", "timeout-minutes": 30 } ] @@ -25,20 +17,12 @@ "include": [ { "runner": "avago-runner-m6i-4xlarge-ebs-fast", - "config": "default", - "start-block": 33000001, - "end-block": 33500000, - "block-dir-src": "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-30m-40m-ldb/**", - "current-state-dir-src": "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-33m/**", + "task": "c-chain-reexecution-hashdb-33m-33m500k", "timeout-minutes": 1440 }, { "runner": "avago-runner-i4i-4xlarge-local-ssd", - "config": "default", - "start-block": 33000001, - "end-block": 33500000, - "block-dir-src": "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-30m-40m-ldb/**", - "current-state-dir-src": "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-33m/**", + "task": "c-chain-reexecution-hashdb-33m-33m500k", "timeout-minutes": 1440 } ] diff --git a/.github/workflows/c-chain-reexecution-benchmark-container.yml b/.github/workflows/c-chain-reexecution-benchmark-container.yml index db12a98ad703..115975a35324 100644 --- a/.github/workflows/c-chain-reexecution-benchmark-container.yml +++ b/.github/workflows/c-chain-reexecution-benchmark-container.yml @@ -1,39 +1,35 @@ name: C-Chain Re-Execution Benchmark w/ Container on: - pull_request: + # pull_request: workflow_dispatch: inputs: config: description: 'The config to pass to the VM for the benchmark. See BenchmarkReexecuteRange for details.' - required: false default: '' start-block: description: 'The start block for the benchmark.' - required: false - default: 101 + default: '' end-block: description: 'The end block for the benchmark.' - required: false - default: 250000 + default: '' block-dir-src: description: 'The source block directory. Supports S3 directory/zip and local directories.' - required: false - default: s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-1m-ldb/** + default: '' current-state-dir-src: description: 'The current state directory. Supports S3 directory/zip and local directories.' - required: false - default: s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/** + default: '' + task: + description: 'Taskfile task to execute (e.g., c-chain-reexecution-hashdb-101-250k)' + default: '' runner: description: 'Runner to execute the benchmark. Input to the runs-on field of the job.' - required: false - default: ubuntu-latest + required: true push-post-state: description: 'S3 location to push post-execution state directory. Skips this step if left unpopulated.' default: '' timeout-minutes: description: 'Timeout in minutes for the job.' - required: false default: 30 # Disabled because scheduled trigger is empty. To enable, uncomment and add at least one vector to the schedule @@ -55,12 +51,8 @@ jobs: if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then { echo "matrix< /dev/null; then + sudo apt-get update + sudo apt-get install -y xz-utils + fi + - name: Checkout AvalancheGo + uses: actions/checkout@v4 + - uses: ./.github/actions/setup-go-for-project + - name: Setup AvalancheGo with Custom Firewood + uses: ./.github/actions/avalanchego-setup-action + with: + checkout-path: ${{ env.AVALANCHEGO_CHECKOUT_PATH }} + avalanchego: ${{ github.ref_name }} + firewood: ${{ inputs.firewood-version }} + firewood-path: ${{ env.FIREWOOD_WORKSPACE_PATH }} + coreth: ${{ inputs.coreth-version }} + - name: Run C-Chain Reexecution Benchmark + uses: ./.github/actions/c-chain-reexecution-benchmark + with: + task: ${{ inputs.task-name }} + runner_name: ${{ inputs.runner }} + aws-role: ${{ secrets.AWS_S3_READ_ONLY_ROLE }} + aws-region: 'us-east-2' + prometheus-url: ${{ secrets.PROMETHEUS_URL || '' }} + prometheus-push-url: ${{ secrets.PROMETHEUS_PUSH_URL || '' }} + prometheus-username: ${{ secrets.PROMETHEUS_USERNAME || '' }} + prometheus-password: ${{ secrets.PROMETHEUS_PASSWORD || '' }} + github-token: ${{ secrets.GITHUB_TOKEN }} + push-github-action-benchmark: false + - name: Upload benchmark output + if: always() + uses: actions/upload-artifact@v4 + with: + name: benchmark-output-${{ inputs.task-name }}-${{ github.run_id }} + path: | + benchmark-output.txt + **/*.log + **/*.prof + /tmp/reexecution-data-*/**/*.log + retention-days: 7 + if-no-files-found: ignore + diff --git a/Taskfile.yml b/Taskfile.yml index d871e10118b5..172696727c4d 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -4,6 +4,9 @@ version: '3' +env: + S3_BOOTSTRAP_BUCKET: 's3://avalanchego-bootstrap-testing' + tasks: default: ./scripts/run_task.sh --list @@ -11,6 +14,12 @@ tasks: desc: Builds avalanchego cmd: ./scripts/build.sh + build-with-firewood: + desc: Builds avalanchego with Firewood FFI (specify version with FIREWOOD_VERSION) + vars: + FIREWOOD_VERSION: '{{.FIREWOOD_VERSION | default "ffi/v0.0.12"}}' + cmd: ./scripts/build.sh -f {{.FIREWOOD_VERSION}} + build-antithesis-images-avalanchego: desc: Builds docker images for antithesis for the avalanchego test setup env: @@ -142,8 +151,8 @@ tasks: desc: Imports the C-Chain block and state data to re-execute. Defaults to import the first 200 and the current state created with the default config of the C-Chain (hashdb). vars: EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}' - BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC | default "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-200-ldb/**"}}' - CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC | default "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/**"}}' + BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC | default (printf "%s/cchain-mainnet-blocks-200-ldb/**" .S3_BOOTSTRAP_BUCKET)}}' + CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC | default (printf "%s/cchain-current-state-hashdb-full-100/**" .S3_BOOTSTRAP_BUCKET)}}' cmds: - task: import-s3-to-dir vars: @@ -201,63 +210,127 @@ tasks: vars: CURRENT_STATE_DIR: '{{.CURRENT_STATE_DIR}}' BLOCK_DIR: '{{.BLOCK_DIR}}' - RUNNER_NAME: '{{.RUNNER_NAME | default "dev"}}' CONFIG: '{{.CONFIG | default ""}}' START_BLOCK: '{{.START_BLOCK}}' END_BLOCK: '{{.END_BLOCK}}' LABELS: '{{.LABELS | default ""}}' BENCHMARK_OUTPUT_FILE: '{{.BENCHMARK_OUTPUT_FILE | default ""}}' - METRICS_SERVER_ENABLED: '{{.METRICS_SERVER_ENABLED | default "false"}}' - METRICS_SERVER_PORT: '{{.METRICS_SERVER_PORT}}' - METRICS_COLLECTOR_ENABLED: '{{.METRICS_COLLECTOR_ENABLED | default "false"}}' + TIMESTAMP: '{{.TIMESTAMP | default (now | date "20060102-150405")}}' + EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR | default (printf "/tmp/%s-%s" .TASK_NAME .TIMESTAMP)}}' cmd: | CURRENT_STATE_DIR={{.CURRENT_STATE_DIR}} \ BLOCK_DIR={{.BLOCK_DIR}} \ - RUNNER_NAME='{{.RUNNER_NAME | default "dev"}}' \ CONFIG={{.CONFIG}} \ START_BLOCK={{.START_BLOCK}} \ END_BLOCK={{.END_BLOCK}} \ LABELS={{.LABELS}} \ BENCHMARK_OUTPUT_FILE={{.BENCHMARK_OUTPUT_FILE}} \ - METRICS_SERVER_ENABLED={{.METRICS_SERVER_ENABLED}} \ - METRICS_SERVER_PORT={{.METRICS_SERVER_PORT}} \ - METRICS_COLLECTOR_ENABLED={{.METRICS_COLLECTOR_ENABLED}} \ + EXECUTION_DATA_DIR={{.EXECUTION_DATA_DIR}} \ bash -x ./scripts/benchmark_cchain_range.sh + # Runtime context variables are read from environment by the script: + # - RUNNER_NAME (execution environment) + # - METRICS_SERVER_PORT (monitoring config) + # - METRICS_SERVER_ENABLED (runtime monitoring decision) + # - METRICS_COLLECTOR_ENABLED (runtime monitoring decision) + # - PROMETHEUS_URL, PROMETHEUS_USERNAME, PROMETHEUS_PASSWORD (monitoring config) + # - GH_REPO, GH_WORKFLOW, GH_RUN_ID, etc. (GitHub context) reexecute-cchain-range-with-copied-data: desc: Combines import-cchain-reexecute-range and reexecute-cchain-range vars: - EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}' - BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC | default "s3://avalanchego-bootstrap-testing/cchain-mainnet-blocks-1m-ldb/**"}}' - CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC | default "s3://avalanchego-bootstrap-testing/cchain-current-state-hashdb-full-100/**"}}' - RUNNER_NAME: '{{.RUNNER_NAME | default "dev"}}' - CONFIG: '{{.CONFIG | default ""}}' - START_BLOCK: '{{.START_BLOCK | default "101"}}' - END_BLOCK: '{{.END_BLOCK | default "250000"}}' - LABELS: '{{.LABELS | default ""}}' - BENCHMARK_OUTPUT_FILE: '{{.BENCHMARK_OUTPUT_FILE | default ""}}' - METRICS_SERVER_ENABLED: '{{.METRICS_SERVER_ENABLED | default "false"}}' - METRICS_SERVER_PORT: '{{.METRICS_SERVER_PORT}}' - METRICS_COLLECTOR_ENABLED: '{{.METRICS_COLLECTOR_ENABLED | default "false"}}' + TASK_NAME: '{{.TASK_NAME}}' + BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC}}' + CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC}}' + CONFIG: '{{.CONFIG}}' + START_BLOCK: '{{.START_BLOCK}}' + END_BLOCK: '{{.END_BLOCK}}' + TIMESTAMP: '{{.TIMESTAMP | default (now | date "20060102-150405")}}' + EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR | default (printf "/tmp/%s-%s" .TASK_NAME .TIMESTAMP)}}' cmds: - task: import-cchain-reexecute-range vars: - BLOCK_DIR_SRC: '{{.BLOCK_DIR_SRC}}' - CURRENT_STATE_DIR_SRC: '{{.CURRENT_STATE_DIR_SRC}}' + BLOCK_DIR_SRC: '{{.S3_BOOTSTRAP_BUCKET}}/{{.BLOCK_DIR_SRC}}/**' + CURRENT_STATE_DIR_SRC: '{{.S3_BOOTSTRAP_BUCKET}}/{{.CURRENT_STATE_DIR_SRC}}/**' EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}' - task: reexecute-cchain-range vars: + TASK_NAME: '{{.TASK_NAME}}' BLOCK_DIR: '{{.EXECUTION_DATA_DIR}}/blocks' CURRENT_STATE_DIR: '{{.EXECUTION_DATA_DIR}}/current-state' - RUNNER_NAME: '{{.RUNNER_NAME}}' CONFIG: '{{.CONFIG}}' START_BLOCK: '{{.START_BLOCK}}' END_BLOCK: '{{.END_BLOCK}}' - LABELS: '{{.LABELS}}' - BENCHMARK_OUTPUT_FILE: '{{.BENCHMARK_OUTPUT_FILE}}' - METRICS_SERVER_ENABLED: '{{.METRICS_SERVER_ENABLED}}' - METRICS_SERVER_PORT: '{{.METRICS_SERVER_PORT}}' - METRICS_COLLECTOR_ENABLED: '{{.METRICS_COLLECTOR_ENABLED}}' + EXECUTION_DATA_DIR: '{{.EXECUTION_DATA_DIR}}' + + c-chain-reexecution-hashdb-101-250k: + desc: C-Chain re-execution from block 101 to 250k with hashdb + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 101 + END_BLOCK: 250000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-1m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-hashdb-full-100' + + c-chain-reexecution-hashdb-archive-101-250k: + desc: C-Chain re-execution from block 101 to 250k with hashdb archive + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 101 + END_BLOCK: 250000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-1m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-hashdb-archive-100' + CONFIG: archive + + c-chain-reexecution-hashdb-33m-33m500k: + desc: C-Chain re-execution from block 33m to 33.5m with hashdb + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 33000001 + END_BLOCK: 33500000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-30m-40m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-hashdb-full-33m' + + c-chain-reexecution-firewood-33m-33m500k: + desc: C-Chain re-execution from block 33m to 33.5m with firewood + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 33000001 + END_BLOCK: 33500000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-30m-40m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-firewood-33m' + CONFIG: firewood + + c-chain-reexecution-firewood-33m-40m: + desc: C-Chain re-execution from block 33m to 40m with firewood + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 33000001 + END_BLOCK: 40000000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-30m-40m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-firewood-33m' + CONFIG: firewood + + c-chain-reexecution-firewood-101-250k: + desc: C-Chain re-execution from block 101 to 250k with firewood + cmds: + - task: reexecute-cchain-range-with-copied-data + vars: + TASK_NAME: '{{.TASK}}' + START_BLOCK: 101 + END_BLOCK: 250000 + BLOCK_DIR_SRC: 'cchain-mainnet-blocks-1m-ldb' + CURRENT_STATE_DIR_SRC: 'cchain-current-state-firewood-100' + CONFIG: firewood test-bootstrap-monitor-e2e: desc: Runs bootstrap monitor e2e tests diff --git a/scripts/benchmark_cchain_range.sh b/scripts/benchmark_cchain_range.sh index 0d9d951e7194..896e68f8a559 100755 --- a/scripts/benchmark_cchain_range.sh +++ b/scripts/benchmark_cchain_range.sh @@ -16,14 +16,13 @@ set -euo pipefail : "${BLOCK_DIR:?BLOCK_DIR must be set}" : "${CURRENT_STATE_DIR:?CURRENT_STATE_DIR must be set}" -: "${RUNNER_NAME:?RUNNER_NAME must be set}" : "${START_BLOCK:?START_BLOCK must be set}" : "${END_BLOCK:?END_BLOCK must be set}" cmd="go test -timeout=0 -v -benchtime=1x -bench=BenchmarkReexecuteRange -run=^$ github.com/ava-labs/avalanchego/tests/reexecute/c \ --block-dir=\"${BLOCK_DIR}\" \ --current-state-dir=\"${CURRENT_STATE_DIR}\" \ - --runner=\"${RUNNER_NAME}\" \ + ${RUNNER_NAME:+--runner=\"${RUNNER_NAME}\"} \ ${CONFIG:+--config=\"${CONFIG}\"} \ --start-block=\"${START_BLOCK}\" \ --end-block=\"${END_BLOCK}\" \ diff --git a/scripts/build.sh b/scripts/build.sh index 9ca888030cd0..d5df89a00a04 100755 --- a/scripts/build.sh +++ b/scripts/build.sh @@ -9,19 +9,29 @@ print_usage() { Options: - -r Build with race detector + -r Build with race detector + -f VERSION Build with Firewood FFI + VERSION format: ffi/vX.Y.Z for pre-built, commit/branch for source " } race='' -while getopts 'r' flag; do +firewood_version='' + +while getopts 'rf:' flag; do case "${flag}" in r) echo "Building with race detection enabled" race='-race' ;; - *) print_usage - exit 1 ;; + f) + firewood_version="${OPTARG}" + echo "Building with Firewood version: ${firewood_version}" + ;; + *) + print_usage + exit 1 + ;; esac done @@ -31,6 +41,10 @@ source "${REPO_ROOT}"/scripts/constants.sh # Determine the git commit hash to use for the build source "${REPO_ROOT}"/scripts/git_commit.sh +if [ -n "${firewood_version}" ]; then + "${REPO_ROOT}/scripts/setup_firewood.sh" "${firewood_version}" "${REPO_ROOT}" +fi + echo "Building AvalancheGo with [$(go version)]..." go build ${race} -o "${avalanchego_path}" \ -ldflags "-X github.com/ava-labs/avalanchego/version.GitCommit=$git_commit $static_ld_flags" \ diff --git a/scripts/copy_dir.sh b/scripts/copy_dir.sh index 874b53c74769..a6de180c1dc7 100755 --- a/scripts/copy_dir.sh +++ b/scripts/copy_dir.sh @@ -3,13 +3,13 @@ set -euo pipefail # Usage: ./scripts/copy_dir.sh source_directory destination_directory -# Sources can be S3 URLs (s3://bucket/path) or a local file path # Assumes s5cmd has been installed and is available in the PATH. # s5cmd is included in the nix dev shell. if [ $# -ne 2 ]; then echo "Usage: $0 " - echo "Import from S3 Example: $0 's3://bucket1/path1' /dest/dir" + echo "Import from S3 URL Example: $0 's3://bucket1/path1' /dest/dir" + echo "Import from S3 object key Example: $0 'cchain-mainnet-blocks-1m-ldb' /dest/dir" echo "Export to S3 Example: $0 '/local/path1' 's3://bucket2/path2'" echo "Local Example: $0 '/local/path1' /dest/dir" exit 1 @@ -18,11 +18,18 @@ fi SRC="$1" DST="$2" +# If SRC doesn't start with s3:// or /, assume it's an S3 object key +if [[ "$SRC" != s3://* ]] && [[ "$SRC" != /* ]]; then + echo "Error: SRC must be either an S3 URL (s3://...), a local path (/...), or already expanded" + echo "If using an object key, expand it before calling this script" + exit 1 +fi + # Function to copy from a single source to destination function copy_source() { local source="$1" local dest="$2" - + # Check if source starts with s3:// if [[ "$source" == s3://* || "$dest" == s3://* ]]; then # Use s5cmd to copy from S3 @@ -30,7 +37,7 @@ function copy_source() { time s5cmd cp --show-progress "$source" "$dest" else # Use cp for local filesystem with recursive support - + # Ensure destination directory exists mkdir -p "$dest" diff --git a/scripts/setup_firewood.sh b/scripts/setup_firewood.sh new file mode 100755 index 000000000000..99cad6f71300 --- /dev/null +++ b/scripts/setup_firewood.sh @@ -0,0 +1,77 @@ +#!/usr/bin/env bash + +# Setup Firewood FFI +# +# Clones Firewood repository, builds/fetches the FFI, and updates go.mod +# +# Usage: +# setup_firewood.sh [workspace] +# +# Arguments: +# version Firewood version (ffi/vX.Y.Z for pre-built, commit/branch for source) +# workspace Optional workspace path for Firewood build (default: ${AVALANCHE_PATH}/firewood-workspace) +# +# Output: +# Prints FFI path to stdout on success + +set -euo pipefail + +if [ $# -lt 1 ]; then + echo "Usage: $0 [workspace]" >&2 + exit 1 +fi + +FIREWOOD_VERSION="$1" +AVALANCHE_PATH=$( cd "$( dirname "${BASH_SOURCE[0]}" )"; cd .. && pwd ) +FIREWOOD_CLONE_DIR="${AVALANCHE_PATH}/firewood" + +# Use provided workspace or default to avalanchego/firewood-workspace +if [ $# -ge 2 ] && [ -n "$2" ]; then + WORKSPACE_PATH="$2" +else + WORKSPACE_PATH="${AVALANCHE_PATH}/firewood-workspace" +fi + +if [ -d "${FIREWOOD_CLONE_DIR}" ]; then + echo "Removing existing Firewood directory..." >&2 + rm -rf "${FIREWOOD_CLONE_DIR}" +fi + +echo "Setting up Firewood FFI version: ${FIREWOOD_VERSION}" >&2 +echo "Using workspace: ${WORKSPACE_PATH}" >&2 + +git clone https://github.com/ava-labs/firewood "${FIREWOOD_CLONE_DIR}" \ + --quiet --depth 1 --branch composable-ci-action + +SETUP_FIREWOOD_SCRIPT="${FIREWOOD_CLONE_DIR}/scripts/build-firewood.sh" + +if [ ! -f "${SETUP_FIREWOOD_SCRIPT}" ]; then + echo "Error: Setup Firewood script not found at ${SETUP_FIREWOOD_SCRIPT}" >&2 + exit 1 +fi + +# Build or fetch Firewood FFI with custom workspace +# Capture only the last line which is the FFI path +FFI_PATH=$("${SETUP_FIREWOOD_SCRIPT}" "${FIREWOOD_VERSION}" --workspace "${WORKSPACE_PATH}" | tail -n 1) + +if [ -z "${FFI_PATH}" ]; then + echo "Error: Failed to build/fetch Firewood FFI" >&2 + exit 1 +fi + +cd "${AVALANCHE_PATH}" + +# Verify go.mod exists +if [ ! -f "go.mod" ]; then + echo "Error: go.mod not found in ${AVALANCHE_PATH}" >&2 + exit 1 +fi + +echo "Updating go.mod with FFI path: ${FFI_PATH}" >&2 +go mod edit -replace github.com/ava-labs/firewood-go-ethhash/ffi="${FFI_PATH}" + +go mod tidy +go mod download + +# Output FFI path to stdout for consumption by other scripts +echo "${FFI_PATH}" diff --git a/tests/reexecute/c/vm_reexecute_test.go b/tests/reexecute/c/vm_reexecute_test.go index 2cb50b91fe21..b396a8eacac2 100644 --- a/tests/reexecute/c/vm_reexecute_test.go +++ b/tests/reexecute/c/vm_reexecute_test.go @@ -208,6 +208,12 @@ func benchmarkReexecuteRange( ) log.Info("re-executing block range with params", + zap.String("runner", runnerNameArg), + zap.String("config", configNameArg), + zap.String("labels", labelsArg), + zap.String("metrics-server-enabled", strconv.FormatBool(metricsServerEnabled)), + zap.Uint64("metrics-server-port", metricsPort), + zap.String("metrics-collector-enabled", strconv.FormatBool(metricsCollectorEnabled)), zap.String("block-dir", blockDir), zap.String("vm-db-dir", vmDBDir), zap.String("chain-data-dir", chainDataDir),