Τεκμηρίωση SolanaΑνάπτυξη προγραμμάτωνΠρογράμματα δοκιμών

Mollusk

Το Mollusk είναι ένα ελαφρύ πλαίσιο δοκιμών για τον έλεγχο προγραμμάτων Solana. Παρέχει μια απλή διεπαφή για τον έλεγχο εντολών προγραμμάτων Solana σε ένα ελαχιστοποιημένο περιβάλλον Solana Virtual Machine (SVM). Όλοι οι λογαριασμοί δοκιμών πρέπει να οριστούν ρητά, διασφαλίζοντας ντετερμινιστικές και επαναλαμβανόμενες δοκιμές.

Εγκατάσταση

Προσθέστε το mollusk-svm ως εξάρτηση στο Cargo.toml:

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

Για τη συγκριτική αξιολόγηση της χρήσης υπολογιστικών μονάδων, προσθέστε το mollusk-svm-bencher ως εξάρτηση στο Cargo.toml:

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

Για να χρησιμοποιήσετε το Token Program, το token2022 program (Token Extensions) και το Associated Token Program για δοκιμές με το Mollusk, προσθέστε το mollusk-svm-programs-token ως εξάρτηση στο Cargo.toml:

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

Mollusk SVM

Το παρακάτω παράδειγμα δείχνει μια ελάχιστη ρύθμιση για τον έλεγχο ενός βασικού προγράμματος Solana χρησιμοποιώντας το Mollusk.

Πρόγραμμα Hello World

Αυτό το παράδειγμα δείχνει πώς να ελέγξετε ένα βασικό πρόγραμμα Solana χρησιμοποιώντας το Mollusk. Το πρόγραμμα απλά εκτυπώνει "Hello, world!" στα αρχεία καταγραφής του προγράμματος όταν καλείται.

Η εκτέλεση του cargo build-sbf δημιουργεί το μεταγλωττισμένο πρόγραμμα στο /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()]);
}
}

Για να ελέγξετε ένα πρόγραμμα Solana με το Mollusk:

  1. Δημιουργήστε ένα στιγμιότυπο Mollusk - Αρχικοποιήστε το Mollusk με ένα program ID και τη διαδρομή προς το μεταγλωττισμένο πρόγραμμα (αρχείο .so)
  2. Δημιουργήστε μια εντολή - Δημιουργήστε μια εντολή για να καλέσετε το πρόγραμμα
  3. Επεξεργαστείτε και επικυρώστε - Επεξεργαστείτε την εντολή χρησιμοποιώντας το Mollusk και επικυρώστε το αποτέλεσμα
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()]);
}
}

Για να εκτελέσετε τη δοκιμή, τρέξτε cargo test.

Όταν η δοκιμή εκτελεστεί επιτυχώς, θα δείτε έξοδο παρόμοια με την ακόλουθη:

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

Αυτό το παράδειγμα δείχνει πώς να ελέγξετε ένα βασικό πρόγραμμα Solana χρησιμοποιώντας το Mollusk. Το πρόγραμμα απλά εκτυπώνει "Hello, world!" στα αρχεία καταγραφής του προγράμματος όταν καλείται.

Η εκτέλεση του cargo build-sbf δημιουργεί το μεταγλωττισμένο πρόγραμμα στο /target/deploy/<program_name>.so.

Για να ελέγξετε ένα πρόγραμμα Solana με το Mollusk:

  1. Δημιουργήστε ένα στιγμιότυπο Mollusk - Αρχικοποιήστε το Mollusk με ένα program ID και τη διαδρομή προς το μεταγλωττισμένο πρόγραμμα (αρχείο .so)
  2. Δημιουργήστε μια εντολή - Δημιουργήστε μια εντολή για να καλέσετε το πρόγραμμα
  3. Επεξεργαστείτε και επικυρώστε - Επεξεργαστείτε την εντολή χρησιμοποιώντας το Mollusk και επικυρώστε το αποτέλεσμα
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()]);
}
}

Για να εκτελέσετε τη δοκιμή, τρέξτε cargo test.

Όταν η δοκιμή εκτελεστεί επιτυχώς, θα δείτε έξοδο παρόμοια με την ακόλουθη:

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 παρέχει μια απλή διεπαφή για τη δοκιμή προγραμμάτων Solana. Όλα τα πεδία μπορούν να τροποποιηθούν μέσω μερικών βοηθητικών μεθόδων, αλλά οι χρήστες μπορούν επίσης να έχουν άμεση πρόσβαση και να τα τροποποιήσουν αν επιθυμούν περισσότερο έλεγχο.

Για να αρχικοποιήσετε το Mollusk με μια προεπιλεγμένη παρουσία, χρησιμοποιήστε τη μέθοδο Mollusk::default.

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

Για να αρχικοποιήσετε το Mollusk με ένα συγκεκριμένο πρόγραμμα, χρησιμοποιήστε τη μέθοδο 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");

Για να προσθέσετε ένα πρόγραμμα στο Mollusk, χρησιμοποιήστε τη μέθοδο 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(),
);

Όταν παρέχετε τη διαδρομή αρχείου, μην συμπεριλάβετε την επέκταση .so. Για παράδειγμα, το "path/to/my_program" είναι σωστό, αλλά το "path/to/my_program.so" δεν είναι.

Επεξεργασία εντολών

Το Mollusk παρέχει τέσσερις κύριες μεθόδους για την επεξεργασία εντολών:

ΜέθοδοςΠεριγραφή
process_instructionΕπεξεργάζεται μια εντολή και επιστρέφει το αποτέλεσμα.
process_and_validate_instructionΕπεξεργάζεται μια εντολή και εκτελεί μια σειρά ελέγχων στο αποτέλεσμα, προκαλώντας πανικό αν αποτύχει κάποιος έλεγχος.
process_instruction_chainΕπεξεργάζεται πολλαπλές εντολές και επιστρέφει το αποτέλεσμα.
process_and_validate_instruction_chainΕπεξεργάζεται πολλαπλές εντολές και εκτελεί μια σειρά ελέγχων σε κάθε αποτέλεσμα, προκαλώντας πανικό αν αποτύχει κάποιος έλεγχος.

Το InstructionResult περιέχει τις λεπτομέρειες μιας επεξεργασμένης εντολής.

Μονή εντολή

Χρησιμοποιήστε τη μέθοδο process_instruction για να επεξεργαστείτε μια μονή εντολή χωρίς ελέγχους στο αποτέλεσμα. Μπορείτε να επικυρώσετε χειροκίνητα τα αποτελέσματα μετά την επεξεργασία.

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

Το ακόλουθο παράδειγμα επεξεργάζεται μια εντολή μεταφοράς SOL χωρίς ελέγχους επικύρωσης.

Τα παρακάτω παραδείγματα εκτελούν το Mollusk στη συνάρτηση main για λόγους επίδειξης. Στην πράξη, συνήθως θα χρησιμοποιείτε το Mollusk σε μια ενότητα δοκιμών που επισημαίνεται με το χαρακτηριστικό #[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.

Μονή εντολή με ελέγχους

Χρησιμοποιήστε τη μέθοδο process_and_validate_instruction για την επεξεργασία μιας μεμονωμένης εντολής με ελέγχους επικύρωσης. Αυτή η μέθοδος θα διακόψει τη λειτουργία αν αποτύχει οποιοσδήποτε έλεγχος.

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

Το ακόλουθο παράδειγμα επεξεργάζεται μια εντολή μεταφοράς SOL με ελέγχους επικύρωσης.

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.

Πολλαπλές εντολές

Χρησιμοποιήστε τη μέθοδο process_instruction_chain για την επεξεργασία πολλαπλών εντολών διαδοχικά χωρίς ελέγχους επικύρωσης.

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

Το ακόλουθο παράδειγμα επεξεργάζεται δύο εντολές μεταφοράς SOL χωρίς ελέγχους επικύρωσης.

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.

Πολλαπλές εντολές με ελέγχους

Χρησιμοποιήστε τη μέθοδο process_and_validate_instruction_chain για την επεξεργασία πολλαπλών εντολών με ελέγχους επικύρωσης μετά από κάθε εντολή. Κάθε εντολή έχει το δικό της σύνολο ελέγχων που πρέπει να περάσουν.

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

Το ακόλουθο παράδειγμα επεξεργάζεται μια αλυσίδα δύο εντολών μεταφοράς SOL με ελέγχους επικύρωσης μετά από κάθε εντολή.

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.

Έλεγχοι Επικύρωσης

Το Mollusk παρέχει ένα σύνολο από βοηθητικές μεθόδους για τον έλεγχο των αποτελεσμάτων μιας επεξεργασμένης εντολής.

Example
use mollusk_svm::result::Check;

Χρησιμοποιήστε τις ακόλουθες μεθόδους για την επικύρωση των αποτελεσμάτων εντολών:

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

Χρησιμοποιήστε τα ακόλουθα για την επικύρωση των καταστάσεων Λογαριασμών:

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

Μόνιμη Κατάσταση Λογαριασμού

Το MolluskContext είναι ένα περίβλημα γύρω από το Mollusk που διατηρεί την κατάσταση του λογαριασμού σε πολλαπλές κλήσεις εντολών μέσω του account_store. Οι μέθοδοι για την επεξεργασία εντολών είναι πανομοιότυπες με το Mollusk.

Σε αντίθεση με το Mollusk, που απαιτεί την παράδοση του accounts σε κάθε μέθοδο (π.χ. process_instruction), το MolluskContext διαχειρίζεται τους λογαριασμούς εσωτερικά μέσω του account_store. Αυτό εξαλείφει την ανάγκη για την παράμετρο accounts κατά την επεξεργασία εντολών.

Δημιουργήστε ένα account_store χρησιμοποιώντας τη μέθοδο 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);

Το ακόλουθο παράδειγμα επεξεργάζεται δύο ξεχωριστές εντολές μεταφοράς SOL με μόνιμη κατάσταση λογαριασμού μεταξύ των εντολών μέσω του 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.

Sysvars του Mollusk

Το Mollusk παρέχει μια προσαρμοσμένη Sysvars δομή για την τροποποίηση των τιμών της για δοκιμές.

Χρησιμοποιήστε τη μέθοδο warp_to_slot για να ενημερώσετε το ρολόι sysvar ώστε να προσομοιώσετε την κίνηση προς τα εμπρός ή προς τα πίσω στο χρόνο σε ένα συγκεκριμένο 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.

Το ακόλουθο παράδειγμα δείχνει πώς να τροποποιήσετε το sysvar του Mollusk απευθείας προσπελαύνοντας το πεδίο sysvars για να αλλάξετε τις παραμέτρους του rent. Μπορείτε να τροποποιήσετε άλλες τιμές sysvar με τον ίδιο τρόπο.

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.

Συγκριτική αξιολόγηση μονάδων υπολογισμού

Το MolluskComputeUnitBencher παρακολουθεί τη χρήση μονάδων υπολογισμού των εντολών ενός προγράμματος. Τα αποτελέσματα καταγράφονται σε αρχείο markdown.

Απαιτεί το mollusk-svm-bencher ως εξάρτηση.

Το παρακάτω παράδειγμα συγκρίνει τη χρήση μονάδων υπολογισμού μιας εντολής μεταφοράς 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();
}

Τα αποτελέσματα της συγκριτικής αξιολόγησης καταγράφονται στο καθορισμένο out_dir ως αρχείο markdown με όνομα 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

Χρησιμοποιήστε το mollusk-svm-programs-token crate για να προσθέσετε το token program, το token2022 program (token extensions) και το associated token program στο Mollusk για δοκιμές.

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

Το παρακάτω παράδειγμα δείχνει τη δοκιμή μιας μεταφοράς token χρησιμοποιώντας το Mollusk.

Το παρακάτω παράδειγμα ορίζει χειροκίνητα τους λογαριασμούς δοκιμής για λόγους επίδειξης. Το mollusk-svm-programs-token περιλαμβάνει επίσης βοηθητικές συναρτήσεις για τη δημιουργία των λογαριασμών mint και 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?