Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add invalidate block method and invalidated_blocks field to NonFinalizedState #9167

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

elijahhampton
Copy link
Contributor

@elijahhampton elijahhampton commented Jan 26, 2025

Motivation

This PR implements a new method invalidate_block to invalidate a block based on the block::Hash along with the blocks descendants. This PR closes the following issue: #8840 , #8841

Specifications & References

Reference: #8634

Solution

  • Adds invalidate_block method to NonFinalizedState
  • Changes visibility to pub(crate) for UpdateWith / RevertPosition in chain.rs
  • Adds test for invalidate_block in vectors.rs
  • Adds new invalidated_blocks state to NonFinalizedState

Tests

Follow-up Work

PR Author's Checklist

  • The PR name will make sense to users.
  • The PR provides a CHANGELOG summary.
  • The solution is tested.
  • The documentation is up to date.
  • The PR has a priority label.

PR Reviewer's Checklist

  • The PR Author's checklist is complete.
  • The PR resolves the issue.

Elijah Hampton added 2 commits January 25, 2025 19:38
…se in vectors.rs. Updates non finalized state to track invalidated_blocks
@elijahhampton elijahhampton requested a review from a team as a code owner January 26, 2025 00:47
@elijahhampton elijahhampton requested review from arya2 and removed request for a team January 26, 2025 00:47
@elijahhampton
Copy link
Contributor Author

Closes #8840 , #8841

Copy link
Contributor

@arya2 arya2 left a comment

Choose a reason for hiding this comment

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

Thank you for getting this done.

This looks excellent. I left some optional suggestions, but none of them are blockers so feel free to resolve them without making changes if you'd like this to merge as-is.

Comment on lines +50 to +51
/// Invalidated blocks and descendants
invalidated_blocks: HashMap<block::Hash, InvalidatedBlockData>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Optional/Nitpick: Ideally this hash map or its values would be in an Arc, because Zebra clones the non-finalized state fairly frequently. It shouldn't be possible to update this field without access to the RPC server, so this would be cleanup, not a security issue.

I'm also wondering if this could be simplified to be HashMap<Hash, Arc<Vec<ContextuallyValidatedBlock>>> where the first item in the value is the explicitly invalidated block?

Suggested change
/// Invalidated blocks and descendants
invalidated_blocks: HashMap<block::Hash, InvalidatedBlockData>,
/// Blocks that have been invalidated in, and removed from, the non-finalized state
/// via the `invalidate` RPC method.
invalidated_blocks: Arc<HashMap<block::Hash, InvalidatedBlockData>>,

Comment on lines +311 to +314

self.update_metrics_for_chains();
self.update_metrics_bars();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

It should update the metrics whenever chain_set is modified.

Optional/Nitpick: This method could drop the chain and return early when the invalidated block is the non-finalized chain root block.

Suggested change
self.update_metrics_for_chains();
self.update_metrics_bars();
}
}
self.update_metrics_for_chains();
self.update_metrics_bars();

Comment on lines +238 to +245
/// Data related to an invalidated block including the [`ContextuallyVerifiedBlock`] and
/// descendants.
#[derive(Clone, Debug)]
pub struct InvalidatedBlockData {
/// The block that was invalidated.
pub block: ContextuallyVerifiedBlock,
/// All descendant blocks that were also removed in order by [`block::Height`].
pub descendants: BTreeMap<block::Height, ContextuallyVerifiedBlock>,
Copy link
Contributor

Choose a reason for hiding this comment

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

There's a suggestion below for removing this struct altogether, but if we're keeping it, minor documentation update:

Suggested change
/// Data related to an invalidated block including the [`ContextuallyVerifiedBlock`] and
/// descendants.
#[derive(Clone, Debug)]
pub struct InvalidatedBlockData {
/// The block that was invalidated.
pub block: ContextuallyVerifiedBlock,
/// All descendant blocks that were also removed in order by [`block::Height`].
pub descendants: BTreeMap<block::Height, ContextuallyVerifiedBlock>,
/// [`ContextuallyVerifiedBlock`]s that were invalidated via the `invalidate` RPC method
/// and removed from the non-finalized state, as well as any of their descendants that may
/// have also been removed.
#[derive(Clone, Debug)]
pub struct InvalidatedBlockData {
/// The block that was invalidated.
pub block: ContextuallyVerifiedBlock,
/// All child blocks of the invalidated block that were removed in order by [`block::Height`].
pub descendants: BTreeMap<block::Height, ContextuallyVerifiedBlock>,

Comment on lines +246 to +247
/// Timestamp in which the block was invalidated.
pub timestamp: SystemTime,
Copy link
Contributor

Choose a reason for hiding this comment

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

What's the intended purpose of this timestamp?

@arya2 arya2 added I-usability Zebra is hard to understand or use C-testing Category: These are tests A-rpc Area: Remote Procedure Call interfaces A-state Area: State / database changes C-feature Category: New features P-Medium ⚡ labels Jan 29, 2025
Comment on lines +286 to +293
let block_height = new_chain.height_by_hash(block_hash).unwrap();

// Split the new chain at the the `block_hash` and invalidate the block with the
// block_hash along with the block's descendants
let mut invalidated_blocks = new_chain.blocks.split_off(&block_height);
for (_, ctx_block) in invalidated_blocks.iter().rev() {
new_chain.revert_chain_with(ctx_block, chain::RevertPosition::Tip);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick/Optional: Ideally we could move this to a Chain method, like pop_tip() but which accepts a block hash and returns a list of ContextuallyValidatedBlocks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-rpc Area: Remote Procedure Call interfaces A-state Area: State / database changes C-feature Category: New features C-testing Category: These are tests I-usability Zebra is hard to understand or use P-Medium ⚡
Projects
None yet
2 participants