协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
blockchain-solana【开发与工程】Use this skill when asked about Solana blockchain, Solana architecture, Proof of History, Solana programming, Anchor framework, Solana runtime, Solana CLI tools, Solana DeFi, Jupiter, Raydium, Metaplex, SPL tokens, and the Solana ecosystem. Covers Solana protocol architecture (PoH, Tower BFT, Turbine, Gulf Stream, SeaLevel, Cloudbreak), smart contrac…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Guide Solana blockchain development covering protocol architecture, smart contract (program) development with Anchor, SPL token standards, validator operations, and ecosystem protocol integration.
"solana", "solana blockchain", "solana architecture", "proof of history", "anchor framework", "solana program", "solana contract", "solana runtime", "solana CLI", "spl token", "solana defi", "jupiter", "raydium", "metaplex", "solana validator", "solana developer", "turbine", "gulf stream", "sealevel", "cloudbreak", "pda", "cpi", "solana account model"
Solana program specification: architecture, account design, instruction handlers, testing strategy, deployment plan.
5000 tokens
Solana program type:
├── Token/SFT → SPL Token + Associated Token Account
├── NFT → Metaplex Token Metadata + Candy Machine
├── AMM/DeFi → Anchor with CPIs to SPL Token + Oracle
├── Custom logic → Anchor (default) or raw BPF
│ ├── Anchor → Most programs (handles PDA bumps, validation, serialization)
│ └── Raw BPF → Performance-critical, no overhead (rarely needed)
└── Upgradable?
├── YES → BPFLoaderUpgradeable (default)
└── NO → BPFLoader (immutable, security critical)
Account type needed:
├── Token account → Associated Token Account (SPL Token)
│ ├── Derivation: PDA(owner, TOKEN_PROGRAM_ID, mint)
│ └── One ATA per owner per mint
├── Program-derived account → PDA
│ ├── Seeds: [b"prefix", pubkey, bump]
│ ├── Bump stored in account or derived on each call
│ └── Space: 8 (discriminator) + struct fields
├── Signer → Transaction signer (wallet or PDA via CPI)
└── Executable → Deployed program account
Account size calculation:
├── Account header: 32B (owner Pubkey) + 8B (lamports) + 1B (executable) + 1B (rent_epoch)
├── Anchor discriminator: 8 bytes (hash of account struct name)
├── Data: struct size (packed, no alignment padding)
└── Rent exemption: ~0.000003 SOL per byte (mainnet 2024)
Min rent: ~0.00088 SOL for 165 byte account (ATA)
Compute budget planning:
├── Default: 200,000 compute units per instruction
│ ├── Simple transfer: ~1,000 CU
│ ├── SPL token transfer: ~40,000 CU
│ ├── PDA derivation: ~2,000 CU
│ ├── CPI call: ~10,000 CU (base) + callee cost
│ └── Log output: ~100 CU per 32 bytes
├── Increase budget: SetComputeUnitLimit (max 1.4M CU)
└── Priority fees: SetComputeUnitPrice (microLamports per CU)
├── 0 priority: may not be included in busy blocks
└── 10,000+ microLamports/CU: likely included
| Component | Purpose | Key Characteristics |
|---|---|---|
| Proof of History (PoH) | Global timestamp / sequence | SHA-256 sequential hashing, verifiable delay |
| Tower BFT | Consensus | Optimistic confirmation, ~400ms slot time |
| Turbine | Block propagation | Fragmented block propagation tree |
| Gulf Stream | Mempool replacement | Forward transaction forwarding, no mempool |
| SeaLevel | Runtime | Parallel transaction execution (read/write sets) |
| Cloudbreak | Account database | Memory-mapped account storage |
| Pipelining | Transaction processing | GPU-optimized signature verification |
// PoH: Sequential SHA-256 hashing creates a verifiable delay
// Each hash output is the input for the next hash
// This proves time elapsed between events
struct PohEntry {
hash: Hash, // SHA-256(previous_hash, event_data)
event_data: Option<Vec<u8>>,
num_hashes: u64, // Number of hashes in this batch
}
// Leader tick: ~100ms of PoH hashes
// Slots: each slot = 4 ticks = ~400ms
// Epoch: 432,000 slots = ~2.5 days
// Optimistic confirmation: validator confirms block after observing
// 2/3+ stake-weighted votes for the same block
// Switch to Tower BFT voting when PoH fork detected
// Voting process:
// 1. Receive block via Turbine
// 2. Execute transactions through SeaLevel
// 3. Compute new bank state hash
// 4. Sign and send vote to leader
// 5. Leader aggregates votes, includes in block
// Fork resolution: PoH provides total ordering
// Tower: each vote locks out earlier slots
// Weight: by stake (more stake = more voting power)
// Turbine: tree-based block propagation
// Block is split into 64 packets (2/3 data, 1/3 parity for erasure coding)
// Each validator forwards to next 2+ peers in tree
// Depth: O(log N) where N = validator count
// Latency: ~500ms for entire network (~2,000 validators)
// Retransmission:
// If neighbor doesn't ACK within 200ms, retransmit to alternative peer
// Erasure coding allows reconstruction even with packet loss
use anchor_lang::prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod my_program {
use super::*;
pub fn initialize(ctx: Context<Initialize>, data: u64) -> Result<()> {
ctx.accounts.my_account.data = data;
ctx.accounts.my_account.authority = ctx.accounts.authority.key();
emit!(DataChanged { data });
Ok(())
}
pub fn update(ctx: Context<Update>, new_data: u64) -> Result<()> {
ctx.accounts.my_account.data = new_data;
emit!(DataChanged { data: new_data });
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = authority,
space = 8 + 8 + 32, // discriminator + u64 + Pubkey
seeds = [b"my_account", authority.key().as_ref()],
bump
)]
pub my_account: Account<'info, MyAccount>,
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Update<'info> {
#[account(
mut,
seeds = [b"my_account", authority.key().as_ref()],
bump,
has_one = authority
)]
pub my_account: Account<'info, MyAccount>,
pub authority: Signer<'info>,
}
#[account]
pub struct MyAccount {
pub data: u64,
pub authority: Pubkey,
}
#[event]
pub struct DataChanged {
pub data: u64,
}
// Calling SPL Token from another program
use anchor_spl::token::{self, Transfer, Token, TokenAccount};
pub fn transfer_tokens(ctx: Context<TransferTokens>, amount: u64) -> Result<()> {
token::transfer(
CpiContext::new(
ctx.accounts.token_program.to_account_info(),
Transfer {
from: ctx.accounts.from.to_account_info(),
to: ctx.accounts.to.to_account_info(),
authority: ctx.accounts.authority.to_account_info(),
},
),
amount,
)?;
Ok(())
}
#[derive(Accounts)]
pub struct TransferTokens<'info> {
#[account(mut)]
pub from: Account<'info, TokenAccount>,
#[account(mut)]
pub to: Account<'info, TokenAccount>,
pub authority: Signer<'info>,
pub token_program: Program<'info, Token>,
}
// Program signs for a PDA derived account
pub fn pda_signed_transfer(ctx: Context<PdaTransfer>, amount: u64) -> Result<()> {
let seeds = &[
b"escrow",
ctx.accounts.escrow.seed.as_ref(),
&[ctx.accounts.escrow.bump],
];
let signer_seeds = &[&seeds[..]];
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
Transfer {
from: ctx.accounts.escrow_token_account.to_account_info(),
to: ctx.accounts.receiver_token_account.to_account_info(),
authority: ctx.accounts.escrow.to_account_info(),
},
signer_seeds,
),
amount,
)?;
Ok(())
}
#[error_code]
pub enum MyError {
#[msg("Insufficient funds")]
InsufficientFunds,
#[msg("Unauthorized signer")]
Unauthorized,
#[msg("Arithmetic overflow")]
ArithmeticError,
#[msg("Invalid account state")]
InvalidAccountState,
}
pub fn checked_operation(ctx: Context<Op>, amount: u64) -> Result<()> {
let account = &mut ctx.accounts.my_account;
require!(account.data >= amount, MyError::InsufficientFunds);
require!(!account.frozen, MyError::InvalidAccountState);
account.data = account.data
.checked_sub(amount)
.ok_or(MyError::ArithmeticError)?;
Ok(())
}
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { MyProgram } from "../target/types/my_program";
import { expect } from "chai";
describe("my_program", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.MyProgram as Program<MyProgram>;
it("initializes and updates", async () => {
const [myAccountPda] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("my_account"), provider.wallet.publicKey.toBuffer()],
program.programId
);
await program.methods
.initialize(new anchor.BN(42))
.accounts({ myAccount: myAccountPda })
.rpc();
const account = await program.account.myAccount.fetch(myAccountPda);
expect(account.data.toNumber()).to.equal(42);
});
it("checks unauthorized access", async () => {
const [myAccountPda] = anchor.web3.PublicKey.findProgramAddressSync(
[Buffer.from("my_account"), provider.wallet.publicKey.toBuffer()],
program.programId
);
const otherUser = anchor.web3.Keypair.generate();
try {
await program.methods
.update(new anchor.BN(99))
.accounts({ myAccount: myAccountPda })
.signers([otherUser])
.rpc();
expect.fail("Should have thrown");
} catch (e) {
expect(e.message).to.contain("Unauthorized");
}
});
it("simulates mainnet fork", async () => {
// Use mainnet fork for testing real protocol interactions
const connection = new anchor.web3.Connection("https://api.mainnet-beta.solana.com");
// ... fork test implementation
});
});
it("measures compute units", async () => {
// Add compute budget tracking
const computeBudget = anchor.web3.ComputeBudgetProgram;
const ix = computeBudget.setComputeUnitLimit({ units: 400_000 });
const tx = new anchor.web3.Transaction().add(ix);
tx.add(
await program.methods
.initialize(new anchor.BN(42))
.accounts({ myAccount: myAccountPda })
.instruction()
);
const result = await anchor.web3.sendAndConfirmTransaction(
provider.connection,
tx,
[provider.wallet.payer]
);
const postCUs = await provider.connection.getTransaction(
result,
{ commitment: "confirmed", maxSupportedTransactionVersion: 0 }
);
console.log("CU consumed:", postCUs?.meta?.computeUnitsConsumed);
});
// SPL Token CLI patterns
// Create mint: spl-token create-token
// Create account: spl-token create-account <MINT>
// Mint: spl-token mint <MINT> <AMOUNT> <ACCOUNT>
// Transfer: spl-token transfer <MINT> <AMOUNT> <DESTINATION>
// Programmatic ATA creation
import { getAssociatedTokenAddressSync, createAssociatedTokenAccountInstruction } from "@solana/spl-token";
const ata = getAssociatedTokenAddressSync(mint, owner);
// Automatically creates ATA if it doesn't exist
// ATA is deterministic: one ATA per mint per owner
// Metaplex Token Metadata program
// Store NFT metadata: name, symbol, URI, creators, royalties
// Master Edition: NFT collection with limited print supply
#[derive(BorshSerialize, BorshDeserialize)]
pub struct Metadata {
pub key: Key,
pub update_authority: Pubkey,
pub mint: Pubkey,
pub name: String, // 32 chars max
pub symbol: String, // 10 chars max
pub uri: String, // 200 chars max
pub seller_fee_basis_points: u16, // Royalty basis points
pub creators: Option<Vec<Creator>>,
pub primary_sale_happened: bool,
pub is_mutable: bool,
}
| Protocol | Category | Description |
|---|---|---|
| Jupiter | DEX Aggregator | Routes swaps across all Solana AMMs |
| Raydium | AMM | Central limit order book + AMM liquidity |
| Metaplex | NFT | Token metadata, Candy Machine (NFT launchpad) |
| Marinade | LSD | mSOL liquid staking derivative |
| Pyth | Oracle | Low-latency price feeds |
| Switchboard | Oracle | Custom oracle solutions |
| Helius | RPC/Infra | Solana RPC, webhooks, digital asset APIs |
| Phantom | Wallet | Most popular Solana wallet |
| Vulnerability | Description | Prevention |
|---|---|---|
| Account confusion | Passing wrong account type | Anchor typed accounts, not AccountInfo |
| Missing signer check | Not verifying signer on privileged ops | Use Signer type in Anchor |
| PDA seed collision | Two PDAs with same seeds but different meanings | Unique seed prefixes per PDA type |
| Rent confusion | Not funding account rent | Use Anchor init constraint |
| Arbitrary CPI | Calling untrusted programs | Verify program_id in CPI context |
| Reinitialization | Re-initializing existing account | Anchor init checks discriminator |
| Integer overflow | Overflow in unchecked arithmetic | Use checked_add, checked_sub |
| Compute budget exhaustion | Exceed 200K CU limit | Profile and optimize compute usage |
blockchain → blockchain-solana