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

Simplify into_responses_with_blobs logic #6927

Open
wants to merge 4 commits into
base: unstable
Choose a base branch
from

Conversation

dapplion
Copy link
Collaborator

@dapplion dapplion commented Feb 6, 2025

Issue Addressed

Proposed Changes

The job of into_responses_with_blobs is to match block and blobs with the same block root. We can just use a HashMap and remove 41 lines of code.

@dapplion dapplion requested a review from jxs as a code owner February 6, 2025 13:48
@dapplion dapplion requested review from pawanjay176 and removed request for jxs February 6, 2025 13:48
@dapplion dapplion force-pushed the into_responses_with_blobs branch from e7d0352 to dd29c33 Compare February 6, 2025 13:58
@realbigsean realbigsean self-requested a review February 6, 2025 18:14
@realbigsean
Copy link
Member

looks like there's a failing test here

Copy link
Member

@pawanjay176 pawanjay176 left a comment

Choose a reason for hiding this comment

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

Looks good.
The one issue I see with this is we aren't enforcing the order of the blobs based on the index of the sidecars.
We will throw the error as KzgCommitmentMismatch when trying to build the rpc block. Not sure if this would be an issue.

Edit: Actually the spec requires the sender to send it in the right order, so we were being quite permissive before

The following blob sidecars, where they exist, MUST be sent in consecutive (slot, index) order

Edit 2: I think it is fine

Copy link
Member

@pawanjay176 pawanjay176 left a comment

Choose a reason for hiding this comment

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

LGTM

@dapplion
Copy link
Collaborator Author

dapplion commented Feb 7, 2025

Actually the spec requires the sender to send it in the right order, so we were being quite permissive before

We can enforce that if we want, but why would we do so if we don't need to? If we had some optimization we can expect that behaviour but I don't see any damage to us from peers sending blobs or blocks out of order

Ok(responses)
// Now collect all blobs that match to the block by block root. BlobsByRange request checks
// the inclusion proof so we know that the commitment is the expected.
// RpcBlock::new ensures that the count of blobs is consistent with the block
Copy link
Member

Choose a reason for hiding this comment

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

We don't actually perform the check if the blob list is empty or None.
Seems like it's worth checking in both cases?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed with 16c95f0

.map(|block| {
let block_root = get_block_root(&block);
let max_blobs_per_block = spec.max_blobs_per_block(block.epoch()) as usize;
let blobs = blobs_by_block.remove(&block_root).unwrap_or_default();
Copy link
Member

Choose a reason for hiding this comment

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

The existing code ensures the blobs are in order, and i think our code does assume they are - I think we should make sure they're in order here?

Copy link
Member

@jimmygchen jimmygchen Feb 14, 2025

Choose a reason for hiding this comment

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

Oh sorry just read Pawan's comment above.

but I don't see any damage to us from peers sending blobs or blocks out of order

Can you confirm this? IIRC we have some assumptions on the blob order in the code somewhere.

Copy link
Member

Choose a reason for hiding this comment

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

There's one here but it's not affected by this change, although i feel like we should remove the assumption here

// NOTE: assumes blob sidecars are ordered by index
let blob_cells_and_proofs_vec = blobs
.into_par_iter()
.map(|blob| {
let blob = blob
.as_ref()
.try_into()
.expect("blob should have a guaranteed size due to FixedVector");
kzg.compute_cells_and_proofs(blob)
})
.collect::<Result<Vec<_>, KzgError>>()?;

Also the comment here mentions the assumption too:

/// This variant is used with parent lookups and by-range responses. It should have all blobs
/// ordered, all block roots matching, and the correct number of blobs for this block.
BlockAndBlobs(Arc<SignedBeaconBlock<E>>, BlobSidecarList<E>),

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

b983fa9 enforces ordered responses on all by_range requests

@jimmygchen jimmygchen added the waiting-on-author The reviewer has suggested changes and awaits thier implementation. label Feb 14, 2025
}
}
if block.num_expected_blobs() != blobs.as_ref().map(|blobs| blobs.len()).unwrap_or(0) {
return Err(AvailabilityCheckError::MissingBlobs);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Now we always check that the blob count is consistent with the block regardless of empty list or None.

for (blob, &block_commitment) in blobs.iter().zip(block_commitments.iter()) {
let blob_commitment = blob.kzg_commitment;
if blob_commitment != block_commitment {
return Err(AvailabilityCheckError::KzgCommitmentMismatch {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We don't need to check the commitment equivalence anymore because:

  • We check the inclusion proof of each blob
  • We match blobs and blocks by block root

Therefore it's impossible for the commitment to not be equivalent

Ok(responses)
// Now collect all blobs that match to the block by block root. BlobsByRange request checks
// the inclusion proof so we know that the commitment is the expected.
// RpcBlock::new ensures that the count of blobs is consistent with the block
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Fixed with 16c95f0

Comment on lines +51 to +53
return Err(LookupVerifyError::DuplicatedData(blob.slot(), blob.index));
} else if blob.index != prev.index + 1 {
return Err(LookupVerifyError::NotSorted("non-sequential indices"));
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We could group these two conditions into the "non-sequential" one. But I feel it's good to know if a sender is faulty due to duplicate data or non-sequential

@dapplion dapplion added ready-for-review The code is ready for review and removed waiting-on-author The reviewer has suggested changes and awaits thier implementation. labels Feb 17, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
ready-for-review The code is ready for review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants