Documentation Index
Fetch the complete documentation index at: https://mintlify.com/provablehq/snarkvm/llms.txt
Use this file to discover all available pages before exploring further.
Overview
SnarkVM uses the aleo-std storage abstraction layer to support multiple storage backends. Understanding storage modes is crucial for optimizing performance, managing disk usage, and ensuring data persistence across different deployment scenarios.
Storage Mode Types
SnarkVM supports three primary storage modes through the StorageMode enum:
Production Mode
Persistent storage using RocksDB, suitable for production deployments.
use aleo_std::StorageMode;
// Production storage in default location
let storage = StorageMode::Production;
// Default paths:
// - Linux: ~/.aleo/storage/ledger-{network_id}/
// - macOS: ~/Library/Application Support/Aleo/storage/ledger-{network_id}/
// - Windows: ~\AppData\Roaming\Aleo\storage\ledger-{network_id}\
Characteristics:
- Persistent across restarts
- RocksDB-backed for durability
- Optimized for production workloads
- Automatic directory creation
- Network ID-specific paths
Use Cases:
- Validator nodes
- Full nodes
- Production applications
- Long-running services
Development Mode
In-memory storage with optional persistence, ideal for testing and development.
// Development storage (in-memory)
let storage = StorageMode::Development(0);
// Multiple isolated instances
let storage_1 = StorageMode::Development(1);
let storage_2 = StorageMode::Development(2);
// With persistence to temp directory
let storage = StorageMode::Development(instance_id);
Characteristics:
- Fast in-memory operations
- Isolated by instance ID
- Optional temp directory persistence
- Automatically cleaned up
- No network ID requirements
Use Cases:
- Unit tests
- Integration tests
- Local development
- Rapid prototyping
- CI/CD pipelines
Custom Mode
User-specified storage path for advanced configurations.
use std::path::PathBuf;
// Custom storage path
let custom_path = PathBuf::from("/mnt/ssd/aleo/ledger");
let storage = StorageMode::Custom(custom_path);
// Relative paths supported
let storage = StorageMode::Custom("./data/ledger".into());
Characteristics:
- User-defined storage location
- Full control over path
- RocksDB-backed
- Supports any valid filesystem path
- No automatic cleanup
Use Cases:
- Custom deployment configurations
- Specific disk/volume requirements
- Network attached storage (NAS)
- Cloud storage volumes
- Multi-node setups
Storage Initialization
Opening a Ledger
use snarkvm::prelude::*;
use aleo_std::StorageMode;
// Load ledger with specific storage mode
let genesis = Block::<MainnetV0>::genesis();
let storage = StorageMode::Production;
let ledger = Ledger::<MainnetV0, ConsensusStore<_, _>>::load(
genesis,
storage,
)?;
Opening a Store
use snarkvm_ledger_store::ConsensusStore;
// Open store directly
let store = ConsensusStore::<MainnetV0, ConsensusStorage<_>>::open(
StorageMode::Production
)?;
Storage Mode Conversion
Storage modes implement Into<StorageMode> for convenience:
// String paths are automatically converted
let store = ConsensusStore::open("/path/to/storage")?;
// PathBuf conversion
let path = PathBuf::from("/custom/path");
let store = ConsensusStore::open(path)?;
// Numeric IDs for development
let store = ConsensusStore::open(0)?; // Development(0)
Storage Components
SnarkVM’s ledger uses multiple storage components:
Block Store
Stores block data, headers, and metadata.
use snarkvm_ledger_store::BlockStore;
// Open block store
let block_store = BlockStore::<MainnetV0, BlockDB<_>>::open(
StorageMode::Production
)?;
// Access storage mode
let mode = block_store.storage_mode();
Transaction Store
Manages transaction data and indices.
use snarkvm_ledger_store::TransactionStore;
// Stores transitions, inputs, outputs
let tx_store = TransactionStore::<_, TransitionDB<_>>::open(
StorageMode::Production
)?;
Program Store
Stores deployed programs and their state.
use snarkvm_synthesizer::store::ProgramStore;
// Program storage
let program_store = ProgramStore::<MainnetV0, ProgramDB<_>>::open(
StorageMode::Production
)?;
In-Memory (Development)
Advantages:
- Fastest read/write operations
- No disk I/O overhead
- Deterministic test behavior
- Easy cleanup
Limitations:
- Limited by available RAM
- Data lost on restart
- Not suitable for large datasets
- No durability guarantees
Typical Performance:
- Read latency: <1μs
- Write latency: <10μs
- Throughput: Memory bandwidth limited
RocksDB (Production/Custom)
Advantages:
- Persistent and durable
- Scales to large datasets
- Built-in compression
- Background compaction
- Crash recovery
Limitations:
- Slower than in-memory
- Disk I/O dependent
- Requires more configuration
- Compaction overhead
Typical Performance:
- Read latency: 10-100μs (with cache)
- Write latency: 50-500μs
- Throughput: Disk-dependent (NVMe: 100K+ ops/sec)
Configuration Examples
Production Validator
use snarkvm::prelude::*;
use aleo_std::StorageMode;
// High-performance production setup
let storage = if let Ok(custom_path) = std::env::var("ALEO_LEDGER_PATH") {
StorageMode::Custom(custom_path.into())
} else {
StorageMode::Production
};
let ledger = Ledger::<MainnetV0, ConsensusStore<_, _>>::load(
genesis_block,
storage,
)?;
Test Suite
#[cfg(test)]
mod tests {
use super::*;
use aleo_std::StorageMode;
#[test]
fn test_ledger_operations() {
// Isolated test storage
let test_id = 12345;
let storage = StorageMode::Development(test_id);
let ledger = Ledger::<TestnetV0, ConsensusStore<_, _>>::load(
genesis,
storage,
).unwrap();
// Test operations
// ...
// Automatic cleanup on drop
}
#[test]
fn test_parallel_ledgers() {
// Multiple isolated instances
let ledger1 = create_ledger(StorageMode::Development(1));
let ledger2 = create_ledger(StorageMode::Development(2));
// No interference between tests
}
}
Multi-Instance Deployment
// Separate storage for each network
struct NodeConfig {
network: NetworkType,
storage_root: PathBuf,
}
impl NodeConfig {
fn storage_mode(&self) -> StorageMode {
let path = self.storage_root.join(format!("ledger-{}", self.network.id()));
StorageMode::Custom(path)
}
}
// Deploy multiple networks on same machine
let mainnet_config = NodeConfig {
network: NetworkType::Mainnet,
storage_root: "/data/aleo/mainnet".into(),
};
let testnet_config = NodeConfig {
network: NetworkType::Testnet,
storage_root: "/data/aleo/testnet".into(),
};
Storage Backend Selection
Choose the appropriate storage backend using feature flags:
RocksDB Backend
Enable with the rocks feature:
[dependencies]
snarkvm = { version = "4.4.0", features = ["rocks"] }
RocksDB Features:
- Production-ready persistence
- ACID transactions
- Automatic compression (Snappy/LZ4)
- Background compaction
- Write-ahead logging (WAL)
Memory Backend
Default for development and testing:
[dependencies]
snarkvm = { version = "4.4.0", default-features = true }
Memory Features:
- BTreeMap-based storage
- In-process only
- Fastest for small datasets
- Optional temp persistence
Storage Maintenance
Checking Storage Size
use aleo_std::aleo_ledger_dir;
// Get storage directory
let storage_path = aleo_ledger_dir(MainnetV0::ID, &StorageMode::Production);
// Calculate size
fn directory_size(path: &Path) -> u64 {
walkdir::WalkDir::new(path)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.filter_map(|e| e.metadata().ok())
.map(|m| m.len())
.sum()
}
let size_bytes = directory_size(&storage_path);
println!("Ledger storage: {} GB", size_bytes / 1_000_000_000);
Backup and Recovery
# Backup ledger (RocksDB)
# Stop the node first!
sudo systemctl stop aleo-node
# Create backup
tar -czf aleo-ledger-backup-$(date +%Y%m%d).tar.gz \
~/.aleo/storage/ledger-0/
# Restart node
sudo systemctl start aleo-node
# Recovery
tar -xzf aleo-ledger-backup-20240101.tar.gz -C ~/.aleo/storage/
Cleanup
use aleo_std::aleo_ledger_dir;
// Remove ledger storage
fn remove_ledger(network_id: u16, storage_mode: &StorageMode) -> Result<()> {
let path = aleo_ledger_dir(network_id, storage_mode);
if path.exists() {
std::fs::remove_dir_all(path)?;
}
Ok(())
}
// Clean development storage
remove_ledger(TestnetV0::ID, &StorageMode::Development(0))?;
Advanced Configuration
Storage Mode Helper
Get the storage directory path:
use aleo_std::aleo_ledger_dir;
let path = aleo_ledger_dir(MainnetV0::ID, &StorageMode::Production);
println!("Storage path: {:?}", path);
Test Storage Isolation
use aleo_std::StorageMode;
// Generate unique test IDs
fn test_storage(test_name: &str) -> StorageMode {
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
let mut hasher = DefaultHasher::new();
test_name.hash(&mut hasher);
let test_id = hasher.finish() as u32;
StorageMode::Development(test_id)
}
// Use in tests
#[test]
fn test_specific_feature() {
let storage = test_storage("test_specific_feature");
// ...
}
Custom Storage Traits
Implement storage traits for custom backends:
use snarkvm_ledger_store::helpers::{Map, MapRead};
// Custom storage must implement Map trait
struct CustomStorage<K, V> {
// Your storage implementation
}
impl<K, V> Map<K, V> for CustomStorage<K, V> {
fn insert(&self, key: K, value: V) -> Result<()> {
// Custom insertion logic
}
fn remove(&self, key: &K) -> Result<()> {
// Custom removal logic
}
// ... implement remaining trait methods
}
Troubleshooting
Permission Errors
# Fix ownership
chown -R $USER:$USER ~/.aleo/storage/
# Fix permissions
chmod -R 755 ~/.aleo/storage/
Disk Space Issues
Mainnet ledger can exceed 100GB. Ensure adequate disk space before syncing.
# Check available space
df -h ~/.aleo/storage/
# Monitor growth
watch -n 60 du -sh ~/.aleo/storage/ledger-0/
Corrupted Storage
If storage becomes corrupted:
# 1. Stop the node
sudo systemctl stop aleo-node
# 2. Backup current state (if possible)
mv ~/.aleo/storage/ledger-0 ~/.aleo/storage/ledger-0.corrupted
# 3. Restore from backup or resync
# Restore:
tar -xzf backup.tar.gz -C ~/.aleo/storage/
# Or resync from genesis (will take time)
sudo systemctl start aleo-node
// Profile storage operations
use aleo_std::prelude::*;
let timer = timer!("Storage operation");
// ... perform operation
lap!(timer);
println!("Duration: {}", finish!(timer));
Best Practices
Development
- Use
Development mode for all tests
- Generate unique test IDs to avoid conflicts
- Avoid persistent storage in CI/CD
Production
- Use
Production or Custom mode
- Mount ledger storage on fast SSD/NVMe
- Monitor disk usage and I/O
- Implement regular backups
- Plan for growth (10-20GB/month typical)
Testing
- Use deterministic test IDs for reproducibility
- Clean up storage in test teardown if needed
- Use
Development mode to avoid filesystem overhead