Why LiteSVM
Understand how LiteSVM works and why it's different
Overview
Think of LiteSVM as a Solana VM running inside your test function. Not as a separate process, not as a network service - it's just a library call in your code.
Traditional Testing
// Traditional approach - slow and complex
let validator = TestValidator::new().await; // Starts separate process
let client = RpcClient::new(validator.url()); // Network connection
// Every operation is async and goes over network
let balance = client.get_balance(&pubkey).await?;
tokio::time::sleep(Duration::from_secs(1)).await; // Wait for confirmation// Traditional approach - slow and complex
const validator = await startTestValidator(); // Starts separate process
const rpc = createSolanaRpc(validator.url);
// Every operation is async and goes over network
const balance = await rpc.getBalance(address).send();LiteSVM Testing
// LiteSVM - fast and simple
let mut svm = LiteSVM::new(); // Just a struct in memory
// Everything is synchronous and immediate
let balance = svm.get_balance(&pubkey).unwrap_or(0);// LiteSVM - fast and simple
const client = createEmptyClient().use(litesvm()); // Just an object in memory
// Everything is synchronous and immediate
const balance = client.svm.getBalance(pubkey) ?? 0n;Key Principles
1. Everything is Synchronous
No async, no await, no delays:
// Send transaction and check result immediately
svm.send_transaction(tx).unwrap();
let balance = svm.get_balance(&account).unwrap(); // Already updated!// Send transaction and check result immediately
client.svm.sendTransaction(signedTx);
const balance = client.svm.getBalance(account); // Already updated!2. Direct State Manipulation
// Create any account with any data
svm.set_account(pubkey, Account {
lamports: 1_000_000_000,
data: vec![1, 2, 3, 4],
owner: program_id,
executable: false,
rent_epoch: 0,
}).unwrap();// Create any account with any data
client.svm.setAccount(pubkey, {
lamports: 1_000_000_000n,
data: new Uint8Array([1, 2, 3, 4]),
owner: programId,
executable: false,
rentEpoch: 0n,
});3. Time is Under Your Control
// Jump to any slot instantly
svm.warp_to_slot(1000);
// Expire blockhashes on demand
svm.expire_blockhash();
// Set any sysvar
let mut clock = svm.get_sysvar::<Clock>();
clock.unix_timestamp = 1735689600; // Jan 1, 2025
svm.set_sysvar(&clock);// Jump to any slot instantly
client.svm.warpToSlot(1000n);
// Expire blockhashes on demand
client.svm.expireBlockhash();
// Set the clock sysvar
client.svm.setClock({
slot: 1000n,
epochStartTimestamp: 0n,
epoch: 0n,
leaderScheduleEpoch: 0n,
unixTimestamp: 1735689600n, // Jan 1, 2025
});4. Errors are Immediate and Clear
match svm.send_transaction(tx) {
Ok(meta) => {
// Transaction succeeded
println!("Compute units: {}", meta.compute_units_consumed);
}
Err(e) => {
// Error with full details
println!("Error: {:?}", e.err);
println!("Logs: {:?}", e.meta.logs);
}
}const result = client.svm.sendTransaction(signedTx);
if ('err' in result && result.err()) {
// Error with full details
console.log('Error:', result.err());
console.log('Logs:', result.logs());
} else {
// Transaction succeeded
console.log('Compute units:', result.computeUnitsConsumed());
}Next Steps
- Testing Your Program → Learn how to test your own Solana program
- Examples → View copy-paste solutions for common scenarios and full repository examples
- API Reference → Learn advanced features and custom configurations
- Testing Your Program → Learn how to test your own Solana program using LiteSVM for TypeScript
- Examples → View copy-paste solutions for common scenarios
- API Reference → Learn advanced features and custom configurations