13 KiB
Production Deployment Guide for Solana Programs
Best practices for deploying verified, production-ready Solana programs to mainnet and serious devnet environments.
Overview
Production deployments require verified builds that prove deployed bytecode matches public source code. This guide covers the proper workflow for production deployments, particularly with Anchor framework.
Key principle: Transparency and verifiability build trust. Always use deterministic builds for production.
Why Verified Builds Matter
Without verified builds:
- Users cannot verify deployed code matches GitHub source
- Audits cannot confirm they reviewed the exact deployed binary
- No transparency into what code actually runs on-chain
- Security researchers cannot validate the program
With verified builds:
- ✅ Provably deterministic builds (Docker-based)
- ✅ Anyone can verify deployed bytecode matches source
- ✅ Explorer verification badges (Solana Explorer, SolanaFM)
- ✅ Audit reports apply to exact deployed binary
- ✅ Standard for all serious Solana projects
All major Solana protocols use verified builds: Jupiter, Marinade, Orca, Metaplex, etc.
The Problem with anchor deploy
Anchor 0.32.1 and Earlier
⚠️ CRITICAL: Do NOT use anchor deploy for production deployments
Why anchor deploy is unsuitable for production:
-
Non-deterministic builds
- Build output varies by local Rust version
- Different on macOS vs Linux
- Depends on installed toolchain
- Same source → different binaries on different machines
-
Cannot be verified
- No way to prove deployed code matches GitHub
- Verification tools cannot reproduce the build
- Breaks audit trail
-
Lacks transparency
- Users must trust deployer
- No verification badges on explorers
- Goes against Solana ecosystem standards
When Anchor v1 may improve this:
- Anchor v1 is expected to have better support for verified builds
- May integrate
solana-verifydirectly - Check Anchor docs for updates when v1 releases
For now (Anchor 0.32.1): Use the verified deployment workflow below.
Production Deployment Workflow
Step 1: Build Verifiably
Use solana-verify build instead of anchor build for the final production build:
# Install solana-verify if not already installed
cargo install solana-verify
# Navigate to project root (where Cargo.toml with workspace is)
cd my-project
# Build verifiably in Docker (deterministic)
solana-verify build --library-name my_program
# Verify the build succeeded
ls -la target/deploy/my_program.so
What this does:
- Builds in Docker container (consistent environment)
- Uses exact dependencies from
Cargo.lock - Same input → same output (deterministic)
- Anyone can reproduce this exact binary
Important: Do NOT run anchor build after solana-verify build - it will regenerate a different binary!
Step 2: Deploy the Verified Binary
Use solana program deploy directly (NOT anchor deploy):
For devnet:
solana program deploy target/deploy/my_program.so \
--program-id target/deploy/my_program-keypair.json \
-u devnet \
--with-compute-unit-price 1000
For mainnet:
# Use your deployer keypair and appropriate priority fees
solana program deploy target/deploy/my_program.so \
--program-id target/deploy/my_program-keypair.json \
--keypair ~/.config/solana/deployer.json \
-u mainnet-beta \
--with-compute-unit-price 100000 \
--max-sign-attempts 100 \
--use-rpc
Why use solana program deploy directly:
- Works with verified builds
- More control over deployment parameters
- Standard across all Solana programs
- Same tool for Anchor and native Rust
Step 3: Verify Against Repository
After deployment, verify the on-chain program matches your source:
solana-verify verify-from-repo \
-u devnet \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo \
--library-name my_program
# Or specify exact commit
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo \
--commit-hash <COMMIT_HASH> \
--library-name my_program
When prompted, upload verification data on-chain:
Would you like to upload verification data on-chain? (y/n)
Select yes to enable:
- Verification badge on Solana Explorer
- OtterSec verification API listing
- SolanaFM verification display
Step 4: Verify Hash Match (Sanity Check)
Before step 3, you can manually verify hashes match:
# Get on-chain program hash
solana-verify get-program-hash -u devnet <PROGRAM_ID>
# Get local executable hash
solana-verify get-executable-hash target/deploy/my_program.so
# These MUST match exactly
Complete Production Deployment Checklist
Pre-Deployment
- All tests pass (
cargo test,anchor test) - Security audit completed (for mainnet)
Cargo.lockcommitted to git- Git tag created for release (e.g.,
v1.0.0) - Sufficient SOL in deployer wallet
- Multisig or governance ready (mainnet)
Build
- Run
solana-verify build --library-name my_program - Verify
.sofile exists intarget/deploy/ - Do NOT run
anchor buildafter this - Get hash:
solana-verify get-executable-hash target/deploy/my_program.so
Deploy
- Use
solana program deploy(NOTanchor deploy) - Specify correct program ID keypair
- Use appropriate priority fees
- Verify deployment:
solana program show <PROGRAM_ID>
Verify
- Run
solana-verify verify-from-repowith your GitHub URL - Upload verification data on-chain when prompted
- Check verification appears on explorer
- Optional: Submit remote verification job
Post-Deployment
- Transfer upgrade authority to multisig (mainnet)
- Smoke test critical instructions on-chain
- Set up monitoring
- Announce deployment with verification link
Example: Complete Mainnet Deployment
# 1. Prepare
git tag v1.0.0
git push origin v1.0.0
# 2. Build verifiably
solana-verify build --library-name cascade_splits
# 3. Check hash
solana-verify get-executable-hash target/deploy/cascade_splits.so
# Output: abc123def456...
# 4. Deploy to mainnet
solana program deploy target/deploy/cascade_splits.so \
--program-id target/deploy/cascade_splits-keypair.json \
--keypair ~/.config/solana/mainnet-deployer.json \
-u mainnet-beta \
--with-compute-unit-price 100000 \
--max-sign-attempts 100 \
--use-rpc
# Output: Program Id: SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB
# 5. Verify on-chain hash matches
solana-verify get-program-hash -u mainnet-beta SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB
# Output: abc123def456... (must match step 3!)
# 6. Verify against repository
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB \
https://github.com/cascade-protocol/splits \
--commit-hash v1.0.0 \
--library-name cascade_splits
# When prompted: Upload verification data on-chain? → YES
# 7. Transfer authority to multisig
SQUADS_VAULT="YourSquadsVaultAddress"
solana program set-upgrade-authority SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB \
--new-upgrade-authority $SQUADS_VAULT
# 8. Verify on explorer
# Visit: https://explorer.solana.com/address/SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB
# Should show verification badge
# 9. Check OtterSec verification
# Visit: https://verify.osec.io/status/SPL1T3rERcu6P6dyBiG7K8LUr21CssZqDAszwANzNMB
Program Upgrades with Verified Builds
Upgrade Workflow
# 1. Make changes, test, commit
git add .
git commit -m "feat: add new feature"
git tag v1.1.0
git push origin main v1.1.0
# 2. Build verifiably
solana-verify build --library-name my_program
# 3. Check if program size increased
OLD_SIZE=$(solana program show <PROGRAM_ID> | grep "Data Length" | awk '{print $3}')
NEW_SIZE=$(wc -c < target/deploy/my_program.so)
# 4. Extend if needed
if [ $NEW_SIZE -gt $OLD_SIZE ]; then
DIFF=$((NEW_SIZE - OLD_SIZE))
solana program extend <PROGRAM_ID> $DIFF
fi
# 5. Deploy upgrade
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--upgrade-authority ~/.config/solana/deployer.json \
-u mainnet-beta \
--with-compute-unit-price 100000
# 6. Verify new version
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo \
--commit-hash v1.1.0 \
--library-name my_program
Upgrades via Multisig
If upgrade authority is a Squads multisig:
# 1. Build verifiably
solana-verify build --library-name my_program
# 2. Create buffer (not direct upgrade)
solana program write-buffer target/deploy/my_program.so
# Output: Buffer: <BUFFER_ADDRESS>
# 3. Transfer buffer to multisig
solana program set-buffer-authority <BUFFER_ADDRESS> \
--new-buffer-authority <SQUADS_VAULT>
# 4. Create upgrade proposal in Squads UI
# - Navigate to https://v4.squads.so/
# - Create transaction for BPF Upgradeable Loader upgrade
# - Reference buffer address
# - Get approval from multisig members
# - Execute
# 5. After execution, verify
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo \
--commit-hash v1.1.0 \
--library-name my_program
Troubleshooting
Hash Mismatch After Deployment
Problem: On-chain hash doesn't match local hash
Causes:
- Ran
anchor buildorcargo build-sbfaftersolana-verify build - Deployed wrong file
Cargo.locknot committed or out of sync
Solution:
# 1. Clean everything
cargo clean
# 2. Ensure Cargo.lock is committed
git add Cargo.lock
git commit -m "Add Cargo.lock"
# 3. Rebuild verifiably
solana-verify build --library-name my_program
# 4. Redeploy
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID>
# 5. Verify again
solana-verify verify-from-repo ...
Verification Fails: "Could not build from repository"
Problem: solana-verify verify-from-repo cannot build
Causes:
- Missing
Cargo.lockin repository - Wrong commit hash
- Workspace configuration issue
- Missing dependencies in Docker build
Solution:
# 1. Verify Cargo.lock exists in git
git ls-files | grep Cargo.lock
# 2. Check commit hash is correct
git log --oneline
# 3. Ensure workspace Cargo.toml exists at root
cat Cargo.toml # Should have [workspace]
# 4. Try local verification first
solana-verify verify-from-repo \
--program-id <PROGRAM_ID> \
file://$(pwd) \
--library-name my_program
"anchor deploy" Used by Accident
Problem: Deployed with anchor deploy instead of verified build
Solution: Redeploy properly:
# 1. Build verifiably
solana-verify build --library-name my_program
# 2. Redeploy (upgrade) with verified binary
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID>
# 3. Verify
solana-verify verify-from-repo \
-u <NETWORK> \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo
Version-Specific Notes
Anchor 0.32.1
- Status: Current stable version as of November 2024
- Issue:
anchor deploydoes not produce verifiable builds - Workaround: Use workflow in this guide (solana-verify + solana program deploy)
- Uses: Solana SDK 2.2.x
Anchor 0.30.x
- Status: Older stable version
- Issue: Same as 0.32.1
- Workaround: Same workflow applies
- Uses: Solana SDK 2.1.x
Future: Anchor 1.0.0
- Expected: Better integration with verified builds
- Possible:
anchor deploy --verifiableflag - Check: Official Anchor docs when v1 releases
- Until then: Use this guide
Best Practices Summary
Always ✅
- Use
solana-verify buildfor production builds - Commit
Cargo.lockto git - Tag releases with git tags
- Deploy with
solana program deploydirectly - Verify against repository after deployment
- Upload verification data on-chain
- Transfer mainnet authority to multisig
- Test entire flow on devnet first
Never ❌
- Use
anchor deployfor production/mainnet - Run
anchor buildorcargo build-sbfaftersolana-verify build - Deploy without verifying
- Deploy mainnet without devnet testing first
- Deploy mainnet without security audit
- Keep upgrade authority as individual wallet (mainnet)
- Skip uploading verification data
Development Only
anchor deploy is fine for:
- Local validator testing
- Rapid iteration during development
- Devnet experiments
- Non-production testing
Additional Resources
- Solana Verify CLI: https://github.com/Ellipsis-Labs/solana-verifiable-build
- Verified Programs List: https://verify.osec.io/verified-programs
- Solana Explorer: https://explorer.solana.com
- Squads Protocol: https://squads.so
- Anchor Documentation: https://www.anchor-lang.com/docs
Summary
For production Solana program deployments:
- Use
solana-verify build(NOTanchor deploy) - Deploy with
solana program deploydirectly - Verify with
solana-verify verify-from-repo - Upload verification data on-chain
This ensures transparency, verifiability, and trust in your deployed programs.