Using Docker for Verifiable Solana Builds

Verifiable Solana Builds of Native Solana programs with Docker.

Using Docker for Verifiable Solana Builds
Using Docker for Verifiable Solana Builds Blog Cover

What are Verifiable Solana Builds?

Here's a great paragraph on Anchor Lang documentation that quickly sums up the importance of having Verifiable Solana Builds:

Building programs with the Solana CLI may embed machine specific code into the resulting binary. As a result, building the same program on different machines may produce different executables. To get around this problem, one can build inside a docker image with pinned dependencies to produce a verifiable build.

When do verifiable Solana builds matter the most?

This matters a lot to the community that supports you by confirming if what is deployed onchain is equivalent to what you published as Opensource.

By deploying a Verifiable Solana Build, you empower your community with the capacity to audit your integrity as a project owner.

Hence if you're planning to deploy a Solana program any time soon, choose to deploy a verifiable build!

How to create a Verifiable Solana Build?

There are 3 main steps you need to do in creating a Verifiable Solana Build.

  1. Identify the pinned versions of Rust, Solana CLI, and Anchor you will use for your Docker image.
  2. Build the Docker image you will be using for creating a Verifiable Solana Builder with a Dockerfile
  3. Build your program using your image.

To simplify this process, this guide comes with a supplementary Github repository you can use as a reference.

GitHub - kquirapas/verifiable-solana-builds: Supplementary repository for verifiable solana builds guide on kquirapas.com
Supplementary repository for verifiable solana builds guide on kquirapas.com - kquirapas/verifiable-solana-builds

This repository comes with:

  1. A CounterTest Native Solana program you will build using your Docker image
  2. A Dockerfile you will use to build your image.
  3. A build.sh executable file you can use to start building your Solana program using your Docker image.

Identify pinned versions of Rust and Solana CLI

For this guide, you will only be compiling a Native Solana program hence will only need a pinned version of Rust and Solana CLI:

Build your Docker image with a Dockerfile

Here's the multi-stage Dockerfile you'll be using to build your Native Solana program.

# Build Image
ARG RUST_IMAGE_TAG=1.79
FROM --platform=linux/amd64 rust:${RUST_IMAGE_TAG} as builder
ARG SOLANA_CLI=v1.18.16
# Install Solana CLI
RUN curl -sSfL "https://release.solana.com/${SOLANA_CLI}/install" | sh
# Make sure Solana PATH is added to environment
ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}"

# Usage image to build
FROM --platform=linux/amd64 builder
COPY . .
CMD ["cargo", "build-sbf"]

Let's unpack this Dockerfile step by step.

This section defines the base image and establishes the pinned versions of Rust and Solana CLI.

# Build Image
ARG RUST_IMAGE_TAG=1.79
FROM --platform=linux/amd64 rust:${RUST_IMAGE_TAG} as builder
ARG SOLANA_CLI=v1.18.16

This section installs the Solana CLI tool and ensures that it persists in the image's PATH environment variable.

# Install Solana CLI
RUN curl -sSfL "https://release.solana.com/${SOLANA_CLI}/install" | sh
# Make sure Solana PATH is added to environment
ENV PATH="/root/.local/share/solana/install/active_release/bin:${PATH}"

This section focuses on the 2nd stage of the build and utilizes the previously built image named as builder. It also copies the files from host to container and ends with a cargo build-sbf command to build your Native Solana program.

# Usage image to build
FROM --platform=linux/amd64 builder
COPY . .
CMD ["cargo", "build-sbf"]

Build your program with build.sh

After identifying your pinned versions and building your Dockerfile, it's time to build your program.

This is the build.sh script responsible for:

  1. Building your image with docker build
  2. Running your image with docker run
  3. Mounting volumes to synchronous data from container to host with docker run's -v option.
#!/bin/bash

# get repo root for reference point
REPO_ROOT=$(git rev-parse --show-toplevel)

pushd $REPO_ROOT

# configuration
RUST_IMAGE_TAG=1.79
SOLANA_CLI=v1.18.16
# separate folder form target/ to prevent Permission Denied error
HOST_FOLDER_ABSOLUTE_PATH=$REPO_ROOT/verified
CONTAINER_FOLDER_ABSOLUTE_PATH=/target
IMAGE_NAME=verifiable-solana-build

docker build --build-arg "RUST_IMAGE_TAG=$RUST_IMAGE_TAG" --build-arg "SOLANA_CLI=$SOLANA_CLI" -t $IMAGE_NAME .
docker run --rm --name "build-$IMAGE_NAME" -v $HOST_FOLDER_ABSOLUTE_PATH:$CONTAINER_FOLDER_ABSOLUTE_PATH $IMAGE_NAME

popd

The key part of this build script is to make sure that you run (docker run) your image with mounted volumes else your build won't persist in your host device.

In this build script, you sync the files in the container at /target directory to your host machine's ./verified folder inside the repository.

Start building your Verifiable Solana Build!

Change the directory into the root of the supplementary repository, run ./build.sh, and WAIT!

After waiting for the compilation to end, if there are no errors you should be left with a /verifiable folder in your repository containing your artifacts like below.

Snapshot of working directory after building

Conclusion

Deploying a Verifiable Solana Build enables you to build trust by empowering your community to audit your integrity.

Do you find this guide helpful? There's more!

Sign up to comment and let me know what you think!