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

Improving blob propagation post-PeerDAS with Decentralized Blob Building #6268

Merged
merged 46 commits into from
Nov 15, 2024

Conversation

jimmygchen
Copy link
Member

@jimmygchen jimmygchen commented Aug 16, 2024

Issue Addressed

Built on top of #5829, an optimization came up by @michaelsproul, to fetch blobs from the EL to reduce the delay to block import.

This PR goes further to publish the blobs to the network, which helps improve the resiliency of the network, by having nodes with more resources contribute to blob propagation. This experimental solution is an attempt to solve the self building proposer bandwidth issue discussed on R&D Discord and described in @dankrad's post here.

The benefits of this proposals are:

  • Reduces block import latency: nodes can retrieve blobs from EL without waiting for them from gossip, hence making blocks attestable earlier.
  • Improves blob propagation and network resiliency: blob propagation work from is spread out from 1 node to the entire network, which reduces the likelihood of missed block due to delays in propagtion.
  • Allows scaling without sacrificing decentralization: nodes with more resources will participate in blob building and propagation, allowing nodes with limited bandwidth to continue to produce block post-PeerDAS.

Proposed Changes

  • Deneb: fetch_blobs_and_publish is triggered after a node has processed a gossip / rpc block and is still missing blob components. Once the node fetches the blob from EL, it then publishes the remaining blobs that hasn't seen on gossip to the network.
  • PeerDAS: Same trigger as above, however only supernodes will publish data columns that are unseen on gossip to the network.

Next steps:

  • To maintain low bandwidth for smaller stakers (single validator BN), we could allow some optimisation on block publish behaviour for these nodes only. There are some strategies proposed by @cskiraly to bring the outbound bandwidth requirements for a 32 blobs block to the same level as Deneb (6 blobs). However this wouldn't be recommended for nodes with enough bandwidth.
  • Collect some realistic metrics for a network with 32 blobs per block.

Challenges:

  • Current KZG libraries (c-kzg-4844 and rust-eth-kzg) may struggle with constructing large number of cells and proofs at once due to the current memory allocation approach.
  • Even if we are able reduce the bandwidth usage on the CL side, the bandwidth challenge remains on the EL side, as the node still need to pull the blob transactions into its mempool, to a lesser extent though, because:
    • it's dealing with raw blobs (4096kb for 32 blobs) rather than erasure coded blobs
    • it's pulled-based (eth/68) hence doesn't incur the same gossip amplification cost (8x) on the CL.

TODO before merging

Reference:

@jimmygchen jimmygchen added work-in-progress PR is a work-in-progress das Data Availability Sampling labels Aug 16, 2024
@jimmygchen jimmygchen marked this pull request as ready for review August 16, 2024 07:47
@jimmygchen jimmygchen added ready-for-review The code is ready for review and removed work-in-progress PR is a work-in-progress labels Aug 16, 2024
@jimmygchen
Copy link
Member Author

jimmygchen commented Aug 19, 2024

Some early testing results:

  • Proposers withholding all blobs propose blocks with blobs with 100% success rate
  • No outbound bandwidth spike for the full nodes with limited upload

Bandwidth-limited fullnode (cl-01) vs supernode (cl-02):

image
(Thanks to @KatyaRyazantseva for the dashboard above☺️ )

This shows EL inbound traffic (fetch blos from peers) isn't too bad for MAX 6 blobs
The outbound traffic for EL is less relevant here because it includes sending blobs to CL.

image

Next steps:

  • Add more metrics
    • Blocks made available via EL blobs
    • Number of blobs / data columns from EL blobs published
    • EL blob fetch timing
    • Compute cells and proof time
  • Make MAX_BLOBS_PER_BLOCK configurable
  • Try 32 blobs per block
    • EL gas constant update
    • Potential update on derived configs
    • Potential batching of KZG computation to avoid overflow
  • Add --limit-blob-publish (single validator only), which allows for lower mesh peers for data columns topics and withholding certain amount of data columns

@jimmygchen
Copy link
Member Author

This was originally intended experimental but it's been pretty stable, 800 epochs on devnet and 100% participation, and I think we can merge this.
I'll address the review comments, thanks @dapplion for the review 🙏

@dapplion
Copy link
Collaborator

Add --limit-blob-publish (single validator only), which allows for lower mesh peers for data columns topics and withholding certain amount of data columns

Bring the attack to prod

@kevaundray
Copy link
Contributor

@jimmygchen Any issues with the kzg libraries?

@jimmygchen
Copy link
Member Author

Bring the attack to prod

🙈 Trying to not mention the flag I use for testing. Luckily git blame on that line shows someone else's name haha

Just realized we need the execution-apis PR is merged before merge this - although there's probably no harm getting this one merged as soon as the inclusion is confirmed, as the fetch_blobs function handles this gracefully.

beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/beacon_chain.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/beacon_chain/src/fetch_blobs.rs Outdated Show resolved Hide resolved
beacon_node/network/src/network_beacon_processor/mod.rs Outdated Show resolved Hide resolved
consensus/types/src/beacon_block_body.rs Outdated Show resolved Hide resolved
@jimmygchen
Copy link
Member Author

@jimmygchen Any issues with the kzg libraries?

Nope all good so far! I was just flagging the potential challenges that I could imagine when we increase blob count, but I haven't actually run into any issues yet. Will keep you updated, thanks ☺️

@jimmygchen jimmygchen added spec_change A change related to the Eth2 spec optimization Something to make Lighthouse run more efficiently. labels Aug 20, 2024
@jimmygchen jimmygchen mentioned this pull request Aug 21, 2024
52 tasks
@jimmygchen jimmygchen added waiting-on-author The reviewer has suggested changes and awaits thier implementation. and removed ready-for-review The code is ready for review labels Aug 22, 2024
@mergify mergify bot deleted the branch sigp:unstable August 27, 2024 04:10
@mergify mergify bot closed this Aug 27, 2024
@michaelsproul michaelsproul reopened this Aug 27, 2024
@michaelsproul michaelsproul changed the base branch from das to unstable August 27, 2024 04:21
@jimmygchen
Copy link
Member Author

engine_getBlobsV1 now implemented in

@jimmygchen
Copy link
Member Author

jimmygchen commented Oct 30, 2024

I'm observing a few things from testing:

The node sometimes end up publishing all blobs, if the pending component is not found in availability cache after the block has been made available (cached_blob_indexes returns None below):

let blobs_to_publish = match chain
.data_availability_checker
.cached_blob_indexes(&block_root)
{
None => Either::Left(all_blobs_iter),
Some(imported_blob_indices) => Either::Right(
all_blobs_iter.filter(move |b| !imported_blob_indices.contains(&b.index())),
),
};
publish_fn(BlobsOrDataColumns::Blobs(
blobs_to_publish.collect::<Vec<_>>(),
));

The evidence is that we also see a blob processing error DuplicateFullyImported when trying to process the already imported blobs:

Oct 30 10:06:02.780 DEBG Fetching blobs from the EL, num_expected_blobs: 6, block_root: 0x8ae0291f630ab24311fa859a2e86c6fb8995fb2df420516ecbbe3a8eaa339ebf, service: fetch_engine_blobs, service: beacon, module: beacon_chain::fetch_blobs:78
Oct 30 10:06:02.968 DEBG Processing engine blobs, num_fetched_blobs: 6, block_root: 0x8ae0291f630ab24311fa859a2e86c6fb8995fb2df420516ecbbe3a8eaa339ebf, service: fetch_engine_blobs, service: beacon, module: beacon_chain::fetch_blobs:170
Oct 30 10:06:02.968 ERRO Error fetching or processing blobs from EL, block_hash: 0x8ae0291f630ab24311fa859a2e86c6fb8995fb2df420516ecbbe3a8eaa339ebf, error: BlobProcessingError(DuplicateFullyImported(0x8ae0291f630ab24311fa859a2e86c6fb8995fb2df420516ecbbe3a8eaa339ebf)), module: network::network_beacon_processor:937
Oct 30 10:06:03.871 DEBG Batch blob publication complete, block_root: 0x8ae0291f630ab24311fa859a2e86c6fb8995fb2df420516ecbbe3a8eaa339ebf, published_count: 6, blob_count: 6, batch_interval: 300, service: beacon, module: network::network_beacon_processor:1066

Possible solution:

  1. Check fork choice again before publishing and processing engine blobs
  2. Downgrade error BlockError::DuplicateFullyImported to a debug log, as this race can sometimes happens

UPDATE: I think a better solution would be gossip verifying the blobs prior to publishing - this is consistent with our blob publishing logic and if the blob has already been observed, then we would get GossipBlobError::RepeatBlob and not publish and process the duplicate blob.

@jimmygchen
Copy link
Member Author

@dapplion @michaelsproul
I've made a few more changes and have tested this locally. This is ready for review now:

  • Fix invalid inclusion proof for EL blobs
  • Only publish blobs triggered from gossip block and not RPC blocks

I'll deploy this to some testnet nodes.

@jimmygchen
Copy link
Member Author

Some findings from mainnet testing from a small sample size:

  • EL getBlobs only gets triggered once roughly every ~5-10 mins. This is likely because relays publish blobs before blocks. This may change in the future though when blob count increases, or if nodes prioritise block publishing.
  • Interestingly, the pattern is very inconsistent (sometimes getBlobs could get triggered for 5-6 consecutive blocks), and it seems to be happen more on ultrasound relay and non builder blocks. (perhaps they don't prioritise sending blobs as much as other relays?)
  • A large percentage of them are blocks with 5 or 6 blobs - which is what we expect, as proposer would have to disseminate more blob data to its peers and more likely to have delays.
  • With the gradual publication optimisation, we only publish about 1 blob roughly every 10 mins, so it should have minimal impact on outbound bandwidth.

@michaelsproul michaelsproul added ready-for-merge This PR is ready to merge. and removed ready-for-review The code is ready for review labels Nov 15, 2024
@michaelsproul
Copy link
Member

@mergify queue

Copy link

mergify bot commented Nov 15, 2024

queue

✅ The pull request has been merged automatically

The pull request has been merged automatically at 5f053b0

mergify bot added a commit that referenced this pull request Nov 15, 2024
@jimmygchen
Copy link
Member Author

One more thing I was thinking about - we may not want to always fetch blobs on rpc response, as it only makes sense / works if we're close to the head slot, but I guess process_rpc_block only happens if we're close to the head (block lookup and head sync), so I don't think there's anything we need to address here, but just wanted to keep a note.

Ok(AvailabilityProcessingStatus::MissingComponents(..)) => {
// Block is valid, we can now attempt fetching blobs from EL using version hashes
// derived from kzg commitments from the block, without having to wait for all blobs
// to be sent from the peers if we already have them.
let publish_blobs = false;
self.fetch_engine_blobs_and_publish(signed_beacon_block, block_root, publish_blobs)
.await
}

@mergify mergify bot merged commit 5f053b0 into sigp:unstable Nov 15, 2024
29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
das Data Availability Sampling optimization Something to make Lighthouse run more efficiently. ready-for-merge This PR is ready to merge. spec_change A change related to the Eth2 spec v6.0.0 New major release for hierarchical state diffs
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants