Hướng dẫn Khung làm việc Solana Anchor
Learn to build Solana programs with Anchor Framework. Complete guide covering setup, core concepts, security, testing and deployment to devnet.
Khung làm việc Solana Anchor giúp các nhà phát triển xây dựng chương trình với xác thực tài khoản có cấu trúc, định nghĩa lệnh, giao diện được tạo ra và các kiểm tra bảo mật có thể tái sử dụng.
Lưu ý phiên bản: Các phiên bản Anchor, Rust, Solana CLI và client JavaScript thay đổi độc lập. Xác minh tính tương thích hiện tại trong tài liệu Anchor chính thức trước khi cài đặt hoặc triển khai.
Bài viết này chỉ dành cho mục đích giáo dục và không cấu thành lời khuyên tài chính hoặc đầu tư. Đầu tư tiền điện tử mang rủi ro đáng kể. Luôn tự nghiên cứu trước khi đưa ra quyết định đầu tư.
📌 LƯU Ý: Hướng dẫn này sử dụng Anchor v0.29.x và Solana CLI v1.18.x+, hiện hành tính đến năm 2024. Khung làm việc Anchor phát triển nhanh chóng. Chạy anchor --version để xác minh phiên bản đã cài đặt của bạn trước khi làm theo hướng dẫn này.
Mục lục
- Khung làm việc Solana Anchor là gì?
- Mô hình Tài khoản của Solana
- Các Thành phần Cốt lõi của Khung làm việc Solana Anchor
- Điều kiện Tiên quyết
- Cách Cài đặt Khung làm việc Anchor
- Xây dựng và Triển khai Chương trình Anchor đầu tiên của bạn
- Kiểm thử Chương trình Anchor
- Anchor so với các Giải pháp thay thế
- Bảo mật Khung làm việc Anchor
- Khắc phục Lỗi phổ biến của Anchor
- Khung làm việc Anchor và Hệ sinh thái Nhà phát triển Solana
- Câu hỏi thường gặp
- Kết luận
Khung làm việc Solana Anchor là gì?
Khung làm việc Solana Anchor là một framework phát triển mã nguồn mở giúp loại bỏ các đoạn mã lặp lại và sự phức tạp trong xác thực tài khoản khi viết các chương trình Solana (tương đương trên chuỗi của hợp đồng thông minh) bằng Rust thuần túy.
Solana là một blockchain Layer 1 hiệu năng cao, xử lý khoảng 65.000 giao dịch mỗi giây trong điều kiện tối ưu (tính đến năm 2024), với khả năng hoàn tất giao dịch dưới một giây và phí thường dưới 0,001 USD. Solana đạt được thông lượng này một phần nhờ vào cơ chế đồng thuận độc đáo có tên là Proof of History (PoH), tạo ra một đồng hồ mật mã để sắp xếp các giao dịch mà không cần chi phí giao tiếp của các giao thức đồng thuận truyền thống.
Xây dựng trên Solana mà không có framework có nghĩa là phải viết mã Rust cấp thấp, dài dòng cho mỗi chương trình. Các nhà phát triển phải tự xác thực quyền sở hữu tài khoản, tuần tự hóa dữ liệu, xử lý lỗi và quản lý mối quan hệ tài khoản cho mọi giao dịch. Đối với các kỹ sư quen thuộc với backend Web2 hoặc phát triển Ethereum, bức tường học tập này đủ dốc để ngăn hầu hết các dự án bắt đầu.
Anchor thay đổi điều đó. Hãy coi Anchor như Ruby on Rails của việc phát triển Solana: một framework có quy tắc rõ ràng, xử lý các phần kỹ thuật nền để bạn có thể tập trung vào logic chương trình của mình thay vì cơ sở hạ tầng bên dưới nó. Anchor được tạo ra bởi Armani Ferrante và được duy trì bởi Coral XYZ. Bạn có thể tìm thấy mã nguồn và các bản phát hành tại kho lưu trữ GitHub của Anchor (coral-xyz/anchor).) Phiên bản ổn định hiện tại là v0.29.x.
Anchor cho phép các nhà phát triển xây dựng các ứng dụng phi tập trung (dApp). Một dApp là một ứng dụng có logic backend chạy trên blockchain thông qua các chương trình Solana thay vì trên máy chủ tập trung. Chương trình là backend của dApp; client TypeScript mà Anchor tạo ra là cách frontend của bạn gọi nó. Các danh mục dApp được xây dựng bằng Anchor bao gồm các giao thức Tài chính Phi tập trung (DeFi), các nền tảng Token Không thể Thay thế (NFT) (NFT), các tổ chức tự trị phi tập trung (DAO) và các trò chơi Web3.
Khi kết thúc hướng dẫn này, bạn sẽ hiểu kiến trúc cốt lõi của Anchor, có một môi trường phát triển hoạt động, đã triển khai một chương trình trên devnet của Solana (một mạng thử nghiệm với SOL miễn phí, không có giá trị) và có đủ ngữ cảnh để đánh giá xem Anchor có phù hợp với dự án của bạn hay không. Để xem trực tiếp cách Anchor so sánh với các công cụ Ethereum và phát triển Rust gốc, hãy xem cách Anchor so sánh với Hardhat của Ethereum và phát triển Rust gốc.
Bạn sẽ học được:
- Solana là gì và tại sao kiến trúc của nó lại cần thiết cho Anchor
- IDL, macro và PDA mỗi thứ làm gì, và các chương trình gọi nhau như thế nào
- Cách cài đặt toàn bộ môi trường phát triển Anchor
- Cách viết và triển khai chương trình Anchor đầu tiên của bạn
- Các lỗ hổng bảo mật cần tránh trước khi đưa lên mainnet
- Cách khắc phục các lỗi Anchor phổ biến nhất
Mô hình Tài khoản của Solana: Nền tảng bạn cần hiểu trước tiên
Mô hình tài khoản của Solana là nền tảng kiến trúc làm cho Anchor trở nên cần thiết. Nó thực sự khác biệt so với bất kỳ điều gì bạn gặp trong phát triển Ethereum hoặc Web2. Trước khi các trừu tượng hóa của Anchor có ý nghĩa, bạn cần hiểu vấn đề mà chúng giải quyết.
Solana là gì
Solana là một mạng lưới blockchain Layer 1 được thiết kế cho thông lượng cao và chi phí giao dịch thấp. Không giống như Ethereum, mạng này xử lý khoảng 15 đến 30 giao dịch mỗi giây trên mainnet, Solana xử lý khoảng 65.000 giao dịch mỗi giây trong điều kiện tối ưu (tính đến năm 2024). Phí giao dịch thường dưới 0,001 USD. Sự kết hợp giữa tốc độ và chi phí này làm cho Solana phù hợp với các ứng dụng yêu cầu nhiều giao dịch nhỏ, thường xuyên: hệ thống giao dịch DeFi, nền tảng mint NFT và các trò chơi trên chuỗi.
SOL là token gốc của Solana. Nó thanh toán phí giao dịch và chi phí thuê bao mà các tài khoản trên chuỗi phải duy trì để tồn tại trên mạng. Mọi chương trình bạn triển khai và mọi tài khoản mà chương trình của bạn tạo ra đều yêu cầu SOL để tồn tại trên chuỗi. Trên devnet (mạng thử nghiệm miễn phí của Solana), bạn nhận SOL airdrop miễn phí.
Lợi thế về tốc độ tồn tại nhờ các quyết định kiến trúc khiến việc phát triển Solana khó hơn phát triển Ethereum ở cấp độ cơ bản. Anchor giải quyết chính xác những phần khó đó.
Cách Solana Lưu trữ Chương trình và Dữ liệu
Trên Solana, "tài khoản" không phải là tài khoản người dùng hoặc tài khoản ví theo nghĩa thông thường. Tài khoản là các đơn vị lưu trữ trên blockchain: các vùng chứa riêng biệt có thể chứa dữ liệu, số dư SOL hoặc mã chương trình có thể thực thi.
Sự khác biệt kiến trúc cốt lõi: trên Solana, các chương trình (mã thực thi) và dữ liệu (trạng thái) nằm trong các tài khoản riêng biệt. Các chương trình không có trạng thái. Một tài khoản chương trình chỉ chứa mã byte đã biên dịch. Dữ liệu nằm trong các tài khoản dữ liệu riêng biệt mà các chương trình đọc và ghi vào.
Trong Ethereum, một hợp đồng thông minh giống như một căn hộ tự chứa: mã và đồ đạc nằm trong cùng một không gian. Trong Solana, một chương trình giống như một công ty có các phòng ban riêng biệt: logic thực thi nằm trong một tài khoản và dữ liệu mà nó đọc và ghi nằm trong các tài khoản khác.
| Thuộc tính | Hợp đồng Thông minh Ethereum | Chương trình Solana + Tài khoản |
|---|---|---|
| Lưu trữ mã | Bên trong hợp đồng | Tài khoản chương trình riêng biệt |
| Lưu trữ trạng thái | Bên trong hợp đồng | Tài khoản dữ liệu riêng biệt |
| Nhà phát triển quản lý tài khoản? | Không | Có (Anchor tự động hóa điều này) |
| Ngôn ngữ | Solidity | Rust (qua Anchor) |
| Có trạng thái? | Có | Các chương trình không có trạng thái; trạng thái nằm trong các tài khoản |
Mỗi tài khoản Solana có ba thuộc tính: chủ sở hữu (một chương trình kiểm soát nó), địa chỉ Public Key (định danh trên chuỗi của nó), và số dư lamport (đơn vị nhỏ nhất của SOL, với 1 SOL tương đương 1 tỷ lamports). Các tài khoản dữ liệu cũng chứa dữ liệu chương trình đã được tuần tự hóa.
Hệ quả thực tế: khi bạn gọi một chương trình Solana, bạn phải truyền rõ ràng mọi tài khoản mà chương trình sẽ đọc hoặc ghi. Bạn phải chứng minh quyền sở hữu. Bạn phải khai báo tài khoản nào có thể sửa đổi. Bạn phải xác minh tài khoản nào là người ký. Trong Rust thuần, việc quản lý tài khoản này đòi hỏi hàng trăm dòng mã xác thực cho mỗi chương trình.
Việc quản lý tài khoản rõ ràng này chính là vấn đề mà hệ thống ràng buộc của Anchor được thiết kế để giải quyết.
Các Thành phần Cốt lõi của Khung Anchor Solana: IDL, Macros, PDAs và CPI
Anchor cung cấp bốn cơ chế liên kết với nhau, kết hợp lại loại bỏ hầu hết sự phức tạp trong phát triển Solana thuần. Hiểu từng cái theo trình tự là điều kiện tiên quyết để viết chương trình đầu tiên của bạn.
IDL (Ngôn ngữ Định nghĩa Giao diện): Hợp đồng Giao tiếp của Anchor
Anchor tự động tạo một tệp JSON gọi là Ngôn ngữ Định nghĩa Giao diện (IDL) bất cứ khi nào bạn chạy anchor build. Hãy coi nó như một đặc tả OpenAPI cho chương trình trên chuỗi của bạn: một mô tả có thể đọc được bằng máy về mọi chỉ dẫn mà chương trình của bạn chấp nhận, mọi tài khoản mà các chỉ dẫn đó yêu cầu, và mọi kiểu dữ liệu liên quan.
IDL đối với Anchor cũng giống như ABI (Giao diện Nhị phân Ứng dụng) đối với một hợp đồng Solidity trên Ethereum. Nếu bạn đã phát triển trên Ethereum, bạn đã biết ABI cho phép mã giao diện người dùng gọi các hàm hợp đồng với độ an toàn về kiểu như thế nào. IDL của Anchor làm điều tương tự cho các chương trình Solana và nó được tạo tự động từ mã Rust của bạn. Bạn không bao giờ viết nó thủ công.
Tệp IDL nằm ở target/idl/your_program_name.json sau khi chạy anchor build. Bên cạnh đó, Anchor tạo ra target/types/your_program_name.ts, một tệp kiểu TypeScript mà các tập lệnh giao diện người dùng hoặc kiểm thử của bạn nhập vào để có quyền truy cập đầy đủ kiểu vào các chỉ dẫn của chương trình.
Một IDL rút gọn trông như thế này:
{
"version": "0.1.0",
"name": "balance_tracker",
"instructions": [
{
"name": "initialize",
"accounts": [
{ "name": "balanceAccount", "isMut": true, "isSigner": false },
{ "name": "user", "isMut": true, "isSigner": true },
{ "name": "systemProgram", "isMut": false, "isSigner": false }
],
"args": []
},
{
"name": "deposit",
"accounts": [
{ "name": "balanceAccount", "isMut": true, "isSigner": false },
{ "name": "user", "isMut": false, "isSigner": true }
],
"args": [{ "name": "amount", "type": "u64" }]
}
]
}Máy khách TypeScript đọc IDL này và cung cấp cho bạn các lệnh gọi phương thức có kiểu đầy đủ (program.methods.initialize() và program.methods.deposit(amount)) mà không cần viết giao diện thủ công. Kỹ năng TypeScript của bạn được áp dụng trực tiếp ở đây.
Macros của Anchor: Cách Anchor Loại bỏ Mã Lặp lại
Anchor cung cấp một bộ macro Rust, là các trình tạo mã viết logic xác thực lặp đi lặp lại cho bạn. Macro trong Rust là một chú thích mở rộng thành mã tại thời điểm biên dịch. Các macro của Anchor tạo ra mã xác thực tài khoản, tuần tự hóa và xử lý lỗi mà nếu không bạn sẽ phải viết thủ công.
Ba macro tạo thành cốt lõi của mọi chương trình Anchor:
#[program] đánh dấu mô-đun chứa các hàm xử lý chỉ dẫn của bạn. Anchor coi mỗi hàm công khai trong mô-đun này là một chỉ dẫn có thể gọi.
#[derive(Accounts)] tạo mã xác thực tài khoản từ định nghĩa struct Rust. Bạn khai báo chương trình cần những tài khoản nào, và Anchor sẽ tự động tạo mã để xác minh quyền sở hữu và khả năng sửa đổi, cùng với kiểu của mỗi tài khoản.
#[account] đánh dấu một struct là kiểu dữ liệu tài khoản do Anchor quản lý và thêm bộ phân biệt 8 byte giúp Anchor phân biệt kiểu tài khoản của bạn với các kiểu khác.
Đây là cách các macro này xuất hiện trong ngữ cảnh:
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init, // Anchor tạo tài khoản này (xác minh tài khoản chưa tồn tại)
payer = user, // Tài khoản 'user' tài trợ chi phí đặt cọc miễn trừ tiền thuê
space = 8 + 8 // Bộ phân biệt 8 byte + 8 byte cho trường tổng u64
)]
pub balance_account: Account<'info, BalanceAccount>,
#[account(mut)] // Khai báo số dư lamport của tài khoản này sẽ thay đổi
pub user: Signer<'info>, // Kiểu Signer: Anchor xác minh tài khoản này đã ký giao dịch
pub system_program: Program<'info, System>,
}Mỗi thuộc tính bên trong #[account(...)] là một ràng buộc của Anchor. Ràng buộc là các quy tắc xác thực được thực thi tự động trước khi logic chỉ dẫn của bạn chạy. Chúng là lý do chính khiến các chương trình Anchor yêu cầu ít mã xác thực thủ công hơn nhiều so với các chương trình Rust thuần.
Các ràng buộc phổ biến nhất là:
#[derive(Accounts)]
pub struct ExampleAccounts<'info> {
#[account(init, payer = user, space = 8 + 8)]
// init: tạo tài khoản; hoàn nguyên nếu tài khoản đã tồn tại
pub new_account: Account<'info, MyData>,
#[account(mut)]
// mut: khai báo dữ liệu hoặc số dư lamport của tài khoản này sẽ thay đổi
pub existing_account: Account<'info, MyData>,
#[account(seeds = [b"vault", user.key().as_ref()], bump)]
// seeds + bump: suy ra địa chỉ PDA và xác minh bump canonical
pub pda_account: Account<'info, VaultData>,
#[account(constraint = user_account.authority == user.key())]
// constraint: đánh giá biểu thức boolean; thất bại nếu sai
pub user_account: Account<'info, UserData>,
pub user: Signer<'info>,
// Signer: xác minh tài khoản đã ký giao dịch
}Nếu không có ràng buộc, bạn sẽ phải viết từng kiểm tra này bằng tay trong phần thân chỉ dẫn của mình. Với ràng buộc, Anchor thực thi chúng trước khi logic chỉ dẫn của bạn chạy. Đây vừa là một cải tiến về năng suất vừa là một tính năng bảo mật, vì ràng buộc khó quên hơn các kiểm tra thủ công ẩn trong mã chỉ dẫn.
Địa chỉ Suy ra từ Chương trình (PDAs): Lưu trữ Trên chuỗi Xác định
Địa chỉ Suy ra từ Chương trình (PDA) là một trong những khái niệm khó hơn trong phát triển Solana. Hãy lên kế hoạch đọc lại phần này hai lần. PDA mở ra một trong những mẫu mạnh mẽ nhất của Solana, và Anchor làm cho chúng dễ quản lý hơn nhiều so với Rust thuần.
PDA là một địa chỉ tài khoản được suy ra một cách xác định từ một tập hợp các hạt giống (seeds) và ID chương trình. Không giống như địa chỉ ví thông thường, PDA không có khóa riêng tương ứng. Không cá nhân nào có thể ký thay cho một PDA. Chỉ chương trình sở hữu mới có thể ủy quyền các giao dịch liên quan đến nó.
Hãy coi PDA như một hộp ký gửi an toàn mà chỉ ngân hàng (chương trình) mới có thể mở. Không khách hàng nào có chìa khóa; ngân hàng kiểm soát quyền truy cập theo chương trình. Điều này làm cho PDA trở nên lý tưởng cho các kho chứa do chương trình kiểm soát, tài khoản ký quỹ và lưu trữ dành riêng cho người dùng mà chương trình, chứ không phải người dùng, nên có thẩm quyền.
Trong Rust thuần, suy ra PDA yêu cầu gọi Pubkey::find_program_address(&seeds, &program_id) và xác minh thủ công kết quả. Anchor xử lý điều này với ràng buộc seeds:
#[derive(Accounts)]
pub struct CreateVault<'info> {
#[account(
init,
payer = authority,
space = 8 + 32,
seeds = [b"vault", authority.key().as_ref()], // Hạt giống xác định địa chỉ PDA
bump // Anchor tìm và lưu trữ hạt giống bump canonical
)]
pub vault: Account<'info, Vault>, // Tài khoản PDA, không có khóa riêng
#[account(mut)]
pub authority: Signer<'info>,
pub system_program: Program<'info, System>,
}Ràng buộc seeds cho Anchor biết cách suy ra địa chỉ PDA. Trường bump lưu trữ hạt giống "bump" chính tắc, một số nguyên nhỏ đảm bảo địa chỉ suy ra nằm ngoài đường cong elliptic và không có Private Key. Trong Anchor v0.29.x, "bump" chính tắc được suy ra và xác minh tự động.
PDA có tính xác định: với cùng một hạt giống (seeds) và ID chương trình, chúng luôn tạo ra cùng một địa chỉ. Thuộc tính này cho phép máy khách tính toán địa chỉ PDA ngoài chuỗi (off-chain) để lấy dữ liệu, trong khi chương trình kiểm soát quyền truy cập ghi.
Gọi Chương trình Chéo (CPI): Cách các Chương trình Nói chuyện với Nhau
Gọi Chương trình Chéo (CPI) là cơ chế của Solana để một chương trình gọi các lệnh của chương trình khác. Đây là tương đương trên chuỗi (on-chain) của việc gọi một hàm thư viện dùng chung. CPI cho phép tính khả dụng: giao thức DeFi của bạn có thể gọi chương trình SPL Token để chuyển token, hợp đồng quản trị của bạn có thể gọi chương trình Staking, v.v.
Thư viện Chương trình Solana (SPL) là tương đương của Solana với thư viện chuẩn cho các chương trình trên chuỗi (on-chain). SPL Token đối với Solana cũng giống như ERC-20 đối với Ethereum, nhưng được triển khai dưới dạng một chương trình trên chuỗi (on-chain) dùng chung thay vì một mẫu hợp đồng mà mỗi dự án triển khai độc lập. Khi chương trình Anchor của bạn cần tạo hoặc chuyển token, nó sẽ gọi SPL Token thông qua CPI.
Anchor đơn giản hóa các lệnh gọi CPI với crate anchor-spl và CpiContext:
use anchor_spl::token::{self, Transfer, Token};
pub fn withdraw(ctx: Context<Withdraw>, amount: u64) -> Result<()> {
let cpi_accounts = Transfer {
from: ctx.accounts.vault_token_account.to_account_info(), // Tài khoản token nguồn
to: ctx.accounts.user_token_account.to_account_info(), // Tài khoản token đích
authority: ctx.accounts.vault.to_account_info(), // PDA ký cho vault
};
let cpi_ctx = CpiContext::new(ctx.accounts.token_program.to_account_info(), cpi_accounts);
token::transfer(cpi_ctx, amount)?; // Gọi lệnh chuyển của SPL Token
Ok(())
}Không có Anchor, việc tập hợp thông tin tài khoản, xây dựng lệnh và gọi invoke_signed yêu cầu khoảng 30 dòng. Các trình trợ giúp CPI của Anchor giảm điều này xuống thành một lệnh gọi hàm rõ ràng, có thể đọc được và được gõ mạnh.
Bạn sẽ đưa các khái niệm này vào thực hành trong hướng dẫn chương trình từng bước.
Điều kiện tiên quyết: Những gì bạn cần trước khi cài đặt Khung Anchor (Anchor Framework)
Bốn công cụ được yêu cầu trước khi bạn có thể xây dựng với Khung Anchor (Anchor Framework) trên Solana.
Các công cụ yêu cầu:
- Rust và Cargo (qua rustup), khuyến nghị phiên bản 1.70.0 trở lên
- Solana CLI (v1.18.x trở lên), công cụ dòng lệnh chính thức để tương tác với mạng Solana; xử lý quản lý ví, yêu cầu airdrop và cấu hình cluster
- Node.js (v18 trở lên) cộng với Yarn hoặc npm, cần thiết cho client TypeScript và các bài kiểm tra Anchor
- Anchor Version Manager (avm), công cụ cài đặt và quản lý các phiên bản Anchor CLI; luôn cài đặt Anchor qua avm thay vì trực tiếp qua Cargo
Về Rust: Các chương trình Anchor được viết bằng Rust. Rust là bắt buộc. Không có cách nào khác. Tuy nhiên, các macro của Anchor trừu tượng hóa các mẫu Rust khó chịu nhất: xác thực và tuần tự hóa tài khoản, cộng với việc lan truyền lỗi. Bạn không cần nắm vững Rust sâu sắc để xây dựng chương trình đầu tiên của mình.
Những gì bạn cần để bắt đầu: các cấu trúc (structs), hàm, quyền sở hữu cơ bản và các giới hạn kiểu (trait bounds) ở mức bề mặt. Những gì bạn có thể hoãn lại cho sau này: thời gian sống (lifetimes), Rust bất đồng bộ (async Rust) và các điểm chi tiết hơn của trình kiểm tra vay mượn (borrow checker). Kỹ năng TypeScript hoặc JavaScript của bạn áp dụng trực tiếp cho mã phía client của Anchor. Các bài kiểm tra, tương tác giao diện người dùng và các lệnh gọi client được tạo bởi IDL đều sử dụng TypeScript. Bạn không cần phải là chuyên gia Rust để xây dựng với Anchor, giống như bạn không cần phải là chuyên gia Ruby để xây dựng với Ruby on Rails. Nhưng bạn sẽ gặp Rust, và sự quen thuộc cơ bản sẽ giúp ích.
Nếu sự trừu tượng hóa các mẫu Rust của Anchor làm bạn quan tâm, phần các thành phần cốt lõi giải thích chi tiết những gì Anchor trừu tượng hóa từ Rust.
Về Solana CLI so với Anchor CLI: Đây là hai công cụ riêng biệt với các trách nhiệm khác nhau. CLI solana xử lý tương tác mạng: kiểm tra số dư, yêu cầu airdrop và chuyển đổi giữa devnet và mainnet. CLI anchor xử lý vòng đời chương trình của bạn: khởi tạo dự án, biên dịch chương trình, chạy bài kiểm tra và triển khai. Cả hai đều bắt buộc.
Cách cài đặt Khung Anchor (Anchor Framework): Thiết lập từng bước
📌 LƯU Ý: Tất cả các lệnh bên dưới được xác thực cho Anchor v0.29.x và Solana CLI v1.18.x tính đến năm 2024. Chạy anchor --version sau khi cài đặt để xác nhận phiên bản của bạn. Nếu đọc nội dung này sau khi xuất bản, hãy xác minh phiên bản hiện tại tại kho lưu trữ GitHub của Anchor (coral-xyz/anchor).)
Bước 1: Cài đặt Rust qua rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Làm theo hướng dẫn trên màn hình và chọn cài đặt mặc định
source "$HOME/.cargo/env"
rustc --version
# Sẽ hiển thị: rustc 1.70.0 trở lênBước 2: Cài đặt Solana CLI
sh -c "$(curl -sSf https://release.solana.com/stable/install)"
# Làm theo hướng dẫn PATH từ đầu ra của trình cài đặt
solana --version
# Sẽ hiển thị: solana-cli 1.18.x trở lênKhi bạn triển khai một chương trình Anchor lên Solana, nó được lưu trữ trên chuỗi (on-chain) và được các nút xác thực của mạng thực thi bất cứ khi nào một giao dịch gọi nó. Solana CLI là cách bạn tương tác với các nút xác thực đó từ thiết bị đầu cuối của mình.
Bước 3: Cấu hình Solana CLI cho devnet và tạo ví
solana config set --url devnet
solana-keygen new
# Tạo một cặp khóa cục bộ (ví phát triển của bạn)
# Lưu đường dẫn đầu ra. Anchor sử dụng cặp khóa này để ký các giao dịch triển khai💡 MẸO: Lưu đường dẫn tệp cặp khóa của bạn. Anchor đọc cặp khóa này từ tệp cấu hình Anchor.toml của bạn để ký các giao dịch triển khai trên devnet.
Bước 4: Yêu cầu airdrop SOL devnet
solana airdrop 2
solana balance
# Xác nhận số dư hiển thị là 2 SOLBước 5: Cài đặt avm (Anchor Version Manager) và Anchor
cargo install --git https://github.com/coral-xyz/avm avm --locked --force
avm install latest
avm use latest
anchor --version
# Sẽ hiển thị: anchor-cli 0.29.x📌 LƯU Ý: Luôn cài đặt Anchor thông qua avm thay vì trực tiếp qua cargo install anchor-cli. avm cho phép bạn chuyển đổi giữa các phiên bản Anchor mà không cần cài đặt lại. Điều này quan trọng khi các dự án được ghim vào một phiên bản cụ thể hoặc khi bạn đang nâng cấp một dự án hiện có.
Bước 6: Khởi tạo dự án đầu tiên của bạn
anchor init my-first-program
cd my-first-programCấu trúc dự án của bạn sau khi chạy anchor init:
my-first-program/
├── Anchor.toml
├── programs/
│ └── my-first-program/
│ └── src/
│ └── lib.rs
├── tests/
│ └── my-first-program.ts
└── app/💡 MẸO: Lệnh anchor init tạo một chương trình ví dụ hoạt động trong lib.rs. Chạy anchor test ngay lập tức để xác nhận môi trường của bạn đang hoạt động trước khi viết mã của riêng bạn.
Xây dựng và Triển khai Chương trình Anchor đầu tiên của bạn: Hướng dẫn hoàn chỉnh
Phần này đưa bạn từ một dự án trống đến một chương trình đã triển khai trên devnet của Solana. Ví dụ là một trình theo dõi số dư (balance tracker): một chương trình khởi tạo một số dư được lưu trữ thành 0 và sau đó chấp nhận các lệnh Nạp (deposit) để tăng số dư đó. Điều này minh họa vòng đời tài khoản đầy đủ và có chức năng tương đương với chương trình đếm (counter program) nhưng sử dụng tên biến gốc.
Tệp programs/my-first-program/src/lib.rs của bạn đã chứa một cấu trúc mẫu từ anchor init. Thay thế nội dung của nó bằng đoạn mã sau:
// Chương trình Theo dõi Số dư (Balance Tracker) Anchor v0.29.x
use anchor_lang::prelude::*;
Chương trình Theo dõi Số dư (Balance Tracker) Anchor v0.29.x
use anchor_lang::prelude::*;
pub fn initialize(ctx: Context<Initialize>) -> Result<()> {
ctx.accounts.balance_account.total = 0; // Số dư ban đầu là không
Ok(())
}
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
ctx.accounts.balance_account.total += amount; // Tăng số dư đã lưu
Ok(())
}
}
#[derive(Accounts)]
pub struct Initialize<'info> {
#[account(
init,
payer = user,
space = 8 + 8 // Bộ phân biệt Anchor 8 byte + 8 byte cho u64
)]
pub balance_account: Account<'info, BalanceAccount>,
#[account(mut)]
pub user: Signer<'info>,
pub system_program: Program<'info, System>,
}
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub balance_account: Account<'info, BalanceAccount>,
pub user: Signer<'info>,
}
#[account]
pub struct BalanceAccount {
pub total: u64,
}Ba mẫu trong mã này quan trọng trước khi bạn tiếp tục. Đầu tiên, #[derive(Accounts)] tạo toàn bộ logic xác thực tài khoản. Anchor đọc định nghĩa struct của bạn và ghi các kiểm tra quyền sở hữu, kiểm tra tính khả biến và xác minh người ký. Bạn khai báo ý định; Anchor thực thi nó. Thứ hai, space = 8 + 8 cấp phát chính xác số byte mà tài khoản cần: 8 byte cho bộ phân biệt của Anchor (một thẻ duy nhất xác định loại tài khoản và ngăn chặn các cuộc tấn công gây nhầm lẫn tài khoản) cộng với 8 byte cho u64 tổng. Thứ ba, Signer<'info> là kiểu tích hợp sẵn của Anchor để xác minh rằng tài khoản đã ký giao dịch. Nếu không có nó, bất kỳ tài khoản nào cũng có thể gọi lệnh Nạp của bạn.
Kiểm thử Chương trình của bạn với Mocha và TypeScript
Mocha là một trình chạy kiểm thử JavaScript; Chai cung cấp cú pháp khẳng định. Cả hai đều được cài đặt sẵn khi bạn chạy anchor init. Mở tests/my-first-program.ts và thay thế nội dung của nó:
import * as anchor from "@coral-xyz/anchor";
import { Program } from "@coral-xyz/anchor";
import { MyFirstProgram } from "../target/types/my_first_program";
import { assert } from "chai";
describe("balance-tracker", () => {
const provider = anchor.AnchorProvider.env();
anchor.setProvider(provider);
const program = anchor.workspace.MyFirstProgram as Program<MyFirstProgram>;
const balanceAccount = anchor.web3.Keypair.generate();
it("Khởi tạo một tài khoản số dư với tổng = 0", async () => {
await program.methods
.initialize()
.accounts({
balanceAccount: balanceAccount.publicKey,
user: provider.wallet.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
})
.signers([balanceAccount])
.rpc();
const account = await program.account.balanceAccount.fetch(
balanceAccount.publicKey
);
assert.equal(account.total.toNumber(), 0, "Số dư ban đầu phải là 0");
});
it("Nạp 500 và cập nhật số dư đã lưu", async () => {
await program.methods
.deposit(new anchor.BN(500))
.accounts({
balanceAccount: balanceAccount.publicKey,
user: provider.wallet.publicKey,
})
.rpc();
const account = await program.account.balanceAccount.fetch(
balanceAccount.publicKey
);
assert.equal(account.total.toNumber(), 500, "Số dư phải là 500 sau khi Nạp");
});
});Gói npm @coral-xyz/anchor là thư viện client TypeScript của Anchor. Kiểu Program<MyFirstProgram> được tạo tự động từ IDL khi anchor build chạy. Đây là giá trị thực tế của IDL: mã TypeScript của bạn nhận được sự an toàn kiểu hoàn toàn trên giao diện chương trình Rust của bạn mà không cần bất kỳ việc viết giao diện thủ công nào.
Chương trình này cũng là phần phụ trợ của một dApp. Client TypeScript được hiển thị ở trên là cách một ứng dụng front-end sẽ gọi nó. Thêm giao diện React hoặc Next.js phía trên các lệnh gọi phương thức này và bạn có một ứng dụng phi tập trung hoàn chỉnh chạy trên Solana.
Xây dựng và Triển khai lên Devnet
Chạy ba lệnh này theo trình tự từ thư mục gốc của bạn:
anchor build
# Đầu ra: target/deploy/my_first_program.so, target/idl/my_first_program.json, target/types/my_first_program.tsanchor test
# Khởi động trình xác thực cục bộ, triển khai, chạy kiểm thử Mocha, tắt máyanchor deploy --provider.cluster devnet
# Đầu ra bao gồm ID Chương trình của bạn: ABC123...xyz789💡 MẸO: Sao chép ID Chương trình của bạn từ đầu ra triển khai. Cập nhật giá trị declare_id!("...") trong lib.rs với ID đó, sau đó chạy lại anchor build để nhúng địa chỉ chính xác vào chương trình đã biên dịch của bạn. Cũng cập nhật phần [programs.devnet] trong Anchor.toml.
📌 LƯU Ý: Bạn đang triển khai lên devnet, mạng thử nghiệm của Solana. Điều này không tốn SOL thật. Airdrop devnet của bạn từ phần thiết lập sẽ chi trả phí triển khai.
Bạn đã viết và kiểm thử một chương trình Solana, sau đó triển khai nó bằng Anchor Framework. Chương trình tồn tại trên devnet tại ID Chương trình của bạn và thực thi bất cứ khi nào một giao dịch gọi nó.
Kiểm thử Chương trình Anchor: Quy trình anchor test
anchor test là một lệnh duy nhất khởi động trình xác thực Solana cục bộ, triển khai chương trình của bạn lên đó, chạy toàn bộ bộ kiểm thử Mocha của bạn và tắt trình xác thực khi hoàn tất. Bạn không cần quản lý trình xác thực thủ công.
Quy trình kiểm thử theo trình tự:
anchor testđọcAnchor.tomlcủa bạn để lấy cấu hình- Nó khởi động một quy trình trình xác thực cục bộ ở chế độ nền
- Nó xây dựng và triển khai chương trình của bạn lên trình xác thực đó
- Nó chạy tất cả các tệp kiểm thử TypeScript trong thư mục
tests/của bạn bằng Mocha - Nó in kết quả thành công/thất bại và tắt trình xác thực
Cấu trúc tệp kiểm thử: Mọi tệp kiểm thử đều nhập từ @coral-xyz/anchor, thiết lập một nhà cung cấp (kết nối với trình xác thực cục bộ) và tham chiếu chương trình của bạn thông qua đối tượng workspace được tạo từ IDL. Các khối describe và it là cú pháp Mocha tiêu chuẩn.
Truy xuất dữ liệu tài khoản: Sau khi gọi một lệnh, hãy truy xuất tài khoản trên chuỗi để khẳng định trạng thái của nó:
const account = await program.account.balanceAccount.fetch(
balanceAccount.publicKey
);
assert.equal(account.total.toNumber(), 0);Kiểm thử các trường hợp lỗi: Kiểm thử xem các đầu vào không hợp lệ có bị lỗi đúng cách không. Một chương trình được kiểm thử tốt bao gồm các kiểm thử phủ định:
it("Từ chối Nạp từ một tài khoản chưa ký", async () => {
const badActor = anchor.web3.Keypair.generate();
try {
await program.methods
.deposit(new anchor.BN(100))
.accounts({
balanceAccount: balanceAccount.publicKey,
user: badActor.publicKey,
})
.rpc();
assert.fail("Giao dịch lẽ ra phải bị từ chối");
} catch (err) {
assert.ok(err, "Anchor đã từ chối giao dịch chưa ký");
}
});Localnet so với devnet: Sử dụng anchor test (localnet) cho tất cả quá trình phát triển tích cực. Localnet tức thời và miễn phí, và nó đặt lại giữa các lần chạy. Chỉ triển khai lên devnet khi bạn muốn chia sẻ URL cố định hoặc kiểm thử trong điều kiện mạng thực tế.
Mocha là trình chạy kiểm thử (cấu trúc khối describe và it). Chai cung cấp cú pháp khẳng định (assert.equal, assert.ok, expect). Cả hai đều được cấu hình sẵn trong mọi dự án anchor init và không yêu cầu cài đặt riêng.
Anchor so với các lựa chọn thay thế: Chọn Lộ trình Phát triển Solana của bạn
Ba lộ trình phát triển tồn tại để xây dựng trên Solana: Anchor Framework, Rust gốc mà không có framework và Seahorse. Bản thân Solana là một trong nhiều blockchain đáng để đánh giá cho dự án của bạn. Các bảng dưới đây trình bày sự khác biệt chính mà không có sự thiên vị.
Bảng 1: Các Phương pháp Phát triển Solana
| Anchor | Rust Gốc (Không Framework) | Seahorse | |
|---|---|---|---|
| Ngôn ngữ | Rust + TypeScript client | Chỉ Rust | Python (biên dịch sang Rust) |
| Boilerplate yêu cầu | Thấp (macro xử lý xác thực) | Cao (mã xác thực thủ công) | Thấp |
| Độ trưởng thành sản phẩm | Sẵn sàng cho sản phẩm | Sẵn sàng cho sản phẩm | Đang thử nghiệm |
| Quy mô cộng đồng | Lớn (tiêu chuẩn thực tế) | Trung bình | Nhỏ |
| Lộ trình học tập | Trung bình (cần kiến thức Rust cơ bản) | Dốc (cần kiến thức Rust đầy đủ) | Thấp (cú pháp Python) |
| Tạo IDL/client | Tự động | Thủ công | Qua Anchor (bên dưới hệ thống) |
| Tốt nhất cho | Hầu hết phát triển ứng dụng Solana | Các chương trình cấp hệ thống cần toàn quyền kiểm soát | Lập trình viên Python đang tạo nguyên mẫu |
Bảng 2: Công cụ Solana so với Ethereum
| Anchor (Solana) | Hardhat (Ethereum) | Foundry (Ethereum) | |
|---|---|---|---|
| Blockchain | Solana | Ethereum | Ethereum |
| Ngôn ngữ chính | Rust | Solidity + JavaScript | Solidity |
| Ngôn ngữ kiểm thử | TypeScript (Mocha) | JavaScript/TypeScript | Solidity (gốc) |
| Mô hình chương trình | Chương trình không trạng thái + tài khoản riêng biệt | Hợp đồng có trạng thái | Hợp đồng có trạng thái |
| Thông lượng | ~65,000 TPS (tối ưu, tính đến 2024) | ~15–30 TPS (Mainnet, tính đến 2024) | ~15–30 TPS (Mainnet, tính đến 2024) |
| Phí giao dịch | Thường dưới $0.001 | Thay đổi (thường $1–50+ mỗi tx) | Thay đổi (thường $1–50+ mỗi tx) |
| Độ trưởng thành hệ sinh thái | Đang phát triển; trẻ hơn | Hệ sinh thái Hợp đồng Thông minh lớn nhất | Hệ sinh thái Hợp đồng Thông minh lớn nhất |
| Nhóm kiểm toán bảo mật | Nhỏ hơn, đang phát triển | Lớn hơn, đã được thiết lập tốt | Lớn hơn, đã được thiết lập tốt |
| Tốt nhất cho | Các ứng dụng tần suất cao, phí thấp | Hệ sinh thái rộng nhất; hồ sơ theo dõi bảo mật tối đa | Người dùng Ethereum nâng cao ưu tiên kiểm thử Solidity gốc |
Khi nào nên chọn Anchor thay vì Rust gốc: Đối với nhiều trường hợp sử dụng phát triển ứng dụng Solana, bao gồm các giao thức DeFi, nền tảng NFT, hệ thống token-gating, DAO và trò chơi Trên chuỗi, Anchor là điểm khởi đầu phổ biến. Việc cắt giảm mã boilerplate là rất đáng kể: một chương trình yêu cầu 300 dòng trong Rust thô có thể chỉ mất 80 dòng với Anchor. Phát triển bằng Rust gốc sẽ hợp lý khi một chương trình yêu cầu kiểm soát chính xác mức tiêu thụ đơn vị tính toán, khi các lớp trừu tượng của Anchor xung đột với một cấu trúc bất thường hoặc khi một nhóm có chuyên môn sâu về Rust và cần sự linh hoạt tối đa.
Framework Seahorse: Seahorse cho phép các nhà phát triển viết các chương trình Solana bằng Python, sau đó Seahorse sẽ biên dịch thành Rust tương thích với Anchor bên dưới hệ thống. Điều này làm giảm rào cản ngôn ngữ cho các nhà phát triển Python muốn thử nghiệm với Solana mà không cần học Rust. Sự đánh đổi là độ trưởng thành: Seahorse là một dự án cộng đồng với cơ sở người dùng nhỏ hơn nhiều so với Anchor và không được khuyến khích cho các ứng dụng thực tế tính đến năm 2024. Để tạo nguyên mẫu, đây là một lựa chọn hợp lý; đối với sản phẩm thực tế, Anchor vẫn là tiêu chuẩn thực tế.
Ethereum so với Solana: Ethereum cung cấp hệ sinh thái nhà phát triển Hợp đồng Thông minh lớn nhất, lịch sử kiểm toán bảo mật sâu nhất và hỗ trợ công cụ rộng nhất. Solana cung cấp thông lượng cao hơn đáng kể và phí thấp hơn, giúp nó phù hợp hơn cho các ứng dụng mà tần suất giao dịch và chi phí là những ràng buộc chính. Các nền tảng này phù hợp với các hồ sơ ứng dụng khác nhau. Các nhà phát triển xây dựng cơ sở hạ tầng giao dịch tần suất cao hoặc trò chơi giao dịch vi mô có thể ưa chuộng Solana; các nhà phát triển xây dựng hệ thống quản trị hoặc tiêu chuẩn token cần khả năng tương thích hệ sinh thái tối đa có thể ưa chuộng Ethereum. Đối với hầu hết các ứng dụng Solana thực tế, Anchor là điểm khởi đầu phổ biến, được xác nhận bởi các giao thức lớn bao gồm Raydium, Marinade Finance và Metaplex khi chọn Anchor làm nền tảng của họ.
Bảo mật Framework Anchor: Năm lỗ hổng mọi nhà phát triển Solana phải biết
⚠️ CẢNH BÁO: Các lỗ hổng bảo mật trong các chương trình Solana có thể dẫn đến việc mất tiền của người dùng vĩnh viễn, không thể đảo ngược. Trước khi triển khai bất kỳ chương trình nào lên Mainnet, hãy chạy nó qua một công cụ phân tích tĩnh như Soteria và cân nhắc thực hiện kiểm toán bảo mật chuyên nghiệp. Hệ sinh thái Solana đã trải qua những vụ khai thác đáng kể từ chính những lỗ hổng được mô tả dưới đây. Đánh giá bảo mật là không bắt buộc đối với các chương trình sản phẩm. Để đọc sâu hơn, hãy tham khảo tài liệu chính thức của Anchor.
Hệ thống ràng buộc của Anchor, các thuộc tính #[account(...)] trong cấu trúc tài khoản của bạn, là tuyến phòng thủ bảo mật đầu tiên. Nó tự động thực thi các kiểm tra quyền sở hữu, quyền thay đổi và xác minh loại mà nếu không bạn sẽ phải viết thủ công trong Rust thô. Nhưng các ràng buộc chỉ bảo vệ những gì bạn khai báo. Các lỗ hổng bên dưới phát sinh từ những gì nhà phát triển quên khai báo.
Thiếu kiểm tra người ký (Signer Check)
Bất kỳ tài khoản nào cũng có thể gọi lệnh của bạn nếu người gọi không bắt buộc phải ký giao dịch. Điều này cho phép bất kỳ ví nào gọi các lệnh đáng lẽ phải bị hạn chế.
// DỄ BỊ TẤN CÔNG: AccountInfo không xác minh người gọi đã ký giao dịch
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub balance_account: Account<'info, BalanceAccount>,
pub user: AccountInfo<'info>, // Không có xác minh chữ ký
}// AN TOÀN: Signer<'info> làm thất bại giao dịch nếu tài khoản không ký
#[derive(Accounts)]
pub struct Deposit<'info> {
#[account(mut)]
pub balance_account: Account<'info, BalanceAccount>,
pub user: Signer<'info>, // Giao dịch bị đảo ngược nếu người dùng không ký
}Sử dụng Signer<'info> cho bất kỳ tài khoản nào cần ủy quyền một lệnh.
Thiếu kiểm tra quyền sở hữu (Thay thế tài khoản)
Kẻ tấn công có thể thay thế bằng một tài khoản được tạo độc hại có cùng bố cục dữ liệu như tài khoản mong đợi của bạn nhưng thuộc sở hữu của một chương trình khác.
// DỄ BỊ TẤN CÔNG: AccountInfo không xác minh chủ sở hữu chương trình của tài khoản
pub balance_account: AccountInfo<'info>, // Chấp nhận bất kỳ tài khoản nào// AN TOÀN: Account<'info, T> xác minh tài khoản thuộc sở hữu của chương trình của bạn
pub balance_account: Account<'info, BalanceAccount>, // Kiểm tra quyền sở hữu là tự độngLuôn sử dụng trình bao bọc Account<'info, T> có định kiểu của Anchor thay vì AccountInfo<'info> thô cho các tài khoản chứa dữ liệu do chương trình kiểm soát.
Tấn công tái khởi tạo (Reinitialization Attack)
Nếu một lệnh initialize có thể chạy nhiều lần trên cùng một tài khoản, kẻ tấn công có thể Reset trạng thái đáng lẽ phải là vĩnh viễn.
// DỄ BỊ TẤN CÔNG: init_if_needed âm thầm chấp nhận các tài khoản đã được khởi tạo
#[account(init_if_needed, payer = user, space = 8 + 8)]
pub balance_account: Account<'info, BalanceAccount>,// AN TOÀN: init đảo ngược nếu tài khoản đã tồn tại
#[account(init, payer = user, space = 8 + 8)]
pub balance_account: Account<'info, BalanceAccount>,Sử dụng init (không phải init_if_needed) cho các tài khoản chỉ nên được tạo một lần. Nếu init_if_needed thực sự cần thiết, hãy thêm một cờ khởi tạo rõ ràng và kiểm tra nó trong logic lệnh của bạn.
Tràn số nguyên (Integer Overflow và Underflow)
Phép toán của Rust sẽ panic khi bị tràn số trong các bản build debug nhưng lại tự động xoay vòng (wrap) âm thầm trong các bản build release, điều này có thể làm hỏng Số dư tài chính mà không báo lỗi.
// DỄ BỊ TẤN CÔNG: phép toán trực tiếp xoay vòng âm thầm trong chế độ release
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
ctx.accounts.balance_account.total += amount;
Ok(())
}// AN TOÀN: checked_add trả về một Err thay vì xoay vòng khi bị tràn
pub fn deposit(ctx: Context<Deposit>, amount: u64) -> Result<()> {
ctx.accounts.balance_account.total = ctx.accounts.balance_account.total
.checked_add(amount)
.ok_or(error!(ErrorCode::Overflow))?;
Ok(())
}Sử dụng checked_add, checked_sub, và checked_mul cho tất cả các phép toán trên các giá trị tài chính. Định nghĩa một enum ErrorCode tùy chỉnh với biến thể Overflow để có thông báo lỗi rõ ràng.
Chuẩn hóa PDA Bump
Sử dụng seed bump không chuẩn có thể tạo ra một địa chỉ PDA hợp lệ nhưng không mong muốn, cho phép các cuộc tấn công giả mạo địa chỉ.
// VULNERABLE: manual bump not guaranteed to be canonical
#[account(seeds = [b"vault", user.key().as_ref()], bump = ctx.accounts.vault.bump)]
pub vault: Account<'info, Vault>,// SECURE: omit the explicit bump value. Anchor v0.29.x derives and verifies
// the canonical bump automatically
#[account(
seeds = [b"vault", user.key().as_ref()],
bump,
)]
pub vault: Account<'info, Vault>,Trong Anchor v0.29.x, hãy bỏ qua giá trị bump tường minh và để Anchor tự suy ra canonical bump. Nếu bạn lưu trữ bump trong dữ liệu tài khoản, hãy điền nó trong quá trình init bằng cách sử dụng ctx.bumps.vault.
Đối với các thông báo lỗi bạn gặp phải khi triển khai các mô hình bảo mật này, hãy xem phần khắc phục sự cố.
Khắc phục các lỗi Anchor phổ biến
Các lỗi dưới đây đại diện cho những vấn đề phổ biến nhất mà các nhà phát triển gặp phải khi xây dựng với Anchor Framework. Mỗi mục bao gồm thông báo lỗi chính xác, nguyên nhân và cách khắc phục.
📌 LƯU Ý: Sự không khớp phiên bản gây ra phần lớn các lỗi thất bại khi chạy anchor build. Hãy kiểm tra bảng này trước khi tìm hiểu các nguyên nhân khác.
| Phiên bản Anchor | Yêu cầu Solana CLI | Yêu cầu Rust |
|---|---|---|
| v0.29.x | v1.18.x trở lên | 1.70.0 trở lên |
| v0.28.x | v1.16.x trở lên | 1.69.0 trở lên |
Lỗi 1: AccountNotInitialized
AnchorError caused by account: balance_account.
Error Code: AccountNotInitialized.
Error Number: 3012.Nguyên nhân: Chương trình của bạn đã cố gắng đọc một tài khoản dữ liệu chưa tồn tại Trên chuỗi. Chỉ lệnh initialize vẫn chưa được gọi.
Cách khắc phục: Gọi chỉ lệnh initialize của bạn trước bất kỳ chỉ lệnh nào thực hiện đọc từ tài khoản. Trong các bản kiểm thử, hãy đảm bảo khối it khởi tạo chạy trước khối kiểm thử nạp tiền.
Lỗi 2: Type Mismatch (Không khớp kiểu) khi chạy anchor build
error[E0308]: mismatched types
expected struct `anchor_lang::prelude::AccountInfo`
found struct `anchor_lang::accounts::signer::Signer`Nguyên nhân: Mã của bạn sử dụng cú pháp ràng buộc tài khoản từ Anchor v0.26.x trở về trước, vốn đã thay đổi trong v0.29.x.
Cách khắc phục: Kiểm tra tài liệu chính thức của Anchor) để biết cú pháp ràng buộc của v0.29.x. Chạy avm use 0.29.0 để xác nhận phiên bản CLI của bạn khớp với dependency trong Cargo.toml.
Lỗi 3: Không tương thích phiên bản CLI Anchor/Solana
Error: RPC response error -32002: Transaction simulation failedNguyên nhân: Phiên bản CLI Anchor và phiên bản CLI Solana của bạn không tương thích.
Cách khắc phục:
avm use 0.29.0
solana --version # Xác nhận Solana CLI là 1.18.x trở lênLỗi 4: Không khớp declare_id! sau khi triển khai lại
Error: Program Id mismatchNguyên nhân: Bạn đã triển khai lại vào một địa chỉ mới nhưng declare_id!() trong lib.rs vẫn giữ Program ID cũ.
Cách khắc phục:
anchor keys sync
anchor buildLỗi 5: Không đủ tiền trên Devnet
Error: Transaction simulation failed: insufficient fundsNguyên nhân: Ví devnet của bạn không có đủ SOL để trả phí triển khai hoặc phí giao dịch.
Cách khắc phục:
solana airdrop 2
solana balanceLỗi 6: Bản phân nhị phân chương trình vượt quá giới hạn kích thước
Error: account data too small for instructionNguyên nhân: Bản phân nhị phân chương trình đã biên dịch của bạn vượt quá giới hạn kích thước chương trình của Solana đối với các chương trình có thể nâng cấp.
Cách khắc phục: Thêm các tối ưu hóa bản phát hành (release optimizations) vào Cargo.toml của bạn:
[profile.release]
opt-level = "z"
lto = trueXóa các dependency và feature flag không sử dụng khỏi Cargo.toml và Anchor.toml.
Nếu bạn gặp lỗi phiên bản, hãy quay lại hướng dẫn cài đặt và xác minh các phiên bản công cụ của bạn khớp với bảng tương thích ở trên.
Anchor Framework và Hệ sinh thái Nhà phát triển của Solana
Anchor Framework cung cấp sức mạnh cho phần lớn các chương trình thực tế được triển khai trên Mainnet của Solana, bao gồm các giao thức trong Tài chính phi tập trung (DeFi), cơ sở hạ tầng Tài sản Thế giới thực (NFT) và quản trị Trên chuỗi.
Các giao thức thực tế được xây dựng bằng Anchor:
- Raydium: Nhà tạo lập thị trường tự động (AMM) và giao thức thanh khoản
- Marinade Finance: Giao thức Staking thanh khoản cho SOL
- Metaplex: Tiêu chuẩn NFT, siêu dữ liệu token và bộ công cụ
- Drift Protocol: Sàn giao dịch phái sinh phi tập trung
- Kamino Finance: Giao thức Thanh khoản và cho vay
- Jito: Cơ sở hạ tầng validator và Staking nhận biết MEV
Các giao thức DeFi đại diện cho danh mục thống trị của các chương trình được triển khai bằng Anchor. Các sàn giao dịch phi tập trung, Nền tảng cho vay và các công cụ tổng hợp lợi nhuận đều dựa vào thông lượng của Solana (xấp xỉ 65.000 giao dịch mỗi giây trong điều kiện tối ưu, tính đến năm 2024) và phí thấp (thường dưới 0,001 USD cho mỗi giao dịch) cho các hoạt động cốt lõi của chúng. Sự tăng trưởng của các công cụ tài chính Trên chuỗi và token hóa Tài sản Thế giới thực trên Solana phản ánh sự trưởng thành của cơ sở hạ tầng này.
Theo Báo cáo Nhà phát triển Electric Capital (có sẵn tại electriccapital.com để biết các số liệu hiện tại), cơ sở nhà phát triển đang hoạt động của Solana đã tăng trưởng qua từng năm trong suốt năm 2023 và sang năm 2024. Sự gia tăng áp dụng của các nhà phát triển thường góp phần vào sức khỏe của hệ sinh thái Blockchain, mặc dù điều này không nên được hiểu là lời khuyên đầu tư.
SOL đóng vai trò là loại tiền tệ thanh toán phí của mạng lưới Solana. Mỗi giao dịch kích hoạt một chương trình Trên chuỗi đều tốn một lượng nhỏ SOL (có thể giao dịch trên các sàn giao dịch Tiền điện tử lớn bao gồm Coinbase và Binance). Để biết dữ liệu thị trường SOL hiện tại, hãy xem giá SOL hiện tại và dữ liệu thị trường trên CoinGecko.)
Nhiều nhà phát triển xây dựng bằng Anchor hơn có nghĩa là có nhiều chương trình được triển khai hơn, đồng nghĩa với việc mạng lưới Solana được sử dụng tích cực hơn. Mối liên hệ này là một sự quan sát về động lực của hệ sinh thái, không phải là một tín hiệu đầu tư.
Các câu hỏi thường gặp về Solana Anchor Framework
Solana sử dụng ngôn ngữ lập trình nào?
Các chương trình Solana được viết bằng Rust. Môi trường thực thi cũng hỗ trợ C và C++, nhưng Rust là tiêu chuẩn cho việc phát triển thực tế. Đối với mã phía máy khách, bao gồm các bản kiểm thử, tương tác giao diện người dùng và các tập lệnh gọi chương trình của bạn, TypeScript và JavaScript được sử dụng thông qua gói npm @coral-xyz/anchor. Anchor Framework bao gồm cả hai lớp: Rust cho logic chương trình và TypeScript cho mọi thứ tương tác với nó.
Có bắt buộc phải dùng Rust để sử dụng Anchor Framework không?
Có. Các chương trình Anchor được viết bằng Rust, và không có cách nào khác. Tuy nhiên, các macro của Anchor trừu tượng hóa các phần chuyên sâu nhất về Rust của quá trình phát triển Solana: xác thực tài khoản và lan truyền lỗi. Một nhà phát triển có kiến thức cơ bản về Rust (struct, hàm, trait, quyền sở hữu cơ bản) có thể xây dựng và triển khai một chương trình Anchor hoạt động tốt. Không yêu cầu chuyên môn sâu về Rust trong lifetimes, các mô hình không đồng bộ và các generic nâng cao để bắt đầu. Kỹ năng TypeScript hoặc JavaScript của bạn có thể áp dụng trực tiếp vào phía máy khách của mọi dự án Anchor.
Địa chỉ được tạo bởi chương trình (PDA) theo cách hiểu đơn giản là gì?
Địa chỉ được tạo bởi chương trình (PDA) là một địa chỉ tài khoản mà một chương trình kiểm soát thay vì một người dùng có Private Key. Bởi vì PDA không có Private Key, chỉ chương trình sở hữu mới có thể cấp quyền cho các giao dịch liên quan đến chúng. Với cùng các seed và ID chương trình, một PDA luôn cho ra cùng một địa chỉ, điều này cho phép các máy khách tìm thấy các tài khoản do chương trình kiểm soát mà không cần lưu trữ địa chỉ của chúng một cách riêng biệt. Anchor tự động xử lý việc tạo PDA thông qua ràng buộc seeds trong các struct tài khoản của bạn. PDA thường được sử dụng cho các kho lưu trữ do chương trình kiểm soát, tài khoản ký quỹ và lưu trữ dữ liệu cho mỗi người dùng.
Bạn có thể xây dựng NFT bằng Anchor Framework không?
Có. Phần lớn cơ sở hạ tầng NFT của Solana được xây dựng trên Anchor. Tiêu chuẩn Metaplex, xác định siêu dữ liệu token, cấu trúc bộ sưu tập và tiền bản quyền cho các NFT của Solana, bản thân nó là một chương trình dựa trên Anchor. Bất kỳ Nền tảng NFT nào trên Solana đều tương tác với các chương trình của Metaplex thông qua Lời gọi chương trình chéo (CPI) bằng cách sử dụng crate anchor-spl, nơi cung cấp các trình bao bọc an toàn về kiểu dữ liệu (type-safe wrappers) cho các chỉ lệnh SPL Token.
Anchor Framework có được bảo trì tích cực không?
Vâng. Anchor được duy trì bởi Coral XYZ và là tiêu chuẩn thực tế để phát triển chương trình Solana tính đến năm 2024. Phiên bản ổn định hiện tại là v0.29.x. Kho lưu trữ Anchor GitHub (coral-xyz/anchor) nhận được các bản phát hành thường xuyên theo dõi các bản cập nhật thời gian chạy của Solana. Các giao thức sản xuất chính, bao gồm Raydium, Marinade Finance và Metaplex, tiếp tục xây dựng trên Anchor, xác nhận mức độ sẵn sàng cho sản xuất của nó.
Anchor so với Hardhat của Ethereum như thế nào?
Anchor và Hardhat đóng vai trò tương tự trên các Blockchain tương ứng: cả hai đều cung cấp khung dự án, môi trường thử nghiệm và công cụ triển khai. Sự khác biệt bắt đầu từ kiến trúc cơ bản. Hardhat hướng tới mô hình hợp đồng có trạng thái của Ethereum, nơi một Hợp đồng Thông minh nắm giữ cả logic và trạng thái của nó. Anchor hướng tới mô hình chương trình không trạng thái của Solana, nơi các chương trình và dữ liệu nằm trong các tài khoản riêng biệt. Các ngôn ngữ cũng khác nhau: các dự án Hardhat sử dụng Solidity cho các hợp đồng và JavaScript hoặc TypeScript cho các thử nghiệm; các dự án Anchor sử dụng Rust cho các chương trình và TypeScript cho các thử nghiệm. Chi phí giao dịch cũng khác nhau đáng kể: các giao dịch Solana thường có giá dưới 0,001 USD, trong khi phí gas Ethereum thay đổi và có thể lên tới 1 USD đến 50 USD hoặc hơn cho mỗi giao dịch. Để so sánh chi tiết song song, hãy xem các bảng so sánh Anchor và các lựa chọn thay thế.
Mất bao lâu để học Anchor Framework?
Một nhà phát triển có kinh nghiệm về TypeScript hoặc JavaScript và không có kiến thức trước đó về Rust thường có thể xây dựng và triển khai một chương trình Anchor cơ bản lên devnet trong vòng một đến hai ngày bằng cách sử dụng hướng dẫn có cấu trúc. Việc chuyển từ một chương trình cơ bản sang một giao thức DeFi sản xuất mất vài tuần đến vài tháng, tùy thuộc vào độ phức tạp của chương trình và chiều sâu của Rust. Đường cong học tập Rust là biến số chính. Các nhà phát triển dành thời gian cho các kiến thức cơ bản về Rust cùng với Anchor sẽ thấy tiến độ nhanh hơn trên các chương trình không tầm thường.
Thư viện Chương trình Solana (SPL) là gì?
Thư viện Chương trình Solana (SPL) là một tập hợp các chương trình đã được triển khai trước, được kiểm tra trên Solana cho các hoạt động phổ biến. Chương trình SPL Token tương đương với tiêu chuẩn ERC-20 của Solana, được triển khai dưới dạng một chương trình Trên chuỗi dùng chung thay vì một mẫu hợp đồng mà mọi dự án triển khai độc lập. Anchor tích hợp với SPL thông qua crate anchor-spl, cung cấp các trình bao bọc an toàn kiểu cho các hướng dẫn SPL Token bao gồm transfer, mint_to và burn. SPL cũng là nền tảng cho siêu dữ liệu token NFT thông qua chương trình Metaplex.
Proof of History (PoH) trong Solana là gì?
Proof of History (PoH) là một cơ chế đo thời gian mật mã mà Solana sử dụng để sắp xếp các giao dịch trước khi chúng đến tay người xác thực để đồng thuận. Thay vì yêu cầu những người xác thực giao tiếp để đồng ý về thứ tự giao dịch, PoH nhúng một chuỗi dấu thời gian có thể xác minh trực tiếp vào Blockchain. Điều này làm giảm chi phí điều phối của các giao thức đồng thuận truyền thống và là một lý do khiến Solana đạt được khoảng 65.000 giao dịch mỗi giây trong các điều kiện tối ưu tính đến năm 2024.
Solana có tốt cho việc phát triển Hợp đồng Thông minh không?
Solana rất phù hợp cho các ứng dụng mà thông lượng giao dịch và chi phí là những hạn chế chính: các giao thức DeFi tần suất cao, thị trường NFT với nhiều giao dịch nhỏ và trò chơi Trên chuỗi. Mô hình tài khoản của nó đòi hỏi phải tìm hiểu trước nhiều hơn so với Ethereum, nhưng Anchor Framework giúp giảm đáng kể rào cản đó. Việc Solana có phải là lựa chọn đúng đắn hay không tùy thuộc vào hồ sơ ứng dụng của bạn. Ethereum cung cấp một hệ sinh thái lớn hơn và lịch sử kiểm tra bảo mật lâu đời hơn, trong khi Solana cung cấp phí thấp hơn và thông lượng cao hơn cho các trường hợp sử dụng có lợi từ cả hai.
Kết luận: Anchor Framework có phù hợp với dự án Solana của bạn không?
Đối với nhiều quy trình phát triển ứng dụng Solana, Anchor Framework là điểm bắt đầu phổ biến, trong khi Rust gốc vẫn phù hợp khi yêu cầu quyền kiểm soát ở mức thấp hơn.
Anchor giúp giảm đáng kể mã soạn sẵn của việc phát triển Rust thô. Các chương trình yêu cầu hàng trăm dòng mã Solana gốc chỉ tốn một phần nhỏ trong số đó với hệ thống macro của Anchor. Nó thực thi an toàn tài khoản thông qua hệ thống ràng buộc, bắt các lỗi quyền sở hữu và ủy quyền tại thời điểm biên dịch hoặc thời gian chạy thay vì trong sản xuất. Và nó tự động tạo một máy khách TypeScript từ IDL, cung cấp cho các nhà phát triển JavaScript một giao diện có kiểu, quen thuộc cho các chương trình của họ mà không cần viết Rust ở phía máy khách.
Phát triển Rust gốc chỉ đáng cân nhắc khi chương trình của bạn yêu cầu quyền kiểm soát chính xác đối với mức tiêu thụ đơn vị tính toán hoặc khi các lớp trừu tượng của Anchor thực sự xung đột với một kiến trúc bất thường. Đối với phần lớn các chương trình, bao gồm các giao thức DeFi, nền tảng NFT, DAO và hệ thống token-gating, Anchor là nơi bạn nên bắt đầu.
Các bước tiếp theo:
- Triển khai chương trình theo dõi Số dư từ hướng dẫn này lên devnet bằng lệnh
anchor deploy --provider.cluster devnet - Khám phá tài liệu chính thức của Anchor tại anchor-lang.com để biết tài liệu tham khảo API đầy đủ và các tính năng nâng cao
- Duyệt kho lưu trữ các ví dụ trên GitHub của Anchor để biết các chương trình theo mẫu sản xuất
- Tham gia Anchor Discord hoặc Solana Stack Exchange để được cộng đồng hỗ trợ khi bạn gặp vấn đề
Chương trình bạn đã triển khai trong hướng dẫn này là có thật: nó nằm trên devnet của Solana, chấp nhận các giao dịch và lưu trữ trạng thái Trên chuỗi. Đó là nền tảng mà mọi ứng dụng Solana sản xuất đều được xây dựng trên đó.
Hướng dẫn kỹ thuật Solana liên quan
Các nhà phát triển theo dõi SOL cùng với các công cụ hệ sinh thái có thể tham khảo trang giá SOL như một tham chiếu thị trường riêng biệt; nó không xác thực tính bảo mật của chương trình hoặc mức độ sẵn sàng triển khai.