Tài liệu SolanaPhát triển chương trìnhKiểm thử chương trình

Mollusk

Mollusk là một công cụ kiểm thử nhẹ dùng để kiểm thử các chương trình Solana. Nó cung cấp một giao diện đơn giản để kiểm thử các lệnh của chương trình Solana trong môi trường Máy Ảo Solana (SVM) đã được thu gọn. Tất cả các tài khoản kiểm thử phải được định nghĩa rõ ràng, đảm bảo các bài kiểm thử có tính xác định và có thể lặp lại.

Cài đặt

Thêm mollusk-svm như một dependency trong Cargo.toml:

Terminal
$
cargo add mollusk-svm --dev
Cargo.toml
[dev-dependencies]
mollusk-svm = "0.5"

Để đánh giá hiệu suất sử dụng đơn vị tính toán, thêm mollusk-svm-bencher như một dependency trong Cargo.toml:

Terminal
$
cargo add mollusk-svm-bencher --dev
Cargo.toml
[dev-dependencies]
mollusk-svm-bencher = "0.5"

Để sử dụng Token Program, Token2022 Program (Token Extensions), và Associated Token Program cho việc kiểm thử với Mollusk, thêm mollusk-svm-programs-token như một dependency trong Cargo.toml:

Terminal
$
cargo add mollusk-svm-programs-token --dev
Cargo.toml
[dev-dependencies]
mollusk-svm-programs-token = "0.5"

Mollusk SVM

Ví dụ sau đây cho thấy một thiết lập tối thiểu để kiểm thử một chương trình Solana cơ bản sử dụng Mollusk.

Chương trình Hello World

Ví dụ này minh họa cách kiểm thử một chương trình Solana cơ bản sử dụng Mollusk. Chương trình đơn giản in ra "Hello, world!" vào nhật ký chương trình khi được gọi.

Chạy cargo build-sbf sẽ tạo ra chương trình đã biên dịch tại /target/deploy/<program_name>.so.

src/lib.rs
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("Hello, world!");
Ok(())
}
#[cfg(test)]
mod tests {
use mollusk_svm::{result::Check, Mollusk};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
#[test]
fn test_hello_world() {
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");
let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
}
}

Để kiểm thử một chương trình Solana với Mollusk:

  1. Tạo một thể hiện Mollusk - Khởi tạo Mollusk với một program ID và đường dẫn đến chương trình đã biên dịch (tệp .so)
  2. Xây dựng một lệnh - Tạo một lệnh để gọi chương trình
  3. Xử lý và xác thực - Xử lý lệnh sử dụng Mollusk và xác thực kết quả
src/lib.rs
#[cfg(test)]
mod tests {
use mollusk_svm::{result::Check, Mollusk};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
#[test]
fn test_hello_world() {
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");
let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
}
}

Để thực thi bài kiểm tra, hãy chạy cargo test.

Khi bài kiểm tra chạy thành công, bạn sẽ thấy kết quả tương tự như sau:

Terminal
running 1 test
[2025-09-22T19:25:50.427685000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs invoke [1]
[2025-09-22T19:25:50.429669000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, world!
[2025-09-22T19:25:50.429690000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs consumed 211 of 1400000 compute units
[2025-09-22T19:25:50.429726000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs success
test tests::test_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
Doc-tests hello_world

Chương trình Hello World

Ví dụ này minh họa cách kiểm thử một chương trình Solana cơ bản sử dụng Mollusk. Chương trình đơn giản in ra "Hello, world!" vào nhật ký chương trình khi được gọi.

Chạy cargo build-sbf sẽ tạo ra chương trình đã biên dịch tại /target/deploy/<program_name>.so.

Để kiểm thử một chương trình Solana với Mollusk:

  1. Tạo một thể hiện Mollusk - Khởi tạo Mollusk với một program ID và đường dẫn đến chương trình đã biên dịch (tệp .so)
  2. Xây dựng một lệnh - Tạo một lệnh để gọi chương trình
  3. Xử lý và xác thực - Xử lý lệnh sử dụng Mollusk và xác thực kết quả
src/lib.rs
#[cfg(test)]
mod tests {
use mollusk_svm::{result::Check, Mollusk};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
#[test]
fn test_hello_world() {
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");
let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
}
}

Để thực thi bài kiểm tra, hãy chạy cargo test.

Khi bài kiểm tra chạy thành công, bạn sẽ thấy kết quả tương tự như sau:

Terminal
running 1 test
[2025-09-22T19:25:50.427685000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs invoke [1]
[2025-09-22T19:25:50.429669000Z DEBUG solana_runtime::message_processor::stable_log] Program log: Hello, world!
[2025-09-22T19:25:50.429690000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs consumed 211 of 1400000 compute units
[2025-09-22T19:25:50.429726000Z DEBUG solana_runtime::message_processor::stable_log] Program 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs success
test tests::test_hello_world ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.02s
Doc-tests hello_world
lib.rs
hello_world.so
Cargo.toml
use solana_program::{
account_info::AccountInfo, entrypoint, entrypoint::ProgramResult, msg, pubkey::Pubkey,
};
entrypoint!(process_instruction);
pub fn process_instruction(
_program_id: &Pubkey,
_accounts: &[AccountInfo],
_instruction_data: &[u8],
) -> ProgramResult {
msg!("Hello, world!");
Ok(())
}
#[cfg(test)]
mod tests {
use mollusk_svm::{result::Check, Mollusk};
use solana_sdk::{instruction::Instruction, pubkey::Pubkey};
#[test]
fn test_hello_world() {
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/hello_world");
let instruction = Instruction::new_with_bytes(program_id, &[], vec![]);
mollusk.process_and_validate_instruction(&instruction, &[], &[Check::success()]);
}
}

Cấu trúc Mollusk cung cấp một giao diện đơn giản để kiểm tra các chương trình Solana. Tất cả các trường có thể được điều chỉnh thông qua một số phương thức hỗ trợ, nhưng người dùng cũng có thể trực tiếp truy cập và sửa đổi chúng nếu họ muốn kiểm soát nhiều hơn.

Để khởi tạo Mollusk với một thể hiện mặc định, hãy sử dụng phương thức Mollusk::default.

Example
// Default instance with no custom programs
let mollusk = Mollusk::default();

Để khởi tạo Mollusk với một chương trình cụ thể, hãy sử dụng phương thức Mollusk::new.

Example
// Initialize Mollusk with a specific program from a file path
let program_id = Pubkey::new_unique();
let mollusk = Mollusk::new(&program_id, "target/deploy/my_program");

Để thêm một chương trình vào Mollusk, hãy sử dụng phương thức Mollusk::add_program.

Example
let mollusk = Mollusk::default();
let program_id = Pubkey::new_unique();
// Add a program to Mollusk
mollusk.add_program(
&program_id,
"target/deploy/my_program",
&bpf_loader_upgradeable::id(),
);

Khi cung cấp đường dẫn tệp, không bao gồm phần mở rộng .so. Ví dụ, "path/to/my_program" là đúng, nhưng "path/to/my_program.so" thì không.

Xử lý các chỉ thị

Mollusk cung cấp bốn phương thức chính để xử lý các chỉ thị:

Phương thứcMô tả
process_instructionXử lý một chỉ thị và trả về kết quả.
process_and_validate_instructionXử lý một chỉ thị và thực hiện một loạt kiểm tra trên kết quả, gây panic nếu bất kỳ kiểm tra nào thất bại.
process_instruction_chainXử lý nhiều chỉ thị và trả về kết quả.
process_and_validate_instruction_chainXử lý nhiều chỉ thị và thực hiện một loạt kiểm tra trên mỗi kết quả, gây panic nếu bất kỳ kiểm tra nào thất bại.

InstructionResult chứa các chi tiết của một chỉ thị đã được xử lý.

Chỉ thị đơn lẻ

Sử dụng phương thức process_instruction để xử lý một chỉ thị đơn lẻ mà không kiểm tra kết quả. Bạn có thể tự xác thực kết quả sau khi xử lý.

Method Signature
pub fn process_instruction(
&self,
instruction: &Instruction,
accounts: &[(Pubkey, Account)],
) -> InstructionResult

Ví dụ sau đây xử lý một chỉ thị chuyển SOL mà không có kiểm tra xác thực.

Các ví dụ dưới đây chạy Mollusk trong hàm main cho mục đích minh họa. Trong thực tế, bạn thường sẽ sử dụng Mollusk trong một module kiểm thử được chú thích với thuộc tính #[test].

Single Instruction
use {
mollusk_svm::Mollusk,
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
};
fn main() {
// Initialize Mollusk
let mollusk = Mollusk::default();
// Set up accounts
let sender = Pubkey::new_unique();
let recipient = Pubkey::new_unique();
let initial_lamports = 1_000_000;
let transfer_amount = 250_000;
// Create transfer instruction
let instruction = system_instruction::transfer(&sender, &recipient, transfer_amount);
// Define initial account states
let accounts = vec![
(
sender,
Account {
lamports: initial_lamports,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
recipient,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
];
// Process the instruction
let result = mollusk.process_instruction(&instruction, &accounts);
println!("{:#?}", result);
// Check the result
assert!(result.program_result.is_ok());
assert_eq!(result.get_account(&sender).unwrap().lamports, 750_000);
assert_eq!(result.get_account(&recipient).unwrap().lamports, 250_000);
}
Console
Click to execute the code.

Chỉ thị đơn lẻ với kiểm tra

Sử dụng phương thức process_and_validate_instruction để xử lý một chỉ thị đơn lẻ với kiểm tra xác thực. Phương thức này sẽ gây panic nếu bất kỳ kiểm tra nào thất bại.

Method Signature
pub fn process_and_validate_instruction(
&self,
instruction: &Instruction,
accounts: &[(Pubkey, Account)],
checks: &[Check],
) -> InstructionResult

Ví dụ sau đây xử lý một chỉ thị chuyển SOL với kiểm tra xác thực.

With Validation
use {
mollusk_svm::{Mollusk, result::Check},
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
};
fn main() {
let mollusk = Mollusk::default();
let sender = Pubkey::new_unique();
let recipient = Pubkey::new_unique();
let initial_lamports = 1_000_000;
let transfer_amount = 250_000;
let instruction = system_instruction::transfer(&sender, &recipient, transfer_amount);
let accounts = vec![
(
sender,
Account {
lamports: initial_lamports,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
recipient,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
];
// Define validation checks
let checks = vec![
Check::success(),
Check::account(&sender)
.lamports(750_000)
.build(),
Check::account(&recipient)
.lamports(250_000)
.build(),
];
// Process and validate (will panic if any check fails)
let result = mollusk.process_and_validate_instruction(&instruction, &accounts, &checks);
println!("{:#?}", result);
}
Console
Click to execute the code.

Nhiều chỉ thị

Sử dụng phương thức process_instruction_chain để xử lý nhiều chỉ thị tuần tự mà không có kiểm tra xác thực.

Method Signature
pub fn process_instruction_chain(
&self,
instructions: &[Instruction],
accounts: &[(Pubkey, Account)],
) -> InstructionResult

Ví dụ sau đây xử lý hai chỉ thị chuyển SOL mà không có kiểm tra xác thực.

Multiple Instructions
use {
mollusk_svm::Mollusk,
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
};
fn main() {
let mollusk = Mollusk::default();
// Set up accounts
let alice = Pubkey::new_unique();
let bob = Pubkey::new_unique();
let charlie = Pubkey::new_unique();
let initial_lamports = 1_000_000;
// Create chain of transfers
let instructions = vec![
system_instruction::transfer(&alice, &bob, 300_000), // Alice -> Bob
system_instruction::transfer(&bob, &charlie, 100_000), // Bob -> Charlie
];
let accounts = vec![
(
alice,
Account {
lamports: initial_lamports,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
bob,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
charlie,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
];
// Process the instruction chain
let result = mollusk.process_instruction_chain(&instructions, &accounts);
println!("{:#?}", result);
// Final balances: Alice=700K, Bob=200K, Charlie=100K
assert_eq!(result.get_account(&alice).unwrap().lamports, 700_000);
assert_eq!(result.get_account(&bob).unwrap().lamports, 200_000);
assert_eq!(result.get_account(&charlie).unwrap().lamports, 100_000);
}
Console
Click to execute the code.

Nhiều chỉ thị với kiểm tra

Sử dụng phương thức process_and_validate_instruction_chain để xử lý nhiều chỉ thị với kiểm tra xác thực sau mỗi chỉ thị. Mỗi chỉ thị có bộ kiểm tra riêng phải vượt qua.

Method Signature
pub fn process_and_validate_instruction_chain(
&self,
instructions: &[(&Instruction, &[Check])],
accounts: &[(Pubkey, Account)],
) -> InstructionResult

Ví dụ sau đây xử lý một chuỗi hai chỉ thị chuyển SOL với kiểm tra xác thực sau mỗi chỉ thị.

With Validation
use {
mollusk_svm::{result::Check, Mollusk},
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
};
fn main() {
let mollusk = Mollusk::default();
// Create accounts
let alice = Pubkey::new_unique();
let bob = Pubkey::new_unique();
let charlie = Pubkey::new_unique();
let initial_lamports = 1_000_000;
// Create transfer instructions
let transfer1 = system_instruction::transfer(&alice, &bob, 300_000);
let transfer2 = system_instruction::transfer(&bob, &charlie, 100_000);
// Initial accounts
let accounts = vec![
(
alice,
Account {
lamports: initial_lamports,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
bob,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
charlie,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
];
// Define checks for each instruction
let checks_after_transfer1 = vec![
Check::success(),
Check::account(&alice)
.lamports(700_000) // 1M - 300K
.build(),
Check::account(&bob)
.lamports(300_000) // 0 + 300K
.build(),
Check::account(&charlie)
.lamports(0) // Unchanged
.build(),
];
let checks_after_transfer2 = vec![
Check::success(),
Check::account(&alice)
.lamports(700_000) // Unchanged from previous
.build(),
Check::account(&bob)
.lamports(200_000) // 300K - 100K
.build(),
Check::account(&charlie)
.lamports(100_000) // 0 + 100K
.build(),
];
// Process with validation at each step
let instruction_and_checks = [
(&transfer1, checks_after_transfer1.as_slice()),
(&transfer2, checks_after_transfer2.as_slice()),
];
// Execute chain (panics if any check fails)
let result = mollusk.process_and_validate_instruction_chain(&instruction_and_checks, &accounts);
println!("{:#?}", result);
}
Console
Click to execute the code.

Kiểm tra xác thực

Mollusk cung cấp một tập hợp phương thức hỗ trợ để kiểm tra kết quả của một lệnh đã được xử lý.

Example
use mollusk_svm::result::Check;

Sử dụng các phương thức sau để xác thực kết quả lệnh:

Example
// Program execution succeeded
Check::success()
// Program returned specific error
Check::err(ProgramError::InvalidArgument)
// Instruction level error
Check::instruction_err(InstructionError::InsufficientFunds)
// Check with specific program result
Check::program_result(ProgramResult::Success)
// Compute units consumed
Check::compute_units(1000)
// Execution time
Check::time(100)
// Return data from instruction execution
Check::return_data(&[1, 2, 3, 4])

Sử dụng các phương thức sau để xác thực trạng thái Tài khoản:

Example
// Single account validation
Check::account(&pubkey)
.lamports(1_000_000) // Exact lamports
.owner(&program_id) // Account owner
.data(&expected_data) // Exact data match
.data_slice(8, &[1, 2, 3]) // Partial data match at offset
.executable(false) // Executable flag
.space(100) // Account data size
.closed() // Account is closed (0 lamports)
.rent_exempt() // Account is rent-exempt
.build()
// Check all accounts are rent exempt
Check::all_rent_exempt()

Trạng thái Tài khoản Liên tục

MolluskContext là một wrapper bao quanh Mollusk để duy trì trạng thái tài khoản qua nhiều lệnh gọi thông qua account_store. Các phương thức xử lý lệnh giống hệt với Mollusk.

Không giống như Mollusk, yêu cầu truyền accounts vào mỗi phương thức (ví dụ process_instruction), MolluskContext quản lý tài khoản nội bộ thông qua account_store. Điều này loại bỏ nhu cầu tham số accounts khi xử lý các lệnh.

Tạo một account_store bằng cách sử dụng phương thức with_context:

Example
use std::collections::HashMap;
use solana_sdk::{account::Account, pubkey::Pubkey, system_program};
use mollusk_svm::Mollusk;
let mollusk = Mollusk::default();
let account_address = Pubkey::new_unique();
let mut account_store = HashMap::new();
account_store.insert(
account_address,
Account {
lamports: 1_000_000,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
);
let context = mollusk.with_context(account_store);

Ví dụ sau xử lý hai lệnh chuyển SOL riêng biệt với trạng thái tài khoản liên tục giữa các lệnh thông qua account_store.

Stateful Testing
use {
mollusk_svm::Mollusk,
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
std::collections::HashMap,
};
fn main() {
// Initialize Mollusk
let mollusk = Mollusk::default();
// Create accounts
let sender = Pubkey::new_unique();
let recipient = Pubkey::new_unique();
// Create account store with initial balances
let mut account_store = HashMap::new();
account_store.insert(
sender,
Account {
lamports: 1_000_000,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
);
account_store.insert(
recipient,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
);
// Create a stateful context
let context = mollusk.with_context(account_store);
// First transfer: 200,000 lamports
let instruction1 = system_instruction::transfer(&sender, &recipient, 200_000);
context.process_instruction(&instruction1);
// Second transfer: 100,000 lamports (state persists from first transfer)
let instruction2 = system_instruction::transfer(&sender, &recipient, 100_000);
context.process_instruction(&instruction2);
// Check final balances
let store = context.account_store.borrow();
let sender_account = store.get(&sender).unwrap();
let recipient_account = store.get(&recipient).unwrap();
println!("Sender: {:#?}", sender_account);
println!("Recipient: {:#?}", recipient_account);
}
Console
Click to execute the code.

Mollusk Sysvars

Mollusk cung cấp một Sysvars cấu trúc tùy chỉnh để sửa đổi giá trị của nó cho việc kiểm thử.

Sử dụng phương thức warp_to_slot để cập nhật đồng hồ sysvar nhằm mô phỏng việc di chuyển tiến hoặc lùi thời gian đến một slot cụ thể.

Warp to Slot
use mollusk_svm::Mollusk;
fn main() {
// Initialize Mollusk
let mut mollusk = Mollusk::default();
// Show initial slot
println!("Initial slot: {}", mollusk.sysvars.clock.slot);
// Warp to slot 1000
mollusk.warp_to_slot(100);
println!("After warp: {}", mollusk.sysvars.clock.slot);
// Warp to slot 10
mollusk.warp_to_slot(10);
println!("After second warp: {}", mollusk.sysvars.clock.slot);
}
Console
Click to execute the code.

Ví dụ sau cho thấy cách sửa đổi trực tiếp Mollusk sysvar bằng cách truy cập vào trường sysvars để thay đổi các tham số rent. Bạn có thể sửa đổi các giá trị sysvar khác theo cách tương tự.

Modify Sysvars
use {mollusk_svm::Mollusk, solana_sdk::rent::Rent};
fn main() {
let mut mollusk = Mollusk::default();
// Show default rent
println!(
"Default rent exemption for 1000 bytes: {} lamports",
mollusk.sysvars.rent.minimum_balance(1000)
);
// Customize rent parameters
mollusk.sysvars.rent = Rent {
lamports_per_byte_year: 1,
exemption_threshold: 1.0,
burn_percent: 0,
};
// Show custom rent
println!(
"Custom rent exemption for 1000 bytes: {} lamports",
mollusk.sysvars.rent.minimum_balance(1000)
);
}
Console
Click to execute the code.

Đánh giá hiệu suất đơn vị tính toán

MolluskComputeUnitBencher theo dõi mức sử dụng đơn vị tính toán của các lệnh trong chương trình. Kết quả được ghi vào tệp markdown.

Yêu cầu mollusk-svm-bencher làm dependency.

Ví dụ sau đánh giá hiệu suất mức sử dụng đơn vị tính toán của lệnh chuyển SOL.

Benchmark Compute Units
use {
mollusk_svm::Mollusk,
mollusk_svm_bencher::MolluskComputeUnitBencher,
solana_sdk::{account::Account, pubkey::Pubkey, system_instruction, system_program},
};
fn main() {
// Initialize Mollusk
let mollusk = Mollusk::default();
// Create test accounts
let sender = Pubkey::new_unique();
let receiver = Pubkey::new_unique();
// Transfer instruction
let transfer = system_instruction::transfer(&sender, &receiver, 100_000);
let accounts = vec![
(
sender,
Account {
lamports: 1_000_000,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
(
receiver,
Account {
lamports: 0,
data: vec![],
owner: system_program::id(),
executable: false,
rent_epoch: 0,
},
),
];
// Run benchmark
MolluskComputeUnitBencher::new(mollusk)
.bench(("transfer", &transfer, &accounts))
.must_pass(true)
.out_dir("./target/benches")
.execute();
}

Kết quả đánh giá hiệu suất được ghi vào out_dir đã chỉ định dưới dạng tệp markdown có tên compute_units.md.

comput_units.md
#### 2025-09-19 22:28:53.691839 UTC
Solana CLI Version: solana-cli 2.2.20 (src:dabc99a5; feat:3073396398,
client:Agave)
| Name | CUs | Delta |
| -------- | --- | ------- |
| transfer | 150 | - new - |

Kiểm thử Token Program

Sử dụng mollusk-svm-programs-token crate để thêm token program, token2022 program (token extensions), và associated token program vào Mollusk để kiểm thử.

Example
use {
mollusk_svm::Mollusk,
mollusk_svm_programs_token::{associated_token, token, token2022},
};
let mut mollusk = Mollusk::default();
// Add SPL Token Program
token::add_program(&mut mollusk);
// Add SPL Token-2022 Program
token2022::add_program(&mut mollusk);
// Add Associated Token Account Program
associated_token::add_program(&mut mollusk);

Ví dụ sau minh họa việc kiểm thử chuyển token sử dụng Mollusk.

Ví dụ dưới đây định nghĩa thủ công các tài khoản kiểm thử cho mục đích minh họa. mollusk-svm-programs-token cũng bao gồm các hàm trợ giúp để tạo mint và token account.

Token Transfer Example
use {
mollusk_svm::{result::Check, Mollusk},
mollusk_svm_programs_token::token,
solana_sdk::{account::Account, program_pack::Pack, pubkey::Pubkey},
spl_token::{
instruction::transfer_checked,
state::{Account as TokenAccount, Mint},
},
};
fn main() {
// Initialize Mollusk with Token program
let mut mollusk = Mollusk::default();
token::add_program(&mut mollusk);
// Create account keys
let mint = Pubkey::new_unique();
let source = Pubkey::new_unique();
let destination = Pubkey::new_unique();
let authority = Pubkey::new_unique();
// Token configuration
let decimals = 6;
let transfer_amount = 1_000_000; // 1 token with 6 decimals
let initial_balance = 10_000_000; // 10 tokens
// Calculate rent-exempt minimums
let mint_rent = mollusk.sysvars.rent.minimum_balance(Mint::LEN);
let account_rent = mollusk.sysvars.rent.minimum_balance(TokenAccount::LEN);
// Create mint account
let mut mint_data = vec![0u8; Mint::LEN];
Mint::pack(
Mint {
mint_authority: Some(authority).into(),
supply: initial_balance,
decimals,
is_initialized: true,
freeze_authority: None.into(),
},
&mut mint_data,
)
.unwrap();
// Create source token account
let mut source_data = vec![0u8; TokenAccount::LEN];
TokenAccount::pack(
TokenAccount {
mint,
owner: authority,
amount: initial_balance,
delegate: None.into(),
state: spl_token::state::AccountState::Initialized,
is_native: None.into(),
delegated_amount: 0,
close_authority: None.into(),
},
&mut source_data,
)
.unwrap();
// Create destination token account
let mut destination_data = vec![0u8; TokenAccount::LEN];
TokenAccount::pack(
TokenAccount {
mint,
owner: Pubkey::new_unique(),
amount: 0,
delegate: None.into(),
state: spl_token::state::AccountState::Initialized,
is_native: None.into(),
delegated_amount: 0,
close_authority: None.into(),
},
&mut destination_data,
)
.unwrap();
// Setup accounts for transfer_checked
let accounts = vec![
(
source,
Account {
lamports: account_rent,
data: source_data,
owner: token::ID,
executable: false,
rent_epoch: 0,
},
),
(
mint,
Account {
lamports: mint_rent,
data: mint_data,
owner: token::ID,
executable: false,
rent_epoch: 0,
},
),
(
destination,
Account {
lamports: account_rent,
data: destination_data,
owner: token::ID,
executable: false,
rent_epoch: 0,
},
),
(
authority,
Account {
lamports: 1_000_000,
data: vec![],
owner: Pubkey::default(),
executable: false,
rent_epoch: 0,
},
),
];
// Create transfer_checked instruction
let instruction = transfer_checked(
&token::ID,
&source,
&mint,
&destination,
&authority,
&[],
transfer_amount,
decimals,
)
.unwrap();
// Expected balances after transfer
let expected_source_balance = (initial_balance - transfer_amount).to_le_bytes();
let expected_dest_balance = transfer_amount.to_le_bytes();
// Define validation checks
let checks = vec![
Check::success(),
Check::account(&source)
.data_slice(64, &expected_source_balance) // Token amount is at offset 64
.build(),
Check::account(&destination)
.data_slice(64, &expected_dest_balance)
.build(),
];
// Process and validate the instruction
let result = mollusk.process_and_validate_instruction(&instruction, &accounts, &checks);
println!("{:#?}", result);
// Deserialize token account data
let source_account = result.get_account(&source).unwrap();
let source_token = TokenAccount::unpack(&source_account.data).unwrap();
println!("Source Token Account: {:#?}", source_token);
let destination_account = result.get_account(&destination).unwrap();
let dest_token = TokenAccount::unpack(&destination_account.data).unwrap();
println!("Destination Token Account: {:#?}", dest_token);
}
Console
Click to execute the code.

Is this page helpful?