load_saved_blocks.rs
Overview
This file defines functionality for loading saved blockchain blocks from persistent storage into memory, categorizing them by thread identifier and their finalization status. It provides an implementation of the SavedBlocksLoader trait for the repository struct RepositoryImpl, allowing the system to reconstruct the in-memory representation of blocks after a restart or system recovery. The blocks are loaded along with their associated block states from disk, filtered based on finalization and recency criteria, and organized into a map keyed by thread identifiers.
The logic ensures that only relevant blocks are retained in memory, avoiding stale finalized blocks that fall outside of a configurable cache window. This supports efficient block management and retrieval in the broader blockchain system.
Detailed Description
Trait: SavedBlocksLoader
Defines the interface for loading saved blocks into memory.
Method: load_saved_blocks
fn load_saved_blocks(
&mut self,
block_state_repository: &BlockStateRepository,
) -> anyhow::Result<
HashMap<ThreadIdentifier, Vec<(BlockState, Arc<Envelope<GoshBLS, AckiNackiBlock>>)>>,
>;
Parameters:
&mut self: Mutable reference to the implementing repository instance.block_state_repository: Reference to aBlockStateRepositorywhich provides access to block states stored in the system.
Returns: A
Resultwrapping aHashMap:Key:
ThreadIdentifier— identifies the thread to which blocks belong.Value:
Vec<(BlockState, Arc<Envelope<GoshBLS, AckiNackiBlock>>)>— a list of tuples containing the block state and a shared reference to the block’s envelope.
Description: Loads all saved blocks from the filesystem into memory, grouping them by their thread identifiers. It skips blocks that are finalized but considered too old based on the sequence number difference relative to the last finalized block, ensuring only relevant blocks remain cached. Blocks are loaded from disk using file names parsed into
BlockIdentifiers.Usage Example:
let mut repo = RepositoryImpl::new(...);
let block_state_repo = BlockStateRepository::new(...);
let saved_blocks = repo.load_saved_blocks(&block_state_repo)?;
for (thread_id, blocks) in saved_blocks {
println!("Thread {:?} has {} restored blocks", thread_id, blocks.len());
}
Implementation: SavedBlocksLoader for RepositoryImpl
The core logic resides in the load_saved_blocks method implementation for RepositoryImpl.
Key Implementation Details:
Directory Reading:
Retrieves the blocks directory path viaget_blocks_dir_path(). If the directory does not exist, returns an empty map immediately.Finalized Blocks Cache Size:
Obtains the maximum allowed sequence number difference from the finalized blocks cache size to filter out old finalized blocks.Metadata Access:
Collects last finalized sequence numbers per thread from the repository metadata, which is guarded for thread-safe access.Block Loading and Filtering Loop:
Iterates over all block files in the blocks directory:Parses the file name into a
BlockIdentifier.Loads the block data using
Self::load_block.Retrieves the block’s state from
block_state_repository.Checks if the block state is finalized and not invalidated:
Skips blocks missing sequence number or thread ID.
Compares the block sequence number with the last finalized sequence number to exclude blocks too old to cache.
Adds qualifying finalized blocks to the finalized blocks cache.
For unfinalized blocks with a valid thread ID, adds them to the result map under their thread identifier.
Thread Safety:
Uses theGuardedandGuardedMututilities for synchronized read/write access to shared data structures like metadata and finalized blocks cache.Error Handling:
Uses theanyhow::Resulttype to propagate filesystem or parsing errors encountered during block loading.
Interaction with Other Components
BlockStateRepository:
Provides access to block states corresponding to each block identifier. The loaded block states inform filtering decisions based on finalization and invalidation status.RepositoryImpl:
The struct implementing the loading logic; also maintains the finalized blocks cache and metadata required for filtering.Envelope<GoshBLS, AckiNackiBlock>:
Represents the cryptographic envelope for a block, combining BLS signatures and theAckiNackiBlockblock data type. Loaded blocks are wrapped in anArcfor shared ownership.Filesystem:
The blocks are persisted on disk in a directory obtained fromget_blocks_dir_path(). Each block is stored as a file named after itsBlockIdentifier.Utilities (
GuardedandGuardedMut):
Used to ensure safe concurrent access to mutable shared state.
This file thus plays a critical role in the persistence layer of the blockchain system, bridging between the on-disk representation of blocks and their in-memory runtime state.
Mermaid Diagram
flowchart TD
A[RepositoryImpl] -->|calls| B["load_saved_blocks()"]
B --> C["get_blocks_dir_path()"]
B --> D["read_dir(blocks_dir)"]
D --> E[for each file]
E --> F[parse BlockIdentifier]
F --> G["load_block(blocks_dir, block_id)"]
G --> H["block_state_repository.get(block_id)"]
H --> I{block_state finalized?}
I -->|Yes| J{block valid and recent?}
J -->|Yes| K["finalized_blocks_mut().store()"]
J -->|No| L[skip block]
I -->|No| M{block_state has thread_id?}
M -->|Yes| N[add to result map]
M -->|No| L
This flowchart illustrates the flow of the load_saved_blocks method within RepositoryImpl, showing how blocks are loaded, filtered, and categorized before being stored or returned.