Files
gh-tenequm-claude-plugins-s…/skills/solana-development/references/deployment.md
2025-11-30 09:01:25 +08:00

1829 lines
40 KiB
Markdown

# Solana Program Deployment Reference
This reference covers deployment workflows, best practices, and troubleshooting for both Anchor and native Rust Solana programs.
## Table of Contents
- [Deployment Overview](#deployment-overview)
- [Pre-Deployment Checklist](#pre-deployment-checklist)
- [Building Programs](#building-programs)
- [Deploying to Networks](#deploying-to-networks)
- [Program Upgrades](#program-upgrades)
- [Verified Builds](#verified-builds)
- [Program Authority Management](#program-authority-management)
- [Multisig Deployments](#multisig-deployments)
- [Network-Specific Considerations](#network-specific-considerations)
- [Post-Deployment](#post-deployment)
- [Common Issues and Troubleshooting](#common-issues-and-troubleshooting)
- [Best Practices](#best-practices)
---
## Deployment Overview
### Solana Networks
Solana has three primary networks:
**Localhost (127.0.0.1:8899)**
- Local test validator running on your machine
- Fastest iteration, no cost
- Full control over network state
- Use for rapid development and debugging
**Devnet**
- Public development network
- Free SOL via airdrops
- Resets periodically
- Use for integration testing
**Mainnet-beta**
- Production network with real economic value
- Requires real SOL for deployment and transactions
- Immutable deployed programs (unless upgradeable)
- Use for production deployments
### Network Configuration
**Anchor** - Edit `Anchor.toml`:
```toml
[toolchain]
[features]
seeds = false
skip-lint = false
[programs.localnet]
my_program = "11111111111111111111111111111111"
[programs.devnet]
my_program = "YourDevnetProgramID"
[programs.mainnet]
my_program = "YourMainnetProgramID"
[registry]
url = "https://api.apr.dev"
[provider]
cluster = "Localnet" # Change to "Devnet" or "Mainnet"
wallet = "~/.config/solana/id.json"
[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
```
**Native Rust** - Use Solana CLI:
```bash
# View current config
solana config get
# Set network
solana config set --url https://api.devnet.solana.com # Devnet
solana config set --url https://api.mainnet-beta.solana.com # Mainnet
solana config set --url http://localhost:8899 # Localnet
# Set wallet
solana config set --keypair ~/.config/solana/id.json
```
### Cost Considerations
Program deployment requires rent-exempt balance for:
1. **Program Account** - Stores program metadata (small cost)
2. **Program Data Account** - Stores the executable bytecode (major cost)
**Calculate deployment cost:**
```bash
# Get program size
ls -l target/deploy/my_program.so
# Example: 363960 bytes
# Check rent for program data account (1x program size in newer versions)
solana rent 363960
# Output:
# Rent-exempt minimum: ~2.5 SOL
# Add transaction fees (~0.002 SOL) for deployment transactions
```
**Cost breakdown:**
- **363KB program** ≈ 2.5 SOL rent + 0.002 SOL tx fees = **~2.502 SOL**
- **800KB program** ≈ 5.5 SOL rent + 0.002 SOL tx fees = **~5.502 SOL**
**Important:** Since Solana CLI v1.18+, program accounts are sized to 1x the .so file (previously 2x), reducing costs by approximately 50%.
---
## Pre-Deployment Checklist
### 1. Build Verification
**Anchor:**
```bash
# Clean build
anchor clean
anchor build
# Verify build succeeded
ls -la target/deploy/
# Should see: my_program.so and my_program-keypair.json
```
**Native Rust:**
```bash
# Clean build
cargo clean
cargo build-sbf
# Verify build
ls -la target/deploy/
# Should see: my_program.so
```
### 2. Testing Completeness
**Anchor:**
```bash
# Run all tests on local validator
anchor test
# Run tests without redeploying
anchor test --skip-deploy
# Run specific test file
anchor test tests/my-test.ts
```
**Native Rust:**
```bash
# Run Mollusk unit tests
cargo test
# Run integration tests
cargo test-sbf
```
### 3. Security Review
- [ ] All account validations implemented (owner checks, signer checks)
- [ ] No missing arithmetic overflow checks
- [ ] PDA seeds properly validated
- [ ] No uninitialized account usage
- [ ] Authority checks on privileged operations
- [ ] CPI security (check target program IDs)
- [ ] Consider professional audit for mainnet
### 4. Program Size Optimization
**Check current size:**
```bash
ls -lh target/deploy/my_program.so
```
**Optimization techniques:**
```toml
# Cargo.toml - Release profile optimization
[profile.release]
overflow-checks = true
lto = "fat" # Link-time optimization
codegen-units = 1 # Single codegen unit
opt-level = "z" # Optimize for size (use "3" for speed)
strip = true # Strip symbols
[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
```
**Remove unused dependencies:**
```bash
# Check dependency tree
cargo tree
# Remove unused features
# Instead of:
# solana-program = "2.1.0"
# Use:
solana-program = { version = "2.1.0", default-features = false }
```
**Current size limits:**
- Maximum program size: ~1 MB (actual limit varies by compute budget)
- Recommended: Keep under 500KB for reliable deployment
### 5. Rent Calculation
```bash
# Calculate exact rent needed
PROGRAM_SIZE=$(wc -c < target/deploy/my_program.so)
solana rent $PROGRAM_SIZE
# Fund deployment wallet
solana balance
# If insufficient, request airdrop (devnet) or transfer SOL
```
---
## Building Programs
### Anchor Programs
**Standard build:**
```bash
anchor build
```
**What it produces:**
- `target/deploy/my_program.so` - Executable binary
- `target/deploy/my_program-keypair.json` - Program ID keypair
- `target/idl/my_program.json` - Interface definition
- `target/types/my_program.ts` - TypeScript types
**Build specific program in workspace:**
```bash
anchor build --program-name my_program
```
**Verifiable build (Docker-based):**
```bash
# Install solana-verify CLI
cargo install solana-verify
# Build verifiably
solana-verify build
# Build specific program
solana-verify build --library-name my_program
```
**Sync program IDs:**
```bash
# After first build, sync declared IDs with keypair
anchor keys sync
```
### Native Rust Programs
**Standard build:**
```bash
cargo build-sbf
```
**What it produces:**
- `target/deploy/my_program.so` - Executable binary
- No automatic keypair generation (must provide or use deployed ID)
**Verifiable build:**
```bash
solana-verify build --library-name my_program
```
**Build with specific Solana version:**
```bash
# Set platform tools version
cargo build-sbf --sbf-sdk ~/.local/share/solana/install/releases/2.1.0/solana-release/bin/sdk/sbf
```
### Understanding Build Outputs
**.so file:**
- Compiled BPF bytecode
- This is what gets deployed on-chain
- Hash determines if program matches source
**Program ID keypair (Anchor):**
- Generated on first build
- Defines program's on-chain address
- **CRITICAL:** Back this up before deploying
**IDL (Anchor only):**
- JSON describing program interface
- Used by clients to interact with program
- Can be uploaded on-chain for discovery
---
## Deploying to Networks
### Anchor Deployment
**Deploy to configured network:**
```bash
# Deploy to network specified in Anchor.toml [provider] cluster
anchor deploy
# Specify network explicitly
anchor deploy --provider.cluster devnet
anchor deploy --provider.cluster mainnet
```
**Deploy with specific program ID:**
```bash
# First deployment - uses keypair from target/deploy/
anchor deploy
# Redeploy to same address (upgrade)
anchor deploy
```
**Deploy with priority fees (congested networks):**
```bash
# Set priority fee in micro-lamports per compute unit
anchor deploy --provider.cluster mainnet \
--program-name my_program \
-- --with-compute-unit-price 50000
```
**What `anchor deploy` does:**
1. Reads program from `target/deploy/my_program.so`
2. Creates or uses existing program account
3. Uploads program data via multiple write transactions
4. Sets executable flag on program account
5. Optionally uploads IDL to on-chain account
### Native Rust Deployment
**Deploy new program:**
```bash
# Deploy with auto-generated program ID
solana program deploy target/deploy/my_program.so
# Deploy to specific program ID (first time)
solana program deploy target/deploy/my_program.so \
--program-id my_program-keypair.json
```
**Deploy with priority fees:**
```bash
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--with-compute-unit-price 50000 \
--max-sign-attempts 100 \
--use-rpc
```
**Flags explained:**
- `--with-compute-unit-price` - Priority fee (micro-lamports per CU)
- `--max-sign-attempts` - Retries for recent blockhash expiration
- `--use-rpc` - Send transactions individually vs in batches
- `-u <URL>` - Specify RPC endpoint
**Check deployment cost before deploying:**
```bash
# Dry run to estimate cost
solana program deploy target/deploy/my_program.so --dry-run
```
### Deploying with Specific Program ID
**Generate deterministic program ID:**
```bash
# Create new keypair
solana-keygen new -o my-program-keypair.json
# View address
solana-keygen pubkey my-program-keypair.json
```
**For Anchor:**
```bash
# Update lib.rs with new program ID
declare_id!("YourNewProgramID");
# Update Anchor.toml
[programs.devnet]
my_program = "YourNewProgramID"
# Rebuild and deploy
anchor build
anchor keys sync # Verify IDs match
anchor deploy
```
**For Native Rust:**
```bash
# Deploy using keypair
solana program deploy target/deploy/my_program.so \
--program-id my-program-keypair.json
```
### Deployment Costs and Funding
**Check balance before deployment:**
```bash
solana balance
```
**Fund wallet for devnet:**
```bash
# Request airdrop (2 SOL max per request)
solana airdrop 2
# For larger programs, request multiple times
solana airdrop 2 && solana airdrop 2
```
**Fund wallet for mainnet:**
```bash
# Transfer SOL from exchange or another wallet
# No airdrops available on mainnet
```
**Cost estimation:**
```bash
# Program size
PROGRAM_SIZE=$(wc -c < target/deploy/my_program.so)
# Rent cost
solana rent $PROGRAM_SIZE
# Add ~0.002-0.01 SOL for transaction fees
# Add priority fees if network is congested
```
---
## Program Upgrades
### How Upgrades Work
Solana programs deployed via `solana program deploy` or `anchor deploy` are **upgradeable by default**.
**Upgrade mechanism:**
1. Program data lives in separate account from program account
2. Upgrade authority (wallet) can replace program data
3. Program address stays the same
4. All accounts/PDAs remain valid
**Check if program is upgradeable:**
```bash
solana program show <PROGRAM_ID>
# Output shows:
# Program Id: <PROGRAM_ID>
# Owner: BPFLoaderUpgradeable1111111111111111111111111
# ProgramData Address: <DATA_ACCOUNT>
# Authority: <UPGRADE_AUTHORITY> # If upgradeable
# Last Deployed In Slot: ...
# Data Length: ...
```
### Anchor Upgrades
**Upgrade deployed program:**
```bash
anchor upgrade target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--provider.cluster devnet
```
**Note:** In newer Anchor versions, `anchor deploy` automatically upgrades if program exists.
**Upgrade with priority fees:**
```bash
anchor upgrade target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--provider.cluster mainnet \
-- --with-compute-unit-price 50000
```
### Native Rust Upgrades
**Upgrade using same deploy command:**
```bash
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
--upgrade-authority ~/.config/solana/id.json
```
### Extending Program Accounts
**Problem:** If new program is larger than allocated space:
```
Error: account data too small for instruction
```
**Solution:** Extend program account before upgrading:
```bash
# Check current program size
solana program show <PROGRAM_ID>
# Shows: Data Length: 363960 bytes
# New build is larger
NEW_SIZE=$(wc -c < target/deploy/my_program.so)
echo $NEW_SIZE
# Shows: 380000 bytes
# Calculate additional bytes needed
ADDITIONAL_BYTES=$((NEW_SIZE - 363960))
echo $ADDITIONAL_BYTES
# Shows: 16040 bytes
# Extend program account
solana program extend <PROGRAM_ID> $ADDITIONAL_BYTES
# Check rent cost for extension
solana rent $ADDITIONAL_BYTES
# Example: 0.2 SOL
# Now upgrade works
solana program deploy target/deploy/my_program.so --program-id <PROGRAM_ID>
```
**Note:** Program extension support added in Solana CLI v1.18+
### Data Migration Strategies
**Account structure changes:**
When upgrading programs that change account layouts:
**Option 1: Version field**
```rust
#[account]
pub struct MyAccount {
pub version: u8, // Add version field
pub data: u64,
// New fields in v2
pub new_field: Option<String>,
}
// In instruction handler
if account.version == 1 {
// Migrate from v1 to v2
account.new_field = Some("default".to_string());
account.version = 2;
}
```
**Option 2: Separate migration instruction**
```rust
pub fn migrate_account_v1_to_v2(ctx: Context<MigrateAccount>) -> Result<()> {
let account = &mut ctx.accounts.account;
// Perform migration logic
account.new_field = compute_new_field(&account.data);
account.version = 2;
Ok(())
}
```
**Option 3: New program version with migration path**
- Deploy new program ID
- Create migration instructions that move data
- Deprecate old program gradually
---
## Verified Builds
Verified builds prove deployed bytecode matches public source code.
### Why Verify?
- **Transparency:** Users can audit your program's source
- **Trust:** Proves deployed program matches GitHub repository
- **Security:** Enables community security reviews
- **Ecosystem:** Explorers display verified status
- **Wallets:** May whitelist verified programs
### Tools for Verification
**Solana Verify CLI:**
```bash
cargo install solana-verify
```
**Docker (required for deterministic builds):**
- Install Docker: https://docs.docker.com/engine/install/
- Ensure Docker daemon is running
### Building Verifiable Programs
**Verifiable build process:**
```bash
# Navigate to project root (with Cargo.toml)
cd my-project
# Build in Docker container for deterministic output
solana-verify build
# For workspace with specific program
solana-verify build --library-name my_program
# Get hash of built executable
solana-verify get-executable-hash target/deploy/my_program.so
```
**What makes builds verifiable:**
1. **Docker environment:** Ensures consistent build environment
2. **Locked dependencies:** `Cargo.lock` pins exact versions
3. **Same toolchain:** Uses specific Rust/Solana version
4. **Deterministic compilation:** Same input → same output
**Project structure requirements:**
```
my-project/
├── Cargo.toml # Workspace manifest
├── Cargo.lock # Locked dependencies (required!)
├── programs/
│ └── my_program/
│ ├── Cargo.toml
│ └── src/
│ └── lib.rs
```
**Workspace Cargo.toml example:**
```toml
[workspace]
members = ["programs/*"]
resolver = "2"
[workspace.dependencies]
solana-program = "2.1.0"
[profile.release]
overflow-checks = true
lto = "fat"
codegen-units = 1
[profile.release.build-override]
opt-level = 3
incremental = false
codegen-units = 1
```
### Deploying Verifiable Programs
**Deploy verified build:**
```bash
# IMPORTANT: Use the binary from solana-verify build
# DO NOT run `anchor build` or `cargo build-sbf` after verification build
# Deploy with priority fees for reliability
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
-u https://api.mainnet-beta.solana.com \
--with-compute-unit-price 50000 \
--max-sign-attempts 100 \
--use-rpc
```
**Verify deployed program matches built executable:**
```bash
# Get on-chain program hash
solana-verify get-program-hash -u mainnet-beta <PROGRAM_ID>
# Get local executable hash
solana-verify get-executable-hash target/deploy/my_program.so
# Hashes must match!
```
### Verifying Against Repository
**Verify from GitHub repository:**
```bash
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 \
--mount-path programs/my_program
```
**Parameters explained:**
- `--program-id`: On-chain program address
- `--commit-hash`: Git commit to build from (optional, uses latest if omitted)
- `--library-name`: Crate name from Cargo.toml `[lib]` section
- `--mount-path`: Path to program directory in repo (for workspaces)
**Upload verification data on-chain:**
When prompted during verification:
```
Would you like to upload verification data on-chain? (y/n)
```
Select **yes** to write verification PDA. This enables:
- Solana Explorer verification badge
- OtterSec API verification
- SolanaFM verification display
### Remote Verification with OtterSec API
**Submit verification job:**
```bash
solana-verify verify-from-repo \
--remote \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/your-repo
```
**Manual job submission:**
```bash
solana-verify remote submit-job \
--program-id <PROGRAM_ID> \
--uploader <UPGRADE_AUTHORITY>
```
**Check verification status:**
```bash
solana-verify remote get-job-status --job-id <JOB_ID>
```
**Verification API endpoint:**
```
https://verify.osec.io/status/<PROGRAM_ID>
```
**Where verified status appears:**
- [Solana Explorer](https://explorer.solana.com)
- [SolanaFM](https://solana.fm)
- [SolScan](https://solscan.io)
- [SolanaVerify.org](https://solanaverify.org)
- [OtterSec API](https://verify.osec.io/verified-programs)
### security.txt Integration
**Add security contact info:**
```rust
#[cfg(not(feature = "no-entrypoint"))]
solana_security_txt::security_txt! {
name: "My Program",
project_url: "https://myproject.com",
contacts: "email:security@myproject.com,discord:myproject",
policy: "https://github.com/myproject/security/blob/main/SECURITY.md",
preferred_languages: "en",
source_code: "https://github.com/myproject/program",
source_release: "v1.0.0",
auditors: "Audit Firm Name"
}
```
**Benefits:**
- Security researchers know how to contact you
- Shows commitment to security
- Standard across Solana ecosystem
---
## Program Authority Management
### Viewing Program Information
**Check program authority:**
```bash
solana program show <PROGRAM_ID>
# Output:
# Program Id: YourProgramId
# Owner: BPFLoaderUpgradeable1111111111111111111111111
# ProgramData Address: <DATA_ACCOUNT_ADDRESS>
# Authority: <CURRENT_AUTHORITY> # Current upgrade authority
# Last Deployed In Slot: 123456789
# Data Length: 363960 bytes (0x58e38 bytes)
```
**View all your deployed programs:**
```bash
solana program show --programs
# Shows all programs where your wallet is authority
```
### Transferring Upgrade Authority
**Transfer to new authority:**
```bash
solana program set-upgrade-authority <PROGRAM_ID> \
--new-upgrade-authority <NEW_AUTHORITY_PUBKEY>
```
**Common use cases:**
- Transfer to multisig (Squads Protocol)
- Transfer to governance program
- Transfer to team member
- Transfer to DAO
**Transfer to multisig (Squads):**
```bash
# Get Squads vault address from https://v4.squads.so/
SQUADS_VAULT="YourSquadsVaultAddress"
solana program set-upgrade-authority <PROGRAM_ID> \
--new-upgrade-authority $SQUADS_VAULT
```
### Making Programs Immutable
**WARNING:** This is irreversible!
```bash
solana program set-upgrade-authority <PROGRAM_ID> --final
# Confirms immutability - program can NEVER be upgraded
```
**Use cases for immutability:**
- DeFi protocols requiring immutable guarantees
- After extensive auditing, lock the program
- Community trust through code permanence
**Considerations:**
- Cannot fix bugs after making immutable
- Cannot add features
- Ensure thorough testing and auditing first
- Consider governance/multisig instead
### Buffer Accounts for Deployment
**Understanding buffers:**
When deploying, the Solana CLI creates temporary buffer accounts:
1. Creates buffer account
2. Writes program data to buffer
3. Deploys buffer to program account
4. Closes buffer (if successful)
**View your buffer accounts:**
```bash
solana program show --buffers
# Output:
# Buffer Address | Authority | Balance
# Abc123... | YourWallet... | 2.5 SOL
```
**Close buffer manually (failed deployment):**
```bash
solana program close <BUFFER_ADDRESS>
# Recovers rent SOL back to wallet
```
**Common scenarios:**
- Deployment failed mid-process
- Want to cancel deployment
- Need to reclaim SOL from old buffers
---
## Multisig Deployments
Deploying with multisig (Squads Protocol) provides security for production programs.
### Why Use Multisig?
- **Security:** No single point of failure
- **Governance:** Team/DAO approval for upgrades
- **Transparency:** On-chain approval trail
- **Best practice:** Standard for serious projects
### Workflow Overview
1. Build verifiable program
2. Deploy with temporary authority
3. Verify against repository
4. Transfer authority to multisig
5. Export PDA transaction for verification upload
6. Submit through Squads UI
7. Remote verification
### Detailed Multisig Deployment
**1. Build verifiable program:**
```bash
solana-verify build --library-name my_program
```
**2. Deploy with your wallet as initial authority:**
```bash
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
-u mainnet-beta \
--with-compute-unit-price 50000
```
**3. Verify locally:**
```bash
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/repo \
--commit-hash <COMMIT>
```
**4. Transfer authority to Squads multisig:**
Get Squads vault address from https://v4.squads.so/
```bash
SQUADS_VAULT="YourSquadsVaultAddress"
solana program set-upgrade-authority <PROGRAM_ID> \
--new-upgrade-authority $SQUADS_VAULT
```
**5. Export verification PDA transaction:**
```bash
solana-verify verify-from-repo \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/repo \
--export-pda-tx verification_tx.json
```
**6. Submit transaction in Squads:**
- Go to https://v4.squads.so/
- Navigate to your multisig
- Create new transaction
- Import `verification_tx.json`
- Get approval from multisig members
- Execute transaction
**7. Submit remote verification:**
After Squads transaction executes:
```bash
solana-verify remote submit-job \
--program-id <PROGRAM_ID> \
--uploader <SQUADS_VAULT>
```
**8. Monitor verification:**
```bash
# Check job status
solana-verify remote get-job-status --job-id <JOB_ID>
# Or visit
https://verify.osec.io/status/<PROGRAM_ID>
```
### Upgrading via Multisig
**Create upgrade buffer:**
```bash
# Build new version
solana-verify build --library-name my_program
# Write to buffer (not direct upgrade)
solana program write-buffer target/deploy/my_program.so
# Output: Buffer address: <BUFFER_ADDRESS>
```
**Transfer buffer authority to multisig:**
```bash
solana program set-buffer-authority <BUFFER_ADDRESS> \
--new-buffer-authority <SQUADS_VAULT>
```
**Create Squads transaction for upgrade:**
Use Squads CLI or UI to propose:
```bash
# Using Squads SDK/CLI
npx ts-node scripts/program-upgrade.ts \
--rpc "https://api.mainnet-beta.solana.com" \
--program "<PROGRAM_ID>" \
--buffer "<BUFFER_ADDRESS>" \
--multisig "<MULTISIG_ADDRESS>" \
--member "<YOUR_PUBKEY>" \
--name "Upgrade my_program v2"
```
**Close buffer via Squads (if needed):**
```bash
npx ts-node scripts/squad-closebuffer.ts \
--rpc "https://api.mainnet-beta.solana.com" \
--multisig "<MULTISIG_ADDRESS>" \
--buffer "<BUFFER_ADDRESS>" \
--program "<PROGRAM_ID>"
```
---
## Network-Specific Considerations
### Localhost Development
**Start test validator:**
```bash
# Basic
solana-test-validator
# With program pre-deployed
solana-test-validator --bpf-program <PROGRAM_ID> target/deploy/my_program.so
# With cloned mainnet accounts
solana-test-validator \
--clone <ACCOUNT_ADDRESS> \
--url mainnet-beta
# Reset ledger on restart
solana-test-validator --reset
```
**Deploy to local validator:**
```bash
# Anchor
anchor localnet # Starts validator and deploys
# Or
anchor deploy --provider.cluster localnet
# Native Rust
solana program deploy target/deploy/my_program.so -ul
```
**Benefits:**
- Instant transaction confirmation
- Unlimited free SOL
- Full control over clock and state
- Fast iteration
**Limitations:**
- No network effects
- Single validator (no consensus)
- State doesn't persist (unless configured)
### Devnet Deployment
**Configure network:**
```bash
solana config set --url devnet
```
**Fund wallet:**
```bash
solana airdrop 2
# Repeat as needed, max 2 SOL per request
```
**Deploy:**
```bash
# Anchor
anchor deploy --provider.cluster devnet
# Native Rust
solana program deploy target/deploy/my_program.so \
-u devnet \
--with-compute-unit-price 1000
```
**Benefits:**
- Real network conditions
- Free SOL via airdrops
- Test integrations with other programs
- Longer-lived state than localnet
**Limitations:**
- Network resets occasionally
- Potential rate limiting
- Slower than localnet
- Public network (anyone can interact)
**Best practices:**
- Test all upgrade paths on devnet first
- Monitor transaction success rates
- Test with realistic compute budgets
- Validate against cloned mainnet accounts
### Testnet Deployment
Testnet is less commonly used but available for staging:
```bash
solana config set --url testnet
solana airdrop 2 # If available
```
**Use cases:**
- Staging environment before mainnet
- Testing between devnet and mainnet
- Longer-term testing without mainnet costs
### Mainnet Deployment
**Pre-deployment checklist:**
- [ ] Thoroughly tested on devnet
- [ ] Security audit completed (for DeFi/high-value programs)
- [ ] Verified build prepared
- [ ] Upgrade authority configured (multisig recommended)
- [ ] Sufficient SOL for deployment (check `solana rent`)
- [ ] Monitoring/alerting setup
- [ ] Rollback plan documented
- [ ] Team coordination for deployment time
**Configure mainnet:**
```bash
solana config set --url mainnet-beta
# Use paid RPC for reliability (recommended)
solana config set --url https://your-rpc-provider.com
```
**Fund wallet:**
```bash
# Transfer from exchange or another wallet
# Calculate needed SOL:
PROGRAM_SIZE=$(wc -c < target/deploy/my_program.so)
solana rent $PROGRAM_SIZE
# Add ~0.5 SOL buffer for transaction fees and priority fees
```
**Deploy with appropriate priority fees:**
Check current priority fee recommendations:
- https://www.quicknode.com/gas-tracker/solana
- https://solanacompass.com/gas-fees
```bash
# Typical priority fee: 50,000-300,000 micro-lamports per CU
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
-u mainnet-beta \
--with-compute-unit-price 100000 \
--max-sign-attempts 100 \
--use-rpc
```
**Post-deployment verification:**
```bash
# Verify deployment
solana program show <PROGRAM_ID> -u mainnet-beta
# Verify hash matches
solana-verify get-program-hash -u mainnet-beta <PROGRAM_ID>
# Submit verification job
solana-verify verify-from-repo \
--remote \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/repo
```
**Cost considerations:**
- 200KB program: ~1.5 SOL
- 500KB program: ~3.5 SOL
- 800KB program: ~5.5 SOL
- Plus transaction fees: ~0.01-0.05 SOL
- Priority fees during congestion: +0.1-1 SOL
---
## Post-Deployment
### Verifying Deployment Success
**Check program was deployed:**
```bash
solana program show <PROGRAM_ID>
# Verify output shows:
# - Correct ProgramData address
# - Your authority
# - Expected data length
# - Recent slot number
```
**Compare program hash:**
```bash
# On-chain hash
solana-verify get-program-hash -u <NETWORK> <PROGRAM_ID>
# Local build hash
solana-verify get-executable-hash target/deploy/my_program.so
# Must match exactly
```
### Testing On-Chain
**Anchor:**
```bash
# Run tests against deployed program
anchor test --skip-deploy --provider.cluster devnet
# Or run specific test
anchor run test-on-devnet
```
**Native Rust / TypeScript client:**
```typescript
import { Connection, PublicKey } from '@solana/web3.js';
const connection = new Connection('https://api.devnet.solana.com');
const programId = new PublicKey('YourProgramId');
// Send test transaction
const tx = await program.methods
.yourInstruction()
.accounts({ /* ... */ })
.rpc();
console.log('Transaction:', tx);
```
**Smoke tests:**
- Call each instruction with valid inputs
- Verify account state changes
- Check events are emitted correctly
- Test error cases return expected errors
### Monitoring Program Usage
**View recent transactions:**
```bash
# Get recent transactions for program
solana transaction-history <PROGRAM_ID> --limit 10
# Or use explorers:
# https://explorer.solana.com/address/<PROGRAM_ID>
# https://solscan.io/account/<PROGRAM_ID>
```
**Set up monitoring:**
Use services like:
- [Helius webhooks](https://www.helius.dev/)
- [QuickNode functions](https://www.quicknode.com/)
- [SolanaFM API](https://solana.fm/)
**Monitor for:**
- Transaction success rate
- Compute unit usage
- Error frequency
- Unusual activity patterns
### Publishing IDL (Anchor)
**Upload IDL to on-chain account:**
```bash
anchor idl init <PROGRAM_ID> \
--filepath target/idl/my_program.json \
--provider.cluster devnet
```
**Upgrade IDL after program upgrade:**
```bash
anchor idl upgrade <PROGRAM_ID> \
--filepath target/idl/my_program.json \
--provider.cluster devnet
```
**Fetch published IDL:**
```bash
anchor idl fetch <PROGRAM_ID> \
--provider.cluster devnet \
--out fetched_idl.json
```
**Benefits of publishing IDL:**
- Clients can auto-discover your interface
- Explorers can decode instructions
- Reduces integration friction
- Standard for Anchor programs
### Closing Programs and Reclaiming SOL
**Close buffer accounts:**
```bash
# View all buffers
solana program show --buffers
# Close specific buffer
solana program close <BUFFER_ADDRESS>
# Reclaims rent SOL to wallet
```
**Close entire program (irreversible!):**
```bash
solana program close <PROGRAM_ID>
# WARNING: This deletes the program permanently
# Cannot be undone
# Only do this for test programs
```
**When to close:**
- Failed test deployments on devnet
- Obsolete test programs
- Reclaim SOL from old projects
**When NOT to close:**
- Any program with active users
- Programs other contracts depend on
- Mainnet programs (almost never)
---
## Common Issues and Troubleshooting
### Insufficient Balance
**Error:**
```
Error: Account <WALLET> has insufficient funds for spend (1.5 SOL) + fee (0.002 SOL)
```
**Solution:**
```bash
# Check current balance
solana balance
# Devnet - request airdrop
solana airdrop 2
# Mainnet - transfer SOL
# Calculate needed amount:
PROGRAM_SIZE=$(wc -c < target/deploy/my_program.so)
solana rent $PROGRAM_SIZE
# Add 0.5 SOL buffer
```
### Program Too Large
**Error:**
```
Error: Program too large. Maximum size: 1048576 bytes
```
**Solutions:**
**1. Optimize build:**
```toml
[profile.release]
lto = "fat"
codegen-units = 1
opt-level = "z" # Optimize for size
strip = true
```
**2. Remove unused dependencies:**
```bash
cargo tree # Identify large dependencies
```
**3. Use feature flags to exclude optional code:**
```toml
[dependencies]
solana-program = { version = "2.1.0", default-features = false }
```
**4. Split program into multiple programs:**
- Separate complex logic into multiple programs
- Use CPI to communicate between them
### Account Data Too Small for Instruction
**Error:**
```
Error: account data too small for instruction
```
**Cause:** Upgrade would exceed allocated program size.
**Solution:**
```bash
# Check current size
solana program show <PROGRAM_ID>
# Data Length: 363960 bytes
# Check new size
NEW_SIZE=$(wc -c < target/deploy/my_program.so)
echo $NEW_SIZE
# 380000 bytes
# Calculate difference
DIFF=$((NEW_SIZE - 363960))
# Extend program
solana program extend <PROGRAM_ID> $DIFF
# Check rent for extension
solana rent $DIFF
# Now deploy upgrade
solana program deploy target/deploy/my_program.so --program-id <PROGRAM_ID>
```
### Network Congestion / Blockhash Expiration
**Error:**
```
Error: Transaction simulation failed: Blockhash not found
```
**Cause:** High network congestion or large program deployment.
**Solutions:**
**1. Increase priority fees:**
```bash
solana program deploy target/deploy/my_program.so \
--with-compute-unit-price 300000 \ # Higher priority
--max-sign-attempts 100 \
--use-rpc
```
**2. Use paid RPC endpoint:**
```bash
solana config set --url https://your-premium-rpc.com
# Paid RPCs often have:
# - Higher rate limits
# - Better transaction success rates
# - Priority queue access
```
**3. Deploy during low traffic:**
- Avoid peak hours (US/Europe daytime)
- Early morning UTC often less congested
**4. Break into smaller chunks:**
For very large programs, manually create buffer and write in batches.
### Keypair Issues
**Error:**
```
Error: Dynamic program error: Invalid keypair file
```
**Solutions:**
**1. Verify keypair format:**
```bash
# Should be JSON array of numbers
cat program-keypair.json
# [123, 45, 67, ...]
# Or base58 string
```
**2. Regenerate if corrupted:**
```bash
solana-keygen new -o program-keypair.json --force
```
**3. Check file permissions:**
```bash
chmod 600 program-keypair.json
```
### Anchor Build vs Deploy Mismatch
**Error:**
```
Error: Program <ID> does not match declared program id in lib.rs
```
**Solution:**
```bash
# Sync program IDs
anchor keys sync
# Rebuilds and updates declare_id! to match keypair
```
### Native Rust: Missing Program ID
**Error:**
```
Error: No program keypair found
```
**Solution:**
Native Rust doesn't auto-generate keypairs. Either:
**Option 1: Create keypair:**
```bash
solana-keygen new -o target/deploy/my_program-keypair.json
solana program deploy target/deploy/my_program.so \
--program-id target/deploy/my_program-keypair.json
```
**Option 2: Use existing program ID:**
```bash
solana program deploy target/deploy/my_program.so \
--program-id <EXISTING_PROGRAM_ID>
```
### Verification Failures
**Error:**
```
Verification failed: Hash mismatch
On-chain: abc123...
Local: def456...
```
**Causes and solutions:**
**1. Built outside Docker:**
```bash
# Must use solana-verify build for deterministic build
solana-verify build
```
**2. Cargo.lock mismatch:**
```bash
# Ensure Cargo.lock committed to git
git add Cargo.lock
git commit -m "Add Cargo.lock for verifiable builds"
```
**3. Rebuild after verification:**
```bash
# Don't run `anchor build` or `cargo build-sbf` after solana-verify build
# This regenerates binary with different hash
# If you did, rebuild verifiably:
solana-verify build
solana program deploy target/deploy/my_program.so --program-id <PROGRAM_ID>
```
**4. Wrong commit hash:**
```bash
# Ensure you're verifying against correct commit
git log # Find exact commit used for deployment
solana-verify verify-from-repo \
--commit-hash <EXACT_COMMIT> \
...
```
---
## Best Practices
### Deployment Workflow
**Recommended deployment process:**
1. **Local development**
- Develop on localnet
- Unit test with Mollusk (native) or Bankrun/Anchor tests
- Iterate quickly
2. **Devnet testing**
- Deploy to devnet
- Integration testing
- Test upgrade paths
- Load testing if applicable
3. **Devnet verification**
- Build verifiable
- Deploy and verify on devnet
- Ensure verification succeeds
4. **Security review**
- Internal code review
- Automated analysis (Soteria, Sec3, etc.)
- Professional audit (for mainnet)
5. **Mainnet staging**
- Build final verifiable version
- Generate program ID
- Set up multisig/governance
6. **Mainnet deployment**
- Deploy during low-traffic period
- Use paid RPC
- Set appropriate priority fees
- Monitor closely
7. **Post-deployment**
- Submit verification
- Smoke test critical functions
- Set up monitoring
- Transfer authority to multisig
### Version Control
**Always commit:**
- `Cargo.lock` (required for verified builds)
- Program keypairs (for test programs only)
- IDL files
- Migration scripts
**Never commit:**
- Mainnet keypairs (use environment variables)
- Wallet private keys
- RPC API keys
**Tag deployments:**
```bash
git tag -a v1.0.0-mainnet -m "Mainnet deployment v1.0.0"
git push origin v1.0.0-mainnet
```
**Link verification to tags:**
```bash
solana-verify verify-from-repo \
--commit-hash v1.0.0-mainnet \
...
```
### Backup Strategies
**Critical to back up:**
1. **Program keypairs**
```bash
# Mainnet program keypairs
cp target/deploy/my_program-keypair.json ~/secure-backup/
# Encrypted backup
gpg -c target/deploy/my_program-keypair.json
```
2. **Upgrade authority keypairs**
```bash
# If not using multisig
cp ~/.config/solana/id.json ~/secure-backup/upgrade-authority.json
```
3. **Buffer accounts during deployment**
```bash
# Save buffer address immediately after creating
echo "Buffer: <ADDRESS>" >> deployment-log.txt
```
4. **Deployment artifacts**
- Built .so files
- IDL files
- Verification data
- Transaction signatures
**Backup locations:**
- Encrypted cloud storage (Google Drive, Dropbox)
- Hardware wallet (for keypairs)
- Offline USB drives (encrypted)
- Team password manager (1Password, Bitwarden)
**Test backup restoration:**
```bash
# Periodically verify backups work
cp ~/secure-backup/my_program-keypair.json /tmp/test-restore.json
solana-keygen pubkey /tmp/test-restore.json
# Should output expected program ID
```
### Framework-Specific Best Practices
**Anchor:**
- Always run `anchor keys sync` after first build
- Keep `Anchor.toml` in source control
- Use workspace for multi-program projects
- Upload IDL on-chain for discoverability
- Version your IDL files alongside code
**Native Rust:**
- Use `no-entrypoint` feature for testing
- Implement security.txt for contact info
- Document your instruction format
- Provide client SDK (TypeScript/Rust) for integrations
- Include example transaction builders
### Testing Before Deployment
**Progressive testing strategy:**
```bash
# 1. Unit tests (Mollusk for native, Anchor tests)
cargo test
# 2. Integration tests on localnet
anchor test # or cargo test-sbf
# 3. Devnet deployment test
anchor deploy --provider.cluster devnet
# Test all functions on devnet
# 4. Upgrade test on devnet
# Make small change, rebuild, upgrade
anchor build
anchor upgrade <PROGRAM_ID> target/deploy/program.so --provider.cluster devnet
# Verify upgrade worked
# 5. Verified build test
solana-verify build
solana-verify verify-from-repo --program-id <DEVNET_ID> https://github.com/...
# 6. Final smoke tests on devnet
# Run critical user flows
# 7. Mainnet deployment
# Only after all above pass
```
### Documentation
**Document your deployment:**
Create `DEPLOYMENT.md` in your repo:
```markdown
# Deployment Guide
## Program IDs
- Devnet: ABC123...
- Mainnet: DEF456...
## Build
```bash
solana-verify build --library-name my_program
```
## Deploy
### Devnet
```bash
anchor deploy --provider.cluster devnet
```
### Mainnet
```bash
solana program deploy target/deploy/my_program.so \
--program-id <PROGRAM_ID> \
-u mainnet-beta \
--with-compute-unit-price 100000
```
## Verify
```bash
solana-verify verify-from-repo \
--remote \
-u mainnet-beta \
--program-id <PROGRAM_ID> \
https://github.com/your-org/repo \
--commit-hash v1.0.0
```
## Upgrade Authority
Mainnet: Squads Multisig `GHI789...`
## Last Deployment
- Date: 2025-01-15
- Version: v1.0.0
- Commit: abc123def456
- Deployed by: @deployer
- Verification: https://verify.osec.io/status/<PROGRAM_ID>
```
---
## Summary
**Key takeaways:**
1. **Always test on devnet first** - Never deploy untested code to mainnet
2. **Use verified builds for mainnet** - Transparency builds trust
3. **Calculate costs before deploying** - Use `solana rent` to estimate
4. **Set up multisig for mainnet** - Prevents single points of failure
5. **Monitor after deployment** - Watch for errors and unusual activity
6. **Back up keypairs** - Lose keypair = lose upgrade authority
7. **Document your deployments** - Future you will thank you
8. **Use priority fees on mainnet** - Ensures reliable deployment
9. **Test upgrade paths** - Practice on devnet first
10. **Never make programs immutable hastily** - Irreversible decision
**Resources:**
- Solana CLI docs: https://docs.solana.com/cli
- Anchor docs: https://www.anchor-lang.com/
- Solana Verify: https://github.com/Ellipsis-Labs/solana-verifiable-build
- OtterSec Verify API: https://verify.osec.io/
- Squads Protocol: https://squads.so/
- Security.txt: https://github.com/neodyme-labs/solana-security-txt
Deploy with confidence!