Solana documentatieProgramma's ontwikkelenTestprogramma's

Mollusk

Mollusk is een lichtgewicht test framework voor het testen van Solana-programma's. Het biedt een eenvoudige interface voor het testen van Solana-programma-instructies in een geminimaliseerde Solana Virtual Machine (SVM) omgeving. Alle testaccounts moeten expliciet worden gedefinieerd, wat zorgt voor deterministische en herhaalbare tests.

Installatie

Voeg mollusk-svm toe als dependency in Cargo.toml:

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

Om het gebruik van compute units te benchmarken, voeg mollusk-svm-bencher toe als dependency in Cargo.toml:

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

Om het Token Program, token2022 programma (Token Extensions) en Associated Token Program te gebruiken voor testen met Mollusk, voeg mollusk-svm-programs-token toe als dependency in Cargo.toml:

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

Mollusk SVM

Het volgende voorbeeld toont een minimale setup voor het testen van een eenvoudig Solana-programma met Mollusk.

Hello World-programma

Dit voorbeeld laat zien hoe je een eenvoudig Solana-programma kunt testen met Mollusk. Het programma print simpelweg "Hello, world!" naar de programmalogs wanneer het wordt aangeroepen.

Het uitvoeren van cargo build-sbf genereert het gecompileerde programma op /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()]);
}
}

Om een Solana-programma te testen met Mollusk:

  1. Maak een Mollusk instantie - Initialiseer Mollusk met een programma-ID en het pad naar het gecompileerde programma (.so bestand)
  2. Bouw een instructie - Maak een instructie om het programma aan te roepen
  3. Verwerk en valideer - Verwerk de instructie met behulp van Mollusk en valideer het resultaat
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()]);
}
}

Om de test uit te voeren, voer cargo test uit.

Wanneer de test succesvol wordt uitgevoerd, zie je uitvoer vergelijkbaar met het volgende:

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

Dit voorbeeld laat zien hoe je een eenvoudig Solana-programma kunt testen met Mollusk. Het programma print simpelweg "Hello, world!" naar de programmalogs wanneer het wordt aangeroepen.

Het uitvoeren van cargo build-sbf genereert het gecompileerde programma op /target/deploy/<program_name>.so.

Om een Solana-programma te testen met Mollusk:

  1. Maak een Mollusk instantie - Initialiseer Mollusk met een programma-ID en het pad naar het gecompileerde programma (.so bestand)
  2. Bouw een instructie - Maak een instructie om het programma aan te roepen
  3. Verwerk en valideer - Verwerk de instructie met behulp van Mollusk en valideer het resultaat
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()]);
}
}

Om de test uit te voeren, voer cargo test uit.

Wanneer de test succesvol wordt uitgevoerd, zie je uitvoer vergelijkbaar met het volgende:

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

De Mollusk struct biedt een eenvoudige interface voor het testen van Solana-programma's. Alle velden kunnen worden gemanipuleerd via een handvol hulpmethoden, maar gebruikers kunnen ze ook direct openen en wijzigen als ze meer controle willen.

Om Mollusk te initialiseren met een standaard instantie gebruik je de Mollusk::default methode.

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

Om Mollusk te initialiseren met een specifiek programma gebruik je de Mollusk::new methode.

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

Om een programma toe te voegen aan Mollusk gebruik je de Mollusk::add_program methode.

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

Wanneer je het bestandspad opgeeft, voeg dan niet de .so extensie toe. Bijvoorbeeld, "path/to/my_program" is correct, maar "path/to/my_program.so" is niet correct.

Instructies verwerken

Mollusk biedt vier hoofdmethoden voor het verwerken van instructies:

MethodeBeschrijving
process_instructionVerwerk een instructie en retourneer het resultaat.
process_and_validate_instructionVerwerk een instructie en voer een reeks controles uit op het resultaat, met paniek als een controle faalt.
process_instruction_chainVerwerk meerdere instructies en retourneer het resultaat.
process_and_validate_instruction_chainVerwerk meerdere instructies en voer een reeks controles uit op elk resultaat, met paniek als een controle faalt.

Het InstructionResult bevat de details van een verwerkte instructie.

Enkele instructie

Gebruik de process_instruction methode om een enkele instructie te verwerken zonder controles op het resultaat. Je kunt de resultaten handmatig valideren na verwerking.

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

Het volgende voorbeeld verwerkt een SOL overdrachts-instructie zonder validatie controles.

De onderstaande voorbeelden draaien Mollusk in de main functie ter demonstratiedoeleinden. In de praktijk gebruik je Mollusk doorgaans in een testmodule geannoteerd met het #[test] attribuut.

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.

Enkele instructie met controles

Gebruik de process_and_validate_instruction methode om een enkele instructie te verwerken met validatiecontroles. Deze methode zal in paniek raken als een controle faalt.

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

Het volgende voorbeeld verwerkt een SOL-overdrachtsinstructie met validatiecontroles.

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.

Meerdere instructies

Gebruik de process_instruction_chain methode om meerdere instructies sequentieel te verwerken zonder validatiecontroles.

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

Het volgende voorbeeld verwerkt twee SOL-overdrachtsinstructies zonder validatiecontroles.

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.

Meerdere instructies met controles

Gebruik de process_and_validate_instruction_chain methode om meerdere instructies te verwerken met validatiecontroles na elke instructie. Elke instructie heeft zijn eigen set controles die moeten slagen.

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

Het volgende voorbeeld verwerkt een reeks van twee SOL-overdrachtsinstructies met validatiecontroles na elke instructie.

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.

Validatiecontroles

Mollusk biedt een reeks hulpmethoden om de resultaten van een verwerkte instructie te controleren.

Example
use mollusk_svm::result::Check;

Gebruik de volgende methoden om instructieresultaten te valideren:

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

Gebruik het volgende om accountstatussen te valideren:

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

Permanente accountstatus

De MolluskContext is een wrapper rond Mollusk die accountstatus behoudt over meerdere instructie-aanroepen heen via zijn account_store. De methoden voor het verwerken van instructies zijn identiek aan Mollusk.

In tegenstelling tot Mollusk, dat vereist dat accounts aan elke methode wordt doorgegeven (bijv. process_instruction), beheert MolluskContext accounts intern via zijn account_store. Dit elimineert de noodzaak voor de accounts-parameter bij het verwerken van instructies.

Maak een account_store aan met de with_context-methode:

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

Het volgende voorbeeld verwerkt twee afzonderlijke SOL-overdrachtsinstructies met persistente accountstatus tussen de instructies via de account_store.

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 biedt een aangepaste Sysvars-struct voor het aanpassen van waarden voor testen.

Gebruik de warp_to_slot-methode om de sysvar-klok bij te werken om vooruit of achteruit in de tijd te simuleren naar een specifiek slot.

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.

Het volgende voorbeeld toont hoe je de Mollusk-sysvar direct kunt aanpassen door toegang te krijgen tot het sysvars-veld om de rent-parameters te wijzigen. Je kunt andere sysvar-waarden op dezelfde manier aanpassen.

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 benchmarking

MolluskComputeUnitBencher volgt het gebruik van compute units van de instructies van een programma. De resultaten worden naar een markdown-bestand geschreven.

Vereist mollusk-svm-bencher als afhankelijkheid.

Het volgende voorbeeld benchmarkt het compute unit gebruik van een SOL transfer instructie.

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

De benchmarkresultaten worden naar de opgegeven out_dir geschreven als een markdown-bestand met de naam 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 - |

Token Program testen

Gebruik de mollusk-svm-programs-token-crate om het Token Program, Token2022 Program (Token Extensions) en Associated Token Program toe te voegen aan Mollusk voor testen.

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

Het volgende voorbeeld demonstreert het testen van een token-overdracht met Mollusk.

Het onderstaande voorbeeld definieert de testaccounts handmatig ter demonstratie. De mollusk-svm-programs-token bevat ook hulpfuncties om de mint- en tokenaccounts aan te maken.

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?

Inhoudsopgave

Pagina Bewerken

Beheerd door

© 2026 Solana Foundation.
Alle rechten voorbehouden.
Blijf Verbonden