find_last_prefinalized.rs
Overview
This file provides functionality to identify the last prefinalized block within a particular thread in a blockchain-like data structure. It operates by traversing from the last finalized block of a thread and iteratively finding the next block that is prefinalized, ensuring the correct sequence of blocks is maintained. The file primarily exposes two functions:
find_next_prefinalized: Finds the next prefinalized child block of a given block.find_last_prefinalized: Locates the last prefinalized block for a specific thread by starting from the last finalized block and traversing forward.
These functions work with BlockState, BlockStateRepository, and RepositoryImpl abstractions to access and query block states and their relationships.
Functions
find_next_prefinalized
pub(super) fn find_next_prefinalized(
block_state: &BlockState,
thread_identifier: &ThreadIdentifier,
block_state_repository: &BlockStateRepository,
) -> Option<BlockState>
Description
This function attempts to find the next prefinalized block among the children of the given block_state for the specified thread_identifier. It returns the child block that is either finalized or prefinalized but not invalidated.
Parameters
block_state: &BlockState
The current block state from which the children will be examined.thread_identifier: &ThreadIdentifier
Identifier for the thread to scope the children blocks.block_state_repository: &BlockStateRepository
Repository to fetch block states by their identifiers.
Returns
Option<BlockState>
ReturnsSome(child_block_state)if a finalized or valid prefinalized child exists; otherwise,None.
Behavior and Implementation Details
The function retrieves all known children of the current block state for the given thread.
It iterates over each child block identifier:
If a child is finalized, it immediately returns that child.
If a child is prefinalized and not invalidated, it stores it as a candidate.
Asserts that there can be at most one prefinalized candidate child.
If no finalized child is found, returns the single prefinalized candidate if it exists.
Usage Example
let next_block = find_next_prefinalized(¤t_block_state, &thread_id, &block_state_repo);
if let Some(block) = next_block {
// process the next prefinalized or finalized block
}
find_last_prefinalized
pub fn find_last_prefinalized(
thread_identifier: &ThreadIdentifier,
block_repository: &RepositoryImpl,
block_state_repository: &BlockStateRepository,
) -> anyhow::Result<BlockState>
Description
Finds the last prefinalized block for a given thread by starting from the last finalized block and iteratively traversing to the next prefinalized block until no further prefinalized block exists.
Parameters
thread_identifier: &ThreadIdentifier
The thread for which the last prefinalized block is sought.block_repository: &RepositoryImpl
Repository to query finalized blocks associated with the thread.block_state_repository: &BlockStateRepository
Repository to fetch block states by block identifiers.
Returns
anyhow::Result<BlockState>
Returns the last prefinalized block state for the thread on success, or an error if the lookup fails.
Behavior and Implementation Details
Attempts to find the last finalized block for the thread using
block_repository.select_thread_last_finalized_block.If no finalized block is found (meaning the thread has no blocks), it retrieves the root block of the thread from
thread_identifier.spawning_block_id()and performs a safety check:Ensures no child of the root block is finalized.
Panics if a race condition or unexpected state is detected.
Initializes a cursor at the last finalized block (or root block if none finalized).
Uses a loop to repeatedly call
find_next_prefinalizedto walk through prefinalized blocks.Stops when no further prefinalized blocks are found and returns the current cursor block.
Uses tracing logs to provide debug information.
Usage Example
match find_last_prefinalized(&thread_id, &block_repo, &block_state_repo) {
Ok(last_prefinalized_block) => {
// use the last prefinalized block
}
Err(e) => {
// handle error
}
}
Important Implementation Details and Algorithms
Traversal from finalized to prefinalized: The file implements a traversal algorithm starting at the last finalized block and moving forward to the next prefinalized block, ensuring the chain of blocks is correctly followed.
Single prefinalized child assertion: Within
find_next_prefinalized, an assertion is in place to guarantee that there is at most one prefinalized child block, preventing ambiguous states.Safety checks: When no finalized blocks are present for a thread, the root block is used with checks to ensure no finalized child exists, preventing inconsistencies possibly caused by race conditions.
Use of guarded access: The code accesses internal state of blocks via a
guardedclosure ensuring safe concurrent access, as seen in calls likeblock_state.guarded(|e| e.is_finalized()).
Interaction with Other Components
BlockStateandBlockStateRepository: These abstractions provide access to block metadata and relationships. The functions use them to query block children, status flags (finalized, prefinalized, invalidated), and to retrieve blocks by their identifiers.RepositoryImpl: The main repository interface to query the last finalized block for a thread.ThreadIdentifier: Used to scope queries and identify which thread's blocks are being examined.BlockIdentifier: Used as keys to identify blocks and retrieve their states.Guarded: Provides safe internal state access, ensuring thread-safe reads.
This file effectively bridges the querying of block states and the navigation logic needed for identifying the last prefinalized block in a thread, enabling higher-level components to operate on finalized and prefinalized block sequences.
Structure Flowchart
flowchart TD
A[find_last_prefinalized] --> B[select_thread_last_finalized_block]
B -->|Some| C[Get last finalized block state]
B -->|None| D[Get root block state and safety check]
C --> E[Loop: find_next_prefinalized]
D --> E
E --> F{find_next_prefinalized returns Some?}
F -->|Yes| G[Update cursor to next prefinalized block]
G --> E
F -->|No| H[Return cursor as last prefinalized block]
subgraph find_next_prefinalized
I[Get known children] --> J[Iterate children]
J --> K{Child is finalized?}
K -->|Yes| L[Return child]
K -->|No| M{Child is prefinalized and not invalidated?}
M -->|Yes| N[Set candidate]
M -->|No| J
J --> O[Return candidate or None]
end
E --> find_next_prefinalized