docs.rs failed to build dig-blockstore-0.1.2
Please check the
build logs for more information.
See
Builds for ideas on how to fix a failed build,
or
Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault,
open an issue.
dig-blockstore
Persistent block storage for the DIG L2 network. RocksDB-backed with six column families, dual-layer canonical chain indexing (memory-mapped file + RocksDB), sharded in-memory LRU caches, zstd compression with trained dictionaries, async write pipeline, rollback/reorg support, checkpoint storage, pruning, and snapshot export/import.
Architecture
┌─────────────────────────────────────────────────────────┐
│ BlockStore │
│ ┌──────────┐ ┌──────────┐ ┌───────────────────────┐ │
│ │ block │ │ header │ │ record cache │ │
│ │ cache │ │ cache │ │ (HashMap, RAM-only) │ │
│ │ (sharded │ │ (sharded │ │ │ │
│ │ LRU) │ │ LRU) │ │ + height index cache │ │
│ └────┬─────┘ └────┬─────┘ │ + hash→height cache │ │
│ │ │ └───────────┬───────────┘ │
│ ┌────┴──────────────┴────────────────────┴───────────┐ │
│ │ RocksDB (6 column families) │ │
│ │ CF_BLOCKS CF_HEADERS CF_CANONICAL CF_METADATA │ │
│ │ CF_ATTESTED CF_CHECKPOINTS │ │
│ └────────────────────────────────────────────────────┘ │
│ ┌────────────────────────────────────────────────────┐ │
│ │ canonical.bin (memory-mapped dense height→hash) │ │
│ └────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Quick Start
use dig_blockstore::{
BlockStore, BlockStoreConfig, ChainTip,
L2Block, L2BlockHeader, Bytes32, BlockStatus, };
let config = BlockStoreConfig {
path: "data/my-blockstore".into(),
..Default::default()
};
let store = BlockStore::open(config)?;
store.init_genesis(&genesis_block)?;
store.extend_chain(&block)?;
let block = store.get_block(&hash)?;
let header = store.get_header_by_height(42)?;
let tip = store.tip();
Public API Reference
BlockStore — Constructors
| Method |
Input |
Output |
Description |
open(config) |
BlockStoreConfig |
Result<BlockStore> |
Open or create a store at config.path. Creates all column families, loads tip from metadata, optionally warms caches. |
open_readonly(path) |
impl AsRef<Path> |
Result<BlockStore> |
Open existing database read-only. All mutation methods return ERR_MUTATION_READ_ONLY. Path must exist. |
BlockStore — Genesis & Chain Tip
| Method |
Input |
Output |
Description |
init_genesis(&self, block) |
&L2Block |
Result<()> |
Initialize an empty store with the genesis block. Atomic WriteBatch writes block + header + canonical index + tip + genesis hash. Fails if already initialized. |
tip(&self) |
— |
Option<ChainTip> |
Current canonical chain tip (hash + height). None before genesis. Lock-free read from RwLock. |
height(&self) |
— |
Option<u64> |
Shorthand for tip().map(|t| t.height). |
set_tip(&self, tip) |
ChainTip |
Result<()> |
Persist a new chain tip to CF_METADATA/META_TIP (40 bytes: hash || height LE). Updates in-memory cache. |
BlockStore — Block Storage (Write)
| Method |
Input |
Output |
Description |
put_block(&self, block, canonical) |
&L2Block, bool |
Result<bool> |
Store a block. Returns true if novel, false if duplicate (idempotent). When canonical=true, also writes height→hash to CF_CANONICAL. Triggers dictionary training when block count reaches 1000. |
put(&self, block, canonical) |
&L2Block, bool |
Result<bool> |
Alias for put_block. |
extend_chain(&self, block) |
&L2Block |
Result<bool> |
Primary ingestion API: put(block, true) + set_tip. Returns false for duplicates. Does NOT validate parent-hash linkage (caller's responsibility). |
put_pipelined(&self, block, canonical) |
L2Block, bool |
Result<Receiver<Result<bool>>> |
Async batched write. Enqueues into bounded channel; background task flushes via single WriteBatch. Returns oneshot receiver for per-block ack. Requires tokio runtime. |
BlockStore — Block Retrieval (Read)
| Method |
Input |
Output |
Description |
get_block(&self, hash) |
&Bytes32 |
Result<Option<L2Block>> |
Three-tier lookup: sharded LRU cache → RocksDB CF_BLOCKS (zstd decompress) → None. Populates cache on miss. |
get_header(&self, hash) |
&Bytes32 |
Result<Option<L2BlockHeader>> |
Header cache → RocksDB CF_HEADERS (bincode, no zstd) → None. |
get_record(&self, hash) |
&Bytes32 |
Result<Option<BlockRecord>> |
Record cache → header cache (derive) → CF_HEADERS (deserialize + derive) → None. Records are never persisted. |
has_block(&self, hash) |
&Bytes32 |
Result<bool> |
Lightweight existence check. Probes caches first (no LRU promotion), then RocksDB key existence (no deserialization). |
get_blocks_by_hash(&self, hashes) |
&[Bytes32] |
Result<Vec<Option<L2Block>>> |
Batch retrieval. Cache hits served individually; all misses consolidated into one multi_get_cf. Output index matches input order. |
BlockStore — Canonical Chain (Height-Based)
| Method |
Input |
Output |
Description |
get_hash_by_height(&self, height) |
u64 |
Result<Option<Bytes32>> |
Resolve canonical hash. Checks: BTreeMap cache → mmap canonical.bin → RocksDB CF_CANONICAL. Returns None for non-canonical or pruned heights. |
get_block_by_height(&self, height) |
u64 |
Result<Option<L2Block>> |
get_hash_by_height → get_block. |
get_header_by_height(&self, height) |
u64 |
Result<Option<L2BlockHeader>> |
get_hash_by_height → get_header. |
get_record_by_height(&self, height) |
u64 |
Result<Option<BlockRecord>> |
get_hash_by_height → get_record. |
get_epoch_block_hashes(&self, epoch) |
u64 |
Result<Vec<Bytes32>> |
Collect canonical hashes for all heights in the epoch. Stops at chain tip. Uses dig_epoch::epoch_height_range. |
set_canonical(&self, hash) |
&Bytes32 |
Result<()> |
Mark an already-stored block as canonical at its height. Updates CF_CANONICAL + mmap + caches. |
set_canonical_batch(&self, hashes) |
&[Bytes32] |
Result<()> |
Atomic batch canonicalization via single WriteBatch. |
BlockStore — Range Queries
| Method |
Input |
Output |
Description |
get_blocks_in_range(&self, start, end) |
u64, u64 |
Result<Vec<L2Block>> |
Eagerly load canonical blocks in [start, end] inclusive. Ascending order. Skips gaps. |
get_records_in_range(&self, start, end) |
u64, u64 |
Result<Vec<BlockRecord>> |
Same range semantics but returns lightweight records (no zstd decompression). |
stream_blocks_in_range(&self, start, end) |
u64, u64 |
StreamBlocksInRange |
Iterator with RocksDB readahead. Yields Result<L2Block> per height. Memory-efficient for large ranges. |
BlockStore — Rollback & Reorg
| Method |
Input |
Output |
Description |
blocks_to_revert(&self, target_height) |
u64 |
Result<Vec<Bytes32>> |
Read-only preview. Returns canonical hashes that WOULD be reverted, descending height order. Empty if target >= tip or no tip. |
rollback_to_height(&self, target_height) |
u64 |
Result<Vec<Bytes32>> |
Revert canonical chain. Validates: NoTip, RollbackAboveTip, RollbackBelowMin. Deletes CF_CANONICAL entries, truncates mmap, updates tip, marks records non-canonical. Block data preserved. Returns reverted hashes (descending). |
find_common_ancestor(&self, hash, max_depth) |
&Bytes32, u64 |
Result<Option<(Bytes32, u64)>> |
Walk parent_hash chain backward. Returns first canonical ancestor as (hash, height). None if not found within max_depth steps. |
apply_reorg(&self, ancestor_height, new_chain_hashes) |
u64, &[Bytes32] |
Result<ReorgResult> |
Atomic fork-switch. Single WriteBatch: delete old canonical entries above ancestor, write new entries, update tip. Post-commit: mmap truncate + rewrite, cache updates. |
BlockStore — Attestation Storage
| Method |
Input |
Output |
Description |
put_attestation(&self, hash, attested) |
&Bytes32, &AttestedBlock |
Result<()> |
Persist attested block in CF_ATTESTED. Overwrites existing. |
get_attestation(&self, hash) |
&Bytes32 |
Result<Option<AttestedBlock>> |
Retrieve attestation by block hash. |
BlockStore — Checkpoint Storage
| Method |
Input |
Output |
Description |
put_checkpoint(&self, checkpoint) |
&StoredCheckpoint |
Result<()> |
Store checkpoint keyed by epoch (big-endian). Idempotent overwrite. |
get_checkpoint(&self, epoch) |
u64 |
Result<Option<StoredCheckpoint>> |
Retrieve checkpoint by epoch. |
get_latest_checkpoint(&self) |
— |
Result<Option<StoredCheckpoint>> |
Reverse iterator on CF_CHECKPOINTS. Returns highest-epoch entry. |
get_checkpoints_in_range(&self, start, end) |
u64, u64 |
Result<Vec<StoredCheckpoint>> |
Forward iterator. Range [start, end] inclusive. Ascending epoch order. |
BlockStore — Snapshot Export/Import
| Method |
Input |
Output |
Description |
export_snapshot(&self, start, end, writer) |
u64, u64, &mut impl Write |
Result<SnapshotManifest> |
Write manifest + length-prefixed compressed blocks + SHA-256 checksum. Uses pre-compressed bytes from CF_BLOCKS (no recompression). |
import_snapshot(&self, reader) |
&mut impl Read |
Result<SnapshotManifest> |
Read manifest, validate version, ingest blocks (height contiguity + parent link checks), verify trailing SHA-256 checksum. |
BlockStore — Pruning
| Method |
Input |
Output |
Description |
prune_before_height(&self, height) |
u64 |
Result<usize> |
Delete blocks/headers/attestations/canonical entries below height. Includes non-canonical blocks. Single WriteBatch. Updates min_retained_height. Returns count pruned. |
prune_checkpoints_before_epoch(&self, epoch) |
u64 |
Result<usize> |
Delete checkpoints with epoch < target. Returns count pruned. |
min_retained_height(&self) |
— |
Result<u64> |
Pruning floor. Returns 0 if no pruning has occurred. Fast (AtomicU64 read). |
BlockStore — Statistics & Maintenance
| Method |
Input |
Output |
Description |
stats(&self) |
— |
Result<StorageStats> |
Aggregate counts: block_count, canonical_block_count, header_count, checkpoint_count, attested_count, tip_height, min_height, total_size_bytes. |
flush(&self) |
— |
Result<()> |
Force WAL flush to disk. |
compact(&self) |
— |
Result<()> |
Trigger manual compaction on all column families. |
BlockStore — Async Methods
| Method |
Input |
Output |
Description |
get_block_async(&self, hash) |
&Bytes32 |
Result<Option<L2Block>> |
Cache hit served directly; miss dispatched to spawn_blocking. |
get_header_async(&self, hash) |
&Bytes32 |
Result<Option<L2BlockHeader>> |
Same pattern as get_block_async. |
get_block_by_height_async(&self, height) |
u64 |
Result<Option<L2Block>> |
Always spawn_blocking (height→hash uses I/O). |
Data Types
ChainTip
pub struct ChainTip {
pub hash: Bytes32, pub height: u64, }
to_bytes() -> [u8; 40] — Encode: hash[0..32] || height_LE[32..40]
from_bytes(&[u8]) -> Result<Self> — Decode from exactly 40 bytes
BlockRecord
In-memory block metadata. Never persisted to RocksDB. Derived from headers via from_header.
pub struct BlockRecord {
pub hash: Bytes32,
pub height: u64,
pub epoch: u64,
pub parent_hash: Bytes32,
pub in_canonical_chain: bool, pub status: BlockStatus, pub timestamp: u64,
pub proposer_index: u32,
pub spend_bundle_count: u32,
pub total_cost: u64,
pub total_fees: u64,
pub additions_count: u32,
pub removals_count: u32,
pub block_size: u64, pub l1_height: u32,
pub l1_hash: Bytes32,
pub state_root: Bytes32,
}
StorageStats
pub struct StorageStats {
pub block_count: u64, pub canonical_block_count: u64, pub header_count: u64,
pub checkpoint_count: u64,
pub attested_count: u64,
pub tip_height: Option<u64>,
pub min_height: Option<u64>, pub total_size_bytes: u64, }
ReorgResult
pub struct ReorgResult {
pub reverted: Vec<Bytes32>, pub applied: Vec<Bytes32>, pub new_tip: ChainTip,
}
StoredCheckpoint
pub struct StoredCheckpoint {
pub checkpoint: Checkpoint, pub signer_bitmap: SignerBitmap,
pub aggregate_signature: Signature, pub aggregate_pubkey: PublicKey, pub score: u64,
pub submitter: u32,
pub l1_height: Option<u32>,
pub l1_coin_id: Option<Bytes32>,
pub stored_at: u64, }
SnapshotManifest
pub struct SnapshotManifest {
pub version: u32, pub start_height: u64,
pub end_height: u64,
pub block_count: u64, pub state_root: Bytes32,
pub checksum: Bytes32, }
Error Types
pub enum BlockStoreError {
RocksDb(rocksdb::Error), Serialization(String), Compression(String), BlockNotFound(Bytes32), CheckpointNotFound(u64), BlockNotInStore(Bytes32), RollbackBelowMin { target: u64, min: u64 }, RollbackAboveTip { target: u64, tip: u64 }, NoTip, SchemaMismatch { expected: u32, found: u32 }, NotInitialized, EmptyReorgChain, PipelineClosed, }
Configuration
All fields of BlockStoreConfig with defaults:
| Field |
Type |
Default |
Description |
path |
PathBuf |
"data/blockstore" |
RocksDB directory |
block_cache_capacity |
usize |
1000 |
Max blocks in sharded LRU |
header_cache_capacity |
usize |
2000 |
Max headers in sharded LRU |
cache_shards |
usize |
16 |
Shard count (power of 2) |
warm_cache_on_open |
bool |
true |
Preload recent blocks on open |
warm_cache_depth |
u64 |
64 |
Heights to warm from tip |
write_buffer_size |
usize |
67_108_864 |
RocksDB memtable (64 MiB) |
block_cache_size |
usize |
134_217_728 |
RocksDB block cache (128 MiB) |
max_open_files |
i32 |
1000 |
File descriptor budget |
enable_blob_db |
bool |
true |
BlobDB for large block values |
compress_blocks |
bool |
true |
Application-level zstd |
compression_level |
i32 |
3 |
Zstd level |
use_compression_dict |
bool |
true |
Trained dictionary after 1000 blocks |
max_decompressed_block_bytes |
usize |
134_217_728 |
Decompression bomb cap (128 MiB) |
zstd_dictionary_override |
Option<Vec<u8>> |
None |
Inject dictionary for tests |
write_pipeline_batch_size |
usize |
64 |
Max blocks per WriteBatch flush |
write_pipeline_flush_ms |
u64 |
100 |
Partial batch flush timer |
write_pipeline_channel_capacity |
usize |
256 |
Bounded async channel depth |
sync_writes |
bool |
false |
WAL sync per write |
readahead_size |
usize |
2_097_152 |
Sequential readahead hint (2 MiB) |
canonical_height_cache_capacity |
usize |
10_000 |
Height→hash BTreeMap entries |
hash_to_height_cache_capacity |
usize |
10_000 |
Hash→height reverse LRU entries |
enable_compaction_pruning |
bool |
false |
Register compaction filter |
min_retained_height |
Option<u64> |
None |
Pruning floor (config override) |
Column Families
| Name |
Key |
Value |
Purpose |
blocks |
hash (32 bytes) |
zstd-compressed bincode L2Block |
Full block bodies |
headers |
hash (32 bytes) |
bincode L2BlockHeader |
Block headers (no compression) |
canonical |
height (8 bytes BE) |
hash (32 bytes) |
Canonical chain height→hash index |
metadata |
UTF-8 string |
varies |
Tip, genesis hash, schema version, zstd dict, min height |
checkpoints |
epoch (8 bytes BE) |
bincode StoredCheckpoint |
Consensus checkpoints by epoch |
attested |
hash (32 bytes) |
bincode AttestedBlock |
Attested block data |
Key Encoding Functions
| Function |
Input |
Output |
Description |
hash_key(hash) |
&Bytes32 |
&[u8; 32] |
Raw 32-byte hash for CF_BLOCKS/CF_HEADERS/CF_ATTESTED keys |
height_key(height) |
u64 |
[u8; 8] |
Big-endian 8-byte key for CF_CANONICAL (preserves sort order) |
decode_height_key(key) |
&[u8; 8] |
u64 |
Decode big-endian height key |
epoch_key(epoch) |
u64 |
[u8; 8] |
Big-endian 8-byte key for CF_CHECKPOINTS |
decode_epoch_key(key) |
&[u8; 8] |
u64 |
Decode big-endian epoch key |
metadata_key(name) |
&str |
&[u8] |
UTF-8 bytes for CF_METADATA keys |
Wire Format (Chia Streamable)
| Function |
Input |
Output |
Description |
block_to_wire_bytes(block) |
&L2Block |
Result<Vec<u8>> |
Chia Streamable encoding (big-endian, length-prefixed lists). NOT bincode. |
block_from_wire_bytes(bytes) |
&[u8] |
Result<L2Block> |
Decode Streamable wire format. Rejects trailing garbage. |
Snapshot Stream Format
[ SnapshotManifest (bincode) ]
[ block_0_len: u32 LE ] [ block_0_compressed_bytes ]
[ block_1_len: u32 LE ] [ block_1_compressed_bytes ]
...
[ SHA-256 checksum: 32 bytes ]
The checksum covers all bytes from the start of the manifest through the last block (exclusive of the trailing 32-byte checksum itself). Computed via chia_sha2::Sha256.
Crate Dependencies
| Crate |
Purpose |
dig-block |
L2Block, L2BlockHeader, BlockStatus, AttestedBlock, Checkpoint types |
dig-epoch |
Epoch height range calculation |
dig-constants |
Network constants |
chia-protocol |
Bytes32 fixed-size hash type |
chia-bls |
BLS Signature, PublicKey for checkpoint storage |
chia-sha2 |
SHA-256 for snapshot checksums |
chia-traits |
Streamable trait for wire format |
rocksdb |
Storage backend with column families, WriteBatch, iterators |
zstd |
Block body compression with optional trained dictionary |
bincode |
Fast binary serialization for headers, checkpoints, blocks |
serde |
Serialization framework (derive) |
thiserror |
Error type derivation |
parking_lot |
Fast RwLock/Mutex (no poisoning) |
lru |
LRU cache implementation |
tokio |
Async runtime for write pipeline and async read APIs |
memmap2 |
Memory-mapped canonical.bin file |
Thread Safety
BlockStore is Send + Sync + Clone. All public methods take &self.
- Clone is cheap (
Arc<Inner> bump).
- Concurrent reads are safe: sharded LRU caches use per-shard
parking_lot::RwLock.
- Concurrent writes are safe: RocksDB handles internal locking; record cache uses
Mutex.
- Async methods (
get_block_async, put_pipelined) are designed for tokio runtimes.
All upstream types re-exported from crate root (L2Block, Bytes32, BlockStatus, etc.) — consumers need only dig-blockstore in their Cargo.toml.