All Articles

Solana Anchor verifiable builds

anchor build

If you’re creating a program for the Solana blockchain using the Anchor framework, it’s recommended to publish it as a verifiable build. You can do this easily by running anchor build --verifiable, and the result to deploy to devnet.

Why should you use a verifiable build?

When you deploy a verifiable build to the Solana network, you can verify that the program binary is the same as one the deployer declares. You can check out the source code of the program at a particular commit and run anchor verify against it to see if the binary matches the checked-out code, and if no changes were made to the program.

To verify a deployed program, it must(!) be published as a verifiable build; otherwise, the anchor verify command will fail.

Note
This article talks about experiences at the Anchor version 0.27.0.

What is a Verifiable Build?

A verifiable build is a program build that is created in a predefined and clean environment, in this case, in the Docker container. By default, the docker image used is project-serum/anchor, configured at anchor cli in particular docker tag. You can specify to use a specific image with the CLI arguments -d, --docker-image <DOCKER_IMAGE>. Or specify docker tag in Anchor.toml file with anchor_version parameter (project-serum/anchor is the image for the tag).

When you run the anchor build --verifiable command, the build process is executed inside the docker container.

anchor build --verifiable

The docker image is pulled from Docker Hub, and the build is executed inside it. As it’s a clean environment, the build process requires the download of all dependencies and the compilation takes some time. The result of the build is a standard .so binary file, which is stored at directory ./target/verifiable/. The build also generates the IDLs, which are stored at ./target/idl/ and ./target/types.

You can publish the compiled binary to the network (while I haven’t found a way to use anchor deploy for this purpose). Instead, you can use the solana CLI tools.

solana program deploy -v -u devnet --keypair ~/.config/solana/devnet.json \
  --program-id <PROGRAM_ID_KEYPAIR> \
  --upgrade-authority <PATH_TO_KEYPAIR> \
  ./target/verifiable/program.so
Note
usually <PROGRAM_ID> is defined at Anchor.toml and for initial deployment we need to provide the keypair as the new account needs to be initialized

Uploading Anchor IDL

When you deploy the program, you also need to publish the Anchor IDL. Omitting to do so will result in a build verification failure. Use the IDL created by the verifiable build process.

 anchor idl init --provider.cluster devnet \
   --filepath ./target/idl/program.json \
   <PROGRAM_ID>

Once you have uploaded the IDL, you can update the IDL account with the upgrade subcommand using anchor idl upgrade …​. Note that the IDL authority defines who has got the permission to upgrade the IDL.

anchor idl authority --provider.cluster devnet <PROGRAM_ID>

# one can change the idl account authority
anchor idl set-authority --provider.cluster devnet \
  --program-id <PROGRAM_ID> \
  --new-authority <AUTHORITY_PUBKEY>

# when a new authority is set --provider.wallet is for define what authority is used on idl upgrade
anchor idl upgrade \
  --provider.cluster devnet \
  --provider.wallet <AUTHORITY_KEYPAIR_PATH> \
  --filepath ./target/idl/program.json \
  <PROGRAM_ID>
Note
command anchor idl upgrade consists of two instructions which are sent to the network and are defined within the anchor framework and are available as separate CLI commands as well. It’s write-buffer (idl data saved at blockchain) and set-buffer (the saved data loaded into program idl account). To combine write-buffer with set-buffer to manage IDL authority being multisig see https://gist.github.com/ochaloup/e013a7912858818ad2855e13754edf36

Verifying the build

To verify the build, run the anchor verify command. This command runs inside the docker image, builds the program, generates the IDL, and compares the result with the one deployed to the network.

To start the verification process, check out the source code of the program at the commit declared being used for the build, and then run the anchor verify command.

# git checkout
git clone <GIT_REPOSITORY>
git checkout <COMMIT_HASH>

# anchor verify
anchor --provider.cluster devnet verify \
  -p <PROGRAM_NAME> <PROGRAM_ID>
...
Copying out the build artifacts
Cleaning up the docker target directory
Removing the docker container
595f4e94d9028adff8573512672adfc31a7dcce324a8b8976334acad963f1e0a
Extracting the IDL
Writing the IDL file
Writing the .ts file
Build success
<PROGRAM_ID> is verified.

The <PROGRAM_NAME>` refers to the name of the library defined in the Cargo.toml file. The repository is usually in hyphenated form, while the library name is in underscore form. When the name of the directory structure is programs/marinade-finance, then the <PROGRAM_NAME> would most likely be marinade_finance.

`<PROGRAM_ID>` refers to the address of the program that has been deployed on the blockchain, in our case, the one deployed on Devnet.

Two Additional Points

It’s worth noting that verification can be performed not only against the deployed program but also against the buffer. When you write binary to the buffer, you can verify the buffer content.

# write the program to buffer (-ud is shortcut for devnet cluster)
solana -ud program write-buffer ./target/verifiable/program.so
# buffer authority can be changed in case (not needed for verification)
solana -ud program -um set-buffer-authority \
  --new-buffer-authority <AUTHORITY_PUBKEY> <BUFFER_ID>
# verify the buffer
anchor --provider.cluster devnet verify -p <PROGRAM_NAME> <BUFFER_ID>

Another point to note is that the verifiable build and verification process can also be performed with non-Anchor programs. We successfully used this with the SPL Governance and it worked well. However, since the IDL is not generated, there is no check for the IDL, and it works without it.

# get source code
git clone https://github.com/solana-labs/solana-program-library -b governance-v3.1.0
cd solana-program-library/governance/program
# do the build
anchor build --verifiable
# deploy the program (-k is keypair paying fee)
cd ../..
solana -um -k ~/.config/solana/mainnet.json program write-buffer \
  --buffer-authority <SOME_AUTORITY_KEYPAIR> \
  ./target/verifiable/spl_governance.so
# later the program can be upgraded from buffer to <PROGRAM_ID>
solana program -um -k ~/.config/solana/mainnet.json deploy \
  --program-id <PROGRAM_ID> \
  --upgrade-authority <SOME_AUTORITY_KEYPAIR> \
  --buffer <BUFFER_PUBKEY>

# verify the build
anchor --provider.cluster mainnet verify -p spl_governance <PROGRAM_ID>

Issues

A docker image build error

My Docker build was failing with the anchor build --verifiable command and returning the error message:

ERROR (5963): ENOENT: no such file or directory, open '/root/.config/solana/id.json'

To work around this issue, I used a different Docker image with a newer version of Anchor. The projectserum/build:v0.27.0 image worked for me (use -d switch or anchor_version attribute). Alternatively, you could use my own Docker image from https://github.com/ochaloup/projectserum-build-docker (build it first locally).

anchor build --verifiable -d 'projectserum/build:v0.27.0'
Warning
When using a different Docker image for verification, be sure to double-check the result. The later verification is done against the IDL generated by the Docker image, and the IDL can be generated differently in dependency on anchor version.

IDL upgrade error

As I built the program first with an old version of Anchor (such as 0.18.2) the older version ommitted some fields, such as comments. In comparison to the IDL built with a newer version of Anchor (such as 0.26.0).

The anchor idl init command creates the IDL account with a size that is double the size of the IDL data being uploaded. Unfortunately, when comments are included in the IDL, the data size exceeds the limit, causing the verification of the IDL to fail (because the IDL built by the old Anchor version does not match the content with comments), and the IDL cannot be upgraded, as the account size is too small.

I experienced the error

Idl buffer created: HhH987yt7K...
Error: Error processing Instruction 0: custom program error: 0xbbc

Caused by:
    Error processing Instruction 0: custom program error: 0xbbc

The error 0xbbc/3004 means Failed to serialize the account, indicating that there is not enough space.

The solution could be to initialize the IDL again, but initialization of an already-existing account is not possible and will result in an error message (Error processing Instruction 0: custom program error: 0x0).

What may help is Anchor version 0.27.0, which introduces the anchor idl close command. However, you have to build the verifiable binary compiled with Anchor 0.27.0. Be aware that default tag for anchor build --verifiable is 0.26.0.

A program that was build with older Anchor version does not implement the command idl close, instead error 0x66/102 The program could not deserialize the given instruction is emitted.

BONUS: solana-security-txt

It is good practice for a contract to provide metadata about the program, including a link to the source code, information about audits, and how to contact the author. This is not only useful for security researchers.

Neodyme Labs has created a Rust library that defines a macro, called solana-security-txt inspired by security.txt standard.

To use this library, the program creator should add the Rust dependency`solana-security-txt = "1.1.0"` to Cargo.toml file, and then add the metadata to the library source code using the security_txt! macro definition. A simple example can be seen below.

/// solana-security-txt for admin contract
use solana_security_txt::security_txt;
security_txt! {
    name: "Simple admin contract for testing purposes",
    project_url: "https://github.com/ochaloup/simple-admin",
    contacts: "twitter: @_chalda",
    policy: "",
    preferred_languages: "en, cz",
    auditors: "None"
}

The format, required fields, and other details are described in the library’s README on GitHub.

One of the benefits of this standard is that it is integrated within the Solana explorer, allowing easy access to the metadata by anyone who wishes to check it.

Conclusion

Verifiable builds allow for the verification of the program binary against the source code. This is the recommended way to publish a program to the Solana blockchain.

Published May 2, 2023

Developer notes.