Solana DokümantasyonuProgram geliştirmeTest Programları

Mollusk

Mollusk, Solana programlarını test etmek için hafif bir test harness'ıdır. Küçültülmüş bir Solana Virtual Machine (SVM) ortamında Solana program talimatlarını test etmek için basit bir arayüz sağlar. Tüm test hesapları açıkça tanımlanmalıdır, bu da deterministik ve tekrarlanabilir testler sağlar.

Kurulum

mollusk-svm dosyasına Cargo.toml bağımlılığı olarak ekleyin:

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

Compute unit kullanımını kıyaslamak için Cargo.toml dosyasına mollusk-svm-bencher bağımlılığını ekleyin:

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

Mollusk ile test için Token Program, token2022 programı (Token Extensions) ve Associated Token Program kullanmak için Cargo.toml dosyasına mollusk-svm-programs-token bağımlılığını ekleyin:

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

Mollusk SVM

Aşağıdaki örnek, Mollusk kullanarak temel bir Solana programını test etmek için minimal bir kurulum göstermektedir.

Hello World programı

Bu örnek, Mollusk kullanarak temel bir Solana programının nasıl test edileceğini göstermektedir. Program çağrıldığında program loglarına basitçe "Hello, world!" yazdırır.

cargo build-sbf komutunu çalıştırmak, derlenmiş programı /target/deploy/<program_name>.so konumunda oluşturur.

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()]);
}
}

Mollusk ile bir Solana programını test etmek için:

  1. Mollusk instance oluşturun - Mollusk'u bir program ID'si ve derlenmiş programa (.so dosyası) giden yol ile başlatın
  2. Bir talimat oluşturun - Programı çağırmak için bir talimat oluşturun
  3. İşleyin ve doğrulayın - Mollusk kullanarak talimatı işleyin ve sonucu doğrulayın
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()]);
}
}

Testi çalıştırmak için cargo test komutunu çalıştırın.

Test başarıyla çalıştığında, aşağıdakine benzer bir çıktı göreceksiniz:

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

Hello World programı

Bu örnek, Mollusk kullanarak temel bir Solana programının nasıl test edileceğini göstermektedir. Program çağrıldığında program loglarına basitçe "Hello, world!" yazdırır.

cargo build-sbf komutunu çalıştırmak, derlenmiş programı /target/deploy/<program_name>.so konumunda oluşturur.

Mollusk ile bir Solana programını test etmek için:

  1. Mollusk instance oluşturun - Mollusk'u bir program ID'si ve derlenmiş programa (.so dosyası) giden yol ile başlatın
  2. Bir talimat oluşturun - Programı çağırmak için bir talimat oluşturun
  3. İşleyin ve doğrulayın - Mollusk kullanarak talimatı işleyin ve sonucu doğrulayın
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()]);
}
}

Testi çalıştırmak için cargo test komutunu çalıştırın.

Test başarıyla çalıştığında, aşağıdakine benzer bir çıktı göreceksiniz:

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()]);
}
}

Mollusk struct'ı, Solana programlarını test etmek için basit bir arayüz sağlar. Tüm alanlar bir avuç yardımcı metot aracılığıyla manipüle edilebilir, ancak kullanıcılar daha fazla kontrol isterlerse bunlara doğrudan erişebilir ve değiştirebilir.

Mollusk'u varsayılan bir instance ile başlatmak için Mollusk::default metodunu kullanın.

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

Mollusk'u belirli bir programla başlatmak için Mollusk::new metodunu kullanın.

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");

Mollusk'a bir program eklemek için Mollusk::add_program metodunu kullanın.

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(),
);

Dosya yolunu sağlarken, .so uzantısını eklemeyin. Örneğin, "path/to/my_program" doğrudur, ancak "path/to/my_program.so" yanlıştır.

Instruction'ları işleme

Mollusk, instruction'ları işlemek için dört ana metot sağlar:

MetotAçıklama
process_instructionBir instruction'ı işler ve sonucu döndürür.
process_and_validate_instructionBir instruction'ı işler ve sonuç üzerinde bir dizi kontrol gerçekleştirir, herhangi bir kontrol başarısız olursa panic yapar.
process_instruction_chainBirden fazla instruction'ı işler ve sonucu döndürür.
process_and_validate_instruction_chainBirden fazla instruction'ı işler ve her sonuç üzerinde bir dizi kontrol gerçekleştirir, herhangi bir kontrol başarısız olursa panic yapar.

InstructionResult, işlenmiş bir instruction'ın detaylarını içerir.

Tek talimat

Sonuç üzerinde kontrol yapmadan tek bir talimatı işlemek için process_instruction yöntemini kullanın. İşlemden sonra sonuçları manuel olarak doğrulayabilirsiniz.

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

Aşağıdaki örnek, doğrulama kontrolleri olmadan bir SOL transfer talimatını işler.

Aşağıdaki örnekler, gösterim amacıyla Mollusk'u main fonksiyonunda çalıştırır. Pratikte, Mollusk'u genellikle #[test] niteliğiyle işaretlenmiş bir test modülünde kullanacaksınız.

Single Instruction
use mollusk_svm::Mollusk;
use solana_sdk::{account::Account, pubkey::Pubkey};
use solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID};
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 = 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.

Kontrollerle tek talimat

Doğrulama kontrolleriyle tek bir talimatı işlemek için process_and_validate_instruction yöntemini kullanın. Bu yöntem, herhangi bir kontrol başarısız olursa panic yapar.

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

Aşağıdaki örnek, doğrulama kontrolleriyle bir SOL transfer talimatını işler.

With Validation
use {
mollusk_svm::{result::Check, Mollusk},
solana_sdk::{account::Account, pubkey::Pubkey},
solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};
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 = 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.

Birden fazla talimat

Doğrulama kontrolleri olmadan birden fazla talimatı sırayla işlemek için process_instruction_chain yöntemini kullanın.

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

Aşağıdaki örnek, doğrulama kontrolleri olmadan iki SOL transfer talimatını işler.

Multiple Instructions
use {
mollusk_svm::Mollusk,
solana_sdk::{account::Account, pubkey::Pubkey},
solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};
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![
transfer(&alice, &bob, 300_000), // Alice -> Bob
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.

Kontrollerle birden fazla talimat

Her talimatın ardından doğrulama kontrolleriyle birden fazla talimatı işlemek için process_and_validate_instruction_chain yöntemini kullanın. Her talimatın geçmesi gereken kendi kontrol seti vardır.

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

Aşağıdaki örnek, her talimatın ardından doğrulama kontrolleriyle iki SOL transfer talimatından oluşan bir zinciri işler.

With Validation
use {
mollusk_svm::{result::Check, Mollusk},
solana_sdk::{account::Account, pubkey::Pubkey},
solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};
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 = transfer(&alice, &bob, 300_000);
let transfer2 = 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.

Doğrulama kontrolleri

Mollusk, işlenmiş bir talimatın sonuçlarını kontrol etmek için bir dizi yardımcı yöntem sağlar.

Example
use mollusk_svm::result::Check;

Talimat sonuçlarını doğrulamak için aşağıdaki yöntemleri kullanın:

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])

Account durumlarını doğrulamak için aşağıdakileri kullanı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()

Kalıcı account durumu

MolluskContext, Mollusk etrafında, account_store aracılığıyla birden fazla talimat çağrısı boyunca account durumunu koruyan bir sarmalayıcıdır. Talimatları işleme yöntemleri Mollusk ile aynıdır.

Mollusk'den farklı olarak, her yönteme accounts iletilmesini gerektiren (örn. process_instruction), MolluskContext account'ları account_store aracılığıyla dahili olarak yönetir. Bu, talimatları işlerken accounts parametresine ihtiyacı ortadan kaldırır.

with_context yöntemini kullanarak bir account_store oluşturun:

Example
use std::collections::HashMap;
use solana_sdk::{account::Account, pubkey::Pubkey};
use solana_system_interface::program::ID as SYSTEM_PROGRAM_ID;
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);

Aşağıdaki örnek, account_store aracılığıyla talimatlar arasında kalıcı account durumu ile iki ayrı SOL transfer talimatını işler.

Stateful Testing
use {
mollusk_svm::Mollusk,
solana_sdk::{account::Account, pubkey::Pubkey},
solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
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 = transfer(&sender, &recipient, 200_000);
context.process_instruction(&instruction1);
// Second transfer: 100,000 lamports (state persists from first transfer)
let instruction2 = 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, test için değerlerini değiştirmek üzere özel bir Sysvars struct'ı sağlar.

Belirli bir slot'a zamanda ileri veya geri gitmek için sysvar clock'u güncellemek üzere warp_to_slot yöntemini kullanın.

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.

Aşağıdaki örnek, rent parametrelerini değiştirmek için sysvars alanına erişerek Mollusk sysvar'ını doğrudan nasıl değiştireceğinizi gösterir. Diğer sysvar değerlerini de aynı şekilde değiştirebilirsiniz.

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.

Compute unit kıyaslaması

MolluskComputeUnitBencher bir programın talimatlarının compute unit kullanımını takip eder. Sonuçlar bir markdown dosyasına yazılır.

Bağımlılık olarak mollusk-svm-bencher gerektirir.

Aşağıdaki örnek, bir SOL transfer talimatının compute unit kullanımını kıyaslar.

Benchmark Compute Units
use {
mollusk_svm::Mollusk,
mollusk_svm_bencher::MolluskComputeUnitBencher,
solana_sdk::{account::Account, pubkey::Pubkey},
solana_system_interface::{instruction::transfer, program::ID as SYSTEM_PROGRAM_ID},
};
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 = 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ıyaslama sonuçları, belirtilen out_dir konumuna compute_units.md adlı bir markdown dosyası olarak yazılır.

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 - |

Token Program testi

Test için Token Program, token2022 programı (Token Extensions) ve Associated Token Program'ı Mollusk'a eklemek için mollusk-svm-programs-token crate'ini kullanın.

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);

Aşağıdaki örnek, Mollusk kullanarak bir token transferinin test edilmesini gösterir.

Aşağıdaki örnek, gösterim amacıyla test hesaplarını manuel olarak tanımlar. mollusk-svm-programs-token, mint ve token hesapları oluşturmak için yardımcı fonksiyonlar da içerir.

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_interface::{
instruction::transfer_checked,
state::{Account as TokenAccount, AccountState, 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: 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: 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?

İçindekiler

Sayfayı Düzenle

Yönetici

© 2026 Solana Vakfı.
Tüm hakları saklıdır.
Bağlanın