unfinalized_ancestor_blocks.rs

Overview

This file provides functionality to select and retrieve a chain of unfinalized ancestor blocks from a blockchain-like data structure, starting from a given tail block and moving backward through its ancestry. It defines an error enumeration to represent various failure modes encountered during the retrieval process, a trait specifying the block selection behavior, and an implementation of that trait for a block repository. The main purpose is to traverse the block history while respecting finalization state, sequence number cutoffs, and invalidation conditions.

Error Enumeration: UnfinalizedAncestorBlocksSelectError

This enumeration defines the possible errors that can arise when selecting unfinalized ancestor blocks:

Debug Implementation

A custom Debug trait implementation provides concise, human-readable string representations for each error variant, including the chain of blocks when relevant.

Trait: UnfinalizedAncestorBlocks

Defines a contract for selecting unfinalized ancestor blocks from a given starting block:

Method: select_unfinalized_ancestor_blocks

fn select_unfinalized_ancestor_blocks(
    &self,
    tail: &BlockState,
    cutoff: BlockSeqNo,
) -> anyhow::Result<Vec<BlockState>, UnfinalizedAncestorBlocksSelectError>;
let ancestors_result = repository.select_unfinalized_ancestor_blocks(&tail_block, cutoff_seq_no);
match ancestors_result {
    Ok(ancestors) => {
        // Process the chain of unfinalized ancestors
    }
    Err(e) => {
        // Handle errors such as incomplete history or cutoff reached
    }
}

Implementation for BlockStateRepository

The trait UnfinalizedAncestorBlocks is implemented for BlockStateRepository, enabling repository instances to perform ancestor selection.

Algorithm Details

  1. Initialize an empty vector chain to accumulate ancestor blocks.

  2. Set cursor to the given tail block.

  3. Enter a loop:

    • Use the guarded method on cursor to safely access its inner data and extract:

      • Whether the block is finalized.

      • The parent block identifier.

      • The block sequence number.

    • If the block is invalidated but not finalized, return an InvalidatedParent error including the chain so far.

    • If any required metadata is missing, return an IncompleteHistory error.

    • If the current block is finalized, return the accumulated chain in the correct order (oldest first).

    • If the block sequence number is below the cutoff, return a BlockSeqNoCutoff error including the chain.

    • Otherwise, push the current block to the chain and advance the cursor to its parent block by loading it from the repository.

    • If loading the parent block fails, return a FailedToLoadBlockState error.

This traversal ensures correctness by stopping at finalized blocks, respecting the cutoff limit, and validating block states to prevent processing invalid or incomplete histories.

Test Module

The test module contains unit tests verifying the error behavior of the ancestor selection:

Interaction with Other Components

The ancestor selection relies on querying the repository for parent blocks and inspecting their states to build the chain.


Mermaid Diagram: Structure of unfinalized_ancestor_blocks.rs

classDiagram
class UnfinalizedAncestorBlocksSelectError {
<<enum>>
+IncompleteHistory
+BlockSeqNoCutoff(chain: Vec<BlockState>)
+InvalidatedParent(chain: Vec<BlockState>)
+FailedToLoadBlockState
+fmt()
}
class UnfinalizedAncestorBlocks {
<<trait>>
+select_unfinalized_ancestor_blocks(tail: &BlockState, cutoff: BlockSeqNo) Result<Vec<BlockState>, UnfinalizedAncestorBlocksSelectError>
}
class BlockStateRepository {
+select_unfinalized_ancestor_blocks(tail: &BlockState, cutoff: BlockSeqNo) Result<Vec<BlockState>, UnfinalizedAncestorBlocksSelectError>
+get(block_id: &BlockIdentifier) -> Result<BlockState>
}
UnfinalizedAncestorBlocksSelectError <|-- UnfinalizedAncestorBlocksSelectError
UnfinalizedAncestorBlocks <|.. BlockStateRepository