Skip to content

Conversation

ethDreamer
Copy link
Member

Issue Addressed

This is useful for managing lock contention and will be really useful for gloas.

@ethDreamer ethDreamer changed the base branch from stable to unstable September 29, 2025 20:06
@ethDreamer
Copy link
Member Author

status_table (1)

@ethDreamer
Copy link
Member Author

Basic Functionality

Whenever a component of a block is seen from the network:

if block_status_table.insert_pending(component.block_hash) {
    // block inserted with status PENDING
}

match da_cache.insert(component) {
    Availability::Available(block) => {
        if block_status_table.compare_and_swap_status(
            block.hash,
            BlockStatus::Pending,
            BlockStatus::Importing, // post gloas it will be BlockStatus::Executing
        ) {
            // proceed with importing the block into fork-choice
        }
        else {
            // someone beat you to it; you're done
        }
    }
    Availability::MissingComponents(..) => // you're done
}

any thread that needs to know the status of a block can subscribe for events:

let Some((status, mut rx)) = block_status_table.subscribe(block_hash) else {
    // block doesn't exist
}
if status.is_terminal() {
    // evaluate what to do based on status
}
while let Ok(status) = rx.recv().await {
    if status.is_terminal() {
        // decide what to do based on status
    }
}

Comment on lines 60 to 65
/// The underlying concurrent hash map storing block status as AtomicU8
table: DashMap<Hash256, AtomicU8>,
/// Broadcast channels for notifying subscribers of status changes
notifiers: DashMap<Hash256, broadcast::Sender<BlockStatus>>,
/// Counter for tracking the number of entries (for metrics/debugging)
entry_count: AtomicUsize,
Copy link
Collaborator

@dapplion dapplion Sep 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be the initial design be the simplest approach possible?

pub enum BlockStatus {
    Pending,
    Executing(broadcast::Sender<BlockStatus>),
    Invalid,
    Importing(broadcast::Sender<BlockStatus>),
    Imported.
}

pub struct BlockStatusTable {
    table: DashMap<Hash256, BlockStatus>,
}

We can optimize later with more dashmaps if we happen to observe and measure performance degradation due to lock contention

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have changed the design to use a single dashmap and I think the code is both simpler and more efficient - let me know what you think! :D

return Err(BlockError::BlobNotRequired(blob.slot()));
}

// TODO: there appears to be no check on the parent block being in fork choice here..
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's checked here

let Some(parent_block) = fork_choice.get_block(&block_parent_root) else {

// TODO: if somehow this blob is older than finalization, we need to not insert it - where is this checked?
let status = self
.block_status_table
.get_status_or_insert_pending(block_root, slot)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why insert here?

) {
Ok(_) => {
let result = self.import_available_block(block).await;
if let Ok(AvailabilityProcessingStatus::Imported(_)) = result.as_ref() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is equivalent to a match with a default statement, which have been very problematic in the past as we modify the variants. Can you do a full match on result?

Comment on lines 3805 to 3807
BlockStatusTableError::InvalidStatusTransition { .. } => {
Err(BlockError::DuplicateFullyImported(block_root))
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true, this error will trigger if the current status is != Pending. If that status happens to be Invalid you will return DuplicateFullyImported which is incorrect

Err(BlockError::DuplicateFullyImported(block_root))
}
// other errors should not occur
e => Err(BlockError::InternalError(format!(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid default match statement, just match explicitly the variants BlockNotFound / InvalidStatus. Are you sure BlockNotFound can never happen?

@ethDreamer ethDreamer requested a review from jxs as a code owner October 3, 2025 23:31
/// Block (or blob) has been seen
Seen = 0,
/// Someone is running process_block() on the block
Processing = 1,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As part of process_block, the block can be executing and importing, are these statuses overlapping?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants