Skip to content

fix: Docker build on macOS #143

fix: Docker build on macOS

fix: Docker build on macOS #143

Workflow file for this run

---
name: CI
on:
push:
branches: ['*']
pull_request:
branches: [main]
jobs:
fmt-clippy:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Setup Rust toolchain
uses: actions-rust-lang/setup-rust-toolchain@v1
with:
components: rustfmt, clippy
- name: Check formatting
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings
integration-test:
runs-on: ["self-hosted", "linux", "x64", "16xlarge+gpu"]
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
# Free up disk space on GitHub Actions runner to avoid "no space left" errors
- name: "EXEC: {Free up disk space}, independent"
uses: endersonmenezes/free-disk-space@v3
with:
remove_android: true
remove_dotnet: true
remove_haskell: true
remove_tool_cache: true
remove_swap: true
remove_packages: "azure-cli google-cloud-cli microsoft-edge-stable google-chrome-stable firefox postgresql* temurin-* *llvm* mysql* dotnet-sdk-*"
remove_packages_one_command: true
remove_folders: "/usr/share/swift /usr/share/miniconda /usr/share/az* /usr/local/lib/node_modules /usr/local/share/chromium /usr/local/share/powershell /usr/local/julia /usr/local/aws-cli /usr/local/aws-sam-cli /usr/share/gradle"
rm_cmd: "rmz"
rmz_version: "3.1.1"
# Setup Rust toolchain and restore cached dependencies
- name: "EXEC: {Setup Rust toolchain}, independent"
uses: actions-rust-lang/setup-rust-toolchain@v1
# CACHE-RUST: Rust dependencies and build artifacts
# These are keyed on the Cargo.lock file to ensure cache validity
- name: "CACHE_RESTORE: {C-rust-cache}"
id: cache-rust
uses: actions/cache/restore@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-rust-build-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-rust-build-
# Setup Docker for building and running containers
- name: "EXEC: {Setup Docker}, independent"
uses: docker/setup-buildx-action@v3
- name: "EXEC: {Install build dependencies}, independent"
run: |
sudo apt-get update
sudo apt-get install -y tar openssl pkg-config libssl-dev
# Build the foc-devnet binary
- name: "EXEC: {Build foc-devnet binary}, DEP: {C-rust-cache}"
run: cargo build --release
# CACHE-RUST: Save Rust build cache for future runs
- name: "CACHE_SAVE: {C-rust-cache}"
if: steps.cache-rust.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: |
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cargo/git/db/
target/
key: ${{ runner.os }}-rust-build-${{ hashFiles('**/Cargo.lock') }}
# Copy binary and clean up Rust artifacts to save disk space
- name: "EXEC: {Copy binary and clean cache}, DEP: {C-rust-cache}"
run: |
cp ./target/release/foc-devnet ./foc-devnet
rm -rf ~/.cargo/registry/
rm -rf ~/.cargo/git/db/
rm -rf target/
df -h
# Compute cache keys based on version info and source files
# - CODE_HASH: Changes when Lotus/Curio versions change (for build artifacts cache)
# - DOCKER_HASH: Changes when Dockerfiles change (for Docker images cache)
- name: "CHECK: {Compute version hashes}"
id: version-hashes
run: |
# Get version output
VERSION_OUTPUT=$(./foc-devnet version 2>&1)
# Compute CODE_HASH from all default:code: lines (Lotus/Curio versions)
CODE_HASH=$(echo "$VERSION_OUTPUT" | grep 'default:code:' | sha256sum | cut -d' ' -f1)
echo "code-hash=$CODE_HASH" >> $GITHUB_OUTPUT
echo "CODE_HASH: $CODE_HASH"
# Compute DOCKER_HASH from docker/ directory (Dockerfile changes)
DOCKER_HASH=$(find docker -type f -exec sha256sum {} \; | sort | sha256sum | cut -d' ' -f1)
echo "docker-hash=$DOCKER_HASH" >> $GITHUB_OUTPUT
echo "DOCKER_HASH: $DOCKER_HASH"
# CACHE-DOCKER: Try to restore pre-built Docker images (foc-lotus, foc-lotus-miner, foc-builder, foc-curio, foc-yugabyte)
# These images contain YugabyteDB and all build dependencies
- name: "CACHE_RESTORE: {C-docker-images-cache}"
id: cache-docker-images
uses: actions/cache/restore@v4
with:
path: ~/.docker-images-cache
key: ${{ runner.os }}-docker-images-${{ steps.version-hashes.outputs.docker-hash }}
# CACHE-DOCKER: If Docker images are cached, load them from tarballs
- name: "EXEC: {Load Docker images}, DEP: {C-docker-images-cache}"
if: steps.cache-docker-images.outputs.cache-hit == 'true'
run: |
echo "Loading Docker images from cache..."
for image in ~/.docker-images-cache/*.tar; do
if [ -f "$image" ]; then
echo "Loading $(basename $image)..."
docker load -i "$image"
fi
done
echo "Docker images loaded successfully, list:"
docker images
rm -rf ~/.docker-images-cache
df -h
# If Docker images are cached, skip building them AND skip downloading YugabyteDB
# (YugabyteDB is already baked into the foc-yugabyte Docker image)
- name: "EXEC: {Initialize with cached Docker}, DEP: {C-docker-images-cache}"
if: steps.cache-docker-images.outputs.cache-hit == 'true'
run: |
rm -rf ~/.foc-devnet
./foc-devnet init --no-docker-build
# If Docker images are not cached, do full init (downloads YugabyteDB and builds all images)
- name: "EXEC: {Initialize without cache}, independent"
if: steps.cache-docker-images.outputs.cache-hit != 'true'
run: |
rm -rf ~/.foc-devnet
./foc-devnet init
# CACHE-DOCKER: Build Docker images if not cached
- name: "EXEC: {Build Docker images}, DEP: {C-docker-images-cache}"
if: steps.cache-docker-images.outputs.cache-hit != 'true'
run: |-
mkdir -p ~/.docker-images-cache
echo "Building Docker images for cache..."
docker save foc-lotus -o ~/.docker-images-cache/foc-lotus.tar
docker save foc-lotus-miner -o ~/.docker-images-cache/foc-lotus-miner.tar
docker save foc-builder -o ~/.docker-images-cache/foc-builder.tar
docker save foc-curio -o ~/.docker-images-cache/foc-curio.tar
docker save foc-yugabyte -o ~/.docker-images-cache/foc-yugabyte.tar
echo "Docker images saved to cache"
ls -lath ~/.docker-images-cache/
df -h
# CACHE-DOCKER: Save Docker images cache for future runs
- name: "CACHE_SAVE: {C-docker-images-cache}"
if: steps.cache-docker-images.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.docker-images-cache
key: ${{ runner.os }}-docker-images-${{ steps.version-hashes.outputs.docker-hash }}
# CACHE-BINARIES: Try to restore previously built Lotus/Curio binaries
- name: "CACHE_RESTORE: {C-build-artifacts-cache}"
id: cache-binaries
uses: actions/cache/restore@v4
with:
path: ~/.foc-devnet/bin
key: ${{ runner.os }}-binaries-${{ steps.version-hashes.outputs.code-hash }}
- name: "EXEC: {Ensure permissions on binaries}, DEP: {C-build-artifacts-cache}"
if: steps.cache-binaries.outputs.cache-hit == 'true'
run: sudo chown -R $USER:$USER ~/.foc-devnet/bin/
# CACHE-GO: Try to restore foc-builder Go module cache to speed up Lotus/Curio builds
- name: "CACHE_RESTORE: {C-foc-builder-cache}"
id: cache-go
if: steps.cache-binaries.outputs.cache-hit != 'true'
uses: actions/cache/restore@v4
with:
path: ~/.foc-devnet/docker/volumes/cache/foc-builder
key: ${{ runner.os }}-foc-builder-cache-${{ hashFiles('docker/**') }}-${{ hashFiles('src/config.rs') }}
restore-keys: |
${{ runner.os }}-foc-builder-cache-
- name: "EXEC: {Ensure permissions}, DEP: {C-foc-builder-cache}"
if: steps.cache-binaries.outputs.cache-hit != 'true' &&
steps.cache-go.outputs.cache-hit == 'true'
run: sudo chown -R $USER:$USER ~/.foc-devnet/
- name: "EXEC: {Check disk space}, independent"
run: df -h
# Build Lotus and Curio if not cached
- name: "EXEC: {Build Lotus}, DEP: {C-build-artifacts-cache}"
if: steps.cache-binaries.outputs.cache-hit != 'true'
run: ./foc-devnet build lotus
- name: "EXEC: {Build Curio}, DEP: {C-build-artifacts-cache}"
if: steps.cache-binaries.outputs.cache-hit != 'true'
run: ./foc-devnet build curio
# CACHE-GO: Save Go module cache for future builds
- name: "CACHE_SAVE: {C-foc-builder-cache}"
if: steps.cache-binaries.outputs.cache-hit != 'true' &&
steps.cache-go.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.foc-devnet/docker/volumes/cache/foc-builder
key: ${{ runner.os }}-foc-builder-cache-${{ hashFiles('docker/**') }}-${{ hashFiles('src/config.rs') }}
# CACHE-BINARIES: Save built Lotus/Curio binaries for future runs
- name: "CACHE_SAVE: {C-build-artifacts-cache}"
if: steps.cache-binaries.outputs.cache-hit != 'true'
uses: actions/cache/save@v4
with:
path: ~/.foc-devnet/bin
key: ${{ runner.os }}-binaries-${{ steps.version-hashes.outputs.code-hash }}
# Disk free-up
- name: "EXEC: {Clean up Go modules}, DEP: {C-build-artifacts-cache}"
run: |
sudo rm -rf ~/.foc-devnet/docker/volumes/cache
sudo rm -rf ~/.foc-devnet/code/lotus
sudo rm -rf ~/.foc-devnet/code/curio
df -h
# Download and extract Filecoin proof parameters from S3
- name: "EXEC: {Download proof parameters from S3}, independent"
run: |
mkdir -p ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/
curl -L https://fil-proof-params-2k-cache.s3.us-east-2.amazonaws.com/filecoin-proof-params-2k.tar -o /tmp/filecoin-proof-params-2k.tar
tar -xf /tmp/filecoin-proof-params-2k.tar -C ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/
rm /tmp/filecoin-proof-params-2k.tar
ls -lath ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters/
PROOF_PARAMS_HASH=$(find ~/.foc-devnet/docker/volumes/cache/filecoin-proof-parameters -type f -exec sha256sum {} \; | cut -d' ' -f1 | sort | sha256sum | cut -d' ' -f1)
echo "Downloaded proof parameters with hash: $PROOF_PARAMS_HASH"
# Verify cluster is running correctly
- name: "EXEC: {Check cluster status}, independent"
run: ./foc-devnet status
# Start the full Filecoin localnet cluster
- name: "EXEC: {Start cluster}, independent"
id: start_cluster
continue-on-error: true
run: ./foc-devnet start --parallel
# On failure, collect and print Docker container logs for debugging
- name: "EXEC: {Collect Docker logs on failure}, independent"
run: |
echo "+++++++++++ foc-devnet version run"
cat ~/.foc-devnet/state/latest/version.txt 2>/dev/null || echo "No version file found"
echo "+++++++++++ Listing runs in foc-devnet..."
ls -1 ~/.foc-devnet/run/ 2>/dev/null || echo "No runs directory found"
echo "+++++++++++ Get latest run ID"
LATEST_RUN=$(ls -t ~/.foc-devnet/run/ 2>/dev/null | head -1)
if [ -n "$LATEST_RUN" ]; then
echo "Latest run: $LATEST_RUN"
RUN_DIR="$HOME/.foc-devnet/run/$LATEST_RUN"
else
RUN_DIR="$HOME/.foc-devnet/state/latest"
fi
echo "+++++++++++ Disk space..."
sudo df -h 2>/dev/null || echo "df command failed"
echo "+++++++++++ Latest Run Directory"
ls -lath "$RUN_DIR" 2>/dev/null || echo "No run directory found at $RUN_DIR"
ls -lath "$RUN_DIR/logs" 2>/dev/null || echo "No logs directory found at $RUN_DIR/logs"
echo "+++++++++++ Contract Addresses"
cat "$RUN_DIR/contract_addresses.json" 2>/dev/null || echo "No contract addresses file found"
echo "+++++++++++ Step Context"
cat "$RUN_DIR/step_context.json" 2>/dev/null || echo "No step context file found"
echo "+++++++++++ FOC metadata"
cat "$RUN_DIR/foc_metadata.json" 2>/dev/null || echo "No foc metadata file found"
echo "+++++++++++ Container Logs"
if [ -d "$RUN_DIR/logs" ]; then
for logfile in "$RUN_DIR/logs"/*; do
if [ -f "$logfile" ]; then
echo ""
echo "📰📰📰📰📰📰📰📰📰📰📰 Logs from $(basename "$logfile") 📰📰📰📰📰📰📰📰📰📰📰📰📰"
cat "$logfile" 2>/dev/null || echo "Failed to read $logfile"
echo "📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰📰"
fi
done
else
echo "No container logs directory found at $RUN_DIR/logs"
fi
# Verify cluster is running correctly
- name: "EXEC: {Check cluster status}, independent"
run: ./foc-devnet status
- name: "EXEC: {List foc-* containers}, independent"
run: |
echo "Containers using foc-* images (running or exited):"
docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
# Clean shutdown
- name: "EXEC: {Stop cluster}, independent"
run: ./foc-devnet stop
# Mark job as failed if the start step failed, but only after all steps
- name: "CHECK: {Fail job if start failed}"
if: ${{ always() && steps.start_cluster.outcome == 'failure' }}
run: |
echo "Start cluster failed earlier; marking job as failed." >&2
exit 1