# 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 \ --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 ` - 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 # Output shows: # Program Id: # Owner: BPFLoaderUpgradeable1111111111111111111111111 # ProgramData Address: # Authority: # If upgradeable # Last Deployed In Slot: ... # Data Length: ... ``` ### Anchor Upgrades **Upgrade deployed program:** ```bash anchor upgrade target/deploy/my_program.so \ --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 \ --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 \ --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 # 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 $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 ``` **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, } // 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) -> 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 \ -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 # 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 \ https://github.com/your-org/your-repo \ --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 \ https://github.com/your-org/your-repo ``` **Manual job submission:** ```bash solana-verify remote submit-job \ --program-id \ --uploader ``` **Check verification status:** ```bash solana-verify remote get-job-status --job-id ``` **Verification API endpoint:** ``` https://verify.osec.io/status/ ``` **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 # Output: # Program Id: YourProgramId # Owner: BPFLoaderUpgradeable1111111111111111111111111 # ProgramData Address: # 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 \ --new-upgrade-authority ``` **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 \ --new-upgrade-authority $SQUADS_VAULT ``` ### Making Programs Immutable **WARNING:** This is irreversible! ```bash solana program set-upgrade-authority --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 # 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 \ -u mainnet-beta \ --with-compute-unit-price 50000 ``` **3. Verify locally:** ```bash solana-verify verify-from-repo \ -u mainnet-beta \ --program-id \ https://github.com/your-org/repo \ --commit-hash ``` **4. Transfer authority to Squads multisig:** Get Squads vault address from https://v4.squads.so/ ```bash SQUADS_VAULT="YourSquadsVaultAddress" solana program set-upgrade-authority \ --new-upgrade-authority $SQUADS_VAULT ``` **5. Export verification PDA transaction:** ```bash solana-verify verify-from-repo \ -u mainnet-beta \ --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 \ --uploader ``` **8. Monitor verification:** ```bash # Check job status solana-verify remote get-job-status --job-id # Or visit https://verify.osec.io/status/ ``` ### 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: ``` **Transfer buffer authority to multisig:** ```bash solana program set-buffer-authority \ --new-buffer-authority ``` **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 "" \ --buffer "" \ --multisig "" \ --member "" \ --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 "" \ --buffer "" \ --program "" ``` --- ## Network-Specific Considerations ### Localhost Development **Start test validator:** ```bash # Basic solana-test-validator # With program pre-deployed solana-test-validator --bpf-program target/deploy/my_program.so # With cloned mainnet accounts solana-test-validator \ --clone \ --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 \ -u mainnet-beta \ --with-compute-unit-price 100000 \ --max-sign-attempts 100 \ --use-rpc ``` **Post-deployment verification:** ```bash # Verify deployment solana program show -u mainnet-beta # Verify hash matches solana-verify get-program-hash -u mainnet-beta # Submit verification job solana-verify verify-from-repo \ --remote \ -u mainnet-beta \ --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 # 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 # 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 --limit 10 # Or use explorers: # https://explorer.solana.com/address/ # https://solscan.io/account/ ``` **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 \ --filepath target/idl/my_program.json \ --provider.cluster devnet ``` **Upgrade IDL after program upgrade:** ```bash anchor idl upgrade \ --filepath target/idl/my_program.json \ --provider.cluster devnet ``` **Fetch published IDL:** ```bash anchor idl fetch \ --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 # Reclaims rent SOL to wallet ``` **Close entire program (irreversible!):** ```bash solana program close # 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 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 # 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 $DIFF # Check rent for extension solana rent $DIFF # Now deploy upgrade solana program deploy target/deploy/my_program.so --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 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 ``` ### 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 ``` **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 \ ... ``` --- ## 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:
" >> 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 target/deploy/program.so --provider.cluster devnet # Verify upgrade worked # 5. Verified build test solana-verify build solana-verify verify-from-repo --program-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 \ -u mainnet-beta \ --with-compute-unit-price 100000 ``` ## Verify ```bash solana-verify verify-from-repo \ --remote \ -u mainnet-beta \ --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/ ``` --- ## 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!